ElasticSearch的映射与文档

概述

映射官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/7.17/mapping.html

映射(mapping)是ES中一个很重要的概念,我们知道ES的索引类似于MySQL中的表,而映射就类似于MySQL中的表结构,而文档(Document)就是MySQL表中的一行行数据。

映射(Mapping)的作用是定义文档的结构与数据类型,同时也能设置如何对文档进行索引

映射分为动态映射和显示映射

  • 动态映射是只需在ES中添加文档即可自动添加新字段。您可以将字段添加到顶级映射以及内部object 和nested外部字段。
  • 显示映射是需要你添加文档前定义好每个字段的数据类型,例如:
    • 哪些字符串字段应被视为全文字段
    • 哪些字段包含数字、日期或地理位置
    • 日期值的 格式
    • 自定义规则来控制动态添加字段 的映射

数据类型介绍

官方文档:https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/field-data-types

常见类型

  • binary

    • 存储编码为 Base64 字符串的二进制值类型。
  • boolean

    • 只包含true和false两个值
  • keyword

    • 用于结构化内容,例如 ID、电子邮件地址、主机名、状态代码、邮政编码或标签。使用分词器时不会被分词
  • text

    • 用于全文内容(例如电子邮件正文或产品描述)的传统字段类型。适合全文检索
  • date

    • 用于存储日期,可使用format指定格式化类型
  • 数字

    • ES中数字类型有很多种,基本的可参考Java中的数据类型
      • byte:一个有符号的 8 位整数,最小值为-128,最大值为127
      • short:一个有符号的 16 位整数,最小值为-32,768,最大值为32,767
      • integer:一个有符号的 32 位整数,最小值为-231,最大值为231 - 1
      • long:一个有符号的 64 位整数,最小值为-263,最大值为263 - 1。
      • double:双精度 64 位 IEEE 754 浮点数,限制为有限值。
      • float:单精度 32 位 IEEE 754 浮点数,限制为有限值。
      • half_float:半精度 16 位 IEEE 754 浮点数,限制为有限值。
      • scaled_float:由 支持的浮点数long,按固定double比例因子缩放
      • unsigned_long:一个无符号的 64 位整数,最小值为 0,最大值为2^64 - 1
  • 数组

    • Elasticsearch 没有专门的array数据类型。默认情况下,任何字段都可以包含零个或多个值,但是,数组中的所有值必须属于相同的数据类型。例如:
      • 字符串数组:[ "one", "two"]
      • 整数数组:[ 1, 2]
      • 数组的数组: [ 1, [ 2, 3]] 相当于 [ 1, 2, 3]
      • 对象数组:[ { "name": "Mary", "age": 12 }, { "name": "John", "age": 10 }]
  • 对象

    • JSON 文档本质上是分层的:文档可能包含内部对象,而内部对象本身又可能包含内部对象:
  • IP

    • 用于存储IPv4或IPv6地址。

常用的数据类型就是以上几种,如果需要其它的场景,可以参考官方文档

映射的管理

创建映射

静态映射(显示创建)

创建索引时定义映射,控制字段类型和配置:

复制代码
PUT /my_index
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "refresh_interval": "1s"
  }
  // 定义映射
  "mappings": {
    "properties": {
      "title": { "type": "text" },
      "price": { "type": "double" },
      "tags": { "type": "keyword" },
      "created_at": { "type": "date", "format": "yyyy-MM-dd" }
    }
  }
}

动态映射(自动创建)

当插入文档时,如果字段不存在,ES 会根据数据类型自动创建映射。例如:

复制代码
PUT /my_index/_doc/1
{
  "title": "Elasticsearch Guide",
  "price": 49.99,
  "tags": ["search", "database"]
}

ES 会自动为字段 title(text+keyword)、price(double)和 tags(keyword)创建映射。

查看映射

  • 查看单个索引的映射

    GET /my_index/_mapping

  • 查看多个索引的映射

    GET /index1,index2/_mapping

  • 查看所有索引的映射

    GET /_mapping

