本篇文章主要说明match执行过程中的低级查询(bool term)以及涉及到评分规则(包括同义词)。elasticsearch一些较复杂业
务查询中 match 多词和同义词搜索可能会遇到的问题。
match或者query_string这样的查询是高级查询(High-level Queries),它们能够理解一个字段的映射,一旦查询得到了一个词条列表,
它就会使用列表中的每个词条来执行合适的低级查询,然后将得到的结果进行合并,最终产生每份文档的相关度分值。term是代表完全
匹配,即不进行分词器分析,文档中必须包含整个搜索的词汇,只会在倒排索引中寻找该词条的精确匹配。
业务场景:有个title为“衣服很漂亮”,其中“衣服”对应同义词“服饰”、“服装”两个。
A:搜索关键字:“穿服饰”。
B:搜索关键字为:“服饰”。
match查询应该是你的首选。它是一个高级全文查询,意味着它知道如何处理全文字段(Full-text, analyzed)和精确值字段(Exact-
value,not_analyzed)。直接用match查询很容易满足该业务实现A。其中minimum_should_match 设置为67%,向下取整数,控制匹配精
度。DSL实现语句如下:
{
"explain": true,
"fields": [
"title"
],
"query": {
"filtered": {
"query": {
"bool": {
"should": [
{
"match": {
"title.ik": {
"query": “穿服装",
"minimum_should_match": "67%"
}
}
}
]
}
},
"filter": {
"bool": {
"must": {
"term": {
"cityId": 310100
}
}
}
}
}
}
}
不难发现A很好实现,但是B,只单是搜索“衣服”,那么就出现问题了,会出现搜索不到结果的情况,为什么会出现这种情况????
因为同义词有3个!!!而minimum_should_match=“67%",3*67%=2.01,必须至少匹配两个。所以B是搜索不出来结果的。分解成低级
bool查询的时候,检索关系:“穿” OR (“衣服” OR “服饰” OR “服装” ) DSL如下:
{
"bool": {
"should": [
{
"term": {
"title.ik": "衣服"
}
},
{
"term": {
"title.ik": "服饰"
}
},
{
"term": {
"title.ik": "服装"
}
}
]
}
}
match查询的多词查询只是简单地将生成的term查询包含在了一个bool查询中。通过默认的or操作符,每个term查询都以一个语句
被添加,所以至少一个should语句需要被匹配。bool 查询默认会对所有 should 语句使用协调功能,当我们使用 bool 查询将多个高级查
询如 match 查询包裹的时候,让协调功能打开是有意义的,匹配的语句越多,查询请求与返回文档间的重叠度就越高。
但在某些高级应用中,我们将协调功能关闭可能更好。假如我们正在查找同义词 “衣服”,“服装”,“服饰”。我们并不关心会出现
多少个同义词,因为它们都表示一个意思,实际上,只有其中一个同义词会出现,当我们使用同义词的时候(参照:同义词
(Synonyms)),Lucene内部是这样的:重写的的查询会为同义词关闭协调功能(coord=1),大多数关闭操作的应用场景是自动处理
的,无须为此担心。对于elasticsearch match查询来说,遇到同义词的时候,也会自动为同义词关闭协调功能。通过
disable_coord=ture实现对A的DSL macth查询的解析。
对应的的DSL应该如下:
{
"explain": true,
"fields": [
"title"
],
"query": {
"filtered": {
"query": {
"bool": {
"minimum_should_match": "67%",
"should": [
{
"term": {
"title.ik": "穿"
}
},
{
"bool": {
"disable_coord": true,
"should": [
{
"term": {
"title.ik": "衣服"
}
},
{
"term": {
"title.ik": "服饰"
}
},
{
"term": {
"title.ik": "服装"
}
}
]
}
}
]
}
},
"filter": {
"bool": {
"must": {
"term": {
"cityId": 310100
}
}
}
}
}
}
}