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+树索引 | 支持搜索查询 | 需要搜索的字段 |
通过合理配置这三个参数,可以在存储空间、查询性能和内存使用之间找到最佳平衡点。