-
在此之前,ES所有的查询都是针对整个词进行操作,也就是说倒排索引存了
hello
这个词,一定得输入hello才能找到这个词,输入 h 或是 he 都找不到倒排索引中的hello
-
然而在现实情况下,用户已经渐渐习惯在输入完查询内容之前,就能为他们展现搜索结果,这就是所谓的即时搜索(instant search),或是可以称为 输入即搜索(search-as-you-type)
-
虽然ES提供了一系列的前缀搜索match_phrase、prefix、wildcard、regexp,然而这样的查询的性能非常差,要知道用户每多输入一个新的字母,就意味著要重新进行一次搜索,在实时的web系统中,100毫秒可能就会是一个难以忍受的延迟
-
因此为了加快 输入即搜索 的查询效率,可以改使用
edge n-gram
建立索引,如此可以避免使用前缀查询,在建立索引时就进行优化,使用空间换取时间,让查询的速率增快
-
-
使用
edge n-gram
建立索引-
假设有一个词
hello
,普通建索引时,就是把这个词hello
放入倒排索引-
用户输入h、he时会找不到索引(倒排索引中只有hello),因此匹配失败
-
-
而对于输入即搜索这种应用场景,可以使用一种特殊的n-gram,称爲 边界n-grams (edge n-grams)
-
所谓的edge n-gram,就是指它会固定词语开始的一边滑动窗口,他的结果取决于 n 的选择长度
-
以单词
hello
爲例,它的edge n-gram的结果如下h he hel hell hello
-
因此可以发现到,在使用edge n-gram建索引时,一个单词会生成好几个索引,而这些索引一定是重头开始
-
这符合了输入即搜索的特性,即是用户打h、he能找到倒排中的索引
h
、he
,而这些索引对应著的数据就是hello
-
-
-
具体实例
-
建立索引时使用edge n-gram的token过滤器,为每个经过这个token过滤器的词条们,都生成从头开始的字符组合
-
假设有一个输入
QUICK! RUN!
,分词器会先将它分词成两个词quick
和run
,此时这些词再一一的通过edge n-gram token过滤器,产生了8个索引q、qu、qui、quic、quick、r、ru、run,接著存入倒排索引中 -
如此,任何词条像是quick、run,都能生成他们自己的n-gram
-
-
另外要注意,要额外定义一个
search_analyzer
分析器,供查询使用-
原因是因为我们为了要保证倒排索引中包含各种组合的词,所以在建索引时才加入了edge n-gram过滤器,然而在查询时,我们只想匹配用户输入的完整词组,像是用户的输入
run
或qu
-
因此需要定义两套分析器,一套是建索引的分析器(包含edge n-gram过滤器),另一套是查询使用的正常的分析器
PUT 127.0.0.1:9200/my_index { "settings": { "number_of_shards": 1, "analysis": { "filter": { //定义一个edge n-gram的token过滤器,并设置任何通过这个过滤器的词条,都会生成一个最小固定值为1,最大固定值为20的n-gram "my_autocomplete_filter": { "type": "edge_ngram", "min_gram": 1, "max_gram": 20 } }, "analyzer": { //自定义一个分析器,并使用自定义的edge n-gram过滤器 "my_autocomplete_analyzer": { "type": "custom", "tokenizer": "standard", "filter": [ "lowercase", "my_autocomplete_filter" ] } } } }, "mapping": { "my_type": { "properties": { "name": { "type": "text", "analyzer": "my_autocomplete_analyzer", //在索引时用,生成edge n-gram的每个词 "search_analyzer": "standard" //查询用,只搜索用户输入的词 } } } } }
-
-
让非text字段也能使用edge n-gram
-
由于edge n-gram是一个token过滤器,他包含在analyzer分析器裡面,因此只有
text
类型的字段才能使用 (其他类型的字段不会被分词,所以不会使用到analyzer,因此不能用edge n-gram) -
但是可能会有一种情况是,有些精确值也希望能通过edge n-gram生成组合,这时就要搭配使用一个叫做
keyword
的分词器-
注意,此
keyword
分词器和keyword
字段类型是不同的东西 -
keyword分词器主要的功用是,将输入的词条,原封不动的output出来,不对其内容做任何改变
-
因此可以利用这个特性,将精确值的字段类型改成text,但是分词器使用keyword,如此就可以避免分词的效果,又能使用edge n-gram
-
-
具体实例
-
将postcode这个本来是keyword类型的精确值,改成使用text类型并搭配keyword分词器
-
因此假设有一个输入
ABC EF
,先经过keyword分词器分词成ABC EF
(和输入一模一样),接著再经过edge n-gram生成A、AB、ABC、ABC (有一个空格) 、ABC E、ABC EF-
如果是使用正常的分词器,生成的edge n-gram会是A、AB、ABC、E、EF,是有差别的
PUT 127.0.0.1:9200/my_index { "settings": { "analysis": { "filter": { "postcode_filter": { "type": "edge_ngram", "min_gram": 1, "max_gram": 8 } }, "analyzer": { "postcode_index": { "tokenizer": "keyword", "filter": [ "postcode_filter" ] }, "postcode_search": { "tokenizer": "keyword" } } } }, "mapping": { "my_type": { "properties": { "postcode": { "type": "text", "analyzer": "postcode_index", "search_analyzer": "postcode_search" } } } } }
-
-
-
-
ElasticSearch - 输入即搜索 edge n-gram
猜你喜欢
转载自blog.csdn.net/weixin_40341116/article/details/81842989
今日推荐
周排行