elasticsearch 深入 —— Search Type检索类型
在此我们再给出那个查询的代码:
$ curl -XGET localhost:9200/startswith/test/_search?pretty -d '{
"query": {
"match_phrase_prefix": {
"title": {
"query": "d",
"max_expansions": 5
}
}
}
}' | grep title
"_score" : 1.0, "_source" : {"title":"drunk"}
"_score" : 0.30685282, "_source" : {"title":"dzone"}
"_score" : 0.30685282, "_source" : {"title":"data"}
"_score" : 0.30685282, "_source" : {"title":"drive"}
为何文档“drunk”分数为1.0
,而其余的分数是0.3
?难道这些文档不应该是相同的分数么,因为他们都同等地匹配了“d”。答案是肯定的,但是这个分数本身也有比较合理的地方。
相关性打分
ES使用的打分算法包含了称之为“TF-IDF”的统计信息来帮助计算处于那个索引中的文档的相关性。
TFIDF基本思想就是“一个项在文档中出现的次数越多,那么这个文档更加相关;但相关性会被这个项在整个文档库中的次数削弱”。
稀有项出现在相对少的文档中,那么任何查询匹配了一个稀有项的相关性就变得很高。相反,平常项到处都有,他们的相关性就低了。
当用户执行一个搜索时,ES面对一个有趣的困境。你的查询需要找到所有相关的文档,但是这些文档分布在你的cluster中的任何数目的shard中。
每个shard是一个Lucene的索引,保存了自身的TF和DF统计信息。一个shard只知道在其自身中出现的次数,而非整个cluster。
但是相关算法使用了TF-IDF,它需要知道对于整个索引的而不是对每个shard的TF和DF么?
默认搜索类型:query then fetch
答案:是也不是。默认情形下,ES会使用一个称之为Query then fetch
的搜索类型。它运作的方式如下:
- 发送查询到每个shard
- 找到所有匹配的文档,并使用本地的Term/Document Frequency信息进行打分
- 对结果构建一个优先队列(排序,标页等)
- 返回关于结果的元数据到请求节点。注意,实际文档还没有发送,只是分数
- 来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择
- 最终,实际文档从他们各自所在的独立的shard上检索出来
- 结果被返回给用户
这个系统一般是能够良好地运作的。大多数情形下,你的索引有足够的文档来平滑Term/Document frequency统计信息。因此,尽管每个shard不一定拥有完整的关于整个cluster的frequency信息,结果仍然足够好,因为fequency在每个地方基本上是类似的。
但是在我们开头提起的那个查询,默认搜索类型有时候会失败。
dfs query then fetch
在上篇文章中,我们默认建立了一个索引,ES通常使用5个shard。接着插入了5个文档进入索引,向ES发送请求返回相关结果和准确的分数。其结果并不是很公平,对吧?
这是由于默认的搜索类型导致的,每个shard仅仅包含一个或者两个文档(ES使用hash确保随机分布)。当我们要求ES计算分数时候,每个shard仅仅拥有关于五个文档的一个很窄的视角。所以分数是不准确的。
幸运的是,ES并没有让你无所适从。如果你遇到了这样的打分偏离的情形,ES提供了一个称为“DFS Query Then Fetch”。这个过程基本和Query Then Fetch类型,除了它执行了一个预查询来计算整体文档的frequency。
- 预查询每个shard,询问Term和Document frequency
- 发送查询到每个shard
- 找到所有匹配的文档,并使用全局的Term/Document Frequency信息进行打分
- 对结果构建一个优先队列(排序,标页等)
- 返回关于结果的元数据到请求节点。注意,实际文档还没有发送,只是分数
- 来自所有shard的分数合并起来,并在请求节点上进行排序,文档被按照查询要求进行选择
- 最终,实际文档从他们各自所在的独立的shard上检索出来
- 结果被返回给用户
如果我们使用这个新的搜索类型,那么获得的结果更加合理了(这些都一样的):
$ curl -XGET 'localhost:9200/startswith/test/_search?pretty=true&search_type=dfs_query_then_fetch' -d '{
"query": {
"match_phrase_prefix": {
"title": {
"query": "d",
"max_expansions": 5
}
}
}
}' | grep title
"_score" : 1.9162908, "_source" : {"title":"dzone"}
"_score" : 1.9162908, "_source" : {"title":"data"}
"_score" : 1.9162908, "_source" : {"title":"drunk"}
"_score" : 1.9162908, "_source" : {"title":"drive"}
结论
当然,更好准确性不是免费的。预查询本身会有一个额外的在shard中的轮询,这个当然会有性能上的问题(跟索引的大小,shard的数量,查询的频率等)。在大多数情形下,是没有必要的,拥有足够的数据可以解决这样的问题。
但是有时候,你可能会遇到奇特的打分场景,在这些情况中,知道如何使用DFS query then fetch
去进行搜索执行过程的微调还是有用的。
elasticsearch 深入 —— Search Type检索类型的更多相关文章
- elasticsearch.net search入门使用指南中文版(翻译)
elasticsearch.net search入门使用指南中文版,elasticsearch.Net是一个非常底层且灵活的客户端,它不在意你如何的构建自己的请求和响应.它非常抽象,因此所有的elas ...
- elasticsearch.net search入门使用指南中文版
原文:http://edu.dmeiyang.com/book/nestusing.html elasticsearch.net为什么会有两个客户端? Elasticsearch.Net是一个非常底层 ...
- kibana和ElasticSearch的信息查询检索
使用kibana来进行ElasticSearch的信息查询检索 大家经常会听到使用ELK搭建日志管理平台.完成日志聚合检索的功能,那么这个平台到底是个什么概念,怎么搭建,怎么使用呢? ELK包括Ela ...
- Elasticsearch URI search 查询语法整理
Elasticsearch URI search 一.请求体查询与空查询 1. 请求体查询(request body search) 简单查询语句(lite)是一种有效的命令行adhoc查询.但是,如 ...
- Elasticsearch Sliced Scroll分页检索案例分享
面试:你懂什么是分布式系统吗?Redis分布式锁都不会?>>> The best elasticsearch highlevel java rest api-----bboss ...
- media query(媒体查询)和media type(媒体类型)
media type(媒体类型)是css 2中的一个非常有用的属性,通过media type我们可以对不同的设备指定特定的样式,从而实现更丰富的界面.media query(媒体查询)是对media ...
- 【Type】类型 ParameterizedType
Type 接口[重要] Type接口完整的定义: public interface java.lang.reflect.Type { /** * Returns a string describing ...
- Type Java类型
参考:https://blog.csdn.net/a327369238/article/details/52621043 Type —— Java类型 Type是一个空接口,所有类型的公共接口(父接口 ...
- Python Type Hint类型注解
原文地址:https://realpython.com/python-type-checking/ 在本指南中,你将了解Python类型检查.传统上,Python解释器以灵活但隐式的方式处理类型.Py ...
随机推荐
- php object
一.访问控制 <?php class Computer{ public $cpu = 880; private $name = 'xiaomi'; public function getname ...
- BitMap位图
BitMap位图算法https://blog.csdn.net/varyall/article/details/79662029 常见面试题 题1:在2.5亿个整数找出不重复的整数,内存不足以容纳着2 ...
- 【串线篇】spring boot日志使用
一.默认配置 1.SpringBoot默认帮我们配置好了日志: //记录器 Logger logger = LoggerFactory.getLogger(getClass()); @Test pub ...
- 免插件,简单实现上拉加载loading
上拉加载是前端经常遇到的问题,采用插件往往能够轻松解决,这里介绍一种免插件简单实现上拉加载的方法,参考一下,下面分享一下代码. html <body> <ul> <li& ...
- AGC036C GP 2
由于近期集训做的一直都是校内题 然后好久都怎么写题了( 发篇博客证明我还活着 (其实也没人关心 好像并不是很难的一道计数 就是脑子总是缺一块导致会做不出来( 首先我们可以分析性质 1.$\sum A_ ...
- BZOJ 5046 分糖果游戏
网页崩溃了 心态也崩溃了 MD劳资写了那么多 题意: 有a,b两个人分糖,每个人都有一个能量值.每个人每一轮可以选择进行两种操作: 1.取走最左边的糖果,补充相应的能量值并获取相应的美味度. 2.跳过 ...
- QT5 QTreeView添加右键菜单
C++ QT5学习--QTreeView控件创建右键菜单 QTreeView是QWidget的子类,我们再改写QTreeView类的时候,注意的是继承关系. 1.TreeView.h class Tr ...
- 组建MySQL集群的几种方案
组建MySQL集群的几种方案LVS+Keepalived+MySQL(有脑裂问题?但似乎很多人推荐这个)DRBD+Heartbeat+MySQL(有一台机器空余?Heartbeat切换时间较长?有脑裂 ...
- Sending forms through JavaScript[form提交 form data]
https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript As in the ...
- 跨域、this指向
不要再问我跨域的问题了: https://segmentfault.com/a/1190000015597029?utm_source=tag-newest 不要再问我this的指向问题了: http ...