Elasticsearch: Ngrams, edge ngrams, and shingles
Ngrams 和 edge ngrams 是在 Elasticsearch 中 token 文本的兩種更獨特的方式。 Ngrams 是一種將一個 token 分成一個單詞的每個部分的多個子字符的方法。 ngram 和 edge ngram 過濾器都允許你指定 min_gram 以及 max_gram 設置。 這些設置控制單詞被分割成的 token 的大小。 這可能令人困惑,讓我們看一個例子。 假設你想用 ngram 分析儀分析 “spaghetti” 這個詞,讓我們從最簡單的情況開始,1-gams(也稱為 unigrams)。
在實際的搜索例子中,比如谷歌搜索:
每當我們打入前面的幾個字母時,就會出現相應的很多的候選名單。這個就是 autocomplete 功能。在 Elasticsearch 中,我們可以通過 Edge ngram 來實現這個目的。
1-grams
“spaghetti” 的 1-grams 是 s,p,a,g,h,e,t,t,i。 根據 ngram 的大小將字符串拆分為較小的 token。 在這種情況下,每個 token 都是一個字符,因為我們談論的是 unigrams。
Bigrams
如果你要將字符串拆分為雙字母組(這意味著大小為2),你將獲得以下較小的 token:sp,pa,ag,gh,he,et,tt,ti。
Trigrams
再說一次,如果你要使用三個大小,你將得到 token 為 spa,pag,agh,ghe,het,ett,tti。
設置 min_gram 和 max_gram
使用此分析器時,需要設置兩種不同的大小:一種指定要生成的最小 ngrams(min_gram 設置),另一種指定要生成的最大 ngrams。 使用前面的示例,如果你指定 min_gram 為 2 且 max_gram 為 3,則你將獲得前兩個示例中的組合分詞:
sp, spa, pa, pag, ag, agh, gh, ghe, he, het, et, ett, tt, tti, ti如果你要將 min_gram 設置為1并將 max_gram 設置為3,那么你將得到更多的 token,從 s,sp,spa,p,pa,pag,a,....開始。
以這種方式分析文本具有一個有趣的優點。 當你查詢文本時,你的查詢將以相同的方式被分割成文本,所以說你正在尋找拼寫錯誤的單詞“ spaghety”。搜索這個的一種方法是做一個?fuzzy query,它允許你 指定單詞的編輯距離以檢查匹配。 但是你可以通過使用 ngrams 來獲得類似的行為。 讓我們將原始單詞(“spaghetti”)生成的 bigrams 與拼寫錯誤的單詞(“spaghety”)進行比較:
- “spaghetti” 的 bigrams:sp,pa,ag,gh,he,et,tt,ti
- “spaghety” 的 bigrams:sp,pa,ag,gh,he,et,ty
你可以看到六個 token 重疊,因此當查詢包含 “spaghety” 時,其中帶有 “spaghetti” 的單詞仍然匹配。請記住,這意味著你可能不打算使用的原始 “spaghetti” 單詞更多的單詞 ,所以請務必測試你的查詢相關性!
ngrams 做的另一個有用的事情是允許你在事先不了解語言時或者當你使用與其他歐洲語言不同的方式組合單詞的語言時分析文本。 這還有一個優點,即能夠使用單個分析器處理多種語言,而不必指定。
Edge ngrams
常規 ngram 拆分的變體稱為 edge ngrams,僅從前沿構建 ngram。 在 “spaghetti” 示例中,如果將 min_gram 設置為2并將 max_gram 設置為6,則會獲得以下 token:
sp, spa, spag, spagh, spaghe你可以看到每個 token 都是從邊緣構建的。 這有助于搜索共享相同前綴的單詞而無需實際執行前綴查詢。 如果你需要從一個單詞的后面構建 ngrams,你可以使用 side 屬性從后面而不是默認前面獲取邊緣。
它和 ngram 的區別在于:
Ngram 設置
當你不知道語言是什么時,Ngrams 是分析文本的好方法,因為它們可以分析單詞之間沒有空格的語言。 使用 min 和 max grams 配置 edge ngram analyzer 的示例如下所示:
PUT my_index {"settings": {"analysis": {"analyzer": {"my_analyzer": {"tokenizer": "my_tokenizer"}},"tokenizer": {"my_tokenizer": {"type": "edge_ngram","min_gram": 2,"max_gram": 10,"token_chars": ["letter","digit"]}}}} }我們可以用剛才創建的 my_tokenizer 來分析我們的字符串:
POST my_index/_analyze {"analyzer": "my_analyzer","text": "2 Quick Foxes." }顯示的結果是:
{"tokens" : [{"token" : "Qu","start_offset" : 2,"end_offset" : 4,"type" : "word","position" : 0},{"token" : "Qui","start_offset" : 2,"end_offset" : 5,"type" : "word","position" : 1},{"token" : "Quic","start_offset" : 2,"end_offset" : 6,"type" : "word","position" : 2},{"token" : "Quick","start_offset" : 2,"end_offset" : 7,"type" : "word","position" : 3},{"token" : "Fo","start_offset" : 8,"end_offset" : 10,"type" : "word","position" : 4},{"token" : "Fox","start_offset" : 8,"end_offset" : 11,"type" : "word","position" : 5},{"token" : "Foxe","start_offset" : 8,"end_offset" : 12,"type" : "word","position" : 6},{"token" : "Foxes","start_offset" : 8,"end_offset" : 13,"type" : "word","position" : 7}] }因為我們定義的 min_gram 是2,所以生成的 token 的長度是從2開始的。
通常我們建議在索引時和搜索時使用相同的分析器。 在 edge_ngram tokenizer 的情況下,建議是不同的。 僅在索引時使用 edge_ngram?token 生成器才有意義,以確保部分單詞可用于索引中的匹配。 在搜索時,只需搜索用戶輸入的術語,例如:Quick Fo。
下面是如何為搜索類型設置字段的示例:
PUT my_index {"settings": {"analysis": {"analyzer": {"autocomplete": {"tokenizer": "autocomplete","filter": ["lowercase"]},"autocomplete_search": {"tokenizer": "lowercase"}},"tokenizer": {"autocomplete": {"type": "edge_ngram","min_gram": 2,"max_gram": 10,"token_chars": ["letter"]}}}},"mappings": {"properties": {"title": {"type": "text","analyzer": "autocomplete","search_analyzer": "autocomplete_search"}}} }在我們的例子中,我們索引時和搜索時時用了兩個不同的 analyzer:autocomplete 及 autocomplete_search。
PUT my_index/_doc/1 {"title": "Quick Foxes" }POST my_index/_refresh上面我們加入一個文檔。下面我們來進行搜索:
GET my_index/_search {"query": {"match": {"title": {"query": "Quick Fo", "operator": "and"}}} }顯示結果:
{"took" : 3,"timed_out" : false,"_shards" : {"total" : 1,"successful" : 1,"skipped" : 0,"failed" : 0},"hits" : {"total" : {"value" : 1,"relation" : "eq"},"max_score" : 0.5753642,"hits" : [{"_index" : "my_index","_type" : "_doc","_id" : "1","_score" : 0.5753642,"_source" : {"title" : "Quick Foxes"}}]} }在這里 autocomplete analyzer 可以把字符串 “Quick Foxes” 分解為[qu, qui, quic, quick, fo, fox, foxe, foxes]。而自 autocomplete_search analyzer 搜索條目[quick,fo],兩者都出現在索引中。
當然我們也可以做如下的搜索:
GET my_index/_search {"query": {"match": {"title": {"query": "Fo"}}} }顯示的和上面一樣的結果。
Shingles
與 ngrams 和 edge ngrams一樣,有一個稱為 shingle 的過濾器(不,不是疾病的那個shingle!)。 Shingle token 過濾器基本上是 token 級別的 ngrams 而不是字符級別。
想想我們最喜歡的單詞 “spaghetti”。使用最小和最大設置為 1 和 3 的 ngrams,Elasticsearch 將生成分詞?s,sp,spa,p,pa,pag,a,ag等。 一個 shingle 過濾器在 token 級別執行此操作,因此如果你有文本 “foo bar baz” 并再次使用 in_shingle_size 為?2 且 max_shingle_size 為 3,則你將生成以下 token:
為什么仍然包含單 token 輸出? 這是因為默認情況下,shingle 過濾器包含原始 token,因此原始 token 生成令牌 foo,bar 和 baz,然后將其傳遞給 shingle token 過濾器,生成分詞 foo bar,foo bar baz 和 bar baz。 所有這些 token 組合在一起形成最終 token 流。 你可以通過將 output_unigrams 選項設置為 false 來禁用此行為,也即不需要最原始的 token:foo, bar 及 baz
下一個清單顯示了 shingle token 過濾器的示例; 請注意,min_shingle_size 選項必須大于或等于2。
PUT my_index {"settings": {"analysis": {"analyzer": {"shingle": {"type": "custom","tokenizer": "standard","filter": ["shingle-filter"]}},"filter": {"shingle-filter": {"type": "shingle","min_shingle_size": 2,"max_shingle_size": 3,"output_unigrams": false}}}} }在這里,我們定義了一個叫做 shingle-filter 的過濾器。最小的 shangle 大小是2,最大的 shingle 大小是3。同時我們設置 output_unigrams 為 false,這樣最初的那些 token 將不被包含在最終的結果之中。
下面我們來做一個例子,看看顯示的結果:
GET /my_index/_analyze {"text": "foo bar baz","analyzer": "shingle" }顯示的結果為:
?
參考:
【1】?Edge NGram Tokenizer | Elasticsearch Guide [7.3] | Elastic
總結
以上是生活随笔為你收集整理的Elasticsearch: Ngrams, edge ngrams, and shingles的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Photoshop cs6 如何让图层渐
- 下一篇: 计算机右键菜单太多,鼠标右键菜单选项太多