-
在此之前,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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.