目錄html
昨天是感恩節,上幼兒園的女兒在老師的叮囑下,晚上爲我和老婆洗了腳(形式上的^_^),還給咱們每人端了一杯水。看着孩子一每天的長大,懂事,感受很開心,話說我們程序員這麼辛苦是爲了什麼?不就是爲了老婆,孩子,熱炕頭,有一個溫暖幸福的家庭,再捎帶着用代碼改變一下世界嗎?想到這裏,頓時以爲學習,創做博客的勁頭也的更足了。哈哈,扯遠了,書歸正傳,今天咱們來聊聊 Match Query。java
Match Query 是最經常使用的 Full Text Query 。不管須要查詢什麼字段, match
查詢都應該會是首選的查詢方式。它既能處理全文字段,又能處理精確字段。程序員
爲了可以在後面能深刻理解 Match Query 中的各個屬性的意義,咱們先構建一個 index 示例(有興趣的同窗只要將下面字段粘貼到 sense 中就能夠建立)。json
PUT matchtest { } PUT matchtest/_mapping/people { "properties": { "age": { "type": "integer" }, "hobbies": { "type": "text" }, "name": { "type": "keyword" } } } PUT matchtest/people/1 { "name" : "Jim", "age": 10, "hobbies": "football, basketball, pingpang" } PUT matchtest/people/2 { "name" : "Tom", "age": 12, "hobbies": "swimming, football" }
match
查詢是一種 bool
類型的查詢。什麼意思呢?舉個例子,查詢 people type 的 hobbies 爲 football basketball
api
GET matchtest/people/_search { "query": { "match": { "hobbies": "football basketball" } } }
會將上面的兩個文檔都搜索出來。爲何?上面的查詢其實隱藏了一個默認參數operator
, 它的默認值是 or
,也就是說上面的查詢也能夠寫成這種形式app
GET matchtest/people/_search { "query": { "match": { "hobbies": { "query": "football basketball", "operator": "or" } } } }
這樣就比較容易理解了,既然是 or
操做符,就表示只要查詢的文檔的 hobbies
字段中含有 football
和 basketball
任意一個,就能夠被匹配到。elasticsearch
若是將 operator
操做符的值改成 and
,則表示須要同時包含 football
和 basketball
, 獲得的結果就只能是 文檔 1 Jim 小朋友了。ide
analyzer
屬性是指在對查詢文本分析時的分析器學習
這裏咱們也沒有指定,就會使用默認的,就不舉例了,在後面文章講解 analyzer 時再拓展。優化
默認值是 false
, 表示用來在查詢時若是數據類型不匹配且沒法轉換時會報錯。若是設置成 true
會忽略錯誤。
例如, 例子中的 age
是 integer
類型的,若是查詢 age=xxy
,就會致使沒法轉換而報錯。
GET matchtest/_search { "query": { "match": { "age" : { "query": "xxx" } } } }
而若是將 lenient
參數設置爲 true
,就會忽略這個錯誤
GET matchtest/_search { "query": { "match": { "age" : { "query": "xxx", "lenient": true } } } }
注意,若是將 age
字段的值設置爲字符串 "10", 來查詢,因爲可以轉換成整數,這時 elastic 內部會將 字符串先轉換成整數再作查詢,不會報錯。
fuzziness
參數可使查詢的字段具備模糊搜索的特性。來先了解下什麼是模糊搜索。
模糊搜索是指系統容許被搜索信息和搜索提問之間存在必定的差別,這種差別就是「模糊」在搜索中的含義。例如,查找名字Smith時,就會找出與之類似的Smithe, Smythe, Smyth, Smitt等。
——百度百科
經過模糊搜索能夠查詢出存在必定類似度的單詞,那麼怎麼計算兩個單詞是否有類似度以及類似度的大小呢?這就要了解下另一個概念:Levenshtein Edit Distance
Levenshtein Edit Distance 叫作萊文斯坦距離**,是編輯距離的一種。指兩個字串之間,由一個轉成另外一個所需的最少編輯操做次數。容許的編輯操做包括將一個字符替換成另外一個字符,插入一個字符,刪除一個字符。
例如,單詞 "god" 只須要插入一個 'o' 字符就能夠變爲 "good",所以它們之間的編輯距離爲 1。
瞭解了上面兩個概念,回過頭再來看下 fuzziness
參數。
在查詢 text
或者 keyword
類型的字段時, fuzziness
能夠看作是萊文斯坦距離。
fuzziness
參數的取值以下
0,1,2
表示最大可容許的萊文斯坦距離
AUTO
會根據詞項的長度來產生可編輯距離,它還有兩個可選參數,形式爲AUTO:[low],[high]
, 分別表示短距離參數和長距離參數;若是沒有指定,默認值是 AUTO:3,6
表示的意義以下
0..2
單詞長度爲 0 到 2 之間時必需要精確匹配,這其實很好理解,單詞長度過短是沒有類似度可言的,例如 'a' 和 'b'。
3..5
單詞長度 3 到 5 個字母時,最大編輯距離爲 1
>5
單詞長度大於 5 個字母時,最大編輯距離爲 2
最佳實踐: fuzziness
在絕大多數場合都應該設置成 AUTO
若是不設置 fuziness
參數,查詢是精確匹配的。
來看例子,上面建立了一個 doc
PUT matchtest/people/1 { "name" : "Jim", "age": 10, "hobbies": "football, basketball, pingpang" }
設置 fuzziness
爲 AUTO
,
hobbies
字段的值 football
長度 > 5, 此時咱們找一個編輯距離爲 2 的單詞 footba22
來查詢,應該匹配到name
字段的值 jim
長度在 3 和 5 之間,此時找一個編輯距離爲 1 的單詞 jiO
應匹配到,而編輯距離爲 2 的 jOO
就不該匹配到。來,驗證下
GET matchtest/_search { "query": { "match": { "hobbies": { "query": "footba22", "fuzziness": "AUTO" } } } } GET matchtest/_search { "query": { "match": { "name": { "query": "jiO", "fuzziness": "AUTO" } } } } GET matchtest/_search { "query": { "match": { "name": { "query": "jOO", "fuzziness": "AUTO" } } } }
prefix_length
表示不能沒模糊化的初始字符數。因爲大部分的拼寫錯誤發生在詞的結尾,而不是詞的開始,使用 prefix_length
就能夠完成優化。注意 prefix_length
必須結合 fuzziness
參數使用。
例如,在查詢 hobbies
中的 football
時,將 prefix_length
參數設置爲 3,這時 foatball
將不能被匹配。
GET matchtest/_search { "query": { "match": { "hobbies": { "query": "foatball", "fuzziness": "AUTO", "prefix_length": 3 } } } }
TODO(max_expansions 參數對於 match 查詢而言,沒理解表示的意義,若是您知道這個參數的用法,請給我留言告知,不勝感謝! )
先看例子, 先建立一個文檔 zero_terms_query_test
其中 message
字段使用 stop
分析器,這個分析器會將 stop words 停用詞在索引時全都去掉。
PUT matchtest1 PUT matchtest1/_mapping/zero_terms_query_test { "properties": { "message": { "type": "text", "analyzer": "stop" } } } PUT matchtest1/zero_terms_query_test/1 { "message": "to be or not to be" } GET matchtest1/_search { "query": { "match": { "message": { "query": "to be or not to be", "operator": "and", "zero_terms_query": "none" } } } }
那麼就像 message 字段中的 to be or not to be
這個短語中所有都是中止詞,一過濾,就什麼也沒有了,得不到任何 tokens, 那搜索時豈不什麼都搜不到。
POST _analyze { "analyzer": "stop", "text": "to be or not to be" }
zero_terms_query
就是爲了解決這個問題而生的。它的默認值是 none
,就是搜不到中止詞(對 stop 分析器字段而言),若是設置成 all
,它的效果就和 match_all
相似,就能夠搜到了。
GET matchtest1/_search { "query": { "match": { "message": { "query": "to be or not to be", "operator": "and", "zero_terms_query": "all" } } } }
查詢字符串時的詞項會分紅低頻詞(更重要)和高頻詞(次重要)兩類,像前面所說的停用詞 (stop word)就屬於高頻詞,它雖然出現頻率較高,但在匹配時可能並不太相關。實際上,咱們每每是想要文檔能儘量的匹配那些低頻詞,也就是更重要的詞項。
要實現這個需求,只要在查詢時配置 cutoff_frequency
參數就能夠了。假設咱們將 cutoff_frequency
設置成 0.01
就表示
從而將高頻詞(次重要的詞)挪到可選子查詢中,讓它們只參與評分,而不參與匹配;高頻詞(更重要的詞)參與匹配和評分。
這樣一來,就再也不須要 stopwords 停用詞文件了,從而變成了動態生成停用詞: 高頻詞就會被看作是停用詞。這種配置只是對於詞項比較多的場合如 email body,文章等適用,文字太少, cutoff_frequency
選項設置的意義就不大了。
cutoff_frequency
配置有兩種形式
0.01
)表示出現頻率5
)則表示出現次數下面給個例子, 在建立的 3 個文檔中都包含 "be " 的單詞,在查詢時將 cutoff_frequency
參數設置爲 2, 表示 "be" 就是高頻詞,只會參與評分,但在匹配時不作考慮。
此時查詢的內容爲 "to be key" ,因爲 "be" 詞項是高頻詞,由於在文檔中必需要存在 "to" 或者 "key" 才能匹配,所以文檔 3 不能匹配。
PUT /matchtest2 PUT matchtest2/_mapping/cutoff_frequency_test { "properties": { "message": { "type": "text" } } } PUT matchtest2/cutoff_frequency_test/1 { "message": "to be or not to be to be or" } PUT matchtest2/cutoff_frequency_test/2 { "message": "be key or abc" } PUT matchtest2/cutoff_frequency_test/3 { "message": "or to be or to to be or" } GET matchtest2/_search { "query": { "match": { "message": { "query": "to be key", "cutoff_frequency": 2 } } } }
synonyms 是指同義詞,只要索引和字段中配置了同義詞過濾器,match 查詢是支持多詞條的同義詞擴展的。在應用過濾器後,解析器會對每一個屢次條同義詞建立一個語句查詢。
例如,同義詞 USA, united states of America
就會構建出 (USA OR ("united states of America"))
。看下面例子:
PUT /matchtest4 { "settings": { "index" : { "analysis" : { "analyzer" : { "synonym" : { "tokenizer" : "whitespace", "filter" : ["synonym"] } }, "filter" : { "synonym" : { "type" : "synonym", "synonyms" : [ "USA, united states of America" ] } } } } } } PUT /matchtest4/_mapping/synonyms_test { "properties": { "message": { "type": "text", "analyzer": "synonym" } } } PUT /matchtest4/synonyms_test/1 { "message": "united states of America people" } GET /matchtest4/_search { "query": { "match": { "message": { "query": "USA" } } } }
本文以代碼實例的方式完整的講解了 Match Query 的各類使用場景和參數意義。下篇會講解 Match Phrase Query 敬請期待。