更新映射

新增字段(支持动态更新)

可以向现有映射添加新字段:

复制代码
PUT /my_index/_mapping
{
  "properties": {
    "description": { "type": "text" },
    "in_stock": { "type": "boolean" }
  }
}

修改字段类型(不支持直接修改)

若需修改现有字段类型,需创建新索引并重新索引数据:

复制代码
// 1. 创建新索引并定义正确的映射
PUT /new_my_index
{
  "mappings": {
    "properties": {
      "price": { "type": "integer" } // 原类型为double,现改为integer
    }
  }
}

// 2. 使用_reindex API迁移数据
POST /_reindex
{
  "source": { "index": "my_index" },
  "dest": { "index": "new_my_index" }
}

// 3. 验证数据后删除旧索引
DELETE /my_index

删除映射

  • 删除索引(同时删除映射)

    DELETE /my_index

  • 重置映射(删除后重建)
    删除索引后重新创建并定义新映射:

    DELETE /my_index
    PUT /my_index
    {
    "mappings": { ... } // 新映射定义
    }

映射参数详解

核心参数

  • type:字段类型(text、keyword、integer 等)
  • index:是否索引(true/false)
  • analyzer:指定分词器(如 standard、english)
  • search_analyzer:搜索时使用的分词器(与 analyzer 不同时生效)
  • null_value:替代 null 值的默认值(需与字段类型匹配)
  • dynamic:控制动态添加字段的行为(true/false/strict)

高级参数

  • copy_to:将字段值复制到目标字段,便于组合搜索
  • doc_values:是否存储列式数据(用于聚合和排序,默认 true)
  • norms:是否存储归一化因子(影响评分,text 默认 false)
  • fields:多字段索引(如同时存储 text 和 keyword 类型)

文档的管理

在 Elasticsearch(ES)中,文档(Document)是可被索引的基本数据单元,以 JSON 格式存储

下面只列举了常用的文档管理的api,如果想要了解其它的可以参考官方文档:https://www.elastic.co/docs/api/doc/elasticsearch/group/endpoint-document

文档的基本概念

  • 文档结构:JSON 对象,包含字段和值。
  • 唯一性标识:每个文档在索引中需有唯一 ID(可自动生成或手动指定)。
  • 元数据字段:
    • _index:文档所在的索引名。
    • _id:文档的唯一标识符。
    • _source:原始 JSON 文档。
    • _version:文档版本号,用于乐观锁。

创建文档

指定id创建

复制代码
PUT /my_index/_doc/1
{
  "title": "Getting Started with ES",
  "content": "First steps in Elasticsearch",
  "user": "john_doe",
  "views": 100
}

自动生成id

返回结果包含自动生成的_id。

复制代码
POST /my_index/_doc
{
  "title": "Elasticsearch Tutorial",
  "content": "Learn Elasticsearch basics",
  "tags": ["search", "database"],
  "created_at": "2023-01-01"
}

获取文档

根据 ID 获取单个文档

复制代码
GET /my_index/_doc/1

检查文档是否存在

复制代码
HEAD /my_index/_doc/1

获取文档中指定的字段

复制代码
GET /my_index/_doc/1?_source=filed1,filed2

更新文档

全量更新

复制代码
PUT /my_index/_doc/1
{
  "title": "Updated Title",  // 原文档的其他字段会被删除
  "views": 101
}

部分更新

复制代码
POST /my_index/_update/1
{
  "doc": {
    "views": 102,           // 仅更新views字段
    "updated_at": "now"     // 添加新字段
  }
}

删除文档

根据 ID 删除单个文档

复制代码
DELETE /my_index/_doc/1

基于查询条件删除(需启用 delete-by-query 插件)

复制代码
POST /my_index/_delete_by_query
{
  "query": {
    "term": {
      "user": "john_doe"
    }
  }
}

动态映射详解

官方文档:https://www.elastic.co/docs/manage-data/data-store/mapping/dynamic-mapping

