文章九:ElasticSearch索引字段常见属性

官网地址: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 的核心特性(新手必记)

  1. 仅作用于 object 类型enabled 只能给 type: object 的字段配置,给 keyword/integer/text 等基础类型配置 enabled 完全无效(ES 会忽略该配置)。
  2. 二值开关 :只有 true(默认)和 false 两个取值,无其他可选值。
  3. 不影响 _source 存储enabled: false 仅禁用「索引能力」,不会删除数据 ------ object 内的所有内容仍会完整保存在 _source 字段中,只是无法通过 ES 的检索语法查询。
  4. 全局生效 :对 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 当作「不透明的二进制数据」处理:

  1. ✅ 数据完整保存在 _source 中(可读取原始值);
  2. ❌ 无法对 object 内的任何子字段做检索 / 聚合 / 排序;
  3. ❌ 即使给子字段配置了 mapping(如 user.name),也会被忽略;
  4. 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
      }
    }
  }
}

总结

  1. enabled 核心作用 :仅控制 object 类型字段的「整体索引开关」,false 时仅存于 _source,无法检索 / 聚合;
  2. 适用场景:存储无需检索的冗余数据、超大 object、敏感数据(仅存储不检索);
  3. 关键区别 :和 index(基础字段索引开关)、dynamic(子字段新增权限)是完全不同的维度,新手需重点区分;
  4. 性能影响enabled: false 可降低写入 / 存储开销,适合非核心 object 字段。

doc_values 列式存储机制

在 Elasticsearch(以下简称 ES)的使用过程中,我们常常会遇到这样的场景:明明能通过检索快速找到目标文档,可一旦对字段进行聚合、排序操作,性能就会急剧下降。这背后的核心原因,在于 ES 对数据的双重存储机制------而行式存储(_source)之外的「列式存储」,正是由 doc_values 这个核心属性来控制的。

本章将从基础定义、核心特性、实操配置、场景选择到避坑指南,全面拆解 doc_values,帮你搞懂它的作用、用法,以及如何通过它优化 ES 聚合排序性能。

一、什么是 doc_values?------ ES 的「聚合排序加速器」

要理解 doc_values,首先要明确 ES 的双重存储逻辑:ES 为了兼顾「全文检索」和「聚合/排序」两大核心需求,会将数据以两种形式存储在磁盘上:

  1. 行式存储(_source):这是我们最熟悉的存储形式,按「文档」为单位,完整保存原始 JSON 数据。它的优势是能快速读取整份文档,适合检索后返回完整结果,但如果要对某个字段(比如商品价格、创建时间)进行聚合或排序,就需要遍历所有文档,效率极低。

  2. 列式存储(doc_values) :这是 ES 专为聚合、排序、脚本访问设计的存储形式,按「字段」为单位,将所有文档的同一个字段值集中存储(比如把所有商品的price 字段值单独存为一列)。这种存储方式能让 ES 在聚合排序时,直接定位到目标字段的列,无需遍历所有文档,性能可提升 10 倍以上。

简单来说,doc_values 就是 ES 中控制「是否生成列式存储」的开关------开启它,字段就能高效支持聚合排序;关闭它,字段就只能用于检索,无法进行聚合排序操作。

关键澄清:不是所有字段都有 doc_values

很多新手会误以为「ES 所有字段都会同时存储 _source 和 doc_values」,其实不然:

「doc_values 仅针对可聚合、可排序的字段生效」,比如 keywordintegerlongdateboolean 等类型;而 text 类型字段(主打全文检索,极少用于聚合排序),默认关闭 doc_values ,即使手动配置 doc_values: true,ES 也会直接忽略该配置。

二、doc_values 核心特性(一目了然)

掌握以下特性,能快速避开 80% 的使用坑,先看一张清晰的特性表:

特性 具体说明
默认值 textannotated_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_valuesfielddata,两者都是为了支撑聚合排序,但适用场景和性能差异极大,一张表区分清楚:

特性 doc_values fielddata
存储位置 磁盘(高效、稳定,无内存风险) 内存(易 OOM,性能较差)
适用类型 keyword、numeric、date 等非 text 类型 仅 text 类型(应急使用)
默认状态 开启(除 text 字段) 关闭
业务建议 优先使用,是聚合排序的首选方案 仅应急场景临时开启,不推荐生产使用

