ElasticSearch排序那点事-doc_values

一、为什么要有Doc Values

我们都知道 ElasticSearch 之所以搜索这么快速,归功于他的 倒排索引 的设计,然而它也不是万能的,倒排索引的检索性能是非常快的,但是在字段值排序时却不是理想的结构。下面是一个简单的 倒排索引 的结构:
ElasticSearch排序那点事-doc_values_第1张图片
如上表可以看出,它只有词对应的doc,并不知道每个doc的内容,那么想要排序的话每个doc都去获取一次文档内容就很耗时了。DocValues的出现,那么这个耗时的问题就迎刃而解了。
字段的 doc_values 属性有两个值, true、false。默认为 true ,即开启。当 doc_values 为 fasle 时,无法基于该字段排序、聚合、在脚本中访问字段值。当 doc_values 为 true 时,ES 会增加一个相应的正排索引,这增加的磁盘占用,也会导致索引数据速度慢一些。举例:

PUT /person
{
    "mappings" : {
        "properties" : {
            "name" : {        
                "type" : "keyword",
                "doc_values": true
            },
            "age" : {
                "type" : "integer",
                "doc_values": false
            }
        }
    }
}

二、内核级DocValues机制大揭秘

2.1 什么是DocValues?

DocValues 通过转置倒排索引和正排索引两者间的关系来解决这个问题。倒排索引将词项映射到包含它们的文档, Docvalues 将文档映射到它们包含的词项:
ElasticSearch排序那点事-doc_values_第2张图片
当数据被转置之后,想要收集到每个文档行,获取所有的词项就非常简单了。所以搜索使用倒排索引查找文档,聚合操作收集和聚合 DocValues 里的数据,这就是 ElasticSearch。

2.2 深入理解ElasticSearch的DocValues

DocValues 是在索引时与倒排索引同时生成。也就是说 DocValues 和 倒排索引 一样,基于Segement 生成并且是不可变的。同时 DocValues 和 倒排索引 一样序列化到磁盘,这样对性能和扩展性有很大帮助。
DocValues 通过序列化把数据结构持久化到磁盘,我们可以充分利用操作系统的内存,而不是 JVM 的Heap 。 当 workingset 远小于系统的可用内存,系统会自动将 DocValues 保存在内存中,使得其读写十分高速; 不过,当其远大于可用内存时,操作系统会自动把DocValues 写入磁盘。很显然,这样性能会比在内存中差很多,但是它的大小就不再局限于服务器的内存了。如果是使用 JVM 的 Heap来实现是因为容易 OutOfMemory 导致程序崩溃了。

2.3 DocValues压缩

从广义来说, DocValues 本质上是一个序列化的列式存储,这个结构非常适用于聚合、排序、脚本等操作。而且,这种存储方式也非常便于压缩,特别是数字类型。这样可以减少磁盘空间并且提高访问速度。下面来看一组数字类型的 DocValues :
ElasticSearch排序那点事-doc_values_第3张图片
你会注意到这里每个数字都是 100 的倍数, DocValues 会检测一个段里面的所有数值,并使用一个最大公约数 ,方便做进一步的数据压缩。我们可以对每个数字都除以 100,然后得到:[1,10,15,12,3,19,42] 。现在这些数字变小了,只需要很少的位就可以存储下,也减少了磁盘存放的大小。
DocValues 在压缩过程中使用如下技巧。它会按依次检测以下压缩模式:
●如果所有的数值各不相同(或缺失),设置一个标记并记录这些值
●如果这些值小于 256,将使用一个简单的编码表
●如果这些值大于 256,检测是否存在一个最大公约数
●如果没有存在最大公约数,从最小的数值开始,统一计算偏移量进行编码
当然如果存储 String 类型,其一样可以通过顺序表对 String 类型进行数字编码,然后再把数字类型构建 DocValues 。

2.4 禁用DocValues

DocValues 默认对所有字段启用,除了 analyzed strings 。也就是说所有的数字、地理坐标、日期、IP 和不分析( not_analyzed )字符类型都会默认开启。analyzed strings 暂时还不能使用 DocValues ,是因为经过分析以后的文本会生成大量的Token ,这样非常影响性能。虽然 DocValues 非常好用,但是如果你存储的数据确实不需要这个特性,就不如禁用他,这样不仅节省磁盘空间,也许会提升索引的速度。
要禁用 DocValues ,在字段的映射(mapping)设置 doc_values:false 即可。例如,这里我们创建了一个新的索引,字段 “session_id” 禁用了 DocValues :

PUT my_index
{
    "mappings": {
        "properties": {
            "session_id": {
                "type": "keyword",
                "doc_values": false
            }
        }
    }
}

通过设置 doc_values:false ,这个字段将不能被用于聚合、排序以及脚本操作

你可能感兴趣的:(ElasticSearch,elasticsearch,java,大数据)