store vs docValues vs index

Elasticsearch 核心概念对比:store、docValues、index

概述

这三个概念分别对应 MySQL 中的不同功能,通过列式存储和索引优化来提升查询性能。


1. store - 字段独立存储

概念:将某个字段的数据单独存储,类似于 MySQL 的列存储,用空间换时间。

ES 配置示例

json 复制代码
{
  "properties": {
    "title": {
      "type": "text",
      "store": true    // 原始数据会单独存储
    }
  }
}

MySQL 对比

sql 复制代码
-- 传统行存储(类似 ES 的 _source)
CREATE TABLE articles (
  id INT,
  title VARCHAR(100),
  content TEXT,      -- 假设很大,10KB
  author VARCHAR(50)
);

-- 数据在磁盘上按行存储:
-- Row1: [1, "ES教程", "很长的内容...", "张三"]
-- Row2: [2, "MySQL教程", "很长的内容...", "李四"]

-- 如果 MySQL 支持列存储(类似 ES 的 store: true)
-- title 列单独存储:
-- title_store: ["ES教程", "MySQL教程", ...]
-- 主表仍然存储完整行数据

特点

  • store: true = 类似 MySQL 表中存储完整的列数据
  • store: false (默认)= 数据存在 _source 中,类似 MySQL 的行存储

2. docValues - 聚合排序优化

概念:将某个字段单独存储并建立索引,专门用于排序、聚合、脚本计算。

ES 配置示例

json 复制代码
{
  "properties": {
    "price": {
      "type": "integer",
      "doc_values": true    // 支持排序、聚合
    }
  }
}

MySQL 对比

sql 复制代码
-- MySQL 中类似于列存储引擎或聚合优化
SELECT AVG(price), MAX(price) FROM products;  -- 聚合查询
SELECT * FROM products ORDER BY price;       -- 排序查询

3. index - 搜索索引

概念 :相当于 MySQL 的 B+树索引,控制字段是否可被搜索。

ES 配置示例

json 复制代码
{
  "properties": {
    "email": {
      "type": "keyword",
      "index": true     // 可以被搜索
    },
    "internal_id": {
      "type": "keyword", 
      "index": false    // 不能被搜索,类似不建索引的列
    }
  }
}

MySQL 对比

sql 复制代码
-- MySQL 索引
CREATE TABLE users (
  id INT,
  email VARCHAR(100),
  internal_id VARCHAR(50)
);

CREATE INDEX idx_email ON users(email);  -- email 可以快速查询
-- internal_id 没有索引,查询会全表扫描

数据存储方式对比

原始数据(行式存储)

json 复制代码
Doc1: {"title": "ES教程", "price": 99, "category": "技术"}
Doc2: {"title": "MySQL教程", "price": 199, "category": "技术"}  
Doc3: {"title": "小说", "price": 29, "category": "文学"}

列式存储结果

bash 复制代码
# store: true - 为了快速获取字段值
title_store: ["ES教程", "MySQL教程", "小说"]

# doc_values: true - 为了聚合排序  
price_docvalues: [99, 199, 29]
category_docvalues: ["技术", "技术", "文学"]

关键区别:数据组织方式

store 存储(面向查询)

json 复制代码
// 按文档组织,便于快速返回
{
  "doc1_stored_fields": {"title": "ES教程"},
  "doc2_stored_fields": {"title": "MySQL教程"},
  "doc3_stored_fields": {"title": "小说"}
}

使用场景:获取搜索结果

json 复制代码
GET /books/_search
{
  "_source": false,
  "stored_fields": ["title"]
}

docValues 存储(面向计算)

bash 复制代码
# 按列组织,便于批量计算
price_column: [99, 199, 29]        # 可以快速计算平均价格
category_column: ["技术", "技术", "文学"]  # 可以快速分组统计

# 还会建立排序索引
price_sorted_index: [doc3→29, doc1→99, doc2→199]

实际应用场景

场景1:获取搜索结果的标题

json 复制代码
// 使用 store
GET /books/_search
{
  "query": {"match": {"content": "elasticsearch"}},
  "_source": false,
  "stored_fields": ["title"]    // 快速返回标题,不需要解析完整文档
}

