ElasticSearch之单值多字段查询以及dis max query

写在前面

在查询中经常有这样的查询场景,我们只有一个输入框,但是输入的值需要同时对多个字段进行查询,这就是单值多字段的查询,像下图:

1:例子

首先来准备测试数据:

复制代码
DELETE blogs
PUT /blogs/_doc/1
{
  "title": "Quick brown rabbits",
  "body": "Brown rabbits are commonly seen."
}

PUT /blogs/_doc/2
{
  "title": "Keeping pets healthy",
  "body": "My quick brown fox eats rabbits on a regular basis"
}

假定我们现在搜索brown fox,查询在title或者是body中包含其的文档,很明显我们需要使用should查询:

复制代码
POST /blogs/_search
{
    "query": {
        "bool": {
            "should": [
                {
                    "match": {
                        "title": "Brown fox"
                    }
                },
                {
                    "match": {
                        "body": "Brown fox"
                    }
                }
            ]
        }
    }
}

如图中结果,在文档2的body中存在完全匹配brown fox的内容,按照常理,其应该具有最高的分数,即在最靠前的位置,但事实并非如此,出现这种现象的原因是should查询的算分机制如下:

则文档1的算分过程如下:

复制代码
1:title中包含brown,假定给0.3分,body中包含brown给0.3分,则总分0.6分
2:匹配的文档数是2,所以得分0.6*2=1.2分
3:总文档数2,所以最终得分1.2/2=0.6分

文档2的算分过程如下:

复制代码
1:title中不匹配给0分,body中包含brown和fox给0.9分,则总分0.9分
2:匹配的文档数是1,所以得分0.9*1=0.9分
3:总文档数2,所以最终得分0.9/2=0.45分

所以文档1的最终得分就比文档2的高了。如何解决没有匹配到理想的结果这个问题呢,如果是我们将算分机制从sum变为max就能很轻松的解决这个问题了,这就需要用到disjunction max query,这种查询方式会取所有匹配的最高分作为该文档的最终得分,如下:

复制代码
POST /blogs/_search
{
    "query": {
        "dis_max": {
            "queries": [
                {
                    "match": {
                        "title": "Brown fox"
                    }
                },
                {
                    "match": {
                        "body": "Brown fox"
                    }
                }
            ]
        }
    }
}

接着我们在来看如下的查询:

复制代码
POST /blogs/_search
{
    "query": {
        "dis_max": {
            "queries": [
                {
                    "match": {
                        "title": "quick pets"
                    }
                },
                {
                    "match": {
                        "body": "quick pets"
                    }
                }
            ]
        }
    }
}

查询quick pet,按照dis_max的查询逻辑,文档1和2将会得到相同的分数,结果也确实是如此:

此时情况又不太一样,在文档1的title中包含quick,而body不匹配,但文档2,title中包含pets,body中包含quick,所以应该给文档2更高的分数才符合常理,此时又该怎么做呢?其实在dis_max中是有一个tie_break参数的,如下:

该参数的作用是与非最高分的匹配项的分数相乘,然后再和最高分加在一起作为文档的最终得分,也就是文档最高分+非最高分1*tie_breaker+非最高分2*tie_breaker,当不指定时,es可能按照该值为0处理,或者时干脆就不考虑该参数了,反正不指定tie_breaker时的效果就是取最高分作为文档最终得分,那么咱们这里的情况,只需要指定一个合适的tie_breaker的值就行了,如下:

实际的业务场景中,我们需要使用不同的查询方式并灵活调整参数,来满足不同的业务需求。

写在后面

参考文章列表

相关推荐
frjc8 小时前
数据库选型:如何从众多数据库中选出最理想的那一个
redis·mysql·clickhouse·elasticsearch
xbgRS15 小时前
Elasticsearch的分词器
大数据·elasticsearch·搜索引擎
Wx-bishekaifayuan16 小时前
springboot户外登山社交小程序19787-计算机课程设计、毕业设计
spring boot·后端·python·spring·elasticsearch·django·课程设计
Elasticsearch20 小时前
两个依赖和一个配置块:通过 Prometheus 远程写入将 Spring Boot 指标发送到 Elasticsearch
elasticsearch
Elasticsearch21 小时前
使用两个 Elasticsearch 数据层而不是四个,降低日志存储成本
elasticsearch
Wx-bishekaifayuan1 天前
springboot生活商城系统21035-计算机课程设计、毕业设计
spring boot·后端·python·spring·elasticsearch·golang·课程设计
Elasticsearch1 天前
使用 NVIDIA cuVS 在 Elasticsearch 中实现 GPU 加速的向量索引:在 10 分钟内处理 1.38 亿个向量
elasticsearch
Flynt1 天前
"MySQL搜不动就上ES"?我先在50万行数据上测了它自带的ngram全文索引
mysql·elasticsearch·搜索引擎
柒和远方1 天前
混合检索 RAG 全链路:查询增强、双路召回与重排——向量库和搜索引擎联手补齐召回
elasticsearch·langchain·llm
Elasticsearch1 天前
用自然语言分析跟踪数据,询问 Elastic Agent Builder 为什么运行缓慢
elasticsearch