[Elasticsearch] 全文搜尋 (二)
多詞查詢(Multi-word Queries)
如果我們一次只能搜尋一個詞,那麼全文搜尋就會顯得相當不靈活。幸運的是,通過match
查詢來實現多詞查詢也同樣簡單:
GET /my_index/my_type/_search { "query": { "match": { "title": "BROWN DOG!" } } }
以上的查詢會返回所有的四份文件:
{ "hits": [ { "_id": "4", "_score": 0.73185337, "_source": { "title": "Brown fox brown dog" } }, { "_id": "2", "_score": 0.47486103, "_source": { "title": "The quick brown fox jumps over the lazy dog" } }, { "_id": "3", "_score": 0.47486103, "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "1", "_score": 0.11914785, "_source": { "title": "The quick brown fox" } } ] }
文件4的相關度最高因為它包含了"brown"
兩次和"dog"
一次。
文件2和文件3都包含了"brown"
"dog"
一次,同時它們的title
欄位擁有相同的長度,因此它們的分值相同。
文件1只包含了"brown"
。
因為match
查詢需要查詢兩個詞條 - ["brown","dog"]
-
在內部它需要執行兩個term
查詢,然後將它們的結果合併來得到整體的結果。因此,它會將兩個term
查詢通過一個bool
查詢組織在一起,我們會在合併查詢一節中詳細介紹。
從上面的例子中需要吸取的經驗是,文件的title
欄位中只需要包含至少一個指定的詞條,就能夠匹配該查詢。如果匹配的詞條越多,也就意味著該文件的相關度就越高。
提高精度(Improving Precision)
匹配任何查詢詞條就算作匹配的話,會導致最終結果中有很多看似無關的匹配。它是一個霰彈槍式的策略(Shotgun Approach)。我們大概只想要顯示包含了所有查詢詞條的文件。換言之,相比brown OR
dog
,我們更想要的結果是brown AND dog
。
match
查詢接受一個operator
引數,該引數的預設值是"or"
。你可以將它改變為"and"
來要求所有的詞條都需要被匹配:
GET /my_index/my_type/_search { "query": { "match": { "title": { "query": "BROWN DOG!", "operator": "and" } } } }
match
查詢的結構需要被稍稍改變來容納operator
引數。
這個查詢的結果會將文件1排除在外,因為它只包含了一個查詢詞條。
控制精度(Controlling Precision)
在all和any中選擇有種非黑即白的感覺。如果使用者指定了5個查詢詞條,而一份文件只包含了其中的4個呢?將"operator"
設定成"and"
會將它排除在外。
有時候這正是你想要的,但是對於大多數全文搜尋的使用場景,你會希望將相關度高的文件包含在結果中,將相關度低的排除在外。換言之,我們需要一種介於兩者中間的方案。
match
查詢支援minimum_should_match
引數,它能夠讓你指定有多少詞條必須被匹配才會讓該文件被當做一個相關的文件。儘管你能夠指定一個詞條的絕對數量,但是通常指定一個百分比會更有意義,因為你無法控制使用者會輸入多少個詞條:
GET /my_index/my_type/_search { "query": { "match": { "title": { "query": "quick brown dog", "minimum_should_match": "75%" } } } }
當以百分比的形式指定時,minimum_should_match
會完成剩下的工作:在上面擁有3個詞條的例子中,75%
會被向下舍入到66.6%
,即3個詞條中的2個。無論你輸入的是什麼,至少有2個詞條被匹配時,該文件才會被算作最終結果中的一員。
minimum_should_match
引數非常靈活,根據使用者輸入的詞條的數量,可以適用不同的規則。具體可以參考minimum_should_match
引數的相關文件。
為了更好地瞭解match
查詢是如何處理多詞查詢的,我們需要看看bool
查詢是如何合併多個查詢的。
合併查詢(Combining Queries)
在合併過濾器中我們討論了使用bool
過濾器來合併多個過濾器以實現and
,or
和not
邏輯。bool
查詢也做了類似的事,但有一個顯著的不同。
過濾器做出一個二元的決定:這份文件是否應該被包含在結果列表中?而查詢,則更加微妙。它們不僅要決定是否包含一份文件,還需要決定這份文件有多相關。
和過濾器類似,bool
查詢通過must
,must_not
以及should
引數來接受多個查詢。比如:
GET /my_index/my_type/_search { "query": { "bool": { "must": { "match": { "title": "quick" }}, "must_not": { "match": { "title": "lazy" }}, "should": [ { "match": { "title": "brown" }}, { "match": { "title": "dog" }} ] } } }
title
欄位中含有詞條quick
,且不含有詞條lazy
的任何文件都會被作為結果返回。目前為止,它的工作方式和bool
過濾器十分相似。
差別來自於兩個should
語句,它表達了這種意思:一份文件不被要求需要含有詞條brown
或者dog
,但是如果它含有了,那麼它的相關度應該更高。
{ "hits": [ { "_id": "3", "_score": 0.70134366, "_source": { "title": "The quick brown fox jumps over the quick dog" } }, { "_id": "1", "_score": 0.3312608, "_source": { "title": "The quick brown fox" } } ] }
文件3的分值更高因為它包含了brown
以及dog
。
分值計算(Score Calculation)
bool
查詢通過將匹配的must
和should
語句的_score
相加,然後除以must
和should
語句的總數來得到相關度分值_score
。
must_not
語句不會影響分值;它們唯一的目的是將不需要的文件排除在外。
控制精度(Controlling Precision)
所有的must
語句都需要匹配,而所有的must_not
語句都不能匹配,但是should
語句需要匹配多少個呢?預設情況下,should
語句一個都不要求匹配,只有一個特例:如果查詢中沒有must
語句,那麼至少要匹配一個should
語句。
正如我們可以控制match
查詢的精度,我們也能夠通過minimum_should_match
引數來控制should
語句需要匹配的數量,該引數可以是一個絕對數值或者一個百分比:
GET /my_index/my_type/_search { "query": { "bool": { "should": [ { "match": { "title": "brown" }}, { "match": { "title": "fox" }}, { "match": { "title": "dog" }} ], "minimum_should_match": 2 } } }
以上查詢的而結果僅包含以下文件:
title
欄位包含: "brown"
AND "fox"
或者 "brown" AND "dog"
或者 "fox"
AND "dog"
如果一份文件含有所有三個詞條,那麼它會被認為更相關。