ElasticSearch - 輸入即搜尋 edge n-gram
-
在此之前,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" } } } } }
-
-
-
-