2.X/4. Aggregations

4-10-2. Deep Dive on Doc Values

drscg 2017. 9. 23. 22:38

The last section opened by saying doc values are "fast, efficient and memory-friendly". Those are some nice marketing buzzwords, but how do doc values actually work?

지난 장에서 doc value는 "빠르고, 효율적이며, 메모리 친화적" 이라고 언급했었다. 약간은 멋진 마케팅 전문용어이긴 하지만, 실제로 doc values는 어떻게 동작할까?

Doc values are generated at index-time, alongside the creation of the inverted index. That means doc values are generated on a per-segment basis and are immutable, just like the inverted index used for search. And, like the inverted index, doc values are serialized to disk. This is important to performance and scalability.

doc values는 색인 시에, inverted index의 생성과 동시에 생성된다. 즉, doc values는 검색에 사용되는 inverted index와 마찬가지로, segment별로 생성되며, 불변이다. 그리고, inverted index처럼, doc values는 디스크에 직렬화된다. 이것은 성능과 확장성에 중요하다.

By serializing a persistent data structure to disk, we can rely on the OS’s file system cache to manage memory instead of retaining structures on the JVM heap. In situations where the "working set" of data is smaller than the available memory, the OS will naturally keep the doc values resident in memory. This gives the same performance profile as on-heap data structures.

디스크에 불변의 데이터 구조로 직렬화함으로써, JVM heap에 유지되는 구조 대신 메모리 관리를 OS의 file system cache에 의존할 수 있다. 데이터의 "working set" 이 가용 메모리보다 작은 상황에서는, OS는 자연스럽게 doc values를 메모리에 상주하도록 할 것이다. 이것은 heap 데이터 구조와 동일한 성능 프로파일을 제공할 것이다.

But when your working set is much larger than available memory, the OS will begin paging the doc values on/off disk as required. This will obviously be slower than an entirely memory-resident data structure, but it has the advantage of scaling well beyond the server’s memory capacity. If these data structures were purely on-heap, the only option is to crash with an OutOfMemory exception (or implement a paging scheme just like the OS).

그러나, working set이 가용 메모리보다 훨씬 클 경우에, OS는 doc values를 필요에 따라 디스크에 페이징하기 시작할 것이다. 이것은 전체가 메모리에 상주하는 데이터 구조보다 분명히 느릴 것이다. 그러나, 서버의 메모리 용량 이상으로 잘 확장할 수 있는 이점을 가지는 것이다. 만약 이들 데이터 구조가 완전히 heap에 있다면, 유일한 선택은 OutOfMemory exception과 함께 crash되는 것이다. (또는 OS처럼 페이징 구조를 구현하는 것이다)

Note

Because doc values are not managed by the JVM, Elasticsearch servers can be configured with a much smaller heap. This gives more memory to the OS for caching. It also has the benefit of letting the JVM’s garbage collector work with a smaller heap, which will result in faster and more efficient collection cycles.

doc values가 JVM에 의해 관리되지 않기 때문에, Elasticsearch server는 훨씬 더 작은 heap으로 설정될 수 있다. 이것운 caching을 위해 OS에 더 많은 메모리를 할당한다. 또한, JVM의 garbage collector가 더 작은 heap으로 동작하도록 하는 이점을 가지게 된다. 따라서 더 빠르고, 더 효율적인 collection cycle을 가지게 된다.

Traditionally, the recommendation has been to dedicate 50% of the machine’s memory to the JVM heap. With the introduction of doc values, this recommendation is starting to slide. Consider giving far less to the heap, perhaps 4-16gb on a 64gb machine, instead of the full 32gb previously recommended.

기본적으로, machine 메모리의 50%를 JVM Heap 전용으로 하는 것을 추천한다. doc values의 도입과 함께, 이 추천 사항이 시작점이 된다. heap에 메모리를 훨씬 덜 할당하는 것을 고려하자. 64GB machine에서, 이전에 추천했던 32GB 모두 대신 4-16GB 정도.

For a more detailed discussion, see Heap: Sizing and Swapping.

더 자세한 사항은 Heap: Sizing and Swapping을 참고하자.

Column-store compressionedit

At a high level, doc values are essentially a serialized column-store. As we discussed in the last section, column-stores excel at certain operations because the data is naturally laid out in a fashion that is amenable to those queries.

doc values는 기본적으로 직렬화된 column-store 이다. 지난 장에서 이야기했듯이, column-store는 어떤 연산에 뛰어나다. 왜냐하면 데이터가 해당 query를 잘 처리할 수 있도록 약간은 자연스럽게 배치되어 있기 때문이다.

