Introduction to Elasticsearch2.X Doc values

1. Introduction to doc_values

doc values ​​is an important topic we repeat over and over again, do you realize something?

  • When searching, we need a mapping of "words" to a list of "documents"
  • When sorting, we need a "document" to "word" list mapping, in other words, we need a "forward index" built on the basis of the inverted index

The "forward index" structure here is usually called "column storage" in other systems (such as relational databases). Essentially, it stores all values ​​in one column of the data field, and this structure can be very efficient for certain operations, such as sorting.

This "column storage" in ES is known as "doc values", which is enabled by default, and doc values ​​are created at index-time: when a field is indexed, ES will Add "words" to the inverted index, and also add those words to the "column-oriented" doc values ​​(stored on disk).

doc values ​​are usually used in the following ways:

  • Sort by a field
  • Aggregate based on a field
  • Execute some filters (eg: geolocation filter)
  • One or more fields are referenced in script

Since doc values ​​are serialized to disk at index time, we can use the operating system to quickly access them. How doc values ​​are managed on disk will be discussed later.

Most fields are indexed by default, which makes them searchable. Inverted indexes allow a query to sort based on a vocabulary, as well as quickly access a list of documents that contain a word.

Sorting, aggregating, and accessing some field values ​​in a script all require a different access method, since inverted indexes do not support this access, so we need a structure that can query the document-to-word mapping.

doc values ​​are disk-based data structures created at index time that make the above access possible. doc values ​​support most field types, except for "analyzed" type string fields.

All fields support doc values ​​by default, if you're sure you don't need to sort or aggregate on a field or access it in a script, you can disable it:

 

  1. status_code字段默认开启doc_values
  2. session_id字段禁用了doc_values,虽然被禁用但是还是可以被查询

TIP:doc_values可以在同一个索引的同名字段上设置不同值,它也可以基于一个已存在的字段使用put mapping api来禁用它。

看如下的倒排索引结构:

如果我们想为每一个包含“brown”的文档编辑一份完整的词列表,我们可能会用如下查询:

看上面的查询部分。倒排索引通过词条排好了序,所以我们首先找到包含“brown”的词条列表,然后跨列扫描所有包含“brown”的文档,这里我们很幸运的找到了“Doc_1”和“Doc_2”。

然后在聚合部分,我们需要找Doc_1和Doc_2中找到所有的词,在倒排索引的去做这个操作很非常昂贵的:意味着我们不得不迭代索引中的每一个词,看它们是否包含在doc_1和doc_2中,这个过程是非常缓慢的,而且也是非常傻逼的:因为随着文档词量的增加,我们聚合的执行时间也会增加。

让我们看看下面的结构:

有了这个结构我们就会很容易得到doc_1和doc_2所包含的词条,我们只需要通过上面的结构把两个集合合并起来就行了。

因此,查询和聚合是非常复杂的,查询文档使用的是倒排索引,聚合文档使用的是正排索引(doc_values)

note:doc values不仅仅是用在聚合中,还被用在排序、脚本、子父文档关系(这里暂不做介绍)。

二、深入Doc Values

前面讲到的doc values给我们几个印象:快速访问、高效、基于硬盘。现在我们来看看doc values到底是如何工作的?

doc values是在“索引期“随着倒排索引一起生成的,也就是说 doc values是基于每个索引段生成且是不可改变的(immutable), 和倒排索引一样,doc values也会被序列化到磁盘上,这使得它具有了高效性和可扩展性。

通过序列化一个数据结构到磁盘上,我们可以依赖操作系统的 file system cache 替代JVM的堆内存,当我们的“工作集”小于OS可用内存时,操作系统会自然的加载这些doc values到内存。这时doc values的性能和在JVM堆内存中表现是一样的。

但是当工作集大于操作系统可用内存时,操作系统将会按需加载doc values,这种情况下的访问速度会明显的慢于全量加载doc values的时候。但这种操作使得我们的服务器内存利用率远超过服务器最大内存限制。试想一下,如果全量加载到doc values到内存中势必会造成ES OutOfMemery。

NOTE:由于doc values不受JVM堆内存管理,所以我们可以把ES对内存设置得小一点,把更多的内存留给操作系统来换出(doc values),同时这也可以使JVM的GC工作在更小的堆内存上,更快更高效的执行GC。

通常,我们配置JVM的堆内存基本和操作系统内存各占一半(50%),由于引进了doc values所以我们可以考虑把JVM的堆内存设置得小一些,比如我们可以在一个64G的服务器上设置JVM堆内存为4 – 16GB比设置堆内存为32G更加高效。

三、Column-store compression(列式存储压缩)

本质上doc values是一个被序列化的面向“列式储存”的结构,我们前面讨论过列式存储在某些查询操作上是有优势的,不仅如此它们也更擅长数据压缩,特别是数字,这对磁盘存储和快速访问来说是及其重要的。

为了了解它是如何压缩数据的,我们看下面简单的doc values结构

像上面这种每行一条数据的形式,我们可以得到连续的数字块,如:[100,1000,1500,1200,300,1900,4200]。因为我们知道它们都是数字值可以被排列在一起通过一个一致的偏移量。

跟深层次的,这里有几种压缩方法可以运用在这些数字上。你可能知道上面的数字都是100的倍数,如果索引段上所有的的数字都共享一个“最大公约数”,那么就可以用这个最大公约数去压缩数据。如上面的数字我们可以除以100,得到的数据是[1,10,15,12,3,19,42]。这样这些数字会变得小一些,存储时占用的比特数也会小一些。

doc values使用几种手段来压缩数字。

  1. 如果所有的数字值都相等(或者缺失),会设置一个标记来表示该值
  2. 如果所有数字值的个数小于256个,将会使用一个简单的编码表来压缩
  3. 如果大于了256个,看看是否存在最大公约数,存在则使用最小公倍数压缩
  4. 如果不存在最大公约数,则存储偏移量来压缩数字。

如你看到的,你可能会想“这样做对数值型字段做压缩确实很好,那么对字符串类型呢?”,其实字符串压缩也是和数字压缩一样采用同样的方法通过一个序数表来压缩,字符串被去重、排序后被赋予了一个ID,这些ID就是数字,这样就可以采用上面的方案进行压缩了。对于序数表本身也会采用压缩存储。

 

原文连接参考:http://www.tuicool.com/articles/iuIzUfz

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326612277&siteId=291194637