ElasticSearch
2021-02-25 18:20:22 4 举报
AI智能生成
ElasticSearch
作者其他创作
大纲/内容
基于Lucene的分布式, 高可用, 全文检索的搜索引擎
分布式
集群发现及选主
节点类型
主节点
1. 不涉及到文档级别的变更和搜索等操作
2. 维护并更新Cluster 状态
3. 集群中节点的加入及移除
4. 分片的平衡
候选节点
选主过程中具有成为主节点的资格
数据节点
协调节点
1. 所有节点默认都是 协调节点
2. 请求可以发送到集群中的任一节点, 每个节点都有能力处理任意请求
3. 每个节点都知道集群中任一文档位置,所以可以直接将请求转发到需要的节点上
发现机制
Zen Discovery
单播+种子列表
discovery.zen.ping.unicast.hosts
1. 节点启动后, 先ping单播列表中的host(建议配置3个候选节点)
2. 假如host不存在则ping localhost
3. 当节点联系到单播列表中的成员时,它就会得到整个集群所有节点的状态
4. 联系master节点, 请求加入集群
文件配置发现
选主机制
Bully算法
假定所有节点都有一个唯一的ID,使用该ID对节点进行排序,选择最小的节点作为Master
Paxos算法
1. ping所有节点
2. 过滤出具有Master资格的节点
activeMasters 启用中列表
masterCandidates 候选列表
3. 选出临时Master
优先从activeMasters列表中选取
4. 判断临时Master是否是本节点
是: 等待其他节点选我
否: 不接受其他节点的join请求,并向Master节点发送加入请求
节点失效检测
主节点
定时ping所有节点
当有节点连不上时, 会执行removeNode.
当在线节点低于法定数量, 会放弃master身份执行rejoin以避免脑裂
当有节点连不上时, 会执行removeNode.
当在线节点低于法定数量, 会放弃master身份执行rejoin以避免脑裂
非主节点
定期pingMaster节点是否活跃,Master下线则触发rejoin重新选举
分片路由规则
shard = hash(routing) % number_of_primary_shards
分片数创建索引时便确定, 并且不能修改, 因为分片数涉及到分片路由
文档检索
文档(新建/索引/删除) 交互
1. 客户端向 Node 1 发送新建、索引或者删除请求。
2. 节点使用文档的 _id 确定文档属于分片 0 。请求会被转发到 Node 3,因为分片 0 的主分片目前被分配在 Node 3 上
3. Node 3 在主分片上面执行请求。如果成功了,它将请求并行转发到 Node 1 和 Node 2 的副本分片上。一旦所有的副本分片都报告成功, Node 3 将向协调节点报告成功,协调节点向客户端报告成功
在客户端收到成功响应时,文档变更已经在主分片和所有副本分片执行完成,变更是安全的
文档修改交互
1. 客户端向 Node 1 发送更新请求。
2. 它将请求转发到主分片所在的 Node 3 。
3. Node 3 从主分片检索文档,修改 _source 字段中的 JSON ,并且尝试重新索引主分片的文档。 如果文档已经被另一个进程修改,它会重试步骤 3 ,超过 retry_on_conflict 次后放弃。
4. 如果 Node 3 成功地更新文档,它将新版本的文档并行转发到 Node 1 和 Node 2 上的副本分片,重新建立索引。 一旦所有副本分片都返回成功, Node 3 向协调节点也返回成功,协调节点向客户端返回成功。
在处理读取请求时,协调结点在每次请求的时候都会通过轮询索引的所有副分片来达到负载均衡
文档查询
查询阶段
1. 客户端发送搜索请求到协调节点
2. 查询请求被转发到索引的每个主分片或副本分片中, 分片在本地执行查询并添加结果到大小为 from + size 的本地有序优先队列中
3. 分片返回各自优先队列中所有文档的 ID 和排序值给协调节点
取回阶段
1. 协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求
2. 每个分片加载并 丰富 文档(如果有需要的话),接着返回文档给协调节点
3. 一旦所有的文档都被取回了,协调节点返回结果给客户端。
scroll 游标查询(具有有效时间)
全文检索
Mapping映射及分词机制
Mapping映射
核心数据类型
字符串类型
text 用于索引全文值的字段
keyword 用于索引结构化内容的字段, 只能按其确切值进行搜索
数字类型
long, integer, short, byte, double, float, half_float, scaled_float
布尔型: boolean + 日期: date
动态映射
当索引一个包含新域的文档—之前未曾出现-- Elasticsearch 会使用 动态映射 ,通过JSON中基本数据类型,尝试猜测域类型,使用如下规则
分词机制
倒排索引的过程就是将文档通过Analyzer分成一个一个的Term,每一个Term都指向包含这个Term的文档集合。
当查询query时,Elasticsearch会根据搜索类型决定是否对query进行analyze,然后和倒排索引中的term进行相关性查询,匹配相应的文档
倒排索引
单词 - 文档矩阵
单词 - 文档矩阵是表达两者之间所具有的一种包含关系的概念模型
倒排索引基本概念
文档(Document)
文档集合(Document Collection)
文档编号(Document ID)
单词编号(Word ID)
倒排索引(Inverted Index)
单词词典
单词词典是由文档集合中出现过的所有单词构成的字符串集合,单词词典内每条索引项记载单词本身的一些信息以及指向“倒排列表”的指针
倒排列表
倒排列表记载了出现过某个单词的所有文档的文档列表及单词在该文档中出现的位置信息,每条记录称为一个倒排项(Posting)。根据倒排列表,即可获知哪些文档包含某个单词
文档频率信息(有多少个文档包含这个单词)
文档编号(哪个文档包含这个单词)
单词频率信息(这个单词在文档中的出现次数)
单词在文档出现的位置信息
倒排文件
倒排文件是存储倒排索引的物理文件
索引结构
存储结构
概念
Lucene 中 按段搜索
段 segment
一个索引文件拆分为多个子文件,则每个子文件叫作段
提交点
当段被批量的写入磁盘, 则会生成一个提交点
事务日志 translog
新建索引 -(1)-> 内存缓存 -(2)-> 文件系统缓存 -(3)-> 磁盘
步骤
1. 用户创建了一个新文档,新文档被写入[内存缓存]中 --未可读
2. 每间隔1秒, [内存缓存]中数据会以段的形式写入[文件系统缓存] --可读
3. [文件系统缓存]触发flush刷新, 段被全量提交, 且一个提交点被写入[磁盘] --持久化
分片每30分钟自动刷新(flush)
translog 太大的时候触发刷新
持久化
由于创建新文档时, 数据并不直接落到磁盘, 因此在断电时会存在数据丢失的分险
1. 用户创建一个文档时, 新文档写入[内存缓存]的同时, 也会被追加到[tanslog]
2. 随着 [translog] 变得越来越大,达到一定程度后索引被刷新,在刷新flush之后,段被全量提交,一个提交点被写入硬盘,并且[translog]被清空
段合并
由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增
每一个段都会消耗文件句柄、内存和cpu运行周期。
每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢
1. 小的段被合并到大的段,然后这些大的段再被合并到更大的段
2. 段合并的时候会将那些旧的已删除文档从文件系统中清除
优化
ES内部压缩方案
倒排列表 - postings list 的POR压缩(类似跳表)
Filter cache 的RBM压缩(位图)
分片策略
分片数设置
1. 每个分片占用的硬盘容量不超过ES的最大JVM的堆空间设置(一般设置不超过32G)
预估索引的容量设置分片数, 例如320G的索引容量则至少需要10个分片
预估索引的容量设置分片数, 例如320G的索引容量则至少需要10个分片
2. 分片数不超过节点数的3倍
推迟副本分片分配
默认情况,集群会等待一分钟来查看节点是否会重新加入
通过修改参数 delayed_timeout ,可以延长再均衡的时间
通过修改参数 delayed_timeout ,可以延长再均衡的时间
索引优化
1. 尽量避免使用nested或 parent/child Mapping类型
2. 如果一定要使用nested fields,保证nested fields字段不能过多,目前ES默认限制是50
3. 控制索引的字段数量、mapping深度、索引字段的类型
4. 不需要做模糊检索的字段使用 keyword类型代替 text 类型,这样可以避免在建立索引前对这些文本进行分词
5. 对于那些不需要聚合和排序的索引字段禁用Doc values
查询效率
1. 使用批量请求,批量索引的效率肯定比单条索引的效率要高
2. query_string 或 multi_match 的查询字段越多, 查询越慢。
可以在 mapping 阶段,利用 copy_to 属性将多字段的值索引到一个新字段,multi_match时,用新的字段查询。
可以在 mapping 阶段,利用 copy_to 属性将多字段的值索引到一个新字段,multi_match时,用新的字段查询。
3. 日期字段的查询, 尤其是用now 的查询实际上是不存在缓存的,因此, 可以从业务的角度来考虑是否一定要用now, 毕竟利用 query cache 是能够大大提高查询效率的。
4. 查询结果集的大小(分页深度)不能随意设置成大得离谱的值, 如query.setSize不能设置成 Integer.MAX_VALUE, 因为ES内部需要建立一个数据结构来放指定大小的结果集数据。
5. 避免层级过深的聚合查询, 层级过深的group by , 会导致内存、CPU消耗,建议在服务层通过程序来组装业务,也可以通过pipeline 的方式来优化。
6. cache的设置+使用
filter查询(QueryCache)
1. QueryCache 是节点级别的,每个节点上的所有分片共享一份缓存
2. Query Cache只能在Filter Context中被使用
3. Query Cache实际缓存的是Bitset(位图),一个Query clause对应一个Bitset
4. 缓存要生效,必须满足两个条件
查询对应的segments所持有的文档数必须大于10000
查询对应的segments所持有的文档数必须大于整个索引size的3%
5. 当新索引文档时,Query Cache不会重新计算,而是判断索引的文档是否符合缓存对应的Query clause,满足则加入BitSet中
聚类或排序(FieldDataCache)
ShardRequestCache
查询API
查询/搜索
分页
from, size
分页原理
1. 假设查询请求from=10, size=5
2. 协调节点把查询请求分发到各分片中, 分片查询返回其排序前15的数据到协调节点
3. 假设索引分片数=4, 则协调节点最多会收到60条数据, 并重新进行排序返回5条给客户端
在分布式系统中,对结果排序的成本随分页的深度成指数上升
_all
当索引一个文档的时候,Elasticsearch 取出所有字段的值拼接成一个大的字符串,作为 _all 字段进行索引
除非设置特定字段,否则查询字符串就使用 _all 字段进行搜索
请求体查询
filltter与query的区别: fillter不影响评分
query
fillter
1. 通过倒排索引获取包含该 term 的所有文档
2. 创建 bitset, 一个段对应一个bitset
3. 迭代 bitset(s)
一旦为每个查询生成了 bitsets ,Elasticsearch 就会循环迭代 bitsets 从而找到满足所有过滤条件的匹配文档的集合
一旦为每个查询生成了 bitsets ,Elasticsearch 就会循环迭代 bitsets 从而找到满足所有过滤条件的匹配文档的集合
4. 增量使用计数
查询在最近的 256 次查询中会被用到,那么它就会被缓存到内存中
当 bitset 被缓存后,缓存会在那些低于 10,000 个文档(或少于 3% 的总索引数)的段(segment)中被忽略
query叶子体
match 标准查询
如果在一个全文字段上使用 match 查询,在执行查询前,它将用正确的分析器去分析查询字符串
如果在一个精确值的字段上使用它,那么它将会精确匹配给定的值
multi_match 多个字段上执行相同的 match 查询
range 查询找出那些落在指定区间内的数字或者时间
term 查询被用于精确值匹配
terms 查询和 term 查询一样,但它允许你指定多值进行匹配
exists 查询和 missing 查询被用于查找那些指定字段中有值 (exists) 或无值 (missing) 的文档
bool组合查询
must 文档 必须 匹配这些条件才能被包含进来
must_not 文档 必须不 匹配这些条件才能被包含进来
should 如果满足这些语句中的任意语句,将增加 _score ,否则,无任何影响。它们主要用于修正每个文档的相关性得分
filter 必须 匹配,但它以不评分、过滤模式来进行。这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档。
constant_score查询
以非评分模式来执行 term 查询并以1作为统一评分
0 条评论
下一页