But they also excel at compressing data, particularly numbers. This is important for both saving space on disk and for faster access. Modern CPU’s are many orders of magnitude faster than disk drives (although the gap is narrowing quickly with upcoming NVMe drives). That means it is often advantageous to minimize the amount of data that must be read from disk, even if it requires extra CPU cycles to decompress.

그런데, 그것은 또한 데이터 특히 숫자 압축에 뛰어나다. 이것은 디스크 공간의 절약  더 빠른 access 모두에 대해 중요하다. 요즘의 CPU는 디스크 드라이브보다 몇 배 더 빠르다 (비록 NVMe drive로 인해 그 차이가 급격히 줄어들고 있지만). 즉, 압축을 해제하기 위해, 추가로 CPU가 필요하더라도, 디스크에서 읽어야 하는 데이터의 양을 최소화하는 것이 바람직하다.

To see how it can help compression, take this set of doc values for a numeric field:

압축하는 방법을 알아보기 위해, numeric field애 대한 doc values의 집합을 살펴보자.

Doc      Terms
-----------------------------------------------------------------
Doc_1 | 100
Doc_2 | 1000
Doc_3 | 1500
Doc_4 | 1200
Doc_5 | 300
Doc_6 | 1900
Doc_7 | 4200
-----------------------------------------------------------------

The column-stride layout means we have a contiguous block of numbers:[100,1000,1500,1200,300,1900,4200]. Because we know they are all numbers (instead of a heterogeneous collection like you’d see in a document or row) values can be packed tightly together with uniform offsets.

column별 배치는 숫자의 이어지는 block([100,1000,1500,1200,300,1900,4200])을 가졌다는 것을 의미한다. 그것이 모두 숫자라는 것을 알기 때문에(document나 row애서 보듯이 다른 종류로 이루어진 모음 대신), 값들은 일정한 offset을 가지고, 함께 꽉 묶을 수 있다.

Further, there are a variety of compression tricks we can apply to these numbers. You’ll notice that each of the above numbers are a multiple of 100. Doc values detect when all the values in a segment share a greatest common divisor and use that to compress the values further.

뿐만 아니라, 이들 숫자에 적용할 수 있는 다양한 압축 기술들이 있다. 위의 숫자들 각각은 100의 배수라는 것을 알 수 있다. doc values는 어떤 segment에서 모든 값들이 최대 공약수 를 공유하는 경우를 찾아, 값들을 더 압축하여 사용한다.

If we save 100 as the divisor for this segment, we can divide each number by 100 to get:[1,10,15,12,3,19,42]. Now that the numbers are smaller, they require fewer bits to store and we’ve reduced the size on-disk.

이 segment에서 최대 공약수를 100 으로 했다면, 각 숫자를 100으로 나누어 [1,10,15,12,3,19,42] 를 얻을 수 있다. 이제 숫자는 더 작아졌고, 그것들은 저장시에 더 작은 bit가 필요하며, 디스크 크기를 줄였다.

Doc values use several tricks like this. In order, the following compression schemes are checked:

doc values는 이와 같은 여러가지 기술들을 사용한다. 차례로 다음과 같은 압축방식이 선택된다.

  1. If all values are identical (or missing), set a flag and record the value

    모든 값들이 동일하다면(또는 없다면), flag를 설정하고 값을 기록한다.

  2. If there are fewer than 256 values, a simple table encoding is used

    값이 256개보다 더 적다면, 간단한 table encoding이 사용된다.

  3. If there are > 256 values, check to see if there is a common divisor

    값이 256개 이상이면, 최대 공약수가 있는지 확인한다.

  4. If there is no common divisor, encode everything as an offset from the smallest value

    최대 공약수가 없다면, 가장 작은 값부터 offset으로 모든 것을 인코드한다.

You’ll note that these compression schemes are not "traditional" general purpose compression like DEFLATE or LZ4. Because the structure of column-stores are rigid and well-defined, we can achieve higher compression by using specialized schemes rather than the more general compression algorithms like LZ4.

이러한 압축 방식은 DEFLATE 나 LZ4 같은 "전통적인" 범용 압축이 아니라는 점을 알아야 한다. 왜냐하면, column-store의 구조는 정밀하고 잘 정의되어 있기 때문에, LZ4 같은 좀 더 범용적인 압축 알고리즘보다 특별한 방식을 사용함으로써, 더 높은 압축이 가능하다.

Note

You may be thinking "Well that’s great for numbers, but what about strings?" Strings are encoded similarly, with the help of an ordinal table. The strings are de-duplicated and sorted into a table, assigned an ID, and then those ID’s are used as numeric doc values. Which means strings enjoy many of the same compression benefits that numerics do.

