👉 点击关注不迷路
👉 点击关注不迷路
👉 点击关注不迷路
文章大纲
- [第2章 数据建模与高效写入:ES字段类型选择最佳实践:keyword vs text与nested对象深度解析](#第2章 数据建模与高效写入:ES字段类型选择最佳实践:keyword vs text与nested对象深度解析)
-
- [1. 索引设计核心原则](#1. 索引设计核心原则)
- [2. `keyword`与`text`类型终极对决](#2.
keyword
与text
类型终极对决)
-
- [2.1 核心差异对比](#2.1 核心差异对比)
- [2.2 性能基准测试数据](#2.2 性能基准测试数据)
- [2.3 经典使用场景](#2.3 经典使用场景)
- [3. `nested`对象深度解析](#3.
nested
对象深度解析)
-
- [3.1 问题背景:`对象数组的扁平化---理解体会到扁平化这个词`](#3.1 问题背景:
对象数组的扁平化---理解体会到扁平化这个词
)
- [3.2 `nested`类型解决方案](#3.2
nested
类型解决方案)
- [3.3 nested与普通对象对比](#3.3 nested与普通对象对比)
- [3.4 性能影响测试](#3.4 性能影响测试)
- [4. 实战案例:电商平台商品模型设计](#4. 实战案例:电商平台商品模型设计)
-
- [4.1 需求分析](#4.1 需求分析)
- [4.2 最终映射设计](#4.2 最终映射设计)
- [4.3 查询示例:查找红色库存>100的商品](#4.3 查询示例:查找红色库存>100的商品)
- [5. 最佳实践总结](#5. 最佳实践总结)
-
- [5.1 类型选择决策树](#5.1 类型选择决策树)
- [5.2 黄金法则](#5.2 黄金法则)
- [5.3 常见误区](#5.3 常见误区)
- 附录:性能优化参数参考
第2章 数据建模与高效写入:ES字段类型选择最佳实践:keyword vs text与nested对象深度解析
1. 索引设计核心原则
在Elasticsearch
中,字段类型的选择直接影响以下关键指标:
影响维度 |
说明 |
典型场景示例 |
查询性能 |
类型选择错误可能导致查询延迟增加5-10倍 |
使用text 类型进行精确匹配 |
存储效率 |
合理的类型可减少20-50%的磁盘占用 |
数值类型误设为keyword |
聚合准确性 |
错误类型会导致cardinality聚合误差率高达30% |
高基数字段使用text类型进行聚合 |
功能支持 |
特定功能(如地理位置查询)必须使用专用类型 |
geo_point用于地理位置查询 |
cardinality
是 Elasticsearch
中的一种聚合类型,它可以对指定字段中的唯一值进行近似计数。
- 这里的 "近似" 是因为为了在处理大规模数据时提高性能和减少内存使用,
cardinality
采用了 HyperLogLog++
算法(算法的核心思想基于伯努利试验和概率统计)来估算唯一值的数量,而不是精确统计。
2. keyword
与text
类型终极对决
2.1 核心差异对比
特性 |
keyword类型 |
text类型 |
分词处理 |
不进行分词 |
默认使用标准分词器 |
存储结构 |
原始值完整存储 |
分词后存储倒排索引 |
查询方式 |
精确匹配(term查询) |
全文搜索(match查询) |
排序支持 |
完全支持 |
需要开启fielddata (消耗内存) |
聚合性能 |
高效,适合terms 聚合 |
需要额外配置fielddata ,性能较差 |
典型应用场景 |
标签、状态码、分类ID |
文章内容、产品描述、日志详情 |
存储开销 |
每个值独立存储 |
分词后存储,可能有重复token |
模糊查询 |
支持wildcard(性能差) |
支持多种分词器(如ngram) |
2.2 性能基准测试数据
- 测试环境:3节点集群(16核32GB,NVMe SSD),数据集:1000万条商品记录
测试场景 |
keyword类型耗时 |
text类型耗时 |
性能差异 |
精确匹配查询(term) |
23ms |
520ms |
22.6倍 |
全文搜索(match) |
N/A |
45ms |
- |
terms聚合(1000桶) |
680ms |
4200ms |
6.2倍 |
存储空间占用 |
12.4GB |
18.7GB |
1.5倍 |
2.3 经典使用场景
json
复制代码
{
"product_id": {"type": "keyword"},
"category": {
"type": "keyword",
"ignore_above": 256 // 自动截断超长字段
},
"status": {"type": "keyword"} // 状态枚举值
}
- 适用
text
的情况 :
analyzer
(分析器):将文本拆分成一个个独立的词项(term
),并可对这些词项进行一系列处理,如转换大小写、去除停用词等。
ik_max_word
分词器特点
ik_max_word
是 IK
分词器提供的一种分词模式。IK 分词器是一款专门为中文文本处理设计的开源分词器,在 Elasticsearch
中被广泛应用 。ik_max_word
模式具有以下特点:
- 最大切分粒度 :它会将文本进行最细粒度的拆分,尽可能地将文本拆分成更多的有意义的词 。例如,对于 "研究生命起源" 这句话,
ik_max_word
会将其拆分为 "研究""研究生""生命""起源" 等词项,这样可以提高搜索的召回率,让更多可能相关的文档被检索出来。
- 智能识别 :能够智能识别中文词汇,包括一些常见的专业术语、人名、地名等,使得分词结果更符合中文语言习惯。
json
复制代码
{
"product_description": {
"type": "text",
"analyzer": "ik_max_word", // 使用中文分词器
"fields": {
"keyword": {"type": "keyword"} // 多字段特性
}
}
}
3. nested
对象深度解析
3.1 问题背景:对象数组的扁平化---理解体会到扁平化这个词
json
复制代码
{
"order_id": "1001",
"items": [
{"sku": "A001", "price": 99},
{"sku": "B002", "price": 199}
]
}
bash
复制代码
{
"order_id": "1001",
"items.sku": ["A001", "B002"],
"items.price": [99, 199]
}
3.2 nested
类型解决方案
json
复制代码
{
"order": {
"properties": {
"items": {
"type": "nested",
"properties": {
"sku": {"type": "keyword"},
"price": {"type": "double"}
}
}
}
}
}
3.3 nested与普通对象对比
特性 |
nested类型 |
普通对象数组 |
存储方式 |
独立隐藏文档 |
扁平化存储 |
查询准确性 |
精确维护对象关系 |
可能产生跨对象匹配 |
写入性能 |
比普通对象慢2-3倍 |
最优 |
查询性能 |
需要特殊查询语法,较慢 |
标准查询语法 |
适用场景 |
需要精确维护对象关系的场景 |
不需要维护关系的简单数组 |
内存消耗 |
每个nested对象单独索引 |
整体作为字段处理 |
3.4 性能影响测试
- 测试数据集:500万订单记录,每个订单平均3个商品项
操作类型 |
nested类型耗时 |
普通对象耗时 |
差异倍数 |
写入吞吐量 |
1,200 docs/s |
3,800 docs/s |
3.2倍 |
嵌套查询 |
220ms |
35ms |
6.3倍 |
聚合分析 |
1.8s |
0.9s |
2倍 |
存储空间 |
143GB |
89GB |
1.6倍 |
4. 实战案例:电商平台商品模型设计
4.1 需求分析
- 商品基础信息
- 多规格
SKU
管理
- 用户评论情感分析
- 实时库存查询
4.2 最终映射设计
json
复制代码
{
"mappings": {
"properties": {
"product_id": {"type": "keyword"},
"title": {
"type": "text",
"analyzer": "ik_smart",
"fields": {"keyword": {"type": "keyword"}}
},
"categories": {"type": "keyword"},
"specs": {
"type": "nested",
"properties": {
"color": {"type": "keyword"},
"size": {"type": "keyword"},
"stock": {"type": "integer"}
}
},
"reviews": {
"type": "nested",
"properties": {
"user_id": {"type": "keyword"},
"content": {"type": "text"},
"rating": {"type": "byte"}
}
}
}
}
}
ik_smart
是 IK
分词器提供的一种分词模式。IK
分词器是专为中文文本处理打造的开源分词器,在 Elasticsearch
社区被广泛应用。ik_smart
模式具有以下显著特点:
- 最少切分原则 :它会尽可能将文本进行最粗粒度的拆分,以最少的词数来表达文本的语义 。例如,对于 "研究生命起源" 这句话,
ik_smart
会将其拆分为 "研究""生命起源",这种切分方式更注重整体语义的表达。
- 高效简洁 :由于分词结果的词数相对较少,
在处理大规模文本时,ik_smart 可以减少索引的大小,提高搜索效率
,同时也能一定程度上降低计算资源的消耗。
- 使用场景
- 对搜索效率要求高的场景 :当需要快速处理大量中文文本搜索请求时,
ik_smart
是一个不错的选择。例如,在电商网站的商品搜索功能中,用户输入搜索关键词后,系统需要迅速返回相关商品列表,使用 ik_smart
可以加快搜索速度,提升用户体验。
- 注重整体语义匹配的场景 :在一些对文本整体语义理解要求较高的搜索场景中 ,
ik_smart
的粗粒度分词能够更好地捕捉文本的核心语义 。比如,在企业知识管理系统中搜索相关文档时,用户更关注的是文档的整体主题,ik_smart
可以帮助找到更符合主题的文档。
4.3 查询示例:查找红色库存>100的商品
json
复制代码
{
"query": {
"nested": {
"path": "specs",
"query": {
"bool": {
"must": [
{"term": {"specs.color": "red"}},
{"range": {"specs.stock": {"gt": 100}}}
]
}
}
}
}
}
5. 最佳实践总结
5.1 类型选择决策树
是 否 是 否 是且需维护关系 否 需要全文搜索? 使用text类型 需要精确匹配? 使用keyword 包含子对象? 使用nested 使用合适的基础类型
5.2 黄金法则
-
- 标识性原则 :唯一标识符必须使用
keyword
-
- 长度控制 :超过
256
字符的keyword
字段需设置ignore_above
-
- 混合使用 :重要文本字段应
同时设置text和keyword
-
- 性能代价 :
nested
类型要严格控制数组长度
-
- 版本兼容 :
7.x以上版本优先使用keyword替代string类型
5.3 常见误区
错误场景 |
后果 |
解决方案 |
对text字段进行term查询 |
返回结果不准确 |
使用match查询或.keyword字段 |
过度使用nested类型 |
写入性能急剧下降 |
评估是否真正需要对象关系维护 |
大数组存储为keyword |
导致mapping爆炸 |
使用flattened类型替代 |
数值字段设为text |
范围查询效率降低80% |
严格使用数值类型 |
附录:性能优化参数参考
json
复制代码
// keyword字段优化
// "category" 字段用于存储分类信息,将其类型设置为 "keyword",适用于精确匹配和聚合操作
"category": {
"type": "keyword",
// eager_global_ordinals 设置为 true 表示预加载全局序数
// 全局序数是 Elasticsearch 用于优化聚合操作的一种数据结构
// 预加载全局序数可以加快聚合查询的速度,因为在查询时无需再动态计算
// 但是,这会增加内存开销,尤其是在数据量较大时
// 因此,仅在需要频繁进行聚合操作且内存充足的情况下使用
"eager_global_ordinals": true
},
// nested字段优化
// "specs" 字段用于存储产品规格等嵌套数据,将其类型设置为 "nested"
// "nested" 类型允许在文档中嵌套子文档,并且可以对子文档进行独立的查询和聚合
"specs": {
"type": "nested",
// include_in_parent 设置为 true 表示允许父文档查询嵌套字段
// 这意味着在查询父文档时,可以同时匹配嵌套字段的条件
// 然而,这种方式会增加查询的复杂度和性能开销,因为需要在父文档和嵌套文档之间进行额外的关联操作
// 所以,使用时需要谨慎评估,仅在确实需要进行此类跨层级查询时启用
"include_in_parent": true
}