前言
有些時候,我們搜尋的時候,只會提供一個輸入框,但是會查詢相關的多個欄位,典型的如Google搜尋,我們該如何用 Elasticsearch 如何實現呢?
例項
從單字串查詢的例項說起
建立測試例子的資料
DELETE blogs
PUT blogs/_doc/_bulk
{"index":{"_id":1}}
{"title": "Quick brown rabbits","body": "Brown rabbits are commonly seen."}
{"index":{"_id":2}}
{"title": "Keeping pets healthy","body": "My quick brown fox eats rabbits on a regular basis"}
GET blogs/_search
{
"explain": true,
"query": {
"bool": {
"should": [
{"match": {"title": "Brown fox"}},
{"match": {"body": "Brown fox"}}
]
}
}
}
上面的例子相關性的值是title與body的簡單相加,可以通過“"explain": true”列印出來的資料進行查詢計算的過程。
最優欄位查詢調優
可以使用disjunction max query,讓其匹配最大相關性那個欄位,同時tie_breaker可以調整相關性,取值範圍是0~1,可以控制相關性較小那個值佔用的比例,預設是0,畢竟只要相關性最大那個欄位就好了,其他欄位不打分。
GET blogs/_search
{
"explain": true,
"query": {
"dis_max": {
"queries": [
{"match": {"title": "Brown fox"}},
{"match": {"body": "Brown fox"}}
],
"tie_breaker": 0.7
}
}
}
相關性的值是title與body中的最大值。
multi_match
multi_match 查詢為能在多個欄位上反覆執行相同查詢提供了一種便捷方式。
上面的dis_max例子改寫如下
GET blogs/_search
{
"explain": true,
"query": {
"multi_match": {
"type": "most_fields",
"query": "Brown fox",
"fields": ["title","body"],
"tie_breaker": 0.7
}
}
}
multi_match 查詢
multi_match 支援三種場景
- best_fields——(預設)查詢匹配任何欄位的文件,但是使用最佳匹配欄位的_score。
- most_fields——查詢匹配任何欄位的文件,結合每個欄位的_score。
- cross_fields——用相同的分析器處理欄位,把這些欄位當作一個大欄位。查詢任何欄位的每個單詞。類似copy_to
query中可以指定minimum_should_match、operator等欄位,會把這些欄位傳遞到query語句中
best_fields
當搜尋詞語具體概念的時候,比如 “brown fox” ,片語比各自獨立的單詞更有意義。像 title 和 body 這樣的欄位,儘管它們之間是相關的,但同時又彼此相互競爭。文件在相同欄位 中包含的詞越多越好,評分也來自於最匹配欄位 。
best_fields 語句 等同於 dis_max 語句,可以配置tie_breaker引數。
most_fields
全文搜尋被稱作是 召回率(Recall) 與 精確率(Precision) 的戰場: 召回率 ——返回所有的相關文件; 精確率 ——不返回無關文件。目的是在結果的第一頁中為使用者呈現最為相關的文件。
為了提高召回率的效果,我們擴大搜尋範圍——不僅返回與使用者搜尋詞精確匹配的文件,還會返回我們認為與查詢相關的所有文件。如果一個使用者搜尋 “quick brown box” ,一個包含詞語“fast foxes”的文件被認為是非常合理的返回結果。
提高全文相關性精度的常用方式是為同一文字建立多種方式的索引,每種方式都提供了一個不同的相關度訊號signal。主欄位會以儘可能多的形式的去匹配儘可能多的文件。
DELETE titles
PUT titles
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "english",
"fields": {"std": {"type": "text","analyzer": "standard"}}
}
}
}
}
GET /titles/_search
{
"query": {
"multi_match": {
"query": "barking dogs",
"type": "most_fields",
"fields": [ "title^10", "title.std" ]
}
}
}
比如這個例子,文件中的“title”被索引了兩次,主欄位“title”的分詞器是“english”,會提取詞幹,“a”,“the”等這些會在分詞過程中被過濾掉,“ing”等會去除,子欄位“title.std”的分詞器是“standard”,不會提取詞幹。
同時指定了boost,比如上面的“title^10”,表示“title”的權重是10。
cross_fields
對於某些實體,我們需要在多個欄位中確定其資訊,單個欄位都只能作為整體的一部分:
Person: first_name 和 last_name (人:名和姓)
Book: title 、 author 和 description (書:標題、作者、描述)
Address: street 、 city 、 country 和 postcode (地址:街道、市、國家和郵政編碼)
在這種情況下,我們希望在任何 這些列出的欄位中找到儘可能多的詞,這有如在一個大欄位中進行搜尋,這個大欄位包括了所有列出的欄位。
這個類似copy_to,copy_to需要額外的儲存空間,這個不需要。
支援 operator 操作,如果指定的是“and”,那麼表示所有詞都是必須的。