"숫자에 대해서는 그렇게 잘 되는데, 문자열은 어떤가요" 라고 생각할 수 있다. 문자열은 서수 테이블(ordinal table)의 도움으로 유사하게 인코드된다. 문자열은 중복을 제거하고 ID를 할당하여 테이블에 저장된다. 그리고, 그 ID가 숫자의 doc values로 사용된다. 즉, 문자열은 숫자만큼의 동일한 압축 효율을 가진다.

The ordinal table itself has some compression tricks, such as using fixed, variable or prefix-encoded strings.

서수 테이블 자체는 고정/변수/접두사로 인코딩된 문자열을 사용하는 몇 가지 압축 기술을 가지고 있다.

Disabling Doc Valuesedit

Doc values are enabled by default for all fields except analyzed strings. That means all numerics, geo_points, dates, IPs and not_analyzed strings.

doc values는 analyzed string을 제외한 모든 field에 대해 기본적으로 활성화된다. 즉, 모든 numeric, geo_point, date, IP 그리고 not_analyzed string.

Analyzed strings are not able to use doc values at this time; the analysis process generates many tokens and does not work efficiently with doc values. We’ll discuss using analyzed strings for aggregations in Aggregations and Analysis.

analyzed string은 이 때 doc values를 사용할 수 없다. analysis process는 많은 token을 생성하기에 doc values로는 효율적으로 동작하지 않는다. Aggregations and Analysis에서 aggregation에서 analyzed stringd을 사용하는 것에 대해 이야기할 것이다.

Because doc values are on by default, you have the option to aggregate and sort on most fields in your dataset. But what if you know you will never aggregate, sort or script on a certain field?

doc values가 기본이기 때문에, 대부분의 field에서 aggregation이나 정렬이 가능하다. 그러나 특정 field에서 절대로 aggregation이나 정렬 또는 script를 사용하지 않는다면 어떨까?

While rare, these circumstances do arise and you may wish to disable doc values on that particular field. This will save you some disk space (since the doc values are not being serialized to disk anymore) and may increase indexing speed slightly (since the doc values don’t need to be generated).

드물기는 하지만, 이런 상황은 발생할 것이고, 해당 특정 field에 대해 doc values를 비활성화해야 할 것이다. 이것으로 약간의 디스크 공간을 절약(doc values가 더 이상 디스크에 직렬화되지 않으므로)할 수 있고, 색인 속도를 약간 증가(doc values가 생성될 필요가 없기 때문에)시킬 수 있다.

To disable doc values, set doc_values: false in the field’s mapping. For example, here we create a new index where doc values are disabled for the "session_id" field:

doc values를 비활성화하려면, field mapping에 doc_values: false 를 설정한다. 예를 들어, "session_id" field에 대해 doc values를 비활성화한 새로운 index를 생성해 보자.

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "session_id": {
          "type":       "string",
          "index":      "not_analyzed",
          "doc_values": false 
        }
      }
    }
  }
}

doc_values: false 를 설정함으로써, 이 field는 aggregation, 정렬, script를 사용할 수 없다.

It is possible to configure the inverse relationship too: make a field available for aggregations via doc values, but make it unavailable for normal search by disabling the inverted index. For example:

반대의 경우 또한 설정할 수 있다. 특정 field를 doc values를 이용하여 aggregation은 이용할 수 있지만, inverted index를 비활성화하여, 일반적인 검색을 이용할 수 없도록 한다. 예를 들어 보면,

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "customer_token": {
          "type":       "string",
          "index":      "not_analyzed",
          "doc_values": true, 
          "index": "no" 
        }
      }
    }
  }
}

aggregation이 가능하도록 doc values를 활성화한다.

색인이 비활성화되었다. 즉, field를 query나 search할 수 없다.

By setting doc_values: true and index: no, we generate a field which can only be used in aggregations/sorts/scripts. This is admittedly a very rare requirement, but sometimes useful.

doc_values: true 그리고 index: no 로 설정함으로써, aggregation/정렬/script에서  사용되는 field를 생성하였다. 이것은 분명히 드문 상황이지만, 때때로 유용하다.


'2.X > 4. Aggregations' 카테고리의 다른 글

4-10. Doc Values and Fielddata  (0) 2017.09.23
4-10-1. Doc Values  (0) 2017.09.23
4-10-3. Aggregations and Analysis  (0) 2017.09.23
4-10-4. Limiting Memory Usage  (0) 2017.09.23
4-10-5. Fielddata Filtering  (0) 2017.09.23