Elasticsearch Mapping 解析

Elasticsearch 映射(Mapping)全解析

一、映射核心定义

官方定义翻译与优化

映射(Mapping) 是定义文档及其包含的字段如何被存储、索引和检索的过程,相当于关系型数据库中的「表结构定义」,但具备更强的灵活性和动态扩展能力。

每一篇ES文档都是字段的集合,每个字段都有对应的数据类型。映射的核心载体是映射定义(mapping definition),它包含两部分核心内容:

  1. 文档相关的字段列表,以及每个字段的数据类型、索引规则、分词方式等配置;

  2. 元数据字段(metadata fields),比如_source字段,用于自定义文档关联元数据的处理规则。

1. 映射的核心本质

映射的核心作用,是告诉ES「如何理解你的数据」:

  • 决定一个字符串字段是用于全文检索(text类型) 还是精确匹配/聚合排序(keyword类型)

  • 决定数字、日期、地理坐标等字段用什么格式存储和计算;

  • 决定哪些字段可以被索引、哪些字段可以被排序、哪些字段会被忽略;

  • 控制文本的分词规则、语义向量生成、嵌套对象的解析方式等高级行为。

2. 核心元数据字段全解析

元数据字段是ES为每篇文档自动维护的内置字段,无需用户手动定义,映射中可自定义其行为,9.3.0版本核心元数据字段如下:

元数据字段 核心作用 常用配置说明
_source 存储文档写入时的原始JSON内容 默认开启;关闭可节省50%左右磁盘空间,但无法做文档更新、重索引、字段重建,生产环境非极端场景不建议关闭
_id 文档的唯一标识 可手动指定,也可由ES自动生成;无法修改,只能通过重写文档替换
_index 文档所属的索引名称 只读,由ES自动维护,用于跨索引查询时筛选
_routing 文档路由到分片的路由值 默认用_id计算;自定义路由可将相关文档放到同一个分片,提升联合查询性能
_version 文档的版本号 每次写入/更新自动+1,用于乐观锁控制并发写入
_seq_no 文档的序列号 ES集群级别的单调递增编号,用于并发控制和数据同步
_primary_term 主分片任期号 配合_seq_no实现乐观锁,避免脑裂导致的脏数据
3. 映射的两种核心设计思路

根据数据的确定性,ES提供两种映射定义方式,可组合使用:

  • 动态映射(Dynamic Mapping):ES自动检测文档字段的数据类型,自动创建映射,适合快速上手、字段不确定的场景;

  • 显式映射(Explicit Mapping):用户手动为每个字段指定数据类型和配置,生产环境强推荐,完全掌控数据的索引行为。

原文补充说明:7.0.0版本之前,映射定义包含「类型名称(type name)」,一个索引可包含多个文档类型;7.0.0及之后版本彻底移除了映射类型,不再接受默认映射,一个索引仅支持一个固定的_doc类型。

【深度分析】移除的核心原因:ES底层存储中,同一个索引里不同类型的同名字段,必须使用完全相同的映射,否则会出现倒排索引冲突,「多类型」设计无实际意义,还会增加用户理解成本,因此被彻底废弃。9.3.0版本完全不支持映射类型,所有操作无需指定type名称。


二、动态映射(Dynamic Mapping)

当你使用动态映射时,ES会自动检测文档中字段的数据类型,并为你自动创建对应的映射。如果后续写入的新文档包含之前没有的字段,ES会自动将这些字段添加到映射中;你可以给顶层映射、内部对象字段、嵌套字段新增动态字段。

动态映射能帮你快速上手ES,但由于其自动类型推断的特性,可能会出现不符合业务预期的映射结果,导致特定场景下的性能和功能问题。

你可以使用动态模板(Dynamic Templates),为动态添加的字段,根据匹配规则自定义映射规则。

1. 动态映射的核心类型推断规则(9.3.0版本,踩坑高频点)

ES不会凭空推断类型,有严格的内置推断规则,默认规则如下(优先级从高到低):

