[Elasticsearch] 多字段搜索 (二) - 最佳字段查询及其调优
最佳字段(Best Fields)
假设我们有一个让用户搜索博客文章的网站,就像这两份文档一样:
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."
}
用户输入了"Brown fox",然后按下了搜索键。我们无法预先知道用户搜索的词条会出现在博文的title或者body字段中,但是用户是在搜索和他输入的单词相关的内容。以上的两份文档中,文档2似乎匹配的更好一些,因为它包含了用户寻找的两个单词。
让我们运行下面的bool查询:
{
"query": {
"bool": {
"should": [
{ "match": { "title": "Brown fox" }},
{ "match": { "body": "Brown fox" }}
]
}
}
}
然后我们发现文档1的分值更高:
{
"hits": [
{
"_id": "1",
"_score": 0.14809652,
"_source": {
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
},
{
"_id": "2",
"_score": 0.09256032,
"_source": {
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
}
]
}
要理解原因,想想bool查询是如何计算得到其分值的:
- 运行
should子句中的两个查询 - 相加查询返回的分值
- 将相加得到的分值乘以匹配的查询子句的数量
- 除以总的查询子句的数量
文档1在两个字段中都包含了brown,因此两个match查询都匹配成功并拥有了一个分值。文档2在body字段中包含了brown以及fox,但是在title字段中没有出现任何搜索的单词。因此对body字段查询得到的高分加上对title字段查询得到的零分,然后在乘以匹配的查询子句数量1,最后除以总的查询子句数量2,导致整体分值比文档1的低。
在这个例子中,title和body字段是互相竞争的。我们想要找到一个最佳匹配(Best-matching)的字段。
如果我们不是合并来自每个字段的分值,而是使用最佳匹配字段的分值作为整个查询的整体分值呢?这就会让包含有我们寻找的两个单词的字段有更高的权重,而不是在不同的字段中重复出现的相同单词。
dis_max查询
相比使用bool查询,我们可以使用dis_max查询(Disjuction Max Query)。Disjuction的意思"OR"(而Conjunction的意思是"AND"),因此Disjuction Max Query的意思就是返回匹配了任何查询的文档,并且分值是产生了最佳匹配的查询所对应的分值:
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "Brown fox" }},
{ "match": { "body": "Brown fox" }}
]
}
}
}
它会产生我们期望的结果:
{
"hits": [
{
"_id": "2",
"_score": 0.21509302,
"_source": {
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
},
{
"_id": "1",
"_score": 0.12713557,
"_source": {
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
}
]
}
最佳字段查询的调优
如果用户搜索的是"quick pets",那么会发生什么呢?两份文档都包含了单词quick,但是只有文档2包含了单词pets。两份文档都没能在一个字段中同时包含搜索的两个单词。
一个像下面那样的简单dis_max查询会选择出拥有最佳匹配字段的查询子句,而忽略其他的查询子句:
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "Quick pets" }},
{ "match": { "body": "Quick pets" }}
]
}
}
}
{
"hits": [
{
"_id": "1",
"_score": 0.12713557,
"_source": {
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
},
{
"_id": "2",
"_score": 0.12713557,
"_source": {
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
}
]
}
可以发现,两份文档的分值是一模一样的。
我们期望的是同时匹配了title字段和body字段的文档能够拥有更高的排名,但是结果并非如此。需要记住:dis_max查询只是简单的使用最佳匹配查询子句得到的_score。
tie_breaker
但是,将其它匹配的查询子句考虑进来也是可能的。通过指定tie_breaker参数:
{
"query": {
"dis_max": {
"queries": [
{ "match": { "title": "Quick pets" }},
{ "match": { "body": "Quick pets" }}
],
"tie_breaker": 0.3
}
}
}
它会返回以下结果:
{
"hits": [
{
"_id": "2",
"_score": 0.14757764,
"_source": {
"title": "Keeping pets healthy",
"body": "My quick brown fox eats rabbits on a regular basis."
}
},
{
"_id": "1",
"_score": 0.124275915,
"_source": {
"title": "Quick brown rabbits",
"body": "Brown rabbits are commonly seen."
}
}
]
}
现在文档2的分值比文档1稍高一些。
tie_breaker参数会让dis_max查询的行为更像是dis_max和bool的一种折中。它会通过下面的方式改变分值计算过程:
- 取得最佳匹配查询子句的
_score。 - 将其它每个匹配的子句的分值乘以
tie_breaker。 - 将以上得到的分值进行累加并规范化。
通过tie_breaker参数,所有匹配的子句都会起作用,只不过最佳匹配子句的作用更大。
NOTE
tie_breaker的取值范围是0到1之间的浮点数,取0时即为仅使用最佳匹配子句(译注:和不使用tie_breaker参数的dis_max查询效果相同),取1则会将所有匹配的子句一视同仁。它的确切值需要根据你的数据和查询进行调整,但是一个合理的值会靠近0,(比如,0.1-0.4),来确保不会压倒dis_max查询具有的最佳匹配性质。
[Elasticsearch] 多字段搜索 (二) - 最佳字段查询及其调优的更多相关文章
- [Elasticsearch] 多字段搜索 (二) - 最佳字段查询及其调优(转)
最佳字段(Best Fields) 假设我们有一个让用户搜索博客文章的网站,就像这两份文档一样: PUT /my_index/my_type/1 { "title": " ...
- [Elasticsearch2.x] 多字段搜索 (二) - 最佳字段查询及其调优 <译>
最佳字段(Best Fields) 假设我们有一个让用户搜索博客文章的网站,就像这两份文档一样: PUT /my_index/my_type/ { "title": "Q ...
- Elasticsearch索引和查询性能调优的21条建议
Elasticsearch部署建议 1. 选择合理的硬件配置:尽可能使用 SSD Elasticsearch 最大的瓶颈往往是磁盘读写性能,尤其是随机读取性能.使用SSD(PCI-E接口SSD卡/SA ...
- Elasticsearch 6.x版本全文检索学习之集群调优建议
1.系统设置要到位,遵照官方建议设置所有的系统参数. https://www.elastic.co/guide/en/elasticsearch/reference/6.7/setup.html 部署 ...
- Elasticsearch 全字段搜索_all,query_string查询,不进行分词
最近在使用ELasitcsearch的时候,需要用到关键字搜索,因为是全字段搜索,就需要使用_all字段的query_string进行搜索. 但是在使用的时候,遇到问题了.我们的业务并不需要分词,我在 ...
- [Elasticsearch] 多字段搜索 (五) - 以字段为中心的查询
以字段为中心的查询(Field-centric Queries) 上述提到的三个问题都来源于most_fields是以字段为中心(Field-centric),而不是以词条为中心(Term-centr ...
- Hadoop作业性能指标及參数调优实例 (二)Hadoop作业性能调优7个建议
作者:Shu, Alison Hadoop作业性能调优的两种场景: 一.用户观察到作业性能差,主动寻求帮助. (一)eBayEagle作业性能分析器 1. Hadoop作业性能异常指标 2. Hado ...
- scikit-learn网格搜索来进行高效的参数调优
内容概要¶ 如何使用K折交叉验证来搜索最优调节参数 如何让搜索参数的流程更加高效 如何一次性的搜索多个调节参数 在进行真正的预测之前,如何对调节参数进行处理 如何削减该过程的计算代价 1. K折交叉验 ...
- MySQL架构优化实战系列2:主从复制同步与查询性能调优
随机推荐
- rest_framework --- viewsets
viewsets :from rest_framework import viewsets #导入方式 ViewSetMixin(object): 这个类,大致作用就是重写了as_view()方法,假 ...
- vue、html与iframe html事件相互调用
一.html文件中引入的iframe标签 1.在父html中调用子iframe html 中的事件 通过contentwindow属性 document.getElementById("my ...
- 『ACM C++』HDU杭电OJ | 1415 - Jugs (灌水定理引申)
今天总算开学了,当了班长就是麻烦,明明自己没买书却要带着一波人去领书,那能怎么办呢,只能说我善人心肠哈哈哈,不过我脑子里突然浮起一个念头,大二还要不要继续当这个班委呢,既然已经体验过就可以适当放下了吧 ...
- C++ primer 练习9.52 适配器stack 中缀表达式
//调试环境 VS2015//本人菜鸟一枚,不喜勿喷! 谢谢!!!//主要思想引自 http://www.cnblogs.com/dolphin0520/p/3708602.html//主要代码引自 ...
- c++stl应用入门
在这篇中,我会讲几个简单易懂且比较常用的stl函数,这些函数在noip系列考试中往往被允许使用(既然让用我们自然不用手码了...) (末尾有惊喜!) 1.sort 绝大部分刚入门的oier第一个接触的 ...
- hdu 3966 Aragorn's Story : 树链剖分 O(nlogn)建树 O((logn)²)修改与查询
/** problem: http://acm.hdu.edu.cn/showproblem.php?pid=3966 裸板 **/ #include<stdio.h> #include& ...
- java程序员所必须掌握的内容
以下内容有待细化,并用于考察员工的水平! 从低的往高级的说. 初级 1.掌握java语法 oop+io+网络 2.基本的数据结构 3.基本的算法-例如排序,合并 4.基本的几个javaee框架 spr ...
- 05 shell编程之正则表达式
正则表达式&&文本处理利器 学习目标: l 掌握正则表达式的运用 l 掌握sed.awk文本处理工具的使用 目录结构: 正则表达式 正则表达式概述 l 正则表达式:使用单个字 ...
- js 关于字符串转数字及数字保留位数的控制
1.parseInt()和parseFloat()两个转换函数,将字符串转换成相应的数字. 1.parseInt() parseInt进行转换时,将字符串转成相应的整数.浮点数以后的数字都不要了. p ...
- 关于ECharts内存泄漏问题
最近使用websocket加ECharts做了一个实时监控的功能,发现了一个比较严重的问题,就是浏览器运行一段时间就会非常卡,之前在ECharts官网运行官方实例“动态数据 + 时间坐标轴”时,也遇到 ...