多字符串查詢
GET /_search
{
"query": {
"bool": {
"should": [
{ "match": { "title": "War and Peace" }},
{ "match": { "author": "Leo Tolstoy" }},
{ "bool": {
"should": [
{ "match": { "translator": "Constance Garnett" }},
{ "match": { "translator": "Louise Maude" }}
]
}}
]
}
}
}
4個(gè)match查詢郭蕉,為什么后兩個(gè)使用bool包裹冕象?
同一層查詢每條語(yǔ)句具有相同的權(quán)重\堋F竞馈焙蹭!
語(yǔ)句的優(yōu)先級(jí)
boost
單字符串查詢
用戶期望將所有的搜索項(xiàng)堆積到單個(gè)字段中。
1嫂伞、最佳字段
例如我們搜索“es reindex”孔厉,對(duì)于title和body這樣的兩個(gè)字段拯钻,“es reindex”同時(shí)出現(xiàn)在一個(gè)字段時(shí)的文檔評(píng)分更高
2、多數(shù)字段
為了對(duì)相關(guān)度進(jìn)行微調(diào)烟馅,常用的一個(gè)技術(shù)就是將相同的數(shù)據(jù)索引到不同的字段说庭,使他們具有獨(dú)立的分析鏈。
主字段可能包括它們的詞源郑趁、同義詞以及變音詞或口音詞等刊驴,用來(lái)匹配盡可能多的文檔。
相同的文本被索引到其他字段寡润,提供更精確的匹配捆憎。一個(gè)字段可以包括未經(jīng)詞干提取的原詞;另一個(gè)字段包括口音梭纹,還有一個(gè)字段提供詞語(yǔ)相似性躲惰。
其他字段是作為匹配每個(gè)文檔時(shí)提高相關(guān)度評(píng)分的信號(hào)。
3变抽、混合字段
對(duì)于某些實(shí)體础拨,需要在多個(gè)字段中確認(rèn)其信息,單個(gè)字段都只能作為整體的一部分:
Person: first_name绍载、last_name
如同在Persion這個(gè)大字段中搜索 first_name和last_name這兩個(gè)字段
最佳字段
以兩個(gè)文檔為例
PUT /my_index/my_type/1
{
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
PUT /my_index/my_type/2
{
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
bool查詢诡宗,想要匹配Brown fox
{
"query": {
"bool": {
"should": [
{ "match": { "title": "Brown fox" }},
{ "match": { "body": "Brown fox" }}
]
}
}
}
我們想要的結(jié)果是文檔2,但是文檔1的評(píng)分更高
bool如何計(jì)算評(píng)分:
1击儡、執(zhí)行should語(yǔ)句中的兩個(gè)查詢塔沃。
2、兩個(gè)查詢的評(píng)分相加
3阳谍、乘以匹配語(yǔ)句的總數(shù)
4蛀柴、除以所有語(yǔ)句總數(shù)(這里為2,指的應(yīng)該兩個(gè)字段矫夯?鸽疾??)
文檔1中兩個(gè)字段都包含brown训貌,所以兩個(gè)match語(yǔ)句都有一個(gè)評(píng)分肮韧。
文檔2中body字段包含兩個(gè)詞,獲得較高分旺订,但title字段沒(méi)有包含任何詞,平均一下文檔2的整體分就比文檔1低超燃。
可以使用dis_max分離最大化查詢Disjunction Max Query区拳,大致意思是,將任何與任一查詢匹配的文檔作為結(jié)果返回意乓,但只將最匹配的評(píng)分作為查詢的評(píng)分結(jié)果返回:
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "Brown fox" }},
{ "match": { "body": "Brown fox" }}
]
}
}
}
最佳字段查詢調(diào)優(yōu)
dis_max查詢會(huì)單個(gè)匹配最佳字段樱调,而忽略其他的匹配约素。(單個(gè)最佳匹配語(yǔ)句的評(píng)分作為整體評(píng)分)
可以通過(guò)指定tie_breaker字段將其他語(yǔ)句的評(píng)分也考慮其中。
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "Quick pets" }},
{ "match": { "body": "Quick pets" }}
],
"tie_breaker": 0.3
}
}
}
結(jié)果如下:
{
"hits": [
{
"_id": "2",
"_score": 0.14757764, (1)
"_source": {
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
},
{
"_id": "1",
"_score": 0.124275915, (1)
"_source": {
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
}
]
}
不帶有tie_breaker參數(shù)時(shí)笆凌,評(píng)分1等于評(píng)分2
tie_breaker的評(píng)分方式:
1圣猎、獲得最佳匹配語(yǔ)句的評(píng)分
2、其他語(yǔ)句的評(píng)分結(jié)果乘以tie_breaker
3乞而、上述相加即為最后評(píng)分
tie_breaker的合理值應(yīng)該處于0.1-0.4之間
multi_match多匹配查詢
在多個(gè)字段上反復(fù)執(zhí)行相同的查詢送悔。
multi_match多匹配查詢的類型有多種,其中三種與前文的最佳字段(best_fields)爪模、多數(shù)字段(most_fields)欠啤、跨字段相匹配(cross_fields)
默認(rèn)情況查詢的類型是best_fields,例如:
{
"dis_max": {
"queries": [
{
"match": {
"title": {
"query": "Quick brown fox",
"minimum_should_match": "30%"
}
}
},
{
"match": {
"body": {
"query": "Quick brown fox",
"minimum_should_match": "30%"
}
}
},
],
"tie_breaker": 0.3
}
}
可以使用multi_match重寫成更簡(jiǎn)潔的形式
{
"multi_match": {
"query": "Quick brown fox",
"type": "best_fields", (1)
"fields": [ "title", "body" ],
"tie_breaker": 0.3,
"minimum_should_match": "30%" (2)
}
}
minimum_should_match屋灌、operator 這樣的參數(shù)會(huì)被傳遞到生成的match查詢中
匹配的字段可以使用模糊匹配的方式給出洁段,例如:
{
"multi_match": {
"query": "Quick brown fox",
"fields": "*_title"
}
}
可以使用^
為單個(gè)字段提升權(quán)重
{
"multi_match": {
"query": "Quick brown fox",
"fields": [ "*_title", "chapter_title^2" ] (1)
}
}
多數(shù)字段
召回率:返回所有的相關(guān)文檔
精確率:不返回?zé)o關(guān)文檔
全文搜索的兩個(gè)名詞,目的是在結(jié)果的第一頁(yè)為用戶呈現(xiàn)最為相關(guān)的文檔
多字段映射共郭,首先要做的事情就是對(duì)我們的字段索引兩次祠丝,一次使用詞干模式,一次使用非詞干模式
PUT /my_index
{
"settings": { "number_of_shards": 1 }, (1)
"mappings": {
"my_type": {
"properties": {
"title": { (2)
"type": "string",
"analyzer": "english",
"fields": {
"std": { (3)
"type": "string",
"analyzer": "standard"
}
}
}
}
}
}
}
簡(jiǎn)單的查詢除嘹,兩個(gè)文檔的評(píng)分相同写半;只查詢title.std那么只有文檔2是匹配的
GET /my_index/_search
{
"query": {
"match": {
"title": "jumping rabbits"
}
}
}
如果同時(shí)查詢兩個(gè)字段,然后使用bool查詢將結(jié)果合并憾赁,那么兩個(gè)文檔都是匹配的污朽,文檔2的分更高
GET /my_index/_search
{
"query": {
"multi_match": {
"query": "jumping rabbits",
"type": "most_fields", (1)
"fields": [ "title", "title.std" ]
}
}
}
用廣度匹配字段title
匹配盡可能多的文檔,提升召回率
同時(shí)又使用title.std
作為信號(hào)將相關(guān)度更高的文檔置于結(jié)果頂部
跨字段實(shí)體搜索
多字符串查詢中龙考,我們?yōu)槊總€(gè)字段使用不同的字符串蟆肆,
而跨字段查詢是使用單個(gè)字符串在多個(gè)字段中進(jìn)行搜索。
例如我們搜索Poland Street W1V
這個(gè)地址晦款,它需要匹配多個(gè)字段
假如使用motst_fields會(huì)出現(xiàn)如下問(wèn)題:
1炎功、它是為多數(shù)字段匹配任意詞設(shè)計(jì)的,而不是在所有字段中找到最匹配的
2缓溅、它不能使用operator或minimum_should_match參數(shù)來(lái)降低相關(guān)結(jié)果造成的長(zhǎng)尾效應(yīng)
3蛇损、詞頻對(duì)于每個(gè)字段是不一樣的,而且它們之間的相互影響會(huì)導(dǎo)致不好的排序結(jié)果坛怪。
字段中心式查詢
most_fields(best_fields)出現(xiàn)的問(wèn)題都是因?yàn)樗亲侄沃行氖讲樵冇倨耄皇窃~中心式的。
詞中心式:當(dāng)真正感興趣的事匹配詞的時(shí)候袜匿,它為我們查找的是最匹配的字段
問(wèn)題1:在多個(gè)字段中匹配相同的詞
GET /_validate/query?explain
{
"query": {
"multi_match": {
"query": "Poland Street W1V",
"type": "most_fields",
"fields": [ "street", "city", "country", "postcode" ]
}
}
}
生成的explanation解釋:
(street:poland street:street street:w1v)
(city:poland city:street city:w1v)
(country:poland country:street country:w1v)
(postcode:poland postcode:street postcode:w1v)
可以發(fā)現(xiàn)兩個(gè)字段都與poland匹配的文檔要比一個(gè)字段同時(shí)匹配poland和street文檔的評(píng)分高(可能是順序更啄,得出這樣的結(jié)論)
問(wèn)題2:剪掉長(zhǎng)尾
在精度匹配中,我們可以使用operator和minimum_should_match參數(shù)來(lái)消除結(jié)果中幾乎不相關(guān)的長(zhǎng)尾居灯,但是對(duì)于best_fields和most_fields中祭务,這些參數(shù)會(huì)在match查詢生成時(shí)被傳入内狗,例如操作符and,就會(huì)要求所有詞必須存在與相同字段中义锥,這顯然是不對(duì)的
問(wèn)題3:詞頻
{
"query": {
"multi_match": {
"query": "Peter Smith",
"type": "most_fields",
"fields": [ "*_name" ]
}
}
}
可能在結(jié)果中將“Smith Williams” 置于 “Peter Smith” 之上柳沙。
簡(jiǎn)單來(lái)說(shuō)就是smith在名字段中具有較高的IDF,他會(huì)削弱“Peter”作為名和“smith”作為姓時(shí)低IDF的所起作用拌倍。
解決方案
存在這些問(wèn)題僅僅是因?yàn)槲覀冊(cè)谔幚碇鄠€(gè)字段赂鲤,如果將這些字段組合成單個(gè)字段,問(wèn)題就會(huì)消失贰拿。
{
"first_name": "Peter",
"last_name": "Smith",
"full_name": "Peter Smith"
}
這樣只要查詢full_name剛才的問(wèn)題就會(huì)消失蛤袒,但是數(shù)據(jù)卻會(huì)冗余。取而代之的是另外兩種方案膨更,一個(gè)是在索引時(shí)妙真,另一個(gè)是在搜索時(shí)
自定義_all字段
_all字段的索引方式是將所有其他字段的值作為一個(gè)大字符串索引的。然而這么做并不靈活荚守,為了靈活珍德,我們可以給人名添加一個(gè)自定義_all字段,也為地址添加另一個(gè)_all字段
可以使用copy_to參數(shù)來(lái)實(shí)現(xiàn)這個(gè)功能
PUT /my_index
{
"mappings": {
"person": {
"properties": {
"first_name": {
"type": "string",
"copy_to": "full_name" (1)
},
"last_name": {
"type": "string",
"copy_to": "full_name" (1)
},
"full_name": {
"type": "string"
}
}
}
}
}
first_name和last_name字段的值會(huì)被復(fù)制到full_name中
copy_to設(shè)置對(duì)multi_field無(wú)效矗漾。
多字段只是以不同方式簡(jiǎn)單索引“主”字段锈候,他們沒(méi)有自己的數(shù)據(jù)源,只要對(duì)主字段copy_to就能輕而易舉的達(dá)到相同的效果
PUT /my_index
{
"mappings": {
"person": {
"properties": {
"first_name": {
"type": "string",
"copy_to": "full_name", (1)
"fields": {
"raw": {
"type": "string",
"index": "not_analyzed"
}
}
},
"full_name": {
"type": "string"
}
}
}
}
}
跨字段查詢
搜索時(shí)相應(yīng)的解決方案:使用cross_fields進(jìn)行multi_match查詢敞贡。
cross_fields是詞中心式的查詢泵琳,它將所有字段當(dāng)成一個(gè)大字段,并在每個(gè)字段中查詢每個(gè)詞
GET /_validate/query?explain
{
"query": {
"multi_match": {
"query": "peter smith",
"type": "most_fields",
"operator": "and", (1)
"fields": [ "first_name", "last_name" ]
}
}
}
得到結(jié)果表示peter和smith都必須同時(shí)出現(xiàn)在相同字段中誊役,要么是first_name获列,要么last_name
(+first_name:peter +first_name:smith)
(+last_name:peter +last_name:smith)
然而詞中心式會(huì)使用以下邏輯,意味著peter和smith都必須出現(xiàn)蛔垢,但是可以出現(xiàn)在任意字段中
+(first_name:peter last_name:peter)
+(first_name:smith last_name:smith)
cross_fields類型首先分析查詢字符串并生成一個(gè)詞列表击孩,然后它從所有字段中依次搜索每個(gè)詞。
這種不同的查詢方式自然就解決了前兩個(gè)問(wèn)題鹏漆。
至于IDF問(wèn)題巩梢,它通過(guò)混合不同字段逆向索引文檔頻率的方式解決了詞頻的問(wèn)題。
GET /_validate/query?explain
{
"query": {
"multi_match": {
"query": "peter smith",
"type": "cross_fields", (1)
"operator": "and",
"fields": [ "first_name", "last_name" ]
}
}
}
+blended("peter", fields: [first_name, last_name])
+blended("smith", fields: [first_name, last_name])
換句話說(shuō)艺玲,它會(huì)在兩個(gè)字段字段中查找smith的IDF括蝠,然后使用最小值作為兩個(gè)字段的IDF。
Tip:為了讓cross_fields查詢以最優(yōu)的方式工作饭聚,所有的字段都必須使用相同的分析器忌警,具有相同分析器的字段會(huì)被分組在一起作為混合字段使用。
如果包括了不同分析器的字段若治,它們會(huì)以best_fields的相同方式加入到查詢結(jié)果中慨蓝。
例如將title字段加入到之前的查詢,explanation解釋如下:
(+title:peter +title:smith)
(
+blended("peter", fields: [first_name, last_name])
+blended("smith", fields: [first_name, last_name])
)
當(dāng)在使用minimum_should_match和operator參數(shù)時(shí)端幼,這點(diǎn)尤為重要
按字段提高權(quán)重
使用cross_fields和_all相比礼烈,其中一個(gè)優(yōu)勢(shì)就是它可以在搜索時(shí)為單個(gè)字段提升權(quán)重
正如前文提到的^
自定義單字段查詢能否優(yōu)于多字段查詢,取決于在多字段與單字段自定義_all之間代價(jià)的權(quán)衡婆跑。
Exact-Value精確值字段
將not_analyzed字段與 multi_match中analyzed字段混在一起沒(méi)有多大用處此熬。
如前文的查詢,假如title是not_analyzed
title:peter smith
(
blended("peter", fields: [first_name, last_name])
blended("smith", fields: [first_name, last_name])
)
es會(huì)將peter smith完整的字符串作為查詢條件來(lái)搜索滑进,所以需要在multi_match查詢中避免使用not_analyzed字段