点一下关注吧!!!非常感谢!!持续更新!!!
目前已经更新到了:
- Hadoop(已更完)
- HDFS(已更完)
- MapReduce(已更完)
- Hive(已更完)
- Flume(已更完)
- Sqoop(已更完)
- Zookeeper(已更完)
- HBase(已更完)
- Redis (已更完)
- Kafka(已更完)
- Spark(已更完)
- Flink(已更完)
- ClickHouse(已更完)
- Kudu(已更完)
- Druid(已更完)
- Kylin(已更完)
- Elasticsearch(正在更新...)
章节内容
上节我们完成了如下的内容:
- Elasticsearch 并发冲突处理机制剖析
- Elasticsearch 分布式数据一致性剖析
DocValues 机制
Doc Values 是一种以列式存储的索引机制,用于在检索时优化磁盘读取操作。与反向索引不同,反向索引是基于倒排表的结构,主要用于快速查找文档中包含某个词的情况,而 Doc Values 则是用于在不加载整个文档的情况下高效获取某个字段的值,适用于以下场景:
- 排序:当根据某个字段进行排序时,Doc Values 提供了高效的读取机制。
- 聚合:在执行类似于 terms、sum、average 等聚合操作时,Doc Values 的列存储可以快速读取并计算相关值。
- 过滤:当对文档字段进行范围过滤等操作时,Doc Values 也能加速这些查询。
为什么要有Doc Values
Elasticsearch之所以搜索这么迅速,归功于它的倒排索引设计,然后它也不是万能的,倒排索引的检索性能是非常快的,但是在字段排序时却不是理想的结构:
shell
Term Doc_1 Doc_2
-------------------------
quick | | X
the | X |
brown | X | X
dog | X |
dogs | | X
fox | X |
foxes | | X
in | | X
jumped | X |
lazy | X | X
leap | | X
over | X | X
summer | | X
the | X |
------------------------
如上面的内容中可以看出,它只有词对应doc,但是并不知道每一个doc中的内容,那么如果想排序的话每一个doc都去获取一次文档内容岂不是非常耗时?DocValues的出现使得这个问题迎刃而解。
字段的 doc_values 属性有两个值,true、false,默认是true,即开启。
当 doc_values 为 false 时,无法基于该字段排序、聚合、在脚本中访问字段值。
当 doc_values 为 true 时,ES会增加一个相应的正排索引,这增加的磁盘占用,也会导致索引数据速度慢一些。
Doc Values 是列式存储的,这意味着每个字段值都以列的形式存储在磁盘中,而不是像原始文档那样存储在行中。这种方式有助于优化数据的读取,因为在执行排序或聚合时,Elasticsearch 只需访问与操作相关的字段,而不需要加载整个文档。
每个文档的字段值在索引时被预处理,并以压缩的形式存储为 Doc Values,这些值会以内存映射文件(memory-mapped file)的方式加载到内存中,以便进行快速读取。
Doc Values举例
创建一个索引:
json
PUT /person
{
"mappings" : {
"properties" : {
"name" : {
"type" : "keyword",
"doc_values": true
},
"age" : {
"type" : "integer",
"doc_values": false
}
}
}
}
写入相对应的数据:
shell
POST _bulk
{ "index" : { "_index" : "person", "_id" : "1" } }
{ "name" : "明明", "age": 22 }
{ "index" : { "_index" : "person", "_id" : "2" } }
{ "name" : "丽丽", "age": 18 }
{ "index" : { "_index" : "person", "_id" : "3" } }
{ "name" : "媛媛", "age": 19 }
执行结果如下图所示:
进行全量查询,确认一下数据的情况:
json
POST /person/_search
{
"query": {
"match_all": {}
},
"sort" : [
{
"name": {
"order": "desc"
}
}
]
}
执行结果如下图所示:
什么是Doc Values
Doc Values 通过转置倒排索引和正排索引两者间的关系来解决这个问题,倒排索引将词项映射到包含它的文档:
shell
Doc Terms
-----------------------------------------------------------------
Doc_1 | brown, dog, fox, jumped, lazy, over, quick, the
Doc_2 | brown, dogs, foxes, in, lazy, leap, over, quick, summer
Doc_3 | dog, dogs, fox, jumped, over, quick, the
-----------------------------------------------------------------
当数据被转置后,想要收集到每个文档行,获取所有的词项就非常简单了。
深入理解ES Doc Values
DocValues是索引时与倒排索引同时生成,也就是说DocValues和倒排索引一样,基于Segment生成并且是不可变的,同时DocValues和倒排索引一样序列化到磁盘,这样对性能和扩展性有很大帮助。
DocValues通过序列化把数据结构持久化到磁盘,我们可以充分利用操作系统的内存,而不是JVM的Heap,当workingset远小于系统的可用内存,系统会自动将DocValues保存在内存中,使得读写十分高速。
不过当远大于可用内存时,操作系统会自动把DocValues写入磁盘。很显然,这样性能会比内存要差很多,但是它不会局限于服务器的内存大小。
DocValues 压缩
从广义来说,DocValues本质上是一个序列化的列式存储,这个结构非常适用于聚合、排序、脚本等操作。而且,这种存储方式非常的便于压缩,特别是数字类型,这样可以减少磁盘空间并且提高访问速度。
下面我们看一组数字类型的DocValues:
shell
Doc Terms
-----------------------------------------------------------------
Doc_1 | 100
Doc_2 | 1000
Doc_3 | 1500
Doc_4 | 1200
Doc_5 | 300
Doc_6 | 1900
Doc_7 | 4200
-----------------------------------------------------------------
你会注意到这里每个数字都是100的倍数,DocValues会检测一个段里面的所有数值,并使用一个最大公约数,方便做进一步的数据压缩,我们可以对每个数字都除以100,然后得到:[1,10,15,12,3,19,42]。现在这些数字变小了,只需要很少的位就可以存储下,也减少了磁盘存放的大小。
DocValues在压缩过程中使用如下技巧,它会依次检测以下压缩模式:
- 如果所有的数值各不相同(或缺失),设置一个标记并记录这些值
- 如果这些值小于256,将使用一个简单的编码表
- 如果这些值大于256,检测是否存在一个最大公约数
- 如果没有存在最大公约数,从最小的数值开始,统一计算偏移量进行编码
当然如果存储String类型,其一样可以通过顺序表对String类型进行数字编码,然后再把数字类型构建DocValues。
禁用 Doc Values
DocValues 默认对所有字段启动,除了 analyzed strings。也就是说所有的数字、地理坐标、日期、IP和不分析(not_analyzed)字符类型都会默认开启。
analyzed strings暂时还不能使用 DocValues,是因为经过分析以后得文本会生成大量的Token,这样非常影响性能。
虽然DocValues非常好用,但是如果你存储的数据确实不需要这个特性,就不如禁用它,这样不仅节省磁盘空间,也许会提升索引的速度。
要禁用DocValues,在字段的映射mapping设置doc_values:false即可。例如,这里我们创建了一个新的索引,字段 session_id禁用了DocValues:
json
DELETE /my_index
{
"mappings": {
"properties": {
"session_id": {
"type": "keyword",
"doc_values": false
}
}
}
}
通过设置 doc_values:false,这个字段将不能被用于聚合、排序以及脚本操作
带来的优势
- 减少内存使用:由于 Doc Values 将字段值存储在磁盘上并在需要时读取,因此相比内存中保持字段值的方式(例如 fielddata),它极大地减少了内存的使用。
- 高效的磁盘读取:Doc Values 的列式存储意味着在执行排序或聚合操作时,Elasticsearch 可以只加载所需的字段值,而不必加载整个文档。
- 提高排序和聚合的性能:对于经常需要排序或聚合的字段,Doc Values 可以显著提高性能,因为它优化了读取路径。
使用场景
- 排序:例如,用户需要根据时间戳排序查询结果,Doc Values 会提供优化的列式存储,直接从磁盘读取时间戳的值进行排序,而不需要加载整个文档。
- 聚合:在执行例如统计某个字段的平均值、最大值或分布情况时,Doc Values 可以极大地提高查询的响应速度,因为只需读取相关字段即可。
- 范围查询:例如查找价格在一定范围内的文档时,Doc Values 允许快速扫描价格字段而不涉及文档的其他内容。