如何利用 Doc Values 磁盘列式存储提升 Elasticsearch 聚合性能
在Elasticsearch中,数据检索主要依赖倒排索引(Inverted Index)。然而,倒排索引是为快速搜索文档而优化的(即“哪些文档包含这个词”)。当需要进行聚合(Aggregation)、排序(Sorting)或字段脚本(Scripting)操作时,Elasticsearch需要快速访问特定字段中所有文档的值,这是倒排索引不擅长的任务。
这时,Doc Values(文档值)作为解决方案应运而生。Doc Values是Elasticsearch特有的一种磁盘列式存储结构,它彻底改变了聚合操作的性能和内存使用效率。
什么是 Doc Values?
Doc Values 是在索引时创建的一种面向列的(Column-oriented)数据结构。与面向行的传统存储不同,列式存储将同一字段的所有值连续存储在一起。这使得在执行聚合或排序时,ES可以高效地一次性加载某个字段的所有值,而不是像处理倒排索引那样需要频繁跳转。
Doc Values vs. Fielddata
在 Elasticsearch 早期,如果需要对字段进行聚合,ES 必须将字段数据加载到 JVM 堆内存中,这被称为 Fielddata。Fielddata 很容易导致 JVM 堆内存溢出(OOM),是集群不稳定的主要原因之一。
Doc Values 将数据存储在操作系统的文件系统缓存中,通过内存映射文件(mmap)的方式进行读写,消耗的是非堆内存(Off-Heap Memory)。这意味着它显著减少了 JVM 堆内存压力,提升了集群的稳定性和聚合速度。
实操:确保和利用 Doc Values
对于 keyword, date, numeric, ip, 和 geo_point 类型字段,Doc Values 默认是开启的。对于 text 字段,Doc Values 默认是关闭的(因为它需要Fielddata来支持聚合,但通常建议不要对分析后的 text 字段进行聚合)。
步骤一:创建带有 Doc Values 字段的索引
我们创建一个包含商品价格(price,数字类型)的索引。虽然数字类型默认开启,但我们通过 mapping 来确认其状态。
PUT /products_index
{
"settings": {
"number_of_shards": 1
},
"mappings": {
"properties": {
"product_name": {
"type": "text"
},
"price": {
"type": "float",
"doc_values": true
}
}
}
}
步骤二:插入测试数据
插入几条测试数据,以便进行聚合操作。
POST /products_index/_bulk
{"index":{}}
{"product_name":"Laptop Pro","price":1200.50}
{"index":{}}
{"product_name":"Mouse Gaming","price":50.00}
{"index":{}}
{"product_name":"Monitor 4K","price":450.75}
步骤三:执行高效的聚合查询
现在,我们可以对 price 字段执行聚合操作。由于 Doc Values 的存在,ES 可以快速地从磁盘读取该字段的所有价格值,并计算平均值,而无需大量占用堆内存。
示例:计算平均价格
GET /products_index/_search
{
"size": 0,
"aggs": {
"avg_price_agg": {
"avg": {
"field": "price"
}
}
}
}
步骤四:处理 Text 字段的聚合需求
如果你错误地尝试对一个默认配置的 text 字段进行聚合,ES 会报错提示 Fielddata is disabled。这是因为 Doc Values 默认被关闭以避免存储分析后的词元。
解决方案:使用 **keyword 子字段**
如果需要对文本进行聚合(例如,按品牌名称分组),你应该将该字段配置为多字段,其中包含一个未被分析的 keyword 子字段。keyword 字段天生支持 Doc Values。
PUT /product_brands
{
"mappings": {
"properties": {
"brand": {
"type": "text",
"fields": {
"raw": {
"type": "keyword",
"doc_values": true
}
}
}
}
}
}
# 聚合查询时使用 .raw 字段
GET /product_brands/_search
{
"size": 0,
"aggs": {
"brand_counts": {
"terms": {
"field": "brand.raw"
}
}
}
}
总结
Doc Values 是现代 Elasticsearch 集群高并发聚合和排序操作的基础。通过将聚合数据结构从高成本的 JVM 堆内存 Fielddata 迁移到高效的磁盘列式存储,Doc Values 显著提高了聚合查询的性能、减少了延迟,并极大地增强了集群的稳定性。
汤不热吧