search(10)- elastic4s-multi_match:多欄位全文搜尋
在全文搜尋中我們常常會在多個欄位中匹配同一個查詢條件或者在不同的欄位中匹配不同的條件。比如下面這個例子:
GET /books/_search { "query": { "bool": { "should": [ { "match": { "title": "和平戰爭" }}, { "match": { "author": "託斯泰" }} ] } } }
我們可以用boolQuery來進行查詢語句的組合。全文搜尋會產生匹配度評分。boolQuery採取的評分策略是:符合條件的語句越多,評分就越高。如果查詢結果按評分倒排序的話,那麼排在最前面的就是最有可能的結果了。boolQuery可以包含boolQuery,如下:
GET /books/_search { "query": { "bool": { "should": [ { "match": { "title": "和平戰爭" }}, { "match": { "author": "託斯泰" }}, "bool" : { "should" : [ {"match" : { "translator" : "陳"}}, {"match" : { "translator" : "王"}} ] } ] } } }
增加條件的意思是:如果翻譯者姓陳或姓王,那麼評分就高點。不過把boolQuery嵌入另一個boolQuery會影響外部boolQuery的評分結果。因為嵌入的boolQuery只佔總評分的三分之一。當然可以通過boost來平衡比重,如下:
GET /books/_search { "query": { "bool": { "should": [ { "match": { "title": { "query": "和平戰爭", "boost": 2 } } }, { "match": { "author": "託斯泰" }}, "bool" : { "should" : [ {"match" : { "translator" : "陳"}}, {"match" : { "translator" : "王"}} ] } ] } } }
從上面的例子裡可以看到:boolQuery是典型的多欄位多條件匹配查詢,使用者必須明確分辨那些條件在那些欄位裡匹配。但人們習慣於一句話裡表達多個欄位的條件。或者他們根本不想分辨任何欄位,期望一句話就得到想要的結果。這個時候boolQuery就不太適合使用了。
首先,我們可以嘗試在多個欄位中匹配同樣一個綜合語句如:和平戰爭託斯泰。這時我們可能面臨3種選擇:
1、best-fields:同樣一個條件在不同的欄位裡匹配產生多個評分,整體查詢只取最優評分
2、most-fields: 這個方法有點複雜,需要在建索引時把一個欄位按分詞方式分成多個欄位,查詢時取滿足條件最多欄位的評分
3、cross-fields:把所有涉及的欄位合成一個大欄位,然後用條件來匹配這個組合而成的欄位。這個方法應該最適合我們的要求
我們先分析一下具體場景:一個人想在網站上找一本書,應該會從書名、作者、出版社這幾個方面提供查詢條件(雖然是在一個輸入框輸入條件),也就是說使用者提供的一個查詢條件裡可能包含了書名、作者、出版社這幾方面的資訊。那麼第一個版本的搜尋請求如下:
GET /books/_search { "query": { "multi_match": { "query": "和平與戰爭 託斯泰 人民出版社", "type": "cross_fields", "fields": ["title","author","publisher"] } } }
按理來講書名的比重應該高於作者,出版社,所以應該為title加比重:
GET /books/_search { "query": { "multi_match": { "query": "和平與戰爭 託斯泰 人民出版社", "type": "cross_fields", "fields": ["title^2","author","publisher"] } } }
為了更精確的篩選,詞句terms應該採取and進行關聯:
GET /books/_search { "query": { "multi_match": { "query": "和平與戰爭 託斯泰 人民出版社", "type": "cross_fields", "fields": ["title","author","publisher"], "operator": "and" } } }
得出的結果集會大大縮短。使用者可以取消一些條件來增加結果範圍。做的再仔細點我們還可以在圖書的內容上面做點功夫:
GET /books/_search { "query": { "multi_match": { "query": "和平與戰爭 託斯泰 人民出版社", "type": "cross_fields", "fields": ["title^3","author^2","publisher^2","toc","intro"], "operator": "and" } } }
增加了目錄toc, 內容簡介intro。不過它們的比重是最低的。
elastic4示例如下:
val qMultiMatch = search("books").query( multiMatchQuery("和平與戰爭 託斯泰 人民出版社") .matchType("cross_fields") .operator("and") .fields( "title^3", "author^2", "publisher^2", "toc", "intro" ) ).sourceInclude("ISBN","title","publisher","price","author")
&n