Elasticsearch学习-搜索调优
Elasticsearch学习-搜索调优
系列文章目录
- Elasticsearch学习-关于倒排索引、DocValues、FieldData和全局序号
- Elasticsearch学习-搜索调优
- Elasticsearch学习-Doc原理
0x01 摘要
本文会讲讲es中的4种搜索模式以及该如何选择,还会说一些常用的搜索调优选项。
本文基于ES-2.3.3
0x02 search_type
执行分布式搜索时可以执行不同的执行路径。需要将分布式搜索操作分散到所有相关分片,然后收集所有结果。
分布式搜索中的两个最重要问题:
- 从每个分片中搜索多少结果
- 每个分片独立,所以在特定分片上执行查询时不会考虑其他分片的TF。那么如果需要准确的排序就需要从所有分片搜集TF最后再聚合算出全局TF,利用全局TF来在每个分片上执行查询
Elasticsearch非常灵活,允许控制基于每个搜索请求执行的搜索类型。可以通过在查询字符串中设置search_type参数。
在讲解各个搜索选项前,我们先简单说下ES搜索中的相似度算法。
ES 2.x中默认使用的相似度算法叫 TF(词频)/IDF(逆向)文档频率算法:
- 词频:计算某个词在当前被查询文档里的**某个字段(field)**中出现的频率。出现的频率越高,文档越相关。
- 逆向文档频率:计算某个词在索引内所有文档中出现的百分数。文档出现的频率越高,它的权重就越低。
由于性能原因, ES 不会计算索引内(统筹所有跨节点分片)所有文档的 IDF ,而是每个分片根据该分片内的所有文档计算一个本地 IDF 。
因为文档一般都是均匀分布存储的,也就是说任意两个分片的 IDF 是基本相同的。但如果有 5 个 foo 文档存于分片 1 ,而第 6 个文档存于分片 2 ,在这种场景下, foo 在一个分片里非常普通(所以不那么重要),但是在另一个分片里非常出现很少(所以会显得更重要)。这些 IDF 之间的差异会导致不正确的结果。
但在实际应用中,这并不是一个问题,本地和全局的 IDF 的差异会随着索引里文档数的增多渐渐消失,在真实世界的数据量下,局部的 IDF 会被迅速均化,所以上述问题并不是相关度被破坏所导致的,而是由于数据太少。
2.1 QUERY_THEN_FETCH(查询后取回,默认选择)
思想:先返回足够、尽量少的信息用来打分排序,然后只返回指定数量的数据content字段
查询执行在所有分片上,但是只有部分必要的信息被返回(而不是整个doc内容)。随后结果被普通排序以及根据size做rank排序,在此基础上只需要去相关的那几个分片请求数据的整个content字段。返回的hits的数量的依据的是用户查询时指定的 size 字段,所以只有这些内容会被获取。
- 查询阶段:
- 取回阶段
当要搜索的index有大量分片(不是副本数)的时候,用这种方式搜索特别快。
2.2 QUERY_AND_FETCH(查询并且取回,Deprecated)
思想:直接查询所有相关的分片来返回数据,每个分片都查出指定 size 的数据全部返回给调用者,再做合并、排序、返回。查询、传输的数据量 = shard数 * size
注意:一般不要手动指定为此模式。
已经在 ES 2.0.0 版本中被删除,详情点击这里
query_and_fetch(查询并且取回) 搜索类型将查询和取回阶段合并成一个步骤。这是一个内部优化选项,当搜索请求的目标只是一个分片时可以使用,例如指定了 routing(路由选择) 值时。 虽然你可以手动选择使用这个搜索类型,但是这么做基本上不会有什么效果。
2.3 DFS_QUERY_THEN_FETCH
思想:和QUERY_THEN_FETCH
思想相同,但DFS_QUERY_THEN_FETCH
有一个预查询阶段来从每个相关分片中获取TF
词频计算全局TF以获得更准确的相关性评分
注意:一般不要手动指定为此模式,不要在生产环境上使用 DFS_QUERY_THEN_FETCH 。完全没有必要。只要有足够的数据就能保证词频是均匀分布的。没有理由给每个查询额外加上 DFS 这步
dfs 搜索类型有一个预查询的阶段,它会从全部相关的分片里取回IDF来计算全局的IDF。
有时无法按相关度排序并提供简短的重现步骤: 用户索引了一些文档,运行一个简单的查询,然后发现明显低相关度的结果出现在高相关度结果之上。
可以设想,我们在两个主分片上创建了索引和总共 10 个文档,其中 6 个文档有单词 foo 。可能是分片 1 有其中 3 个 foo 文档,而分片 2 有其中另外 3 个文档,换句话说,所有文档是均匀分布存储的。
2.4 DFS_QUERY_AND_FETCH(Deprecated)
思想:和QUERY_AND_FETCH思想相同,但DFS_QUERY_AND_FETCH
有一个预查询阶段来从每个相关分片中获取TF
词频计算全局TF以获得更准确的相关性评分
注意:一般不要手动指定为此模式
已经在 ES 2.0.0 版本中被删除,详情点击这里
2.5 其他
count
和scan
已经被废弃了。
0x03 搜索选项
合理配置一些query-string
参数能够对搜索效率有很大提升。
3.1 preference
preference 参数允许你控制使用哪个分片或节点来处理搜索请求。她接受如下一些参数 _primary , _primary_first , _local , _only_node:xyz ,_prefer_node:xyz 和 _shards:2,3 。这些参数在文档搜索偏好(search preference)里有详细描述。
然而通常最有用的值是一些随机字符串,它们可以避免结果震荡问题(the bouncing results problem)。
3.2 bouncing results(结果震荡)
想像一下,你正在按照 timestamp 字段来对你的结果排序,并且有两个document有相同的timestamp。由于搜索请求是在所有有效的分片副本间轮询的,这两个document可能在原始分片里是一种顺序,在副本分片里是另一种顺序。(有点类似算法不稳定性)
这就是被称为结果震荡(bouncing results)的问题:用户每次刷新页面,结果顺序会发生变化。避免这个问题方法是对于同一个用户总是使用同一个分片。方法就是使用一个随机字符串例如用户的会话ID(session ID)来设置 preference 参数。
3.3 timeout
通常,协调节点会等待接收所有分片的回答。如果有一个节点遇到问题,它会拖慢整个搜索请求。
timeout 参数告诉协调节点最多等待多久,就可以放弃等待而将已有结果返回。返回部分结果总比什么都没有好。
搜索请求的返回将会指出这个搜索是否超时,以及有多少分片成功答复了:
...
"timed_out": true, (1)
"_shards": {"total": 5,"successful": 4,"failed": 1 (2)
}, ...
(1) 搜索请求超时。
(2) 五个分片中有一个没在超时时间内答复。
如果一个分片的所有副本都因为其他原因失败了——也许是因为硬件故障——这个也同样会反映在该答复的_shards 部分里。
3.4 routing
在路由值那节里,我们解释了如何在建立索引时提供一个自定义的 routing 参数(默认是使用_id
字段进行映射)来保证所有相关的document(如属于单个用户的document)被存放在一个单独的分片中。在搜索时,你可以指定一个或多个routing 值来限制只搜索那些分片而不是搜索index里的全部分片:
这个技术在设计非常大的搜索系统时就会派上用场。
0x04 聚合查询调优
参考:
- 详解Elasticsearch的Global Ordinals与High Cardinality
- Elasticsearch聚合优化 | 聚合速度提升5倍
- ES官网-terms-aggregation-execution-hint
以下转自作者kennywu76
global ordinals方式
Terms aggregation默认的计算方式并非直观感觉上的先查询,然后在查询结果上直接做聚台。ES假定用户需要聚台的数据集是海量的,如果将查询结果全部读取回来放到内存里计算;内存消耗会非常大。因此ES利用了一种叫做global ordinals的数据结构来对聚合的字段来做bucket分配,这个ordinals用有序的数值来代表字段里唯一的一 个字符串,因此为每个ordinals值分配一个bucke就等同于为每个唯一的term分配了 bucket。之后遍历查询结果的时候,可以将结果映射到各个bucket里,就可以很快的统计出每个bucket埋的文档数了。这种计算方式主要开销在构建global ordinals和分配bucket上,如果索引包含的原始文档非常多,查询结果包含的文档也很多,那么默认的这种计算方式是内存消耗最小、速度最快的。
execution_hint:map
如果指定execution_hint:map则会 更改聚合执行的方式,这种方式不需要构造global ordinals ,而是直接将查询结果拿回来在内存里构造一个map来计算,因此在查询结果集很小的情况下会显著的比global ordinals快。要注意的是这中间有一个平衡点,当结果集大到一定程度的时候. map的内存开销带来的代价可能就抵消了构造global ordinals的开销,从而比global ordinals更慢,所以需要根据实际情况测试对比一下才能找好平衡点。
0x05 分页
可参考
es实现分页查询的几种方式
ES深度分页查询详解
Search your data » Paginate search results
ES分页看这篇就够了
page+size 适合少量数据,深分页性能不佳
scroll占用内存,对增量数据不太好(使用快照),适合大数据量查询或导出。不能向前翻页
search_after是官方推荐的性能最好的向后翻页,向前翻页不行
5.1 深度分页定义
查询数据、取回过程虽然支持使用 from 和 size 参数进行分页,但是要在有限范围内 (within limited
)。from+size查询时,每个shard必须构造一个长度为 from+size 的优先队列,全部传回协调节点,随后协调节点需要对shard数量 * (from + size) 个document进行全局排序来找到正确的 size 个document,最后返回客户端。
根据document的数量,shard量以及硬件状况,对10,000到50,000条结果(1,000到 5,000页)深分页是可行的。但是对于很大的 from 值,排序过程将会变得非常繁重(会使用巨大量的CPU,内存和带宽)。因此,强烈不建议使用深分页。
5.2 解决方法
scroll
可以将scan(扫描) 搜索是和 scroll(滚屏) API一起使用,可从Elasticsearch里高效地取回海量结果,而不需要付出深分页的代价。为了解决深分页的问题,elasticsearch提出了一个
scroll
滚动的方式,原理是每次查询后返回一个scroll_id
,并根据这个scroll_id进行下一页的查询,可以理解为关系型数据库中的游标。具体来说,一个scroll滚屏搜索允许我们做一个初始阶段搜索并且持续批量从Elasticsearch里拉取结果直到没有结果为止。 滚屏搜索会及时制作Index快照,这个快照不会包含任何在初始阶段搜索请求后对index做的修改。
但是,这种scroll方式的缺点是不能够进行反复查询,也就是说,只能进行下一页,不能返回上一页。
scan
深度分页代价最高的部分是对结果的全局排序,但如果禁用排序,就能以很低的代价获得全部返回结果。为达成这个目的,可以采用 scan(扫描) 搜索让Elasticsearch不排序。只要shard里还有结果可以返回,就返回一批结果。scan scroll
为了使用scan-and-scroll(扫描和滚屏),需要执行一个搜索请求,将search_type 设置 成 scan ,并且传递一个 scroll 参数来告诉Elasticsearch滚屏应该持续多长时间。
GET /old_index/_search?search_type=scan&scroll=1m
{"query": { "match_all": {}},"size": 1000
}
上述请求中,将保持滚屏开启1分钟。 该请求的response中不包含任何命中的结果,而是包含了一个Base-64编码的 _scroll_id(滚屏 id) 字符串。随后就可以使用该_scroll_id
传递给 _search/scroll 末端来获取第一批1000条结果。每次循环获取数据的时候都需要传入上一次scroll response返回的_scroll_id。滚屏的终止时间会在我们每次执行滚屏请求时刷新。
- search_after
是官方推荐的性能最好的向后翻页,向前翻页不行
0xFE 总结
本文主要讲了一些搜索时调优选项,希望对大家有帮助。
0xFF 参考文档
Elasticsearch: The Definitive Guide
Elasticsearch学习-搜索调优相关推荐
- java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)
java虚拟机学习-深入理解JVM(1) java虚拟机学习-慢慢琢磨JVM(2) java虚拟机学习-慢慢琢磨JVM(2-1)ClassLoader的工作机制 java虚拟机学习-JVM内存管理:深 ...
- Elasticsearch原理与调优
elasticsearch 了解多少,说说你们公司 es 的集群架构,索引数据大小,分片有多少,以及一些调优手段 面试官:想了解应聘者之前公司接触的 ES 使用场景.规模,有没有做过比较大规模的索引设 ...
- 小白学习Spark04-Spark调优与调试
Spark调优与调试 4.1 使用SparkConf配置Spark 4.2 Spark执行的组成部分:作业.任务和步骤 4.3 查找信息 4.3.1 Spark网页用户界面 4.3.2 驱动器进程和执 ...
- ElasticSearch es 参数调优
首先上版本号:ES 版本:6.5.4 一般来说ES 的默认参数已经能够满足大部分场景需求,不需要也不建议我们去调节. 但是根据不同的业务场景我们还是可以做一些系统调优,接下来针对常用的参数总结如下: ...
- 蒸汽预测之网格搜索调优模型
首先,导入所要的库 import warnings warnings.filterwarnings("ignore") import matplotlib.pyplot as pl ...
- Elasticsearch学习-Doc与Segment原理
Elasticsearch学习-Doc与Segment原理 0x00 系列文章目录 Elasticsearch学习-关于倒排索引.DocValues.FieldData和全局序号 Elasticsea ...
- Elasticsearch学习-关于倒排索引、DocValues、FieldData和全局序号
Elasticsearch学习-关于倒排索引.DocValues.FieldData和全局序号 0x00 系列文章目录 Elasticsearch学习-关于倒排索引.DocValues.FieldDa ...
- 深度神经网络之Keras(三)——正则化、超参数调优和学习方向
深度神经网络之Keras(三)--正则化.超参数调优和学习方向 本文将继续探索Keras框架下的深度神经网络知识,主要介绍了利用Keras构建的深度神经网络正则化及超参数调优问题. 目录 深度神经网络 ...
- ElasticSearch还能性能调优,涨见识、涨见识了!!!
ElasticSearch 性能调优 作者: 博学谷狂野架构师 GitHub地址:GitHub地址 (有我们精心准备的130本电子书PDF) 概述 性能优化是个涉及面非常广的问题,不同的环境,不同的业 ...
- elasticsearch 学习须知
人工智能.大数据快速发展的今天,对于 TB 甚至 PB 级大数据的快速检索已然成为刚需.Elasticsearch 作为开源领域的后起之秀,从2010年至今得到飞跃式的发展. Elasticsearc ...
最新文章
- 【转】堆栈和托管堆 c#
- Angular1.x的自定义指令directive参数配置详细说明
- 【运维人员应该掌握哪些常用技术】
- python 如何封装dll_如何为DLL库创建Python包装器
- cve-2017-12629 apache solr xxe rce 漏洞分析
- java-基础练习题3
- 晶体封装越小esr越大_SuperFin晶体管技术加持!英特尔新一代10nm可媲美台积电5nm?...
- RFE筛选出的特征变量竟然是Boruta的4倍之多
- Python calendar日历模块的常用方法
- How do I create 2D water with dynamic waves?
- 使用Kotlin的Android Spinner
- c语言字体取模软件下载,非常好用的lcd汉字取模软件
- Python+Opencv检测模糊图片
- javascript 属性的特性 二十五
- 仿QQ音乐下载歌曲头部导航
- 加密IC 在android 机子上的简单应用
- java 分析内存_Java 内存查看与分析
- 视觉SLAM十四讲学习笔记-第三讲-旋转向量、欧拉角、四元数
- 特殊矩阵——n阶对称矩阵
- nanodet-plus