七、最佳实践总结

结合前面的讲解,总结 4 个生产环境最佳实践,帮你合理配置 doc_values,兼顾性能和磁盘空间:

  1. 核心分析字段(价格、时间、分类等):保留默认 doc_values: true,保障聚合排序性能;

  2. 仅检索字段(trace_id、流水号等):关闭 doc_values: false,节省磁盘空间;

  3. 文本字段需聚合:通过 keyword 子字段实现,避免开启 fielddata;

  4. 提前规划字段用途:创建索引前明确字段是否需要聚合排序,避免上线后因修改 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

三、常见使用场景

  1. 限制关键词长度:例如订单号、商品编码等 keyword 字段,避免超长值占用过多内存(keyword 字段的 doc_values 会存储完整值,超长值会增加内存开销);
  2. 防止恶意超长文本 :例如用户评论等 text 字段,通过 ignore_above 截断超长内容,避免索引过大或性能问题;
  3. 兼容旧数据 :对历史数据中偶发的超长字段值,无需过滤数据,直接通过 ignore_above 忽略 / 截断,保证文档正常写入。

四、注意事项

  1. ignore_above 默认为 2147483647(int 最大值),即默认不限制长度;
  2. 若设置 ignore_above: 0,则该 keyword 字段会被完全忽略(无论值多长);
  3. 对于嵌套在 object/nested 中的字符串字段,ignore_above 同样生效;
  4. 映射创建后,可通过 PUT index/_mapping 修改 ignore_above 值,但仅对修改后写入的文档生效,已写入的文档不会重新索引。

总结

  1. ignore_above 用于限制字符串字段的最大字符长度,keyword 超长度会被忽略,text 超长度会被截断;
  2. 核心作用是控制字段存储 / 索引的长度,减少内存占用、避免超长值引发的性能问题;
  3. 统计单位是 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" // 正常解析
}

结果:文档写入成功!

  • 验证:查询文档能看到 pricebirth_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 值,仅对修改后写入的文档生效;④ 聚合 / 搜索:被忽略的字段无法被搜索、聚合,因为未被索引。

四、适用场景

  1. 非核心字段容错 :例如用户画像中的「年龄」「生日」等非核心字段,即使解析失败,也希望文档能正常写入(核心字段如订单号仍建议 ignore_malformed: false);
  2. 数据来源杂乱:第三方接口 / 日志数据格式不统一,避免个别字段解析失败导致整个文档丢失;
  3. 批量写入兜底:批量导入数据时,忽略少量解析失败的字段,保证大部分数据正常入库(后续可通过监控排查异常字段)。

总结

  1. ignore_malformed 是「字段级失败容错开关」:开启后字段解析失败仅忽略该字段,文档仍写入;关闭则字段解析失败导致整个文档写入失败;
  2. coerce 互补:coerce 处理「可转换的不规范值」,ignore_malformed 处理「无法转换的无效值」;
  3. 核心价值是保证文档写入成功率,适用于非核心字段、数据格式不统一的场景。
相关推荐
左左右右左右摇晃2 小时前
Java笔记——多态
java·笔记·python
WordPress学习笔记2 小时前
WordPress报错 Error establishing a database connection
数据库·wordpress
空空潍2 小时前
2026年IDEA、PyCharm等专业版学生免费申请教育许可证
java·ide·intellij-idea
9稳2 小时前
基于plc的自动化立体仓库控制系统设计
开发语言·网络·数据库·嵌入式硬件·plc
MX_93592 小时前
基于注解方式配置声明式事务
java·开发语言·后端·spring
Java面试题总结2 小时前
Spring AI 初步集成(2)-添加记忆
java·人工智能·spring
野犬寒鸦2 小时前
JVM垃圾回收机制深度解析(G1篇)(垃圾回收过程及专业名词详解)
java·服务器·jvm·后端·面试
清水白石0082 小时前
协程不是线程:深入理解 Python async/await 运行机制
java·linux·python
程序员老乔2 小时前
Java 新纪元 — JDK 25 + Spring Boot 4 全栈实战(五):FFM API,告别JNI在Spring Boot中直连推荐引擎
java·开发语言·spring boot