文章九: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. 核心价值是保证文档写入成功率,适用于非核心字段、数据格式不统一的场景。
相关推荐
枫叶丹4几秒前
Loop Engineering:从提示词到循环系统
数据库·redis·缓存·loop
zhanghaofaowhrql12 分钟前
Spring Data JPA Repository 详解:从基础到高级用法
java·数据库·sql
天蓝的想14 分钟前
Kueue 如何管理 DRA 模式下的 GPU 配额
运维·服务器
ljs64827395118 分钟前
VMware 中部署 HDFS 集群环境(Hadoop 3.4.3)完整指南
大数据·hadoop·hdfs
编程(变成)小辣鸡1 小时前
如何防止接口被恶意刷?
java·后端·网络安全
大圣编程6 小时前
Java 多维数组详解
java·开发语言
万法若空8 小时前
【算法-查找】查找算法
java·数据结构·算法
恒5399 小时前
Linux文件系统I
linux·运维·服务器
雪碧聊技术9 小时前
Badge 应用场景与落地实践指南
大数据·人工智能
阿成学长_Cain9 小时前
Linux ipcs 命令超全详解:查看共享内存 / 消息队列 / 信号量,IPC 运维必备
linux·运维·服务器·网络·数据库