一、ElasticSearch基础
1、什么是Elasticsearch
分布式实时全文搜索引擎(每个字段都被索引并可被搜索)
全文检索是指对每一个词建立一个索引,指明该词在文章中出现的次数和位置。当查询时,根据事先建立的索引进行查找,并将查找的结果反馈给用户的检索方式。这个过程类似于通过字典中的检索字表查字的过程。
2、基本概念
(1)index 索引:索引类似于mysql 中的数据库,存放数据的地方,包含了一堆有相似结构的文档数据。
(2)type 类型:用来定义数据结构,可以认为是 mysql 中的一张表,type 是 index 中的一个逻辑数据分类
(3)document 文档:类似于 MySQL 中的一行,不同之处在于 ES 中的每个文档可以有不同的字段,但是对于通用字段应该具有相同的数据类型,文档是es中的最小数据单元,可以认为一个文档就是一条记录。
(4)Field 字段:Field是Elasticsearch的最小单位,一个document里面有多个field
(5)shard 分片:es可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。
(6)replica 副本:任何一个服务器随时可能故障或宕机,此时 shard 可能会丢失,因此可以为每个 shard 创建多个 replica 副本。replica可以在shard故障时提供备用服务,保证数据不丢失,多个replica还可以提升搜索操作的吞吐量和性能。primary shard(建立索引时一次设置,不能修改,默认5个),replica shard(随时修改数量,默认1个),默认每个索引10个 shard,5个primary shard,5个replica shard,最小的高可用配置,是2台服务器。
(7)分词器(Tokenizer):将文本数据分成一个个词语的工具。ES内置了多种分词器,如标准分词器、简单分词器、路径分词器等,同时也支持自定义分词器。
(8)映射(Mapping):描述文档数据结构。定义了每个字段的数据类型、分词器、索引方式等属性
3、什么是倒排索引:
关键词(字段值)到文档id的映射
例如,某个文档经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。
每个关键词都对应着一系列的文件,这些文件中都出现了该关键词。
要注意倒排索引的两个重要细节:
- 倒排索引中的所有词项对应一个或多个文档
- 倒排索引中的词项 根据字典顺序升序排列
4、DocValues的作用:
文档id到关键词(字段值)的映射
用途:
聚合(如分组):例如根据某一个/多个字段进行分组,必须要知道每个文档中该字段对应的值是什么才能进行分组
排序:例如根据一个/多个字段进行排序,必须要通过文档来知道字段值才能进行排序
某些过滤,比如地理位置过滤
某些与字段相关的脚本计算
总结:任何需要通过文档来获取文档内部字段具体值的操作都依赖DocValues.
原理:
DocValues 就是 es 在构建倒排索引时创建,可以指定某字段是否开启或关闭DocValues
DocValues 保存在操作系统的磁盘中
当docValues大于节点的可用内存,ES可以从操作系统页缓存中加载或弹出,从而避免发生内存溢出的异常
当docValues远小于节点的可用内存,操作系统自然将所有Doc Values存于内存中(堆外内存),有助于快速访问
5、text 和 keyword类型的区别:
两个的区别主要分词的区别:
keyword 类型不会分词
Text 类型先分词然后根据分词后的内容建立倒排索引
6、什么是停顿词过滤:
停顿词可以看成是没有意义的词,比如“的”、“而”,这类词没有必要建立索引
7、query 和 filter 的区别?
filter的作用
通过不同的过滤类型来过滤文档
比如范围过滤(range)、存在过滤(exists)、缺失过滤(missing)等
过滤器不会计算文档的相关性得分,通常用于需要根据数值、日期等非文本内容进行筛选的场景
因为不需要计算相关性得分,所以在性能方面通常比查询更快
query的作用
用来搜索匹配特定条件的文档
比如匹配查询(match)、短语查询(phrase)、前缀查询(prefix)等
查询会计算文档的相关性得分,根据相关性得分进行排序并返回结果
查询通常用于需要根据文本内容进行搜索的场景。
相关性得分如何计算?
1 | 计算分值的过程可以简单的描述为以下几个步骤: |
二、ES的写入流程
1、es 写数据的过程
(1)客户端请求发送至协调节点
(2)协调节点进行路由,转发给对应的node
(3)对应node主节点处理,并将处理结果同步给副本
(4)主节点和副本节点都都执行成功之后,就返回响应结果给客户端
2、写数据的底层原理
(1)refresh(刷新)的过程
数据写入–>memory buffer–(每隔1s)–>segment+Filesystem cache+清空memory buffer
数据被 refresh 到 Filesystem cache 之后才能被搜索到,每秒一次,所以是近实时性
(2)translog用途
用于记录所有的写入操作,在服务器宕机时恢复数据
默认每隔 5 秒刷一次到磁盘中,如果此时机器宕机,会丢失 5 秒钟的数据
(3)flush (冲洗)操作
translog 文件超过 512M或者到达30分钟时执行flush操作
- 先执行refresh
- 将 Filesystem Cache 中所有的数据都 fsync 到磁盘文件中
- 删除旧的 translog 日志文件并创建一个新的 translog 日志文件
三、ES的更新和删除流程
es文档是不可变的,因此删除和更新都是写操作
ES 利用 .del 文件标记文档是否被删除
(1)删除操作是在 .del 文件中被标记为 deleted 状态。该文档依然能匹配查询,但是会在结果中被过滤掉
(2)更新操作,就是将旧的 doc 标识为 deleted 状态,然后创建一个新的 doc
四、ES的搜索流程
搜索被执行成一个两阶段过程,即 Query Then Fetch:
1、Query阶段
- 客户端发送请求到协调节点
- 协调节点将搜索请求广播到所有的 primary shard 或 replica shard
- 每个分片返回查询结果(文档ID和排序值)给协调节点
- 协调节点进行数据的合并、排序、分页等操作
2、Fetch阶段
协调节点根据文档id去查询文档数据,并将返回结果给客户端
协调节点对文档id进行哈希路由,将请求转发到对应的 node,使用随机轮询算法,在主副分片中随机选择一个
五、ES在高并发下如何保证读写一致性
(1)对于写操作
one:要求只要有一个主分片是可用的就可以执行
all:要求所有对主副分片都是可用的才可以执行
quorum:默认的值,要求大多数分片是可用的才可以执行
(2)对于更新操作:采用乐观锁控制版本号实现
(3)对于读操作
可以设置 replication(复制) 为 sync(默认),这使得操作在主分片和副本分片都完成后才会返回
如果设置replication 为 async 时,也可以通过设置搜索请求参数_preference
为 primary 来查询主分片,确保文档是最新版本。
六、ES分布式原理
1、分布式原理
1 | 1. 分片机制:将索引划分为多个分片,每个分片可以分布在不同的节点上,可以提高数据的可用性和可扩展性 |
2、如何选举 Master
集群中可以有多个候选节点,当多数候选节点确认集群中没有master节点时可以发起master选举
通过ZenDiscovery来实现,确保节点间互相通信达到节点信息在集群内的同步
- 设置候选主节点的最少投票通过数量
- 选举节点对所有候选节点根据节点Id 排序,第一位的暂且认为它是master节点
- 如果对某个节点的投票数达到阈值,并且该节点自己也选举自己,那这个节点就是master。否则重新选举一直到满足上述条件。
master节点的作用是什么?
1 | 1. 索引管理:创建、删除、分配和重分配等操作,以及Shard的分配和副本的配置 |
3、如何避免脑裂现象
(1)当集群中 master 候选节点数量不小于3个时,可以通过设置最少投票通过数量,设置超过所有候选节点一半以上来解决脑裂问题,即设置为 (N/2)+1
;
(2)当集群 master 候选节点 只有两个时,这种情况是不合理的,最好把另外一个node.master
改成false。
七、建立索引阶段性能提升方法
1 | 1. 硬件优化:升级cpu、内存、硬盘等 |
八、ES的深度分页与scroll
什么是深度分页?
跳过大量数据来查询更深的数据,这就涉及到大量数据的扫描,性能很低
深度分页的常见方案from+size
from表示从什么位置开始取值,size表示取值数量
这种方案的问题是当from+size>10000时将报错,也就是说只能查询前一万条数据
每次查询时from前的条目也会被搜索,极大浪费系统资源
searchAfter
以数值类型且具备唯一性的字段作为排序字段(放在sort中),每次查询携带上次查询的最后一条数据的排序字段值(放在search_after),从而实现分页.
优点:效率比from+size高
缺点:
1、由于需要sort排序,所以每次查询依然会扫描docvalue,因此搜索越深效率越低
2、只能一页一页翻,不能挑页
3、对排序字段有要求,并不是所有排序字段都能分页
scroll游标
它允许我们在处理大量数据时,持续地获取结果,而不必一次性获取所有结果。其原理如下:
1、第一次发送请求携带scroll参数和查询条件(1m表示有效期1分钟)
1 | POST /my-index-000001/_search?scroll=1m |
2、第一次查询结果携带scroll_id,用于标识此次查询结果集(相当于es保存了查询结果快照)
3、下次查询只需要携带scroll_id和查询条件,ES会返回下一批结果
4、这样不断循环,直到获取到所有查询结果为止
5、当我们完成查询时,需要发送一个清除scroll请求,以释放资源
原理是在查询时生成ScrollContext对象
1 | public final class ScrollContext { |
其中有个关键变量lastEmittedDoc,这个记录了上次scroll遍历到的docId位置,也就是借助这个字段实现深度查询
缺点:非实时、大量数据搜索/下载、不支持跳页
参考资料:
[1]https://segmentfault.com/a/1190000042029202
[2]https://zhuanlan.zhihu.com/p/231790621
版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接,感谢各位看官!!!
本文出自:monkeyGeek
座右铭:生于忧患,死于安乐
欢迎志同道合的朋友一起交流、探讨!
