欢迎光临
我们一直在努力

如何利用 Doc Values 磁盘列式存储提升 Elasticsearch 聚合性能

如何利用 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 显著提高了聚合查询的性能、减少了延迟,并极大地增强了集群的稳定性。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » 如何利用 Doc Values 磁盘列式存储提升 Elasticsearch 聚合性能
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址