Engineers can resist anything except giving their processes more resources: bigger, better, faster, more of cycles, cores, RAM, disks and interconnects! When these resources are not a bottleneck, this is wasteful but harmless. For processes like Elasticsearch that run on the JVM, the luring temptation is to turn the heap up; what harm could possibly come from having more heap? Alas, the story isn't simple.
엔지니어들은 process에 더 많은 resource(더 크고, 더 좋고, 더 빠르고, 더 많은 cycle, core, RAM, Disk및 interconnect)를 제공하는 것외에는 어떤 것도 참을 수 있다! 이러한 resource가 bottleneck이 아닌 경우에는 낭비이지만 부작용은 없다. JVM상에서 구동되는 Elasticsearch와 같은 프로세스의 경우, 매력적인 유혹은 heap을 늘리는 것인데, 이로 인해 어떤 부작용이 발생할 수 있을까? 유감스럽게도, 그 이야기는 간단하지가 않다.
Java is a garbage-collected language. Java objects reside in a runtime area of memory called the heap. When the heap fills up, objects that are no longer referenced by the application (affectionately known as garbage) are automatically released from the heap (such objects are said to have been collected). The maximum size of the heap is specified at application startup and fixed for the life the application; this size impacts allocation speed, garbage collection frequency, and garbage collection duration (most notably the dreaded stop-the-world phase which pauses all application threads). Applications have to strike a balance between small heaps and large heaps; the heap can be too rich or too thin.
java는 garbage-collected language이다. java object는 heap이라고 하는 memory의 runtime 영역에 있다. heap이 가득 차면 application이 더 이상 참조하지 않는 object(garbage라고 함)는 자동으로 heap에서 release된다(이러한 object를 수집되었다(collected)고 한다). heap의 최대 크기는 application을 시작할 때 지정하고, 종료될때 까지 고정된다. 이 크기는 할당 속도(allocation speed), garbage collection 빈도 및 시간(그 중에서 가장 위험한 모든 application thread를 일시 중지하는 가장 위험한 stop-the-world phase)에 영향을 준다. application은 작은 heap과 큰 heap사이의 균형을 맞추어야 한다. heap이 너무 많거나 너무 빈약할 수 있다.
Too Small
If the heap is too small, applications will be prone to the danger of out of memory errors. While that is the most serious risk from an undersized heap, there are additional problems that can arise from a heap that is too small. A heap that is too small relative to the application's allocation rate leads to frequent small latency spikes and reduced throughput from constant garbage collection pauses. Frequent short pauses impact end-user experience as these pauses effectively shift the latency distribution and reduce the number of operations the application can handle. For Elasticsearch, constant short pauses reduce the number of indexing operations and queries per second that can be handled. A small heap also reduces the memory available for indexing buffers, caches, and memory-hungry features like aggregations and suggesters.
heap이 너무 작으면, application에서 memory 부족 error가 발생할 위험이 있다. 이는 평균 이하의 heap에서 발생하는 가장 심각한 위험이지만, 너무 작은 heap에서 발생할 수 있는 추가적인 문제가 있다. application의 할당률(allocation rate)에 비해 너무 작은 heap을 할당하면, 빈번하고 짧은 대기 시간 급증(latency spike)를 일으키고, 지속적인 garbage collection 일시 중지로 인해 처리량(throughput)이 감소한다. 빈번하게 발생하는 짧은 일시 중지는, 실질적으로 대기 시간 분포(latency distribution)를 변경시키고, application이 처리할 수 있는 연산의 수를 감소시키기 때문에 최종 사용자 환경에 영향을 준다. Elasticiearch의 경우, 지속적으로 발생하는 짧은 일시 정지는, 처리할 수 있는 초당 indexing 연산 및 query의 수를 감소시킨다. 또한 작은 heap은 indexing buffer, cash 및 aggregation이나 suggester 같이 memory를 많이 사용하는 기능이 사용할 수 있는 memory를 감소시킨다.
Too Large
If the heap is too large, the application will be prone to infrequent long latency spikes from full-heap garbage collections. Infrequent long pauses impact end-user experience as these pauses increase the tail of the latency distribution; user requests will sometimes see unacceptably-long response times. Long pauses are especially detrimental to a distributed system like Elasticsearch because a long pause is indistinguishable from a node that is unreachable because it is hung, or otherwise isolated from the cluster. During a stop-the-world pause, no Elasticsearch server code is executing: it doesn't call, it doesn't write, and it doesn't send flowers. In the case of an elected master, a long garbage collection pause can cause other nodes to stop following the master and elect a new one. In the case of a data node, a long garbage collection pause can lead to the master removing the node from the cluster and reallocating the paused node's assigned shards. This increases network traffic and disk I/O across the cluster, which hampers normal load. Long garbage collection pauses are a top issue for cluster instability.
heap이 너무 크면, application이, 전체 heap garbage collection으로, 장시간의 대기 시간 급증(latency spike)이 자주 발생하지는 않는다. 흔하지 않은 장시간의 일시 중지는 이들 중지로 인해 대기 시간 분포(latency distribution)의 끝부분이 증가하려 최종 사용자 환경에 영향을 미친다. 때로는 사용자 요청(user request)에 허용할 수 없는 장시간의 응답 시간(response time)이 발생한다. 장시간의 일시 중지는 특히 Elasticsearch와 같은 분산 시스템에 좋지 않다. 왜냐하면, 장시간의 일시 중지는 중단되었거나 cluster에서 분리되어 연결할 수 없는 node와 구분할 수 없기 때문이다. stop-the-world 일시 정지 동안, 어떤 Elasticsearch server code도 실행되지 않는다. server code는 호출(call)도 하지 않고, 쓰지(write)도, 자료도 보내지 않는다. master node의 경우, garbage collection 일시 중지가 길어지면, 다른 node들이 master에 이어 새 node를 선택하는 것을 방해할 수 있다. data node의 경우, garbage collection 일시 중지가 길어지면, master가 cluster에서 node를 제거하고 일시 중지된 node에 할당된 shard를 재할당할 수 있다. 이로 인해 cluster 간의 network traffic과 disk I/O가 증가하여, 정상적인 load를 방해한다. 장시간의 garbage collection 일시 중지는 cluster 불안정성의 주요 이슈이다.
Just Right
The crux of the matter is that undersized heaps are bad, oversized heaps are bad and so it needs to be just right.
문제의 핵심은 평균 이하의 heap도 좋지 않고 너무 큰 heap도 좋지 않다는 것이다. 그래서 정확하게 맞추는 것이 필요하다.
Oops!...I Did It Again
The engineers behind Elasticsearch have long advised keeping the heap size below some threshold near 32 GB1(some docs referred to a 30.5 GB threshold). The reasoning behind this advice arises from the notion of compressed ordinary object pointers (or compressed oops).
Elasticsearch의 엔지니어는 heap 크기를 32 GB 정도의 임계값 아래로 유지할 것을 오랫동안 권고해 왔다(일부 문서에서는 30.5 GB를 임계값으로 언급). 이 권고의 근거는 compressed ordinary object pointers(또는 compressed oops)의 개념에서 비롯된다.
An ordinary object pointer (or oops) is a managed pointer to an object and it has the same size as a native pointer. This means that on a 32-bit JVM an oop is 32-bits in size and on a 64-bit JVM an oop is 64-bits in size. Comparing an application that runs on a 32-bit JVM to an application that runs on a 64-bit JVM, the former will usually2 perform faster. This is because 32-bit pointers require half of the memory space compared to 64-bit pointers; this is friendlier to limited memory bandwidth, precious CPU caches, and leads to fewer garbage collection cycles as there is more room available on the heap.
ordinary object pointer (또는 oops)는 object에 대한 managed pointer이며, native pointer와 동일한 크기이다. 즉, 32-bit JVM의 경우에는 oop가 32-bit이고, 64-bit JVM의 경우에는 64-bit이다. 32-bit JVM에서 실행되는 application과 64-bit JVM에서 실행되는 application을 비교하면, 일반적으로2 전자가 더 빠르게 동작한다. 이는 32-bit pointer가 64 bit pointer에 비해 memory 공간의 절반을 필요로 하기 때문이다. 이는 제한된 memory 대역폭과 부족한 CPU cash에 더 친화적이어서, heap에서 이용할 수 공간이 더 많기 때문에 garbage collection 주기가 더 작아진다.
Applications that run on a 32-bit JVM are limited to a maximum heap size of slightly less than 4 GB. For modern distributed server applications serving large volumes of data, this is usually too small. But there's a neat trick that can be employed: limit the heap to slightly less than 32 GB and then the JVM can get away with 35-bit oops (since 235 = 32 GB). Using thirty-five bits is not friendly to modern CPU architectures, though, so another trick is employed: keep all objects aligned on 8-byte boundaries and then we can assume the last three bits of 35-bit oops are zeros3. Now the JVM can get away with 32-bit object pointers yet still reference 32 GB of heap. These are compressed oops.
32-bit JVM에서 실행되는 application은 최대 heap 크기가 4 GB보다 약간 작도록 제한된다. 대용량 data를 서비스하는 요즘의 분산 서버 application의 경우, 대개 이 크기는 너무 작다. 하지만 여기에 사용할 수 있는 멋진 트릭이 하나 있다. heap을 32 GB 미만으로 제한하면, JVM이 35-bit oop(235 = 32 GB 이므로)로부터 벗어날 수 있다. 35 bit를 사용하는 것은 요즘의 CPU architecture에 적합하지 않아, 또 다른 트릭이 사용된다. 모든 object를 8-byte 단위로 정렬하면, 35-bit의 마지막 3 bit는 zero3 로 가정할 수 있다. 이제 JVM은 32-bit object pointer를 벗어날 수 있지만, 여전히 32 GB heap을 참조한다. 이것이 compressed oop 이다.
Then, exactly like the situation with going from a 32-bit JVM to a 64-bit JVM, comparing an application with a heap size just less than the compressed oops threshold to one with a heap size just more than the compressed oops threshold, the latter will perform worse. What is more, the heap useable to the application will be significantly smaller because of the additional space taken up by the 64-bit oops. Increasing the size of the heap to overcome this loss, however, leads to a larger heap that is subject to the long-pause problem already discussed. For Elasticsearch, our advice is to always stay below the compressed oops threshold.
그러면, 32-bit JVM에서 64-bit JVM으로 변경되는 상황과 정확히 유사하게, compressed oop 임계값보다 작은 heap의 application을 compressed oop 임계값보다 더 큰 heap의 application과 비교하면, 후자가 성능이 더 좋지 않다. 게다가, 64 bit oop가 차지하는 추가 공간 때문에, application에 사용할 수 있는 heap이 상당히 줄어들 것이다. 그러나 이러한 손실을 극복하기 위해 heap의 크기를 늘리면, 이미 논의한 긴 일시 정지(long-pause) 문제가 발생할 수 있는 더 큰 heap이 된다. Elasticsearch에서, 우리의 권고는 항상 compressed oop 임계값 아래이다.
It's Complicated
It turns out that the true story is more complicated than this as there are two additional cutoffs.
2가지 한계가 있어. 사실 이보다 더 복잡하다.
The first is natural and easy to understand. If the heap is smaller than 4 GB, the JVM can just use 32-bit pointers.
첫번째는 당연하고 이해하기 쉽다. heap이 4 GB보다 작으면, JVM은 32-bit pointer만 사용할 수 있다.
The second cutoff is less obvious. If the heap will not fit in the first 4 GB of address space, the JVM will next try to reserve memory for the heap within the first 32 GB of address space and then use a zero base for the heap; this is known as zero-based compressed oops. When this reservation can not be granted, the JVM has to fall back to using a non-zero base for the heap. If a zero base can be used, a simple 3-bit shift is all that is needed for encoding and decoding between native 64-bit pointers and compressed oops.
두번째 한계는 좀 더 불확실하다. heap이 처음 4 GB 주소 공간에 적당하지 않을 경우, JVM은 처음 32 GB 주소 공간 내에 heap memory를 예약한 다음, heap을 zero base로 사용합니다. 이를 zero-based compressed oops라 한다. 이것이 허용되지 않으면, JVM은 heap을 non-zero base 를 사용해야 한다. zero base를 사용할 수 있는 경우, native 64-bit pointer와 compressed oop 사이의 encoding 및 decoding에 필요한 것은 단순히 3-bit shift 뿐이다.
native oop = (compressed oop << 3)
But when the base is non-zero, a null check is needed and that additional base must be added and subtracted when encoding and decoding compressed oops.
그러나 base가 0이 아닌 경우, null 검사가 필요하므로 compressed oop를 encoding 및 decoding할 때 추가로 base를 더하고 빼야 한다.
if (compressed oop is null) native oop = null else native oop = base + (compressed oop << 3)
This causes a significant drop in performance4. The cutoff for using a zero base varies across operating systems5 but 26 GB is a conservative cutoff across a variety of operating systems.
이로 인해 성능4이 크게 저하된다. zero base 사용에 대한 한계는 OS5에 따라 다르지만, 26 GB가 다양한 OS에 대한 보수적인 한계이다.
Less is More
What frequently happens though is that our advice surrounding compressed oops is interpreted as advice to set the heap as high as it can go while staying under the compressed oops threshold. Instead though, it's better to set the heap as low as possible while satisfying your requirements for indexing and query throughput, end-user query response times, yet large enough to have adequate heap space for indexing buffers, and large consumers of heap space like aggregations, and suggesters. The smaller that you can set the heap, the less likely you'll be subject to detrimental long garbage collection pause, and the more physical memory that will be available for the filesystem cache which continues to be used more and more to great effect by Lucene and Elasticsearch.
하지만, compressed oop에 대한 우리의 권고가 compressed oop 임계값 아래에서 heap을 최대한 높게 설정하라는 충고로 해석되는 경우가 자주 있다. 하지만, indexing 및 query 처리량, 사용자 query response time에 대한 요구 사항을 충족하면서도, indexing buffer 및 aggregation, suggester 같은 것들이 대량의 heap 공간을 충분히 확보할 수 있도록, heap을 최대한 낮게 설정하는 것이 더 좋다. heap을 더 작게 설정할수록, 좋지 않은 긴 garbage collection 일시 중지 가능성이 줄어들며, Lucene과 Elasticsearch에서 점점 더 많은 효과를 발휘하는 filesystem cache에 사용할 수 있는 physical memory가 더 많아진다.
Straight Cache Homie
Modern operating systems maintain a filesystem cache of pages accessed from disk. This cache only uses free memory and is handled transparently by the operating system. Once a page is read from the file system and placed in the cache, accessing it is as fast as reading from memory. This means that index segments, term dictionaries, and doc values can be accessed as if they are sitting in memory once they've been placed into the cache. What is more, this cache is not managed by the JVM so we get the benefits of blazingly fast memory speeds without the consequences of being on heap. This is why we continue to recommend having as much memory as possible for the filesystem cache.
최신 OS에서는 disk에서 access하는 page의 filesystem cache를 유지한다. 이 cache는 사용 가능한 memory만 사용하며, OS에서 투명하게 처리된다. 한 page가 file system에서 읽히고 cache에 저장되면, 그 page를 access하는 것은는 memory에서 읽는 것만큼 빠르다. 즉, index segment, term dictionary 그리고 doc values가 cache에 일단 저장된 후에는, 마치 memory에 저장된 것처럼 access될 수 있다. 또한, cache는 JVM에 의해 관리되지 않기 때문에, heap의 영향 없이 엄청나게 빠른 memory 속도의 이점을 누릴 수 있다. 이것이 filesystem cache가 최대한 많은 memory를 가지도록 계속 권장하는 이유이다.
Garbage First
The JVM engineers have developed a concurrent garbage collector known as G1 GC that was first supported starting in JDK 7u4 and is set to be the default collector starting in JDK 96. This collector divides the heap into regions and is designed to first collect regions that are mostly garbage (hence G1: garbage first). This collector still pauses application threads when collecting, but the idea is that by focusing on regions with the most garbage, these collections will be highly efficient so that application threads need to be paused only briefly. This enables G1 GC to operate on large heaps with predictable pause times. This is exactly what we want! Unfortunately, G1 GC has exhibited bugs that lead to corruption in Lucene indices. While the older builds appear to be the ones most impacted by these issues, scary bugs are still being found even in the latest builds. We test Elasticsearch against G1 GC continuously on our CI infrastructure but at this time we recommend against and do not support running Elasticsearch with the G1 collector.
JVM 엔지니어들은 G1 GC라는 concurrent garbage collector를 개발했는데, 이것은 JDK 7u4에서 처음으로지원되었으며, JDK 9에서 기본 collector6로 설정되었다. 이 collector는 heap을 영역(region)으로 나누고, 주로 garbage(G1 garbage 먼저)인 영역을 먼저 수집(collect)하도록 설계되었다. 이 collector는 수집할 때 여전히 application thread를 일시 중지시키지만, 대부분의 garbage가 있는 영역에 초점을 맞춘다는 아이디어이다. application thread가 잠깐만 중지되도록 해야 하기 때문에, 이러한 수집 작업이 매우 효율적일 것이다. 이를 통해, G1 GC를 예측 가능한 중지 시간을 가진 큰 heap으로 운영할 수 있다. 이것이 바로 우리가 원하는 것이다! 안타깝게도, G1 GC는 Lucene indices를 변형시키는 bug가 있다. 오래된 build에서도 이러한 문제들에 가장 많은 영향을 받은 것으로 보이지만, 최근의 build에서도 무시무시한 bug들이 여전히 발견되고 있다. C1 intrastructure에서 G1 GC에 대해 Elasticsearch를 지속적으로 테스트하고 있지만, 이 시점에서 G1 collector에서 Elasticsearch를 실행하는 것을 지원하지 않으며 추천하지 않는다.
Together We Can Prevent Forest Fires
The Elasticsearch heap can be specified at startup through the ES_HEAP_SIZE
environment variable. The ideal scenario, if you can, is to size your heap below 4 GB. If you have to go above 4 GB, try to stay below the zero-based threshold for your system. You can check if you're under the zero-based threshold by starting Elasticsearch with the JVM options -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode
and looking for output similar to
Elasticsearch heap은 시작 시에 ES_HEAP_SIZE 환경 변수를 통해 지정할 수 있다. 가능하다면, 이상적인 시나리오는 4 GB 미만의 heap을 설정하는 것이다. 4 GB 를 초과해야 하는 경우, system의 zero-based 임계값 아래를 유지하자. JVM option -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompressedOopsMode 을 사용하여 Elasticsearch를 시작하면, zero-based 임계값 미만인지 확인할 수 있고,
heap address: 0x000000011be00000, size: 27648 MB, zero based Compressed Oops
showing that zero-based compressed oops are enabled instead of
heap address: 0x0000000118400000, size: 28672 MB, Compressed Oops with base: 0x00000001183ff000
showing that zero-based compressed oops are not enabled. If you have to go above the zero-based threshold, stay below the compressed oops threshold. Starting with Elasticsearch 2.2.0, Elasticsearch logs at startup whether or not it is using compressed oops, and the same information is also available in the nodes info API.
zero-based compressed oop가 활성화되지 않았음을 보여 주는 대신 zero-based compressed oop가 활성화되었음을 보여 주는 것과 유사한 출력을 찾을 수 있다. zero-based 임계값을 초과해야 하는 경우, compressed oop 임계값보다 낮게 유지하자. Elasticsearch 2.2.0 부터, Elasticsearch가 compressed oop를 사용하고 있는지 여부를 시작 시에 로그에 남기고, 동일한 정보를 nodes info API에서도 제공한다.
Here are some points-of-consideration for reducing the need for large heaps:
다음은 대규모 heap의 필요성을 줄이기 위한 몇 가지 고려 사항이다.
- Reduce the use of field data and take advantage of doc values where possible (the default for every possible field starting in Elasticsearch 2.0.0)7.
field data의 사용을 줄이고, 가능한 경우(Elasticsearch 2.0.0 부터 가능한 모든 field의 기본값)7. doc values를 활용하자. - Disk-based norms are available starting in Elasticsearch 2.1.08.
Elasticsearch 2.1.08 부터 Disk-based norms 를 이용할 수 있다. - Doc values consume less memory for multi-fields starting in Elasticsearch 2.2.0.
Elasticsearch 2.2.0 부터 multi-field에 대해 doc values가 더 적은 memory를 사용한다. - Do not over-shard (some advantages among many: a search request across N shards has to collect results from all N shards so fewer shards means smaller result sets to sift through and better request cache utilization, less terms dictionaries, and fewer shards leads to a smaller cluster state).
지나치게 많은 shard를 사용하지 말자. 많은 이점 중 몇 가지를 보면, N개의 shard에 대한 search request는 모두 N개의 shard에서 결과를 수집해야 한다. 따라서, shard의 수가 적을수록 더 작은 결과 집합에서 거르고, 더 나은 request cache 활용, 더 작은 terms dictionary를 의미한다. shard의 수가 적을수록 cluster state의 크기가 더 작아진다. - Do not use overly-large bulk indexing batch sizes (32 MB is okay, 256 MB is probably not).
너무 큰 bulk indexing batch size를 사용하지 말자(32 MB는 괜찮지만, 256 MB는 아마도 아니다). - Do not use large bulk indexing queues (to keep the total bytes across all in-flight requests reasonable; a circuit breaker will limit this starting in Elasticsearch 5.0.0).
대량 bulk indexing queue를 사용하지 말자(전송 중인 모든 request에 대한 총 byte 수를 합리적인 수준으로 유지하기 위해; Elasticsearch 5.0.0부터 circuit breaker가 이를 제한한다). - Do not request too many hits in a single request, use scrolling instead.
단일 request로 너무 많은 결과를 request하지 말자. 대신 scroll을 사용하자. - Do not request too many aggregation buckets or use deeply-nested aggregations.
너무 많은 aggregation bucket을 request하지 말고, 깊은 단계(deeply)의 nested aggregation을 사용하지 말자. - Consider trading performance for memory and use
breadth_first
collection mode for deep aggregations.
memory에 따른 성능의 변화를 고려하고, 깊은 단계(deep)의 aggregation에breadth_first
collection mode를 사용하자. - Use Marvel to monitor the JVM heap over time.
시간별 JVM heap을 모니터하기 위해 Marvel을 사용하자.
The engineers behind Lucene and Elasticsearch continue to investigate ways to reduce the need for a large heap. Stay tuned as we push more components of indices off heap, and find ways within Elasticsearch to reduce the dependency on the heap for executing requests.
Lucene과 Elasticsearch 엔지니어들은 큰 heap에 대한 필요성을 줄이기 위한 방법을 계속 찾고 있다. heap에서 indices의 요소를 더 많이 제거하고, request를 실행할 때 Elasticsearch 내에서 heap의 종속성을 줄이는 방법을 찾는데 주목하고 있다.
- Throughout this post, MB and GB refer to 220 = 1,048,576 and 230 = 1,073,741,824 bytes, respectively.↩
이 post에서 MB와 GB는 각각 220 = 1,048,576 과 230 = 1,073,741,824 bytes를 말한다. - An application that makes extensive use of 64-bit numerical types might be slower on a 32-bit JVM because it can not take advantage of 64-bit registers and instructions.↩
64-bit를 숫자 유형을 광범위하게 사용하는 application은 64-bit register와 명령어를 활용할 수 없기 때문에, 32-bit JVM에서 느려질 수 있다. - Aligned objects do lead to a small amount of slop in the heap, but that's okay because modern CPUs prefer 8-byte aligned addresses.↩
정렬된 object는 heap에서 소량의 slop을 유발할 수 있지만, 요즘의 CPU는 8-byte 정렬 주소를 선호하므로 괜찮다. - Extra CPU instructions are not free, and the branch/predicated instructions that arise from decoding/encoding a non-zero based oop can be especially expensive.↩
추가 CPU 명령어는 비용이 소모된다. 그래서 non-zero based oop를 decoding/encoding할 때 발생하는 branch/predicated 명령어는 특히 많은 비용이 소모될 수 있다.. - On my laptop running OS X 10.11.4 using Oracle JDK 8u74, I can get up to around a 28250 MB heap before the JVM does not use zero-based oops and on my workstation running Fedora 23 using Oracle JDK 8u74, I can get up to around a 30500 MB heap before the JVM does not use zero-based oops.↩
오라클 JDK 8u74를 사용하고 OS X 10.11.4로 동작하는 laptop에서, JVM이 zero-based oops를 사용하면 최대 28250 MB의 heap을 얻을 수 있고, Oracle JDK 8u74을 사용하고 Fedora 23을 실행하는 workstation에서, JVM이 zero-based oops를 사용하면 약 30500 MB의 heap을 얻을 수 있다. - It is interesting to note that G1 GC was initially proposed as a replacement for the CMS collector but is now being touted as a replacement for the throughput collector.↩
처음에는 G1 GC를 CMS collector의 대용으로 제안했었는데, 지금은 throughput collector의 대용으로 권장되고 있다는 점은 흥미롭다. - Field data and doc values are used for aggregations, sorting and script field access.↩
field data와 doc values는 aggregation, 정렬 및 script field access에 사용된다. - Norms are an index-time component of relevance scoring; norms can be disabled if you're not using relevance scoring.↩
norms는 index시에 relevance score 계산 요소이며, relevance score 계산을 사용하고 있지 않으면 비활성화될 수 있다.
이 post와과 관련된 image는 CC BY-NC 2.0 license에 따라 license가 부여되었으며 원본에서 가져왔다. 이 post와 관련된 전체 bleed image는 CC BY 2.0 license에 따라 license가 부여되었으며 원본에서 가져왔다.