写入的字段值 默认推断的字段类型 关键补充说明
true / false boolean 仅严格的布尔值会被推断,字符串"true"/"false"不会
带小数点的数字(如123.45) float 不会推断为double,除非显式指定
整数(如123) long 不会推断为integer/short,避免数值溢出
符合日期格式的字符串 date 默认匹配格式:`strict_date_optional_time
普通字符串(无法转成日期/数字) text + keyword 多字段 这是ES最常用的默认规则:主字段为text类型(用于全文检索),同时自动创建一个.keyword子字段(keyword类型,用于聚合、排序、精确匹配)
嵌套JSON对象({} object 自动递归解析嵌套对象里的字段,支持无限层级(受嵌套深度限制)
数组([] 按数组内第一个非空元素的类型推断 ES数组不要求元素类型完全一致,但会按第一个元素推断类型,不匹配的会写入失败(除非开启ignore_malformed
地理坐标/地理形状 无自动推断 必须显式指定geo_point/geo_shape类型,动态映射不会自动识别
向量数据 无自动推断 必须显式指定dense_vector类型,用于语义搜索
2. 动态映射的核心开关

动态映射的行为可通过dynamic参数控制,可配置在索引级别、单个object字段级别,可选值如下:

dynamic参数值 行为说明 适用场景
true 默认值,开启动态映射,自动添加新字段到映射 测试环境、字段完全不确定的场景
false 关闭动态映射,新字段不会被添加到映射,但会被存储到 _source 不需要检索新字段,仅需要存储原始数据的场景
strict 严格模式,遇到未知字段直接拒绝文档写入,抛出异常 生产环境强推荐,严格控制字段结构,避免映射爆炸
3. 动态模板(Dynamic Templates)全解析

动态模板是动态映射的进阶能力,可自定义「动态添加的字段」的映射规则,解决默认动态映射不符合业务预期的问题。

核心匹配规则

每个动态模板包含2个核心部分:

  • 匹配规则 :支持按字段名(match/unmatch)、字段路径(path_match/path_unmatch)、动态推断的类型(match_mapping_type)匹配;

  • 映射配置:匹配成功后,应用到该字段的映射规则。

实操示例(9.3.0可直接复制)
HTTP 复制代码
# 创建索引,配置动态模板
PUT /my-dynamic-index
{
  "mappings": {
    "dynamic_templates": [
      {
        "strings_as_keyword": {
          "match_mapping_type": "string",
          "match": "*_id",
          "mapping": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      },
      {
        "full_text_fields": {
          "match_mapping_type": "string",
          "unmatch": "*_id",
          "mapping": {
            "type": "text",
            "analyzer": "ik_max_word",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 1024
              }
            }
          }
        }
      },
      {
        "long_to_integer": {
          "match_mapping_type": "long",
          "mapping": {
            "type": "integer"
          }
        }
      }
    ]
  }
}
模板说明
  1. 第一个模板:所有以_id结尾的字符串字段,直接映射为keyword类型,不创建全文索引;

  2. 第二个模板:其他所有字符串字段,映射为text类型(使用ik分词器),同时带keyword子字段;

  3. 第三个模板:所有动态推断为long的整数字段,自动映射为integer类型,节省存储空间。


三、显式映射(Explicit Mapping)

官方内容翻译与优化

显式映射,是指你手动为每个字段指定数据类型和映射配置的方式,是生产环境的推荐方案。通过显式映射,你可以完全掌控数据的索引方式,完全贴合业务的使用场景。

自定义显式映射可以实现以下能力:

  • 定义哪些字符串字段应该作为全文本字段处理;

  • 定义哪些文本字段可以通过语义搜索机器学习模型自动向量化;

  • 定义哪些字段是数字、日期、地理坐标类型;

  • 使用动态映射无法自动识别的数据类型(如geo_pointgeo_shapedense_vector);

  • 自定义日期格式,包括特殊的自定义日期格式;

  • 创建自定义规则,控制动态添加字段的映射;

  • 为字段优化前缀匹配、模糊匹配能力;

  • 配置针对特定语言的文本分词器。

实用技巧:为了适配不同的使用目的,通常会把同一个字段用不同的方式索引(多字段multi-fields)。比如,一个字符串字段可以同时映射为text类型(用于全文检索)和keyword类型(用于排序和聚合);也可以为用户输入的字符串字段,配置多个不同语言的分词器。

1. 显式映射的核心优势(生产环境为什么必须用)
  • 避免类型推断错误:比如日期字符串被推断为普通字符串、数字字符串被推断为文本,导致无法按时间/数字范围查询;

  • 控制存储成本:关闭不需要的索引、doc_values,避免不必要的多字段创建,大幅节省磁盘空间;

  • 优化查询性能:为字段选择最合适的数据类型、分词器、索引规则,查询性能比动态映射高2-5倍;

  • 规避功能限制:地理类型、向量类型、嵌套类型等高级特性,必须通过显式映射定义,动态映射无法支持;

  • 严格管控数据结构 :配合dynamic: strict,避免非法字段写入,保障数据一致性。

2. 多字段(Multi-fields)全解析

多字段是ES映射的核心设计,允许为同一个原始字段值,创建多个不同类型、不同配置的子字段,适配不同的查询场景,无需冗余存储原始数据。

核心适用场景
  1. 字符串字段同时支持全文检索+聚合排序:主字段text用于全文搜索,子字段keyword用于聚合、排序、精确匹配(ES默认动态映射就是这个规则);

  2. 同一个文本字段使用多个分词器:比如一个中文文本,同时用ik分词器做中文检索、用拼音分词器做拼音检索、用英文分词器做英文检索;

  3. 同一个数字字段同时支持范围查询+聚合:主字段integer用于范围查询,子字段keyword用于精确匹配和terms聚合。

实操示例
HTTP 复制代码
PUT /my-explicit-index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "ik_max_word",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 1024
          },
          "pinyin": {
            "type": "text",
            "analyzer": "pinyin_analyzer"
          }
        }
      },
      "price": {
        "type": "float",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}
3. 显式映射的核心数据类型选型指南
数据类型大类 常用子类型 适用场景 选型避坑
字符串类型 text 全文检索场景,如文章标题、内容、日志详情 不要给不需要全文检索的字段用text,会浪费大量存储空间和索引性能
keyword 精确匹配、聚合、排序场景,如ID、状态码、分类、标签 合理设置ignore_above,避免超长字符串占用资源,默认256
数字类型 integer/long 整数场景,如数量、状态码、ID 优先用最小范围的类型,比如能用short就不用integer,能用integer就不用long,节省存储
float/double/scaled_float 小数场景,如价格、金额、指标 金额场景优先用scaled_float,避免浮点精度丢失
日期类型 date 时间戳、日期场景,支持毫秒/秒级时间戳、格式化日期 显式指定日期格式,避免动态映射推断错误,不要用字符串存储日期
date_nanos 纳秒级精度的日期场景,如链路追踪日志 非必要不使用,存储占用更高,查询性能略低
布尔类型 boolean 二值场景,如是否删除、是否生效 不要用字符串/数字存储布尔值,浪费空间且影响查询性能
地理类型 geo_point 经纬度坐标场景,如位置检索、范围查询、距离排序 必须显式指定,动态映射无法识别,不要用两个数字字段存储经纬度
geo_shape 复杂地理形状场景,如多边形、圆形、线路 仅用于复杂地理空间查询,普通经纬度用geo_point即可
嵌套类型 object 普通嵌套JSON对象,无关联查询需求 无法对嵌套对象的多个字段做联合查询,适合简单嵌套场景
nested 嵌套对象需要做联合查询的场景,如订单商品列表 严格控制数量,默认单索引最多50个nested字段,避免性能问题
向量类型 dense_vector 语义搜索、向量检索场景,存储文本/图片的向量 embedding 9.3.0版本支持多种向量相似度算法,必须显式指定维度和相似度类型
扁平类型 flattened 动态JSON对象,避免映射爆炸,如日志的扩展字段 把整个JSON对象映射成单个字段,仅支持精确匹配,不支持全文检索,完美解决动态字段的映射爆炸问题

四、运行时字段(Runtime Fields)

使用运行时字段,可以无需重索引即可修改数据结构。你可以将运行时字段与索引字段结合使用,平衡资源占用和查询性能:使用运行时字段可以让你的索引体积更小,但会带来一定的查询性能损耗。

你可以在搜索请求中直接定义运行时字段,用于:

  1. 试验不同的映射方案,无需修改索引结构;

  2. 修复索引映射中的错误,在查询时覆盖映射中的字段值。

1. 运行时字段核心原理

运行时字段是查询时动态计算的字段,不会写入索引、不占用磁盘空间,ES在执行查询时,通过你定义的Painless脚本实时计算字段值,再执行过滤、聚合、排序等操作,相当于SQL中的「计算列」。

2. 核心适用场景
  • 临时修复映射错误:比如动态映射把日期字段推断成了字符串,无需重索引全量数据,通过运行时字段把字符串转回日期类型,正常做时间范围查询;

  • 临时新增分析字段:业务临时需要对数据做统计分析,新增一个计算字段,无需修改索引映射、无需重索引;

  • 低频查询字段优化:极少查询的字段,无需写入索引,用运行时字段按需计算,节省90%以上的存储成本;

  • 敏感字段脱敏 :查询时对敏感字段做脱敏处理,比如手机号、身份证号,原始数据存储在_source中,运行时字段返回脱敏后的值,避免原始数据泄露。

3. 性能权衡(必须重点关注)
维度 索引字段 运行时字段
存储占用 占用磁盘空间,取决于字段类型和索引配置 完全不占用磁盘空间,零存储成本
写入性能 写入时需要构建索引、doc values,有一定性能损耗 写入时无任何额外开销,写入性能拉满
查询性能 提前构建索引,查询性能极高,支持全量查询能力 查询时需要全量扫描文档,执行脚本计算,性能比索引字段低2-10倍,取决于脚本复杂度和数据量
功能限制 支持全文检索、聚合、排序、过滤所有能力 不支持全文检索,仅支持keyword、数字、日期等简单类型的过滤、聚合、排序
核心原则:高频查询、大结果集的字段,必须用索引字段;低频查询、临时分析、小数据量的场景,适合用运行时字段。
4. 两种定义方式(实操示例)
方式1:在索引映射中定义运行时字段(永久生效)
HTTP 复制代码
# 给索引添加运行时字段,无需重索引
PUT /my-index/_mapping
{
  "runtime": {
    "order_amount": {
      "type": "double",
      "script": {
        "source": "emit(doc['price'].value * doc['quantity'].value)"
      }
    },
    "mobile_desensitized": {
      "type": "keyword",
      "script": {
        "source": "if(doc['mobile'].size()!=0){emit(doc['mobile'].value.substring(0,3)+'****'+doc['mobile'].value.substring(7,11))}"
      }
    }
  }
}

# 直接查询运行时字段,和普通字段用法完全一致
GET /my-index/_search
{
  "query": {
    "range": {
      "order_amount": {
        "gte": 100
      }
    }
  },
  "fields": ["order_amount", "mobile_desensitized"]
}
方式2:在查询请求中临时定义(单次查询生效)
HTTP 复制代码
GET /my-index/_search
{
  "runtime_mappings": {
    "day_of_week": {
      "type": "keyword",
      "script": {
        "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.CHINA))"
      }
    }
  },
  "aggs": {
    "week_stats": {
      "terms": {
        "field": "day_of_week"
      }
    }
  }
}

五、映射的管理与更新规则

显式映射应该在索引创建时,为你提前已知的字段完成定义;随着业务数据的变化,也可以随时给映射添加新的字段。

使用更新映射API(Update Mapping API) 可以更新已有的映射。

核心规则:绝大多数情况下,已经完成映射的字段,无法修改其映射配置,这类修改需要重索引才能生效。

仅以下场景可以更新映射,无需重索引:

  1. 随时可以给已有映射新增字段(动态/显式均可);

  2. 可以给已有字段新增多字段;

补充说明:映射更新前写入的文档,不会自动生成新多字段的值,只有更新/重索引后才会生效;映射更新后写入的新文档,会自动生成新多字段的值。

  1. 部分特定数据类型的字段,可更新部分映射参数。

可更新vs不可更新的完整边界

1. 无需重索引,可直接更新的映射操作
可更新操作 详细说明 注意事项
新增字段 给顶层、嵌套对象、nested字段新增显式字段 新增字段对已有文档无影响,已有文档的该字段值为null,新文档会按新映射写入
给已有字段新增多字段 给已存在的字段添加新的子字段 已有文档不会自动生成子字段的值,必须更新文档/重索引才会生效
更新ignore_above参数 修改keyword字段的最大长度限制 新配置仅对新写入的文档生效,已有文档的超出长度的字段,不会被重新索引
更新ignore_malformed参数 修改是否忽略格式错误的字段 新配置仅对新写入的文档生效,已有文档的格式错误字段不会被处理
更新dynamic参数 修改动态映射的开关(true/false/strict) 立即生效,对所有新写入的文档生效
新增/修改运行时字段 新增、修改、删除运行时字段 立即生效,无需重索引,所有查询都会使用最新的脚本逻辑
更新meta参数 修改映射的元数据备注信息 无业务影响,仅用于备注说明
2. 必须重索引,才能生效的映射修改(绝对不能直接改)
不可直接更新的操作 核心原因 正确处理方式
修改已有字段的数据类型 ES的倒排索引、doc values都是写入时按字段类型构建的,修改类型后,已有数据的索引结构完全不匹配,会导致查询错误、数据丢失 新建索引,定义正确的映射,用reindex API把旧索引数据全量重索引到新索引
修改已有字段的分词器(analyzer) 文本的倒排索引是写入时按分词器生成的,修改分词器后,已有数据的分词结果不会更新,全文检索会出现匹配错误 重索引,或给字段新增多字段,配置新的分词器
修改已有字段的doc_values/fielddata/store参数 这些参数控制字段的存储结构,写入时就已确定,修改后已有数据不会重新构建 重索引
给已有字段新增/修改copy_to参数 copy_to是写入时把字段值复制到目标字段,已有文档不会自动复制 重索引
修改已有字段的index参数(开启/关闭索引) 控制字段是否被索引,写入时已确定,修改后已有数据不会变更 重索引
修改日期字段的format参数 日期格式是写入时解析的,修改后已有日期数据不会重新解析 重索引,或用运行时字段临时兼容
3. 更新映射的实操示例(9.3.0可直接执行)
HTTP 复制代码
# 1. 给已有索引新增字段
PUT /my-index/_mapping
{
  "properties": {
    "new_field": {
      "type": "keyword",
      "ignore_above": 256
    },
    "new_nested_field": {
      "type": "nested",
      "properties": {
        "id": {
          "type": "long"
        },
        "name": {
          "type": "keyword"
        }
      }
    }
  }
}

# 2. 给已有字段新增多字段
PUT /my-index/_mapping
{
  "properties": {
    "title": {
      "type": "text",
      "analyzer": "ik_max_word",
      "fields": {
        "pinyin": {
          "type": "text",
          "analyzer": "pinyin_analyzer"
        }
      }
    }
  }
}

# 3. 修改dynamic参数为严格模式
PUT /my-index/_mapping
{
  "dynamic": "strict"
}

六、映射爆炸(Mapping Explosion)防控

在一个索引中定义过多的字段,会导致映射爆炸,进而引发OOM内存溢出、集群不可用等严重问题,且故障恢复难度极大。

最常见的场景是:开启动态映射后,每一篇新写入的文档都引入新的字段(比如日志中的动态JSON字段),每一个新字段都会被添加到索引映射中,随着字段数量增长,最终引发映射爆炸。

你可以使用映射限制配置(mapping limit settings),限制手动/动态创建的字段映射数量,避免文档引发映射爆炸。

完整防控方案

1. 映射爆炸的根因

ES集群的所有索引的映射元数据,都会加载到集群所有节点的JVM堆内存中,字段数量越多,元数据体积越大,会导致:

  • JVM堆内存占用持续升高,最终触发OOM,节点宕机;

  • 集群元数据同步压力剧增,集群状态变为黄色/红色,元数据更新超时;

  • 索引、写入、查询性能急剧下降,甚至完全不可用。

最常见的触发场景:

  • 日志场景中,把动态JSON格式的日志内容直接展开,每个key都变成一个字段,很快就会突破上万字段;

  • 开启动态映射,业务代码不规范,每次写入都带新的字段名;

  • 多租户场景,每个租户的自定义字段都直接写到索引的顶层,字段数量指数级增长。

2. 9.3.0版本核心防控配置项
配置项 默认值 核心作用
index.mapping.total_fields.limit 1000 单个索引允许的最大字段数量,最核心的防控阈值
index.mapping.depth.limit 20 字段的最大嵌套深度,比如a.b.c.d的深度为4
index.mapping.nested_fields.limit 50 单个索引允许的最大nested字段数量
index.mapping.nested_objects.limit 10000 单个文档中允许的最大nested对象数量
index.mapping.field_name_length.limit 256 单个字段名的最大长度
index.mapping.total_fields.ignore_dynamic_beyond_limit false 字段数量超过阈值后,是否忽略新增的动态字段,而不是拒绝写入(logsdb模式默认开启)
避坑提醒:绝对不要盲目调大index.mapping.total_fields.limit的默认值1000,调大只会延迟故障发生的时间,不会解决根本问题,生产环境单索引字段数建议控制在500以内。
3. 生产环境终极防控方案
  1. 严格关闭动态映射 :索引级别设置dynamic: strict,只允许提前显式定义的字段写入,从根源上杜绝动态字段增长;

  2. 使用 flattened 类型处理动态JSON :对于不确定的动态字段,用flattened类型映射,把整个JSON对象当成一个字段,不会展开成多个独立字段,完美解决映射爆炸;

  3. 合理使用动态模板:对于必须开启的动态映射,用动态模板严格控制字段类型,避免不必要的多字段创建;

  4. 分索引/分租户隔离:多租户场景,按租户分索引,不要把所有租户的字段都放到同一个索引里;

  5. 定期监控字段数量:通过ES集群监控,持续跟踪索引的字段数量,提前预警增长异常。

4. flattened类型防控映射爆炸实操示例
HTTP 复制代码
# 创建索引,用flattened类型处理动态扩展字段
PUT /my-safe-index
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "@timestamp": {
        "type": "date"
      },
      "host.name": {
        "type": "keyword"
      },
      "log.message": {
        "type": "text"
      },
      # 动态扩展字段,全部映射为flattened类型,不会展开
      "ext_fields": {
        "type": "flattened"
      }
    }
  }
}

# 写入数据,ext_fields里的任意JSON内容都可以写入,不会新增字段
POST /my-safe-index/_doc
{
  "@timestamp": "2026-02-14 18:00:00",
  "host.name": "web-server-01",
  "log.message": "user login success",
  "ext_fields": {
    "username": "test",
    "login_ip": "192.168.1.100",
    "user_agent": "chrome",
    "custom_field_1": "value1",
    "custom_field_2": "value2"
  }
}

# 可正常查询ext_fields里的字段
GET /my-safe-index/_search
{
  "query": {
    "term": {
      "ext_fields.username": "test"
    }
  }
}

七、9.3.0版本完整映射实操示例

HTTP 复制代码
# 1. 创建索引,定义完整的显式映射,包含动态模板、防控映射爆炸配置
PUT /my-production-index
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    # 映射爆炸防控配置
    "index.mapping.total_fields.limit": 500,
    "index.mapping.depth.limit": 10
  },
  "mappings": {
    # 严格模式,禁止未知字段写入
    "dynamic": "strict",
    # 动态模板,仅允许指定规则的动态字段
    "dynamic_templates": [
      {
        "id_fields_as_keyword": {
          "match": "*_id",
          "mapping": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    ],
    # 运行时字段,预定义计算字段
    "runtime": {
      "order_total_amount": {
        "type": "double",
        "script": {
          "source": "emit(doc['goods_price'].value * doc['goods_quantity'].value)"
        }
      }
    },
    # 显式字段定义
    "properties": {
      "@timestamp": {
        "type": "date",
        "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
      },
      "order_id": {
        "type": "keyword"
      },
      "user_id": {
        "type": "keyword"
      },
      "goods_name": {
        "type": "text",
        "analyzer": "ik_max_word",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 1024
          }
        }
      },
      "goods_price": {
        "type": "scaled_float",
        "scaling_factor": 100
      },
      "goods_quantity": {
        "type": "integer"
      },
      "order_status": {
        "type": "integer"
      },
      "pay_time": {
        "type": "date"
      },
      "user_address": {
        "type": "geo_point"
      },
      "goods_ext": {
        "type": "flattened"
      }
    }
  }
}

# 2. 验证映射创建成功
GET /my-production-index/_mapping

# 3. 写入测试数据
POST /my-production-index/_doc
{
  "@timestamp": "2026-02-14 18:30:00",
  "order_id": "ORD202602140001",
  "user_id": "U123456",
  "goods_name": "华为Mate 60 Pro 手机",
  "goods_price": 6999.00,
  "goods_quantity": 1,
  "order_status": 1,
  "pay_time": "2026-02-14 18:31:00",
  "user_address": {
    "lat": 30.5728,
    "lon": 104.0668
  },
  "goods_ext": {
    "color": "雅丹黑",
    "storage": "12GB+512GB",
    "supplier": "华为官方旗舰店"
  }
}

# 4. 查询数据,包含运行时字段
GET /my-production-index/_search
{
  "fields": ["*", "order_total_amount"]
}

八、生产环境映射设计最佳实践(9.3.0版本适配)

  1. 生产环境必须使用显式映射 ,配合dynamic: strict严格模式,从根源上避免类型错误和映射爆炸;

  2. 最小字段原则 :只给需要检索、聚合的字段创建索引,不需要检索的字段关闭index,不需要排序聚合的字段关闭doc_values,最大化节省存储;

  3. 字符串字段合理选型 :不需要全文检索的字段,一律用keyword类型,不要用text;需要全文检索的字段,合理配置分词器,避免不必要的多字段;

  4. 数字类型最小化原则 :能用short不用integer,能用integer不用long,金额场景优先用scaled_float避免精度丢失;

  5. 动态字段用 flattened 类型 :不确定的动态JSON字段,一律用flattened类型,绝对不要直接展开成顶层字段;

  6. 高频查询用索引字段,低频临时分析用运行时字段,平衡存储和性能,不要滥用运行时字段;

  7. 严格控制字段数量:单索引字段数建议控制在500以内,绝对不要盲目调大字段数量阈值;

  8. 索引创建时就定义好完整映射,避免后续修改需要重索引,重索引是生产环境的高风险操作;

  9. 特殊类型必须显式指定:日期、地理、向量、嵌套类型,必须显式定义,不要依赖动态映射;

  10. 映射变更必须先测试:生产环境修改映射前,必须在测试环境验证,避免映射错误导致写入失败。

相关推荐
玄〤2 小时前
Elasticsearch 概念与基础实操 (索引、映射与文档操作)(黑马微服务课day12)
大数据·elasticsearch·微服务·全文检索
海兰2 小时前
Elasticsearch 自管理集群配置指南
大数据·elasticsearch·jenkins
MARS_AI_2 小时前
2026年大模型呼叫厂商深度盘点:8家核心玩家及选型指南
大数据·人工智能·自然语言处理·交互·信息与通信
海兰2 小时前
Elasticsearch 全文检索概述
elasticsearch·serverless·全文检索
YangYang9YangYan2 小时前
2026大专大数据与会计专业学习数据分析的价值分析
大数据·学习·数据分析
海兰2 小时前
Elasticsearch 搜索方案与技术栈深度解析
大数据·elasticsearch·django
良策金宝AI10 小时前
让端子排接线图“智能生成”,良策金宝AI推出变电站二次智能设计引擎
大数据·人工智能·工程设计·变电站ai
a2852811 小时前
nginx的重定向
大数据·数据库·nginx
yhdata12 小时前
锁定2032年!区熔硅单晶市场规模有望达71.51亿元,赛道前景持续向好
大数据·人工智能