对于搜索引擎来说,在键入搜索关键词的过程中进行自动提词是个重要的功能,es对此也提供了支持。
这个功能是不是有点类似于prefixquery呢,看上去是的。但是,prefixquery是否会符合条件的doc,而自动提词是返回符合条件的term。所以二者不能混为一谈。因此suggestion模块出现了。我们聚焦下complete。
1:为什么需要一个的单独的suggest?
速度为先:为了提词,一个完整的查询需要检索太多个term,这并不足够快。而自动提词必须是超级快的,不能等待,因此es用了一个叫FST的内存数据结构,来存储term,以此来达到足够快的检索速度。
实时性:es是以实时性著称的。如果在内存中构建FST,则比如要把所有数据都加载进来,这个代价是蛮大的。而且一旦数据发生改变,还需要重建fst,这显然是不合理的。为了达到实时性,es把FST的构建过程从查询阶段放到了没一个segment产生的索引阶段,一个新的segment产生将伴随这个一个fst文件。而这个fst文件载入内存是非常快的。这里会有多个fst文件,因此最终的提词结果是对多个fst文件的汇总。
可读性:用户的输入可能是多种多这样的,比如一个提示词是“Courtyard by Marriot, Munich City”,当用户输入"countyard munich"或者"munich hotel"的时候,都希望能够给出前边的提示词对应的具体信息。我们给出的提示应该是尽量明确,没有疑义的,因此当用户输入上述任何一个短语的时候,我们都应该给出可读性强的提示“Courtyard by Marriot, Munich City”。
提词顺序的定制性:对于一个查询的返回结果,会考虑tf/idf等因素。而对于提词结果,用户可能需要完全的定制。比如希望将折扣比较大的酒店排在最前边等等。
基于这些原因,es提供了一个单独的suggest来完成提词。
2:Completion Suggest的一些设置
多个输入的设定:由FST的结构限制,是从左到右匹配的。所以,为了更灵活的给出题词,可以设定多个输入,这多个输入都对应同样的逻辑意义,无论输入哪一个输入都应该给出正确的题词。设定需要题词字段的input属性即可。
同一的题词:output属性其实是规定了希望给出用户的题词是什么,而不是FST里边保存的term。比如input输入为“Mercure Hotel Munich”,按照从正常题词,如果text设定为M,则会提示Mercure Hotel Munich,而如果设定了output为hotel mercure,则给出的题词为output的内容。
权重问题:设置weight。不同的doc希望用户不同的权重,作用于suggest上,权重高的顺序靠前。如果不设定weight,es会按照查询期间的tf来决定。
用户自定义的信息:payload可以设定一个json结构的字符串,来携带用户自定义的信息。比如可以设定为docid,这样当给出题词的同时,也把docid返回给了用户,用户可以直接浏览这个doc的信息。
同义词:跟查询一样,同义词同样适用,设定对应的filter即可。
忽略停用词:注意了,completion suggest的mapping中默认的index_analyzer是simple analyzer而不是standard analyzer。为什么呢?还是停用词的问题。对于"The Charles hotel",当用户输入"Charles"的时候,应该给出正确的题词,但是却不是这样的,因为stop token filter虽然移除了停用词,但在FST中留下了一个空白符,因此题词以一个空白符开头了,所以会出现问题。为了移除这个空白符,可以设定preserve_position_increments
和preserve_separators为false。
是否应该忽略停用词也是个让人纠结的事情,比如"Simon the Sorcerer",当用户输入"Simon t"的时候,如果忽略了停用词,则无法提词,因为t本身不是停用词。所以为了得到更好的提词结果,我们得充分利用多个输入来表明所有的输入情况,得到正确的提词结果(是不是复杂了。。。)。恩。
以后的计划:
es会针对停用词这块进行处理,另外会支持fuzzy。
版权声明:本文为博主原创文章,未经博主允许不得转载。