动态映射是只需在ES中添加文档即可自动添加新字段。您可以将字段添加到顶级映射以及内部object 和nested外部字段。

验证动态映射

创建一个索引,无需指定映射

复制代码
PUT dynamic-mapping-01
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "refresh_interval": "1s"
  }
}

添加一个文档

复制代码
# 请求
PUT dynamic-mapping-01/_doc/1
{
  "create_date": "2015/09/02",
  "name": "huangsir",
  "age": 18,
  "addr": "BeiJing",
  "ip": "10.0.0.40"
}

查询文档

复制代码
# 请求
GET dynamic-mapping-01/_doc/1

# 预期返回
{
  "_index" : "dynamic-mapping-01", //索引名称
  "_type" : "_doc", // 类型
  "_id" : "1",    // 唯一标识
  "_version" : 1, //版本号
  // 排序
  "_seq_no" : 0,
  // 分片
  "_primary_term" : 1,
  "found" : true,
  // 添加的数据
  "_source" : {
    "create_date" : "2015/09/02",
    "name" : "huangsir",
    "age" : 18,
    "addr" : "BeiJing",
    "ip" : "10.0.0.40"
  }
}

查看映射

复制代码
# 请求
GET /dynamic-mapping-01/_mapping

# 预期返回
{
  "dynamic-mapping-01" : {
    "mappings" : {
      "properties" : {
        "addr" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "age" : {
          "type" : "long"
        },
        "create_date" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        },
        "ip" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

通过上面的验证,发现其对应的字段的数据类型并不是我们想要的,我们可以指定其数据类型

验证静态映射

官方文档:https://www.elastic.co/docs/manage-data/data-store/mapping/explicit-mapping

静态映射是在创建索引时指定映射的字段、数据类型及其它相关的配置

创建索引

复制代码
# 请求
PUT explicit-mapping-01
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "refresh_interval": "1s"
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "age": {
        "type": "byte"
      },
      "addr": {
        "type": "keyword"
      },
      "ip": {
        "type": "ip"
      },
      "create_date": {
        "type": "date",
        "format": "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
      },
      "class": {
        "type": "object", 
        "properties": {
          "name":{
            "type": "text"
          }
        }
      }
    }
  }
}

# 预期返回
{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "explicit-mapping-01"
}

查看映射

复制代码
# 请求
GET explicit-mapping-01/_mapping

# 预期返回
{
  "explicit-mapping-01" : {
    "mappings" : {
      "properties" : {
        "addr" : {
          "type" : "keyword"
        },
        "age" : {
          "type" : "byte"
        },
        "class" : {
          "properties" : {
            "name" : {
              "type" : "text"
            }
          }
        },
        "create_date" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        },
        "ip" : {
          "type" : "geo_point"
        },
        "name" : {
          "type" : "text"
        }
      }
    }
  }
}

创建文档

复制代码
# 请求
POST explicit-mapping-01/_doc
{
  "create_date": "2015/09/02",
  "name": "huangsir",
  "age": 18,
  "addr": "BeiJing",
  "ip": "10.0.0.40",
  "class": {
    "name": "清华大学"
  }
}

# 预期返回
{
  "_index" : "explicit-mapping-01",
  "_type" : "_doc",
  "_id" : "C0JSlpcB-K0y8avWYdSX",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

查看文档

复制代码
# 请求
GET explicit-mapping-01/_doc/C0JSlpcB-K0y8avWYdSX

# 预期返回
{
  "_index" : "explicit-mapping-01",
  "_type" : "_doc",
  "_id" : "C0JSlpcB-K0y8avWYdSX",
  "_version" : 1,
  "_seq_no" : 0,
  "_primary_term" : 1,
  "found" : true,
  "_source" : {
    "create_date" : "2015/09/02",
    "name" : "huangsir",
    "age" : 18,
    "addr" : "BeiJing",
    "ip" : "10.0.0.40",
    "class" : {
      "name" : "清华大学"
    }
  }
}