ElasticSearch 总结
ES 思维导图
ES 的定位
- ES 是 build on top of Lucene 建立的可以集群化部署的搜素引擎。
ES 可以是 document store(此处可以理解为文档仓库或者文档存储),可以结构化解决数据仓库存储的问题。在 es 中一切皆对象,使用对象对数据建模可以很好地处理万事万物的关系。
ES 是海量数据的分析工具能够支持:搜索、分析和实时统计。
ES 的架构有优越的地方:
- 自己使用 pacifica 协议,写入完成就达成共识。
- 节点对内对外都可以使用 RESTful API(or json over http)来通信,易于调试。
- 因为它有很多很好的默认值,所以开箱即用。
- 它天生就是分布式的,可以自己管理多节点。
ES 的架构
ES 是基于 Lucene 的,集群上的每个 node 都有一个 Lucene 的实例。而 Lucene 本身是没有 type 的,所以 ES 最终也去掉了 type。
ES 中每个节点自己都能充当其他节点的 proxy,每个节点都可以成为 primary。用户需要设计拓扑的时候只需要关注种子节点和 initial master 即可。
ES 中的搜索
全文搜索
按照《全文搜索》中的例子,使用 match 总会触发全文搜索。因为在Elasticsearch中,每一个字段的数据都是默认被索引的。也就是说,每个字段专门有一个反向索引用于快速检索。想不要做索引需要对任意的 properties 使用 "index": "not_analyzed"
。
精确(短语)搜索
精确查询的方法有:
短语查询:
1 |
|
这种查询可以查出rock climbing
和a rock climbing
。
term 查询(这种查询是客户端查询里最常用的):
1 |
|
这种查询可以查出rock climbing
,不可以查出a rock climbing
。
另一种 phrase 查询:
1 |
|
精确和不精确查询有好几种方法,详见《elasticsearch 查询(match和term)》 和《finding_exact_values》。
注意,es 的查询可以有很多的变种:
1 |
|
search api 的搜索
参考《空查询》。
倒排索引简析
倒排索引的 key 是 term,value 是文档的指针,可以参考这个《倒排索引》文档。
过滤机制
头机制
x-pack
version 机制
容量与分片
为何分片不宜过大?
- 增加索引读压力-不利于并行查询。
- 不利于集群扩缩容(分片迁移耗费较长时间)。
- 集群发生故障时,恢复时间较长。
类似的问题也会发生在 Redis 之类的架构方案里。
解决大分片的方法
- 索引按月、日进行分割。
- delete_by_query 方法删除索引对索引进行缩容。
- 模板增加主分片数量-存疑,通常只能增加副本数,而无法改变切片比例。
- 扩容数据节点。
- 减小单位分片大小。
一个可实操的方案:
- 修改写入逻辑和 mapping,让新写入的 doc 的 field 变少。
- 对老的索引进行 delete_by_query。
常用查询段
- aggs
- match
- 等于分词以后的 or 查询,依赖于 analyzer。“hello world”如果被分词为 hello 和 world,则类似
term = hello or term = wolrd
。
- 等于分词以后的 or 查询,依赖于 analyzer。“hello world”如果被分词为 hello 和 world,则类似
- match_phrase
- term 出现在一个句子中,句子包含 term,依赖于 analyzer。类似
contains("hello world")
- 这是 String.contains。
- 不匹配 slop,还不如用 term。
- term 出现在一个句子中,句子包含 term,依赖于 analyzer。类似
- page:
- range:是大于等于小于的意思,不是 from 和 size
- search_after
- term
- term 类似于 Collection.contains
"[hello, world]".contains("hello")
和"[hello]".terms("hello")
都成立。
- term 类似于 Collection.contains
- terms:term 的数组形式,类似
in
,是多值或的意思。 - wildcard:
- 允许指定匹配的正则式。它使用标准的 shell 通配符查询:? 匹配任意字符,* 匹配 0 或多个字符。
写入流程
同步双写:对数据的实时性要求极高,通常在一个事务中完成数据的双写动作,保证数据层面的强一致性;
异步解耦:在完成数据库的写动作之后,基于MQ消息解耦索引的写入,流程存在轻微的延迟,如果消费失败会导致数据缺失;
定时任务:通过任务调度的方式,以指定的时间周期执行新增数据的同步机制,存在明显的时效问题;
组件同步:采用合适的同步组件,比如官方提供的组件或者一些第三方开源的组件,在原理上与任务同步类似;
数据同步的选型方案有多种,如何选择完全看具体的场景,在过往的使用过程中,对于核心业务会采用同步双写,对于内部的活动类业务会采用异步的方式,对于业务日志会采用任务调度,对于系统的监控或执行日志则多是依赖同步组件;
数据同步
设计难点
翻页
ES中常用From/Size进行分页查询,但是存在一个限制,在索引的设置中存在max_result_window分页深度的限制,6.8版本默认值是10000条,即10000之后的数据无法使用From/Size翻页;
先从实际应用场景来分析,大多数的翻页需求最多也就前10页左右,所以从这个角度考虑,ES的翻页限制在合理区间,在实践中也存在对部分索引调高的情况,暂未出现明显问题;
再从技术角度来思考一下,如果翻页的参数过大意味着更多的数据过滤,那计算资源的占用也会升高,ES引擎的强大在于搜索能力,检索出符合要求的数据即可;
索引设计
聚合
指标聚合
桶聚合
性能分析
Quantitative Cluster Sizing
It depends.
ES 运行,是要解决 scale 和 speed 的矛盾。
有4种 basic computing resources:
- storage: 热数据放在贵硬件里。分成 warm tier 和 cold tier。
- memory:heap 使用 50% 内存就行了,堆不需要超过30gb,否则 gc 会是大问题:biz object、meta data(index、cluster)、segment。剩下的内存仍然有用,os cache、file cache 用来存储搜索和分析用的数据 in a cache format。es 会有很棒的缓存机制,既缓存最热的,也缓存长尾的(也要关注长尾是很多人意想不到的)。
- ML 节点很消耗内存。
- 如果有必要,使用 dedicated server 来 host master 节点。
- compute:
- 一定要知道我们的核心数、线程数和队列数的关系。
- network:
- 跨级群搜索的时候需要考虑网络问题。这时候我们要考虑“联合客户端”tribe node。
基本操作:
- index: store for future retrieval.
- delete
- update
- search