场景2:按价格排序

json 复制代码
// 使用 docValues  
GET /books/_search
{
  "query": {"match_all": {}},
  "sort": [{"price": "asc"}]      // 利用 price 的 docValues 快速排序
}

场景3:价格统计分析

json 复制代码
// 使用 docValues
GET /books/_search
{
  "size": 0,
  "aggs": {
    "price_stats": {
      "stats": {"field": "price"}   // 利用 price 的 docValues 计算统计信息
    },
    "by_category": {
      "terms": {"field": "category"} // 利用 category 的 docValues 分组
    }
  }
}

存储格式差异

bash 复制代码
# store 存储格式(类似 JSON)
doc1_store: {"title": "ES教程"}
doc2_store: {"title": "MySQL教程"}

# docValues 存储格式(列式 + 索引)
price_docvalues:
  - values: [99, 199, 29]           # 原始值数组
  - sorted_index: [2,0,1]           # 排序索引:29,99,199
  - ordinals: [1,2,0]               # 序数映射(用于分组)

性能对比

json 复制代码
// 查询:获取1000本书的标题
// store 方式:直接读取 title 的独立存储 → 50KB
// _source 方式:读取1000个完整文档后解析 → 10MB

// 聚合:计算各类别的平均价格  
// docValues 方式:顺序扫描 category 和 price 列 → 100KB
// _source 方式:读取所有文档,逐个解析字段 → 10MB

组合使用示例

json 复制代码
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "index": true,          // 需要全文搜索
        "store": true,          // 经常在结果中返回
        "doc_values": false     // text 类型不支持聚合
      },
      "price": {
        "type": "double",
        "index": true,          // 需要范围查询
        "store": false,         // 不常单独返回
        "doc_values": true      // 需要排序和聚合
      },
      "description": {
        "type": "text",
        "index": false,         // 不需要搜索
        "store": false,         // 不需要单独返回
        "doc_values": false     // 不需要聚合
      },
      "summary": {
        "type": "text", 
        "index": true,          // 需要搜索
        "store": true,          // 搜索结果中显示摘要
        "fields": {
          "length": {
            "type": "integer",
            "store": false,     // 长度值不需要单独返回
            "doc_values": true  // 但需要按长度排序/统计
          }
        }
      }
    }
  }
}

内存使用差异

bash 复制代码
# store 只在查询时加载到内存
GET /books/_search → 临时加载需要的 stored_fields

# docValues 可能会被缓存在内存中(用于频繁的聚合排序)
# 但也可以直接从磁盘读取,内存压力更小

总结对比表

ES 概念 MySQL 对应 主要作用 适用场景
store 单列数据存储 单独存储字段原始值 频繁返回的字段
docValues 列存储 + 聚合索引 支持排序、聚合、脚本 需要统计分析的字段
index B+树索引 支持搜索查询 需要搜索的字段

通过合理配置这三个参数,可以在存储空间、查询性能和内存使用之间找到最佳平衡点。

相关推荐
鬼火儿6 小时前
SpringBoot】Spring Boot 项目的打包配置
java·后端
cr7xin7 小时前
缓存三大问题及解决方案
redis·后端·缓存
间彧8 小时前
Kubernetes的Pod与Docker Compose中的服务在概念上有何异同?
后端
间彧8 小时前
从开发到生产,如何将Docker Compose项目平滑迁移到Kubernetes?
后端
间彧8 小时前
如何结合CI/CD流水线自动选择正确的Docker Compose配置?
后端
间彧8 小时前
在多环境(开发、测试、生产)下,如何管理不同的Docker Compose配置?
后端
间彧8 小时前
如何为Docker Compose中的服务配置健康检查,确保服务真正可用?
后端
间彧8 小时前
Docker Compose和Kubernetes在编排服务时有哪些核心区别?
后端
间彧8 小时前
如何在实际项目中集成Arthas Tunnel Server实现Kubernetes集群的远程诊断?
后端
brzhang9 小时前
读懂 MiniMax Agent 的设计逻辑,然后我复刻了一个MiniMax Agent
前端·后端·架构