复合查询
复合查询概述
复合查询是 Elasticsearch 中用来处理多个查询条件组合的一种方式。在实际的业务场景中,我们往往会面对多条件的查询需求,而这些条件可能是复杂的、组合型的,因此需要通过复合查询来实现。
复合查询主要有两种类型:
- 基于逻辑运算的复合查询:将多个子查询使用逻辑运算符组合。
- 影响相关性评分的查询:通过某些方式调整查询文档的相关性评分,以改变文档的排序。
布尔查询(Boolean Query)
布尔查询主要用于根据不同的逻辑条件,组合多个查询子句。常见的逻辑运算符有“与(AND)”、“或(OR)”、“非(NOT)”。在 Elasticsearch 中,布尔查询通过关键字 must
、should
、must_not
和 filter
来实现这些逻辑运算。
布尔查询的基本结构:
GTE /items/_search {"query": {"bool": {"must": [{ "match": { "field": "value" } }],"should": [{ "term": { "field": "value" } }],"must_not": [{ "term": { "field": "value" } }],"filter": [{ "range": { "field": { "gte": 10, "lte": 100 } } }]}}
}
must
:必须匹配,等同于逻辑运算符“与(AND)”,参与评分计算。should
:可以匹配,等同于逻辑运算符“或(OR)”,参与评分计算。must_not
:必须不匹配,等同于逻辑运算符“非(NOT)”不参与评分计算。filter
:过滤条件,与must
相似,但不参与评分计算。
布尔查询关键字解析
must
:表示必须满足的条件。多个must
子查询之间是 与(AND) 的关系,所有条件必须成立,适用于需要“必须满足”的场景。对于需要计算相关性评分的条件,使用must
。should
:表示可选条件。多个should
子查询之间是 或(OR) 的关系,至少有一个条件满足时,查询就成功。should
子查询参与评分,但它不是必需的条件,适用于权重较低但仍需匹配的场景。must_not
:表示必须不满足的条件。多个must_not
子查询之间是 与(AND) 的关系,所有条件必须不成立,适用于需要排除某些结果的场景。filter
:表示过滤条件,通常用于限制结果的范围(如价格、日期等)。它类似于must
,但是 不参与相关性评分,仅用于过滤结果。适用于那些不需要考虑评分的条件。
filter
的特点
filter
和 must
都是用来限定结果集的条件,但它们有显著的区别:
must
:参与评分计算,影响文档排名。filter
:不参与评分计算,仅用于过滤。由于不计算评分,它的性能通常更优。
布尔查询实际应用分析
假设我们有一个在线商城,用户进行商品搜索时,输入了关键字“智能手机”,并通过过滤条件选择了品牌为“华为”和价格范围为 900 到 1599 元。我们需要使用布尔查询来处理这个场景。
- 关键字搜索:用户输入的“智能手机”需要通过全文检索进行匹配。这类查询通常需要计算相关性评分,即匹配度越高的文档越靠前。因此,我们应将其放入
must
中。 - 品牌过滤:用户选择了品牌为“华为”。品牌过滤通常是一个精确匹配的条件,且不需要计算相关性评分。因此,我们将其放入
filter
中。 - 价格范围过滤:用户选择了价格范围 900 到 1599 元。与品牌过滤一样,价格范围也是一个精确匹配条件,同样不参与评分,因此也应放入
filter
中。
实际布尔查询语法:
GET /items/_search
{"query": {"bool": {"must": [{"match": { "name": "智能手机" }}],"filter": [{"term": { "brand": "华为" }},{"range": { "price": { "gte": 90000, "lte": 159900 } }}]}}
}
match
查询用于处理“智能手机”的模糊匹配。term
查询用于处理“品牌”字段的精确匹配。range
查询用于处理“价格”范围的筛选。
返回结果: 返回条件匹配的记录,并按照评分进行排序。
为何使用 filter
而不是 must
?
filter
用于那些不需要参与评分的条件。比如品牌和价格范围等条件,它们并不会影响文档的相关性得分,只决定了文档是否匹配,因此使用 filter
可以提高查询效率。相反,must
是用于那些需要计算相关性评分的条件,它会影响查询结果的排名。
总结
布尔查询(Boolean Query)是 Elasticsearch 中非常强大且灵活的查询方式,能够通过逻辑运算符将多个子查询结合起来。常用的布尔查询关键字有:
must
:用于必须匹配的条件,并参与评分计算。should
:用于可选匹配的条件,且影响评分计算。must_not
:用于排除的条件。filter
:用于过滤的条件,不参与评分计算。
通过合理组合这些关键字,可以实现复杂的查询需求,极大地提高查询的灵活性和性能。
注意事项:
- 性能优化:尽量将不参与评分的条件放入
filter
中,避免影响查询效率。 - 评分影响:对于需要评分的查询条件,应该使用
must
或should
,而不使用filter
。 - 业务场景分析:在实际应用中,根据业务需求分析条件之间的关系,合理使用
must
、should
、must_not
和filter
。
影响相关性评分的查询
相关性评分概述
在 Elasticsearch 中,相关性评分(Relevance Score)是用于衡量一个文档与查询条件的匹配度的分数,通常用于排序文档。Elasticsearch 使用一种称为 TF-IDF(Term Frequency-Inverse Document Frequency) 的算法来计算相关性评分,另外也使用了 BM25 等改进算法。
相关性评分的计算主要受到以下因素的影响:
- 词频(TF):查询词在文档中出现的频率。
- 逆文档频率(IDF):查询词在所有文档中出现的频率,出现频率越低的词对文档的评分影响越大。
- 文档长度:通常来说,文档越短,匹配度越高。
影响相关性评分的查询方式主要是通过改变查询条件来调整文档的得分。
影响相关性评分的查询类型
影响相关性评分的查询通常依赖于对字段的精确匹配或模糊匹配。常见的影响相关性评分的查询类型有:
match
查询:进行全文检索,影响文档的相关性评分。multi_match
查询:用于在多个字段上执行全文检索,影响文档的相关性评分。boost
:通过设置权重,增加某些查询条件对相关性评分的影响。
match
查询
match
查询是最常用的影响相关性评分的查询,它会计算查询词在文档中的匹配度,并返回相关性评分。通常,match
查询用于全文检索,文档中的匹配词出现的越多,评分越高。
示例:
GET /indexName/_search
{"query": {"match": {"description": "智能手机"}}
}
在此查询中,description
字段中包含“智能手机”的文档将会有更高的相关性评分。
multi_match
查询
multi_match
查询是一个扩展的 match
查询,可以在多个字段中执行全文检索。它与多个 match
查询类似,但只需要编写一个查询条件即可应用于多个字段。
示例:
GET /indexName/_search
{"query": {"multi_match": {"query": "智能手机","fields": ["title", "description", "content"]}}
}
在这个例子中,查询会在 title
、description
和 content
三个字段中查找包含“智能手机”的文档,并根据字段匹配度进行相关性评分。
boost
设置
通过 boost
参数可以增强某些查询条件对相关性评分的影响。boost
是一个浮动系数,表示该查询条件相对于其他条件的权重。
示例:
GET /indexName/_search
{"query": {"bool": {"should": [{"match": {"title": {"query": "智能手机","boost": 2}}},{"match": {"description": "智能手机"}}]}}
}
在此查询中,title
字段的匹配结果会被加权处理,相对于 description
字段的匹配结果 ,其得分为 (boost
值的)两倍。
影响评分的其他查询类型
除了上述常见的查询方式,还有一些查询可以直接或间接地影响相关性评分,主要包括:
term
查询:精确匹配某个字段的值。虽然term
查询通常不参与评分计算,但在某些情况下,它可以与其他查询结合,间接影响文档的排序。range
查询:根据字段的范围来过滤文档,range
查询本身不会直接影响评分,但可以通过与must
或should
结合使用,间接调整评分。function_score
查询:允许用户通过自定义函数对文档的相关性评分进行调整,可以结合查询结果和外部因素来进行评分计算。
function_score
查询
function_score
查询允许开发者通过自定义的函数对查询结果的评分进行修改。可以使用不同的评分函数(如权重、衰减函数、随机函数等)来影响文档的最终评分。
示例:
GET /indexName/_search
{"query": {"function_score": {"query": {"match": { "description": "智能手机" }},"boost_mode": "multiply","functions": [{"gauss": {"price": {"origin": "1000","scale": "500","offset": "0","decay": 0.5}}}]}}
}
function_score
查询:这部分会基于查询的结果修改文档的评分。它接收一个查询和一个或多个评分函数,在这个例子中有一个评分函数是gauss
。boost_mode: "multiply"
:这个选项表示查询的原始相关性评分(来自match
查询)将与函数评分结果相乘。这意味着如果函数评分较高,文档的总评分会被放大,影响其在结果中的排名。functions
部分:gauss
函数是一个常用的数学函数,通常用来对某些字段(比如price
)进行评分调整。price
字段表示的是文档的价格。gauss
函数的作用是根据价格的值来对文档的评分进行调整。origin: "1000"
:这是函数的起始值,即价格为1000
时,评分的衰减(Decay)开始。scale: "500"
:这是衰减的范围。当价格偏离1000
达到500
时,评分会降低。offset: "0"
:这个参数表示从1000
开始,计算衰减的“偏移量”,通常设置为0。decay: 0.5
:这个参数决定了衰减的速率。衰减越快,价格越高的文档评分会降低得越快。
结果是:
match
查询会根据description
字段中与“智能手机”的匹配程度来评分文档。gauss
函数会根据文档中的price
字段的值来调整评分。价格接近1000的文档会有更高的评分,价格偏离1000的文档评分会降低。- 最终,两个评分(来自
match
和gauss
)会通过boost_mode: "multiply"
进行相乘,影响文档的最终评分。
dis_max
查询
dis_max
查询允许我们根据多个查询结果返回得分最高的一个,通常用于组合多个查询条件。它会选择所有查询中得分最高的一个,并返回该文档。这个查询适用于某些场景下,想要从多个查询条件中选择最匹配的一个。
示例:
GET /indexName/_search
{"query": {"dis_max": {"queries": [{ "match": { "title": "智能手机" } },{ "match": { "description": "智能手机" } }],"tie_breaker": 0.7}}
}
dis_max
查询的核心组成部分:
queries
:这是一个数组,里面包含了多个查询。在这个例子中,有两个match
查询:match
查询在title
字段中查找“智能手机”。match
查询在description
字段中查找“智能手机”。
tie_breaker
:这个参数用于控制当多个查询的相关性评分差距较小(即评分接近时)如何合并它们的评分。如果tie_breaker
为 0(默认值),那么dis_max
查询只会选择评分最高的查询结果。如果设置为一个值(例如 0.7),则当多个查询的评分相近时,它们的相关性评分会按比例合并,tie_breaker
表示合并的权重。
总结
影响相关性评分的查询是 Elasticsearch 中用于调整和优化查询结果排序的重要工具。通过合理使用以下查询类型,可以极大地提高查询的精准度和业务需求的匹配度:
match
和multi_match
查询:用于全文检索,影响评分计算。boost
:通过权重调整查询条件对评分的影响。function_score
查询:自定义评分函数,灵活调整文档得分。dis_max
查询:选择多个查询结果中得分最高的一个,适用于多条件匹配。
通过结合使用这些查询类型,可以灵活地优化文档的排序和相关性评分,使查询结果更加符合用户的需求。
注意事项:
- 避免过度使用
boost
:虽然boost
可以增加某些条件的权重,但过多使用可能导致其他条件的权重过低,从而影响查询的合理性。 - 调整评分函数时要小心:使用
function_score
时,确保函数的设计符合业务需求,避免因过度复杂的评分函数导致性能问题。 - 性能优化:影响评分的查询会增加计算复杂度,在大量文档的查询场景中,应谨慎使用复杂的查询函数,确保查询效率。