官网地址:dynamic | Elasticsearch Guide [8.16] | Elastic
常用字段属性
index
定义字段是否能被检索,如果设定为false,不可以被检索。
下面的例子中展示除了这个点
PUT index_test
{
"mappings":{
"properties":{
"name":{
"type":"text",
"index":false
},
"age":{
"type":"integer"
}
}
},
"settings":{
"number_of_replicas":0
}
}
PUT index_test/_doc/1
{
"name":"lihua",
"age":11
}
GET index_test/_search
{
"query":{
"term": {
"name": {
"value": "lihua"
}
}
}
}
GET index_test/_search
{
"query":{
"term": {
"age": {
"value": 11
}
}
}
}
查询name这个字段时,给的提示就是:Cannot search on field [name] since it is not indexed
{
"error": {
"root_cause": [
{
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [name] since it is not indexed.",
"index_uuid": "BmTMBhi3TBy61-AS-209gQ",
"index": "index_test"
}
],
"type": "search_phase_execution_exception",
"reason": "all shards failed",
"phase": "query",
"grouped": true,
"failed_shards": [
{
"shard": 0,
"index": "index_test",
"node": "0ah_4y0mR7-RqILdW94ikA",
"reason": {
"type": "query_shard_exception",
"reason": "failed to create query: Cannot search on field [name] since it is not indexed.",
"index_uuid": "BmTMBhi3TBy61-AS-209gQ",
"index": "index_test",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Cannot search on field [name] since it is not indexed."
}
}
}
]
},
"status": 400
}
index属性一旦设定之后是不可以进行修改的,这里需要注意!!!!!!
Store
在 ES 的 Mapping 里,store 是控制字段是否单独存储 的核心属性,新手可以先记住核心结论:store: true = 字段内容额外单独保存 一份;store: false(默认)= 字段内容仅存在于 _source 字段中,不单独存储。
要理解 store,首先要先明确 ES 文档的存储逻辑:ES 会把文档的完整原始数据存在 _source 字段里(默认开启),所有字段的内容都包含在 _source 中。store 属性的作用是:是否为某个字段「额外开一个独立的存储区域」,让它可以脱离 _source 被单独读取。
一、store 的核心用法
1. 默认值与基础语法
store 的默认值是 false,绝大多数场景下无需修改。
json
# 创建索引时定义 store 属性
PUT /user_index
{
"mappings": {
"properties": {
"name": {
"type": "keyword",
"store": false // 默认值,无需显式写
},
"id_card": {
"type": "keyword",
"store": true // 单独存储该字段
},
"age": {
"type": "integer"
}
}
}
}
2. 如何读取 store: true 的字段
通过 stored_fields 参数(而非 fields/_source)读取单独存储的字段:
json
GET /user_index/_search
{
"stored_fields": ["id_card"] // 仅读取单独存储的 id_card 字段
}
返回结果示例:
json
{
"hits": [
{
"_id": "1",
"stored_fields": {
"id_card": ["110101199001011234"]
}
}
]
}
二、store: true 的适用场景(新手必看)
store: true 不是性能优化手段,反而会增加磁盘开销,仅在以下特殊场景使用:
1. 超大 _source 文档,仅需读取少数字段
如果文档的 _source 非常大(比如包含完整的日志文本、长文章),但业务只需要读取少数核心字段(如订单号、用户 ID),设置 store: true 可以避免读取整个 _source,减少 IO 开销。
2. 敏感字段隔离(配合 _source 禁用)
如果想隐藏部分原始数据(比如身份证、手机号),可以禁用 _source("_source": {"enabled": false}),仅将非敏感字段设置 store: true:
json
PUT /user_index
{
"mappings": {
"_source": { "enabled": false }, // 禁用原始文档存储
"properties": {
"name": { "type": "keyword", "store": true }, // 仅存储姓名
"id_card": { "type": "keyword" } // 不存储身份证,也无法读取
}
}
}
3. 字段值需要「精准原始值」(极少用)
比如某些场景下,字段经过分词 / 处理后,_source 中的值和索引中的值可能有差异,store: true 可以获取未经过处理的原始值(但 _source 本身也能做到,此场景几乎可忽略)。
enabled 属性深度解析
enabled 是 ES 中仅作用于 object 类型字段 的核心属性,核心作用是:控制整个 object 字段是否被 ES 索引(分析 / 存储到倒排索引)。
可以把它理解为:给 object 字段加一个「总开关」------ 开关打开(enabled: true,默认),object 内的子字段正常索引;开关关闭(enabled: false),整个 object 仅作为「纯文本」存在于 _source 中,失去所有索引能力(无法检索、聚合、排序)。
一、enabled 的核心特性(新手必记)
- 仅作用于 object 类型 :
enabled只能给type: object的字段配置,给keyword/integer/text等基础类型配置enabled完全无效(ES 会忽略该配置)。 - 二值开关 :只有
true(默认)和false两个取值,无其他可选值。 - 不影响
_source存储 :enabled: false仅禁用「索引能力」,不会删除数据 ------ object 内的所有内容仍会完整保存在_source字段中,只是无法通过 ES 的检索语法查询。 - 全局生效 :对 object 内的所有子字段 生效(不管是预定义的还是动态新增的),一旦
enabled: false,整个 object 下的所有子字段都无法检索。
二、enabled: true(默认值):正常索引
这是默认行为,object 字段的所有子字段会按配置的 mapping 正常索引,支持检索、聚合、排序等所有操作。
示例:enabled: true(显式配置,和默认效果一致)
json
# 创建索引:user是object类型,enabled: true(默认可省略)
PUT index_enabled_demo
{
"mappings": {
"properties": {
"user": {
"type": "object",
"enabled": true, // 显式开启,默认可省略
"properties": {
"name": { "type": "keyword" },
"age": { "type": "integer" }
}
},
"order_no": { "type": "keyword" } // 基础类型,配置enabled无效
}
}
}
# 写入数据
PUT index_enabled_demo/_doc/1
{
"user": {
"name": "lihua",
"age": 11
},
"order_no": "OD1001"
}
# 1. 检索user.name=lihua → 能查到结果
GET index_enabled_demo/_search
{
"query": { "term": { "user.name": "lihua" } }
}
# 2. 聚合user.age → 能正常聚合
GET index_enabled_demo/_search
{
"aggs": {
"avg_age": { "avg": { "field": "user.age" } }
}
}
核心效果 :user 下的 name/age 可正常检索、聚合,和普通字段无区别。
三、enabled: false:禁用索引(核心重点)
配置 enabled: false 后,整个 object 字段会被 ES 当作「不透明的二进制数据」处理:
- ✅ 数据完整保存在
_source中(可读取原始值); - ❌ 无法对 object 内的任何子字段做检索 / 聚合 / 排序;
- ❌ 即使给子字段配置了 mapping(如
user.name),也会被忽略; - ❌
dynamic配置(如dynamic: true)完全失效(因为整个 object 都不索引了)。
示例:enabled: false 完整演示
json
# 重建索引:user设为enabled: false
PUT index_enabled_demo
{
"mappings": {
"properties": {
"user": {
"type": "object",
"enabled": false, // 禁用user的索引能力
"properties": {
"name": { "type": "keyword" }, // 该配置被忽略
"age": { "type": "integer" } // 该配置被忽略
}
},
"order_no": { "type": "keyword" }
}
}
}
# 写入相同数据(成功,无报错)
PUT index_enabled_demo/_doc/1
{
"user": {
"name": "lihua",
"age": 11
},
"order_no": "OD1001"
}
# 1. 读取文档:_source中能看到完整的user数据
GET index_enabled_demo/_doc/1
# 返回结果(关键片段):
# "_source" : {
# "user" : { "name" : "lihua", "age" : 11 },
# "order_no" : "OD1001"
# }
# 2. 检索user.name=lihua → 无结果(无法检索)
GET index_enabled_demo/_search
{
"query": { "term": { "user.name": "lihua" } }
}
# 3. 聚合user.age → 报错(字段不存在)
GET index_enabled_demo/_search
{
"aggs": {
"avg_age": { "avg": { "field": "user.age" } }
}
}
# 报错信息核心:"reason": "No mapping found for [user.age] in order to aggregate on it"
# 4. 检索order_no=OD1001 → 正常查到(order_no不受影响)
GET index_enabled_demo/_search
{
"query": { "term": { "order_no": "OD1001" } }
}
关键细节:enabled: false 后如何读取数据?
只能通过 _source 读取完整的 object 内容,无法单独读取子字段:
json
# 正确:读取整个_source中的user
GET index_enabled_demo/_search
{
"_source": ["user"], // 仅返回user字段
"query": { "match_all": {} }
}
# 错误:无法单独读取user.name(会返回空)
GET index_enabled_demo/_search
{
"fields": ["user.name"],
"_source": false,
"query": { "match_all": {} }
}
四、enabled 的适用场景(新手必懂)
1. 存储「无需检索的冗余数据」(最常用)
比如:
- 订单的「备注信息」「用户提交的原始表单内容」;
- 日志中的「完整请求体」「原始报错堆栈」;
- 这些数据仅需保存备查,无需检索 / 聚合,设置
enabled: false可减少 ES 的索引开销(节省内存 / 磁盘)。
2. 存储「超大 / 结构不固定的 object」
如果 object 内容超大(如几 KB 的 JSON)或结构不固定(如动态的扩展字段),索引该 object 会消耗大量资源,且业务无需检索,此时 enabled: false 是最优选择。
3. 敏感数据「仅存储不检索」
比如用户的「详细地址」「身份证照片元信息」,业务需要保存,但不需要通过这些字段检索,设置 enabled: false 可降低敏感数据被误检索的风险(仅能通过 _source 读取)。
五、enabled 的常见误区(新手必避)
误区 1:「enabled: false 会丢失数据」
❌ 错误:数据完整保存在 _source 中,只是无法检索,可随时通过 _source 读取原始值。
误区 2:「给基础类型(如 keyword)配置 enabled: false 能禁用索引」
❌ 错误:enabled 仅对 object 类型生效,给 keyword/integer 配置 enabled: false 会被 ES 忽略;✅ 正确做法:基础类型禁用索引用 index: false(比如 name: { type: keyword, index: false })。
误区 3:「enabled: false 的 object 内可以单独开启某个子字段的索引」
❌ 错误:enabled: false 是「全局开关」,会禁用整个 object 内所有子字段的索引,无法单独例外。
误区 4:「enabled: false 能提升写入性能」
✅ 正确:ES 无需解析 / 索引 object 内的子字段,写入时的 CPU/IO 开销会降低,适合超大 object 场景。
六、enabled vs index vs dynamic(核心对比)
新手常混淆这三个属性,用表格清晰区分:
表格
| 属性 | 作用对象 | 核心作用 | 取值 |
|---|---|---|---|
enabled |
仅 object 类型 | 控制整个 object 是否被索引 | true/false |
index |
基础类型(keyword/text 等) | 控制单个基础字段是否被索引 | true/false |
dynamic |
仅 object 类型 | 控制 object 内是否允许自动新增子字段 | true/false/strict |
示例:三者结合的最佳实践
json
PUT index_best_practice
{
"mappings": {
"properties": {
"user": { // 核心业务字段:正常索引,严格管控子字段
"type": "object",
"enabled": true,
"dynamic": "strict", // 禁止自动新增子字段
"properties": {
"name": { "type": "keyword" },
"age": { "type": "integer" },
"id_card": { "type": "keyword", "index": false } // 身份证仅存储,不索引
}
},
"ext_info": { // 扩展字段:仅存储,不索引
"type": "object",
"enabled": false // 禁用索引,仅保存在_source
}
}
}
}
总结
enabled核心作用 :仅控制object类型字段的「整体索引开关」,false时仅存于_source,无法检索 / 聚合;- 适用场景:存储无需检索的冗余数据、超大 object、敏感数据(仅存储不检索);
- 关键区别 :和
index(基础字段索引开关)、dynamic(子字段新增权限)是完全不同的维度,新手需重点区分; - 性能影响 :
enabled: false可降低写入 / 存储开销,适合非核心 object 字段。
doc_values 列式存储机制
在 Elasticsearch(以下简称 ES)的使用过程中,我们常常会遇到这样的场景:明明能通过检索快速找到目标文档,可一旦对字段进行聚合、排序操作,性能就会急剧下降。这背后的核心原因,在于 ES 对数据的双重存储机制------而行式存储(_source)之外的「列式存储」,正是由 doc_values 这个核心属性来控制的。
本章将从基础定义、核心特性、实操配置、场景选择到避坑指南,全面拆解 doc_values,帮你搞懂它的作用、用法,以及如何通过它优化 ES 聚合排序性能。
一、什么是 doc_values?------ ES 的「聚合排序加速器」
要理解 doc_values,首先要明确 ES 的双重存储逻辑:ES 为了兼顾「全文检索」和「聚合/排序」两大核心需求,会将数据以两种形式存储在磁盘上:
-
行式存储(_source):这是我们最熟悉的存储形式,按「文档」为单位,完整保存原始 JSON 数据。它的优势是能快速读取整份文档,适合检索后返回完整结果,但如果要对某个字段(比如商品价格、创建时间)进行聚合或排序,就需要遍历所有文档,效率极低。
-
列式存储(doc_values) :这是 ES 专为聚合、排序、脚本访问设计的存储形式,按「字段」为单位,将所有文档的同一个字段值集中存储(比如把所有商品的
price字段值单独存为一列)。这种存储方式能让 ES 在聚合排序时,直接定位到目标字段的列,无需遍历所有文档,性能可提升 10 倍以上。
简单来说,doc_values 就是 ES 中控制「是否生成列式存储」的开关------开启它,字段就能高效支持聚合排序;关闭它,字段就只能用于检索,无法进行聚合排序操作。
关键澄清:不是所有字段都有 doc_values
很多新手会误以为「ES 所有字段都会同时存储 _source 和 doc_values」,其实不然:
「doc_values 仅针对可聚合、可排序的字段生效」,比如 keyword、integer、long、date、boolean 等类型;而 text 类型字段(主打全文检索,极少用于聚合排序),默认关闭 doc_values ,即使手动配置 doc_values: true,ES 也会直接忽略该配置。
二、doc_values 核心特性(一目了然)
掌握以下特性,能快速避开 80% 的使用坑,先看一张清晰的特性表:
| 特性 | 具体说明 |
|---|---|
| 默认值 | 除 text、annotated_text 外,所有字段默认 doc_values: true(自动开启) |
| 生效时机 | 索引创建、文档写入时自动生成,不可动态修改(修改需重建索引) |
| 存储位置 | 默认存储在磁盘(高效、稳定,占用空间可控);text 字段如需聚合,可通过 fielddata 缓存到内存(不推荐) |
| 核心作用 | 支撑字段的聚合、排序、脚本访问,关闭后这些操作会直接失败 |
| 数据安全性 | 关闭 doc_values 仅丢失列式存储,原始数据仍保存在 _source 中,字段可正常检索 |
三、实操配置:如何开启/关闭 doc_values?
doc_values 的配置非常简单,只需在创建索引时,针对具体字段指定即可(注意:创建后无法修改,需提前规划字段用途)。下面结合实际业务场景,给出完整配置示例。
示例:电商商品索引配置
假设我们要创建一个电商商品索引,包含商品名称、追踪ID、创建时间三个字段,根据字段用途配置 doc_values:
// 创建商品索引,配置 doc_values PUT product_index { "mappings": { "properties": { // 场景1:text类型(商品名称,主打检索,默认关闭doc_values) "product_name": { "type": "text", "fields": { // 如需对商品名称聚合(比如统计各商品名称的销量),新增keyword子字段 "keyword": { "type": "keyword", "doc_values": true // 显式开启(可省略,默认true) } } }, // 场景2:keyword类型(追踪ID,仅用于检索,无需聚合排序,关闭doc_values) "trace_id": { "type": "keyword", "doc_values": false // 关闭节省磁盘空间 }, // 场景3:date类型(创建时间,需聚合排序,默认开启doc_values,省略配置) "create_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" } } } }
配置效果验证
写入测试数据后,我们通过几个查询验证配置效果:
// 1. 写入测试数据 PUT product_index/_doc/1 { "product_name": "小米手机", "trace_id": "trace_123456", "create_time": "2026-03-21 10:30:00" } // 2. 对 trace_id 排序 → 报错(doc_values: false,无法排序) GET product_index/_search { "sort": [{"trace_id": "asc"}] } // 报错核心信息:Fielddata is disabled on text fields by default... // 3. 对 create_time 聚合(按天统计商品数量)→ 成功 GET product_index/_search { "size": 0, "aggs": { "daily_product_count": { "date_histogram": { "field": "create_time", "calendar_interval": "day" } } } } // 4. 对 trace_id 检索 → 成功(doc_values不影响检索) GET product_index/_search { "query": { "term": {"trace_id": "trace_123456"} } }
四、场景选择:什么时候开启/关闭 doc_values?
是否开启 doc_values,核心取决于「字段是否需要聚合、排序、脚本访问」,结合业务场景选择即可,无需盲目开启或关闭。
1. 保留默认(doc_values: true)------ 优先选择
适合以下场景:
-
字段需要聚合、排序、脚本访问:比如商品价格(price)、分类(category)、创建时间(create_time)、用户年龄(age)等核心分析字段;
-
绝大多数业务场景的默认选择,优先保障聚合排序性能,磁盘空间充足时无需刻意关闭。
2. 关闭 doc_values: false ------ 按需选择
关闭后能节省磁盘空间,但会失去聚合排序能力,适合以下场景:
-
字段仅用于检索、过滤,完全不需要聚合排序:比如日志的 trace_id、订单流水号、用户唯一标识(user_id)等;
-
超大索引(亿级及以上文档):非核心字段关闭 doc_values,可显著减少索引体积(通常能节省 20%-50% 磁盘空间);
-
临时索引:仅用于数据检索、导出,无需进行任何分析操作的临时存储索引。
五、新手避坑指南:4 个常见误区
在使用 doc_values 时,很多新手会踩一些基础坑,这里集中澄清,帮你少走弯路:
误区1:关闭 doc_values 后,字段无法检索
❌ 错误:doc_values 仅影响「聚合、排序、脚本访问」,不影响检索功能!
比如示例中的trace_id 关闭 doc_values 后,依然可以通过term 查询找到对应文档,只是无法按 trace_id 排序或聚合。
误区2:给 text 字段开启 doc_values
❌ 错误:ES 不支持给 text 类型字段直接开启 doc_values,即使配置了也会被忽略。
✅ 正确做法:如果需要对文本字段聚合排序,必须通过 fields.keyword 生成 keyword 子字段(如示例中的 product_name.keyword),利用子字段的 doc_values 实现。
误区3:doc_values 可以动态修改
❌ 错误:doc_values 是磁盘级别的存储结构,在索引创建时就已确定,后续无法通过 PUT mapping 动态修改。
✅ 正确做法:如果需要调整 doc_values 配置,必须重建索引(先创建新索引,再将旧数据重新写入)。
误区4:用 fielddata 替代 doc_values
⚠️ 不推荐:fielddata 是 ES 为 text 字段提供的「内存版列式存储」,开启后会将字段数据缓存到内存,容易导致内存溢出(OOM),仅适合应急场景(比如临时对 text 字段聚合)。
✅ 正确做法:优先使用 keyword 子字段的 doc_values,避免开启 fielddata。
六、doc_values vs fielddata:核心对比
很多新手会混淆 doc_values 和 fielddata,两者都是为了支撑聚合排序,但适用场景和性能差异极大,一张表区分清楚:
| 特性 | doc_values | fielddata |
|---|---|---|
| 存储位置 | 磁盘(高效、稳定,无内存风险) | 内存(易 OOM,性能较差) |
| 适用类型 | keyword、numeric、date 等非 text 类型 | 仅 text 类型(应急使用) |
| 默认状态 | 开启(除 text 字段) | 关闭 |
| 业务建议 | 优先使用,是聚合排序的首选方案 | 仅应急场景临时开启,不推荐生产使用 |
七、最佳实践总结
结合前面的讲解,总结 4 个生产环境最佳实践,帮你合理配置 doc_values,兼顾性能和磁盘空间:
-
核心分析字段(价格、时间、分类等):保留默认
doc_values: true,保障聚合排序性能; -
仅检索字段(trace_id、流水号等):关闭
doc_values: false,节省磁盘空间; -
文本字段需聚合:通过 keyword 子字段实现,避免开启 fielddata;
-
提前规划字段用途:创建索引前明确字段是否需要聚合排序,避免上线后因修改 doc_values 而重建索引。
至此,关于 doc_values 的核心知识点已全部讲解完毕。合理使用 doc_values,能让你的 ES 索引在聚合排序场景下性能翻倍,同时有效控制磁盘占用------这也是 ES 优化中最基础、最易落地的优化手段之一。
ignore_above
ignore_above 核心概念
ignore_above 是 Elasticsearch 中针对字符串类型字段(keyword/text) 的属性,用于限制字段值的最大字符长度:
- 当字段值的字符长度超过
ignore_above设定值时,ES 会根据字段类型采取不同行为:- keyword 类型:直接忽略该字段(不索引、不存储),文档可正常写入,但该字段无法被搜索 / 聚合;
- text 类型:ES 会截断超出长度的部分,仅索引前 N 个字符(N = ignore_above 值)。
- 注意:
ignore_above统计的是 UTF-8 字符数(非字节数),例如中文、英文、数字均按 1 个字符计算。
二、使用示例(对比理解)
1. 基础配置示例
先创建包含 ignore_above 的映射:
json
PUT index_ignore_demo
{
"mappings": {
"properties": {
"product_code": { // keyword 类型,限制最大长度 5
"type": "keyword",
"ignore_above": 5
},
"product_desc": { // text 类型,限制最大长度 10
"type": "text",
"ignore_above": 10
}
}
}
}
2. 写入不同长度的文档验证
(1)写入符合长度的文档
json
PUT index_ignore_demo/_doc/1
{
"product_code": "A1234", // 长度 5,符合限制
"product_desc": "苹果手机" // 长度 4,符合限制
}
- 搜索验证:能正常匹配到结果
json
GET index_ignore_demo/_search
{
"query": {
"term": {
"product_code": "A1234"
}
}
}
(2)写入超出长度的文档
json
PUT index_ignore_demo/_doc/2
{
"product_code": "B123456", // 长度 7,超过 keyword 类型的 5
"product_desc": "华为Mate60 Pro手机" // 长度 9?不,实际是:华(1)+为(2)+M(3)+a(4)+t(5)+e(6)+6(7)+0(8)+ (9)+P(10)+r(11)+o(12)+手(13)+机(14) → 长度 14,超过 text 类型的 10
}
- 验证 keyword 字段:
product_code:B123456无法被搜索到(已被忽略)
json
GET index_ignore_demo/_search
{
"query": {
"term": {
"product_code": "B123456"
}
}
}
// 结果:hits.total = 0
- 验证 text 字段:仅能匹配前 10 个字符("华为 Mate60 P"),超出部分被截断
json
GET index_ignore_demo/_search
{
"query": {
"match": {
"product_desc": "Pro手机" // 超出截断部分,无法匹配
}
}
}
// 结果:hits.total = 0
GET index_ignore_demo/_search
{
"query": {
"match": {
"product_desc": "华为Mate60" // 前 8 个字符,可匹配
}
}
}
// 结果:能匹配到文档 2
三、常见使用场景
- 限制关键词长度:例如订单号、商品编码等 keyword 字段,避免超长值占用过多内存(keyword 字段的 doc_values 会存储完整值,超长值会增加内存开销);
- 防止恶意超长文本 :例如用户评论等 text 字段,通过
ignore_above截断超长内容,避免索引过大或性能问题; - 兼容旧数据 :对历史数据中偶发的超长字段值,无需过滤数据,直接通过
ignore_above忽略 / 截断,保证文档正常写入。
四、注意事项
ignore_above默认为2147483647(int 最大值),即默认不限制长度;- 若设置
ignore_above: 0,则该 keyword 字段会被完全忽略(无论值多长); - 对于嵌套在 object/nested 中的字符串字段,
ignore_above同样生效; - 映射创建后,可通过
PUT index/_mapping修改ignore_above值,但仅对修改后写入的文档生效,已写入的文档不会重新索引。
总结
ignore_above用于限制字符串字段的最大字符长度,keyword 超长度会被忽略,text 超长度会被截断;- 核心作用是控制字段存储 / 索引的长度,减少内存占用、避免超长值引发的性能问题;
- 统计单位是 UTF-8 字符数,映射修改后仅对新文档生效。
coerce
coerce 是 Elasticsearch 针对数值类型(integer/long/float/double 等) 和 日期类型 字段的「容错转换开关」,核心规则是:
coerce: true(默认) :ES 会尝试对「格式不规范但可转换」的输入值做自动类型转换,仅当转换成功时正常索引,转化失败会直接将数据存储coerce: false:完全禁止任何自动转换,输入值必须是字段定义类型的「原生格式」,哪怕是「可转换的不规范值」(如字符串数字)也会直接报错。
下面的例子中展示创建一个integer类型的字段,再插入别的类型是出现错误:
PUT index_test
{
"mappings": {
"_source": {
"enabled": true
},
"properties": {
"name": {
"type": "keyword",
"index": true,
"doc_values": true,
"ignore_above":2
},
"age": {
"type": "integer",
"coerce":false
},
"user_info": {
"type": "object",
"dynamic": "strict",
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "keyword",
"ignore_above":4
}
}
}
}
},
"settings": {
"number_of_replicas": 0
}
}
PUT index_test/_doc/1
{
"name": "lihua",
"age": 11,
"user_info": {
"id": 1,
"name": "lihua"
}
}
PUT index_test/_doc/2
{
"name": "lihua",
"age": "11.33",
"user_info": {
"id": 1,
"name": "lihua"
}
}
插入第二条的时候出现的错误是:
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "failed to parse field [age] of type [integer] in document with id '2'. Preview of field's value: '11.33'"
}
],
"type": "mapper_parsing_exception",
"reason": "failed to parse field [age] of type [integer] in document with id '2'. Preview of field's value: '11.33'",
"caused_by": {
"type": "illegal_argument_exception",
"reason": "Integer value passed as String"
}
},
"status": 400
}
所以大家再设置数值类型的时候还是建议加上这个字段,防止出现问题。
ignore_malformed
一、ignore_malformed 核心概念
ignore_malformed 是 Elasticsearch 中通用的字段级属性 (几乎支持所有字段类型),核心作用是:当字段值无法被正确解析 / 转换为字段定义的类型时,ES 会「忽略该字段」而非「拒绝整个文档」。
简单理解:
ignore_malformed: true:字段值解析失败时,该字段不会被索引 / 存储,但整个文档仍能正常写入;ignore_malformed: false(默认值):字段值解析失败时,整个文档写入失败,直接抛出异常。
⚠️ 关键区别(和 coerce 对比):
coerce针对「格式不规范但可转换」的值(如字符串数字转整数),是「转换容错」;ignore_malformed针对「完全无法解析 / 转换」的值(如字符串abc转整数),是「字段级失败容错」。
二、使用示例(精准验证行为)
1. 创建带 ignore_malformed 的映射
json
PUT index_ignore_malformed_demo
{
"mappings": {
"properties": {
"age": {
"type": "integer",
"ignore_malformed": true // 开启字段级容错
},
"price": {
"type": "float",
"ignore_malformed": false // 默认关闭,失败则文档写入失败
},
"birth_date": {
"type": "date",
"format": "yyyy-MM-dd",
"ignore_malformed": true // 日期解析失败时忽略该字段
}
}
}
}
2. 验证不同场景的行为
场景 1:ignore_malformed: true 的字段解析失败(age 字段)
写入「无法转换为整数的字符串 abc」:
json
PUT index_ignore_malformed_demo/_doc/1
{
"age": "abc", // 无法转为整数,字段会被忽略
"price": 99.9, // 正常解析
"birth_date": "2004-01-01" // 正常解析
}
结果:文档写入成功!
- 验证:查询文档能看到
price和birth_date,但age字段被忽略(不存在):
json
GET index_ignore_malformed_demo/_doc/1
// 返回结果
{
"_id": "1",
"_source": {
"price": 99.9,
"birth_date": "2004-01-01"
// age 字段被忽略,未存储
}
}
场景 2:ignore_malformed: false 的字段解析失败(price 字段)
写入「无法转换为浮点数的字符串 xyz」:
json
PUT index_ignore_malformed_demo/_doc/2
{
"age": 20,
"price": "xyz", // 无法转为浮点数,且 ignore_malformed=false
"birth_date": "2004-01-01"
}
结果:整个文档写入失败,报错核心信息:
plaintext
"reason": "failed to parse field [price] of type [float] in document with id '2'. Preview of field's value: 'xyz'",
"caused_by": {
"type": "number_format_exception",
"reason": "For input string: \"xyz\""
}
场景 3:日期字段的 ignore_malformed 行为
写入「无效格式的日期 2004/01/01」:
json
PUT index_ignore_malformed_demo/_doc/3
{
"age": 20,
"price": 99.9,
"birth_date": "2004/01/01" // 格式不匹配,字段被忽略
}
结果 :文档写入成功,但 birth_date 字段被忽略:
json
GET index_ignore_malformed_demo/_doc/3
// 返回结果
{
"_id": "3",
"_source": {
"age": 20,
"price": 99.9
// birth_date 字段被忽略
}
}
三、支持的字段类型 & 注意事项
1. 支持的字段类型
ignore_malformed 支持绝大多数字段类型:
- 数值型:integer/long/float/double/short/byte 等;
- 日期型:date;
- 字符串型:keyword/text(极少用,因为字符串几乎不会解析失败);
- 不支持:
object/nested/geo_point/ip等复杂类型(这些类型需通过dynamic: strict控制)。
2. 关键注意事项
① 全局配置:可在 elasticsearch.yml 中设置 index.mapping.ignore_malformed: true,全局开启所有字段的容错(优先级低于字段级配置);② _source 说明:被忽略的字段不会出现在 _source 中 (相当于从未传入该字段);③ 映射修改:创建索引后可通过 PUT index/_mapping 修改 ignore_malformed 值,仅对修改后写入的文档生效;④ 聚合 / 搜索:被忽略的字段无法被搜索、聚合,因为未被索引。
四、适用场景
- 非核心字段容错 :例如用户画像中的「年龄」「生日」等非核心字段,即使解析失败,也希望文档能正常写入(核心字段如订单号仍建议
ignore_malformed: false); - 数据来源杂乱:第三方接口 / 日志数据格式不统一,避免个别字段解析失败导致整个文档丢失;
- 批量写入兜底:批量导入数据时,忽略少量解析失败的字段,保证大部分数据正常入库(后续可通过监控排查异常字段)。
总结
ignore_malformed是「字段级失败容错开关」:开启后字段解析失败仅忽略该字段,文档仍写入;关闭则字段解析失败导致整个文档写入失败;- 与
coerce互补:coerce处理「可转换的不规范值」,ignore_malformed处理「无法转换的无效值」; - 核心价值是保证文档写入成功率,适用于非核心字段、数据格式不统一的场景。