Elasticsearch
文档分布式存储
文档存储在分片上
-
文档会存储在具体的某个主分片和副本分片上:例如文档1,会存储在PO和RO分片.上
-
文档到分片的映射算法
- 确保文档能均匀分布在所用分片.上,充分利用硬件资源,避免部分机器空闲,部分机器繁忙
- 潜在的算法
-
随机/ Round Robin。当查询文档1,分片数很多,需要多次查询才可能查到文档1
-
维护文档到分片的映射关系,当文档数据:量大的时候,维护成本高
-
实时计算,通过文档1,自动算出,需要去那个分片.上获取文档
-
文档到分片的路由算法
- shard = hash(_ routing) % number of .primary_ _shards
- Hash算法确保文档均匀分散到分片中
- 默认的_ _routing 值是文档id
- 可以自行制定routing数值, 例如用相同国家的商品,都分配到指定的shard
- 设置Index Settings后,Primary 数,不能随意修改的根本原因
更新一个文档
删除一个文档
本节知识点回顾
- 可以通过设置Index Settings, 控制数据的分片
- Primary Shard的值不能修改,修改需要重新Index。默认值是5,从7开始,默认值改为1
- 索引写入数据后,Replica 的值可以修改。增加副本,可提高大并发下的读取性能
- 通过控制集群的节点数,设置Primary Shard数,实现水平扩展
分片及其生命周期
分片的内部原理
- 什么是ES的分片
- ES中最小的工作单元/是一个Lucene的Index - 一些问题:
- 为什么ES的搜索是近实时的(1秒后被搜到)
- ES如何保证在断电时数据也不会丢失
- 为什么删除文档,并不会立刻释放空间
倒排索引不可变性
-
倒排索引采 用Immutable Design,一旦生成,不可更改
-
不可变性, 带来了的好处如下:
- 无需考虑并发写文件的问题,避免了锁机制带来的性能问题
- 旦读入内核的文件系统缓存,便留在哪里。只要文件系统存有足够的空间,大部分请求就会直接请求内存,不会命中磁盘,提升了很大的性能缓存容易生成和维护/数据可以被压缩
-
不可变更性,带来了的挑战:如果需要让一个新的文档可以被搜索,需要重建整个索引。
Lucene Index
什么是Refresh
什么是Transaction Log
什么是Flush
Merge
-
Segment 很多,需要被定期被合并
- 减少 Segments /删除已经删除的文档
-
ES和Lucene会自动进行Merge操作
- POST my_ index/ forcemerge
知识点回顾
- Shard 和Lucene Index
- Index Buffer / Segment / Transaction Log
- Refresh & Flush
- Merge
剖析分布式查询及相关性评分
分布式搜索的运行机制
- Elasticsearch 的搜索,会分两阶段进行
- 第一阶段一 Query
- 第二阶段- Fetch .
- Query- -then-Fetch
Query阶段
Fetch阶段
Query Then Fetch 潜在的问题
-
性能问题
- 每个分片,上需要查的文档个数= from + size
- 最终协调节点需要处理: number_ of shard * ( from+size )
- 深度分页
-
相关性算分
- 个分片都基于自己的分片,上的数据进行相关度计算。这会导致打分偏离的情况,特别是数据量很少时。相关性算分在分片之间是相互独立。当文档总数很少的情况下,如果主分片大于1,主分片数越多,相关性算分会越不准
解决算分不准的方法
-
数据量不大的时候,可以将主分片数设置为1
- 当数据量足够大时候,只要保证文档均匀分散在各个分片上,结果一般就不会出现偏差
-
使用 DFS Query Then Fetch
-
搜索的URL 中指定参数“search?search_ type=dfs query _then. _fetch”
-
到每个分片把各分片的词频和文档频率进行搜集,然后完整的进行一次相关性算分,耗费更加多的CPU和内存,执行性能低下,一般不建议使用.
-
相关性算分问题Demo
- 写入 3条记录“Good”/“Good morning”/“good morning everyone’
- 使用1个主分 片测试,Good 应该排在第一,Good DF数值应该是3
- 和20 个主分片,测试
- 当多个个主分片时,3个文档的算分都-样。可 以通过Explain API进行分析
- 在3个主分片上 执行DFS Query Then Fetch,结果和一个分片上一致
Demo
DELETE message
PUT message
{
"settings": {
"number_of_shards": 20
}
}
GET message
POST message/_doc?routing=1
{
"content":"good"
}
POST message/_doc?routing=2
{
"content":"good morning"
}
POST message/_doc?routing=3
{
"content":"good morning everyone"
}
POST message/_search
{
"explain": true,
"query": {
"match_all": {}
}
}
POST message/_search
{
"explain": true,
"query": {
"term": {
"content": {
"value": "good"
}
}
}
}
POST message/_search?search_type=dfs_query_then_fetch
{
"query": {
"term": {
"content": {
"value": "good"
}
}
}
}
本节知识点回顾
- 学习了 分布式搜索Query then Fetch的机制
- Why/How
- Query Then Fetch带来的潜在问题
- 深度分页: 使用Search After
- 算分不准:设置1个主分片/数据量大时,只需要保证文档平均分布/ DFS Query then Fetch