Skip to content

Data Type in ES and Mapping

本文介绍在ES中的数据类型与Mapping。

1. 数据类型

在ES中,数据类型可以分为如下几类:

  • 数字
  • 字符串
  • 日期
  • 布尔值
  • 二进制数据
  • 空间数据类型
  • 对象与对象数组

1.1 数字类型

数字类型具体可分为如下类型:

  • byte:8位(1字节)有符号整数,取值范围为[-128, 127];

  • short:16位(2字节)有符号整数,取值范围为[-32768, 32767];

  • integer:32位(4字节)有符号整数,取值范围为[231,2311]

  • long:64位(8字节)有符号整数,取值范围为[263,2631]

  • unsigned_long:64位(8字节)无符号整数,取值范围为[0,2641]

  • float:单精度(32位)浮点数;

  • double:双精度(64位)浮点数;

  • half_float:半单精度(16位)浮点数;

  • scaled_float:一种特殊的浮点类型,通过缩放因子将浮点数存储为整数。是专门为需要高精度的场景(如金额)设计的类型,它将浮点数乘以一个固定的缩放因子(scaling_factor),然后存储为整数,从而避免浮点数精度问题。

    json
    {
      "mappings": {
        "properties": {
          "amount": {
            "type": "scaled_float",
            "scaling_factor": 100
          }
        }
      }
    }

1.2 字符串

在ES中的字符串,我们通常只关注下面两种类型:

  • keyword:用于存储结构化内容的字符串数据类型,设计用于精确匹配,而不进行分析(analysis)。它将输入字符串作为完整的值存储,不分词,适合需要精确查询的场景。

    keyword 不进行分词,因此查询时匹配整个字符串的值,并且默认使用文档值(doc values)来支持高效的排序和聚合操作。

    例如,商品编码、邮箱地址、邮编地址、标签等可以使用keyword类型。

  • text:用于存储支持全文检索的字符串,默认情况下,text 字段值会被分词为单独的词(tokens),并存储在倒排索引中,适合模糊匹配、短语查询或相关性评分。

    例如,日志内容、邮件内容、文章内容等可以使用text类型。

1.3 日期类型

在ES中,date日期时间类型存储的是自Unix时间戳(1970-01-01 00:00:00 UTC)以来的毫秒时间值(long类型存储)

在ES中,我们可以通过format属性设置date类型可以接受的值,例如:

txt
PUT my-index-000001
{
  "mappings": {
    "properties": {
      "date": {
        "type":   "date",
        "format": "epoch_millis||epoch_second||yyyy-MM-dd HH:mm:ss"
      }
    }
  }
}

format 参数中的 "epoch_millis||epoch_second||yyyy-MM-dd HH:mm:ss" 表示 date 字段可以接受以下三种格式的输入:

  • epoch_millis
    • 毫秒级 Unix 时间戳,表示从 1970-01-01 00:00:00 UTC 到指定时间的毫秒数。
    • 示例:1747064520000 表示 2025-09-12 16:42:00.000 UTC。
  • epoch_second
    • 秒级 Unix 时间戳,表示从 1970-01-01 00:00:00 UTC 到指定时间的秒数。
    • 示例:1747064520 表示 2025-09-12 16:42:00 UTC。
  • yyyy-MM-dd HH:mm:ss
    • 格式化的日期字符串。
    • 示例:"2025-09-12 16:42:00" 表示 2025 年 9 月 12 日 16:42:00(默认假设 UTC,除非指定时区)。
  • 多格式支持:
    • 使用 || 分隔,Elasticsearch 会尝试按顺序解析输入值,直到匹配一种格式。
    • 例如,输入 1747064520000 被解析为 epoch_millis,而 "2025-09-12 16:42:00" 被解析为 yyyy-MM-dd HH:mm:ss。

更多日期时间格式可参考:https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/mapping-date-format

在查询时,输入的格式是什么,就会返回什么格式。

除了date日期时间类型,ES还提供date_nanos类型,用于支持纳秒时间精度。

1.4 布尔值

在ES中,布尔值只有两种取值:truefalse。分别取值如下:

  • False values:false, "false", "" (空字符串)
  • True values:true, "true"

1.5 二进制数据

binary类型用于存储任意的二进制数据,输入时需要将数据编码为 Base64 字符串。Elasticsearch 将这些数据存储为字节数组,但不解析其内容,仅将其视为原始数据。它适合存储非文本的原始字节数据,例如图像、文件或其他二进制内容。

核心特点:

  • 不支持搜索、排序或聚合,仅用于存储和检索。
  • 数据以 Base64 编码字符串形式输入,解码后存储为字节数组。
  • 适合存储无法直接索引的二进制内容,如图像、PDF 文件或加密数据。
  • 常用于需要保存原始数据但不进行分析的场景。

1.6 空间数据类型

空间数据类型包括如下几类:

1.7 对象与对象数组

在ES中,对象类型是object,这是 ES 中最基本、最常用的复杂数据类型。当索引一个包含 JSON 对象的文档时,默认情况下 ES 就会将其映射为 object 类型。

例如,现有一个文档:

json
{
  "title": "Document A",
  "user": {
    "name": "Alice",
    "age": 30
  }
}

那么,对于属性user,ES自动将其映射为object类型。

object的核心特点是扁平化(Flattening):将 JSON 对象中的所有字段拉平到顶层。

例如,如果有一个 user 字段,其中包含 nameage,ES 实际上会将它们索引为 user.nameuser.age,如下:

json
{
  "title": "Document A",
  "user.name": "Alice",
  "user.age": 30
}

对于单个对象来说,上述情况是可以接受的,但是,如果是对象数组,结果从变成:

json
{
  "title": "Document B",
  "users": [
    {
      "name": "Alice",
      "age": 30
    },
    {
      "name": "Bob",
      "age": 40
    }
  ]
}

变为:

json
{
  "title": "Document B",
  "users.name": ["Alice", "Bob"],
  "users.age": [30, 40]
}

这样,我们无法再判断姓名为"Alice"的用户,她的年龄是多少岁。为了保证属性间的关系,ES提出了nested类型。将users的类型设置为nested类型后,数组中的对象就不会被拉平到顶层了:

json
{
  "mappings": {
    "properties": {
      "users": {
        "type": "nested"
      }
    }
  }
}

2. Mapping

2.1 介绍

在 Elasticsearch(ES)中,mapping(映射)定义了索引中存储的文档结构,包括字段的名称、数据类型以及如何对这些字段进行索引和搜索。

它类似于数据库中的表结构,定义了每个字段的类型、索引方式、分词器等信息。Mapping 的主要作用是:

  • 定义字段类型:如字符串(text、keyword)、数字(integer、long、float)、日期(date)、布尔值(boolean)等。
  • 控制索引行为:决定字段是否被索引、如何分词、是否存储等。
  • 优化搜索性能:通过正确的映射设置,提高查询效率和准确性。

2.2 Mapping类型

Elasticsearch 支持两种主要的 mapping 类型:静态Mapping和动态Mapping。

2.2.1 静态Mapping

静态Mapping是指用户在创建索引时显式定义的 mapping。例如:

txt
PUT /demo01
{
  "mappings": {
    "properties": {
      "birth":{
        "type": "date",
        "format": "yyyy-MM-dd"
      },
      "img":{
        "type": "binary"
      },
      "points":{
        "type": "shape"
      }
    }
  }
}

其中HTTP请求中的json就定义了mapping,其在properties中定义了三个属性:

  • birth:类型为date,可接受的日期格式为yyyy-MM-dd

  • img:类型为binary

  • points:类型为shape

2.2.2 动态Mapping

Elasticsearch 会根据插入的文档自动推断字段类型并生成 mapping。

文档(JSON)中的类型与ES中的类型对应关系如下:

JSON data typeElasticsearch data type ("dynamic":"true")
nullNo field added
true or falseboolean
doublefloat
longlong
objectobject
arrayDepends on the first non-null value in the array
string that passes date detectiondate
string that passes numeric detectionfloat or long
string that doesn’t pass date detection or numeric detectiontext with a .keyword sub-field

可以在创建索引的时候设置dynamic的值(默认值为true):

txt
PUT /demo02
{
  "mappings": {
    "dynamic": "true"
  }
}

之后向索引demo02中插入文档:

txt
PUT /demo02/_doc/1
{
  "birth":"1999-01-01",
  "num": 123,
  "str": "abc"
}

查看索引Mapping:

txt
GET /demo02/_mapping

结果如下:

txt
{
  "demo02" : {
    "mappings" : {
      "dynamic" : "true",
      "properties" : {
        "birth" : {
          "type" : "date"
        },
        "num" : {
          "type" : "long"
        },
        "str" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

如果将dynamic的值设置为false,表示禁用动态Mapping。

2.2.3 静态与动态Mapping相结合

我们可以在创建索引的时候,指定静态Mapping,之后,如果插入的索引包含新字段,那么ES也会创建Mapping中的新类型:

txt
PUT /demo03
{
  "mappings": {
    "properties": {
      "num": {
        "type": "long"
      }
    }
  }
}

PUT /demo03/_doc/1
{
  "num":1,
  "str":"hello"
}


GET /demo03/_mapping

结果如下:

txt
{
  "demo03" : {
    "mappings" : {
      "properties" : {
        "num" : {
          "type" : "long"
        },
        "str" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}

如果设置了静态Mapping,在插入文档时,如果新文档包含新字段(静态Mapping中不包含的字段),如果希望报错,即不允许新文档插入成功,我们可以设置dynamic的值为strict

txt
PUT /demo03
{
  "mappings": {
    "dynamic": "strict",
    "properties": {
      "num": {
        "type": "long"
      }
    }
  }
}

在插入包含str字段的新文档时,报错如下:

json
{
  "error" : {
    "root_cause" : [
      {
        "type" : "strict_dynamic_mapping_exception",
        "reason" : "mapping set to strict, dynamic introduction of [str] within [_doc] is not allowed"
      }
    ],
    "type" : "strict_dynamic_mapping_exception",
    "reason" : "mapping set to strict, dynamic introduction of [str] within [_doc] is not allowed"
  },
  "status" : 400
}

2.2.4 dynamic属性小结

dynamic属性控制新字段是否允许被动态添加到Mapping中,取值如下:

  • "true":默认值,新字段允许被添加到Mapping中;

  • "false":禁止为新字段生成动态映射,但允许插入包含新字段的文档。特点如下:

    • 新字段不会被索引,因此无法通过查询搜索这些字段。

    • 新字段的值仍会存储在 _source 中,但不会出现在 mapping 中。

  • "strict":禁止插入包含未定义字段的文档。如果文档包含 mapping 中未定义的字段,插入操作会失败并抛出错误。

dynamic 还有取值为runtime,似乎和取值为true相差不大,此处暂时不列出,以免混淆。

补充:dynamic 可以设置在整个索引的 mapping 级别,也可以设置在某个 object 类型的子字段中,仅控制该对象的子字段。

txt
PUT /demo03
{
  "mappings": {
    "dynamic": "true",
    "properties": {
      "num": {
        "type": "long"
      },
      "user":{
        "dynamic": "strict",
        "type": "object",
        "properties": {
          "name":{
            "type": "keyword"
          },
          "age":{
            "type": "integer"
          }
        }
      }
    }
  }
}

2.3 Mapping 操作

2.3.1 创建Mapping

可以在创建索引时,指定静态Mapping,例如:

txt
PUT my_index
{
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "age": { "type": "integer" }
    }
  }
}

2.3.2 查看Mapping

语法如下:

txt
GET my_index/_mapping

2.3.3 更新Mapping

可以添加新字段,但不能修改已有字段的类型。例如,添加"email"字段:

txt
PUT my_index/_mapping
{
  "properties": {
    "email": { "type": "keyword" }
  }
}

如果需要修改字段类型,通常需要创建一个新索引并迁移数据。

2.3.4 删除Mapping

Mapping 无法单独删除,只能通过删除整个索引来移除:

txt
DELETE my_index

2.4 其他属性

在创建索引时,除了指定字段的名称和类型外,还可以指定其他属性。

2.4.1 analyzer

WARNING

只有text类型的字段才支持analyzer属性

analyzer属性用于指定分词器,除非明确指定search_analyzer属性,否则analyzer属性用于指定创建索引和查询时的分词器。

在使用中,我们一般会使用中文分词器,而ES需要安装中文分词器插件,命令如下:

bash
bin/elasticsearch-plugin install https://get.infini.cloud/elasticsearch/analysis-ik/7.17.28

注意,中文分词器的版本需要和ES的版本对应。

使用如下命令查看插件是否安装成功:

bash
bin/elasticsearch-plugin list

IK 分词器有两种模式

  • ik_smart :智能分词,尽量减少冗余词,适合搜索场景。
    • 示例:将“中华人民共和国国歌”分词为 ["中华人民共和国", "国歌"]。
  • ik_max_word:最大分词,尽可能多地切分,适合索引时最大化覆盖。
    • 示例:将“中华人民共和国国歌”分词为 ["中华", "人民", "共和国", "国歌"]。

在创建索引时,指定中文分词器:

txt
PUT /demo04
{
  "mappings": {
    "properties": {
      "num": { "type": "long" },
      "str": {
        "type": "text",
        "analyzer": "ik_max_word",  // 分词时使用 ik_max_word
        "search_analyzer": "ik_smart" // 搜索时使用 ik_smart
      }
    }
  }
}

我们也可以使用如下方式查看分词结果:

txt
POST /_analyze
{
  "analyzer": "ik_smart",
  "text": "中华人民共和国国歌"
}

2.4.2 fields

fields 属性(也称为多字段映射,multi-fields)允许为同一个字段定义多种数据类型和索引方式,从而支持不同的查询需求。

例如,字段str的类型为text,我们还可以使用fields属性为str指定类型为keyword

txt
PUT /demo03
{
  "mappings": {
    "properties": {
      "str": {
        "type": "text",
        "analyzer": "ik_max_word",  // 中文分词
        "fields": {
          "keyword": {  // keyword 是子属性名称,由自己决定
            "type": "keyword"  // 精确匹配
          }
        }
      }
    }
  }
}

之后查询时,就可以使用str.keyword进行精确匹配:

txt
GET /demo03/_search
{
  "query": {
    "term": {
      "str.keyword": "国歌"
    }
  }
}

2.4.3 ignore_above

ignore_above属性用于设置keyword类型的字段,如果该字段的长度超过ignore_above指定的值,那么该字段值不会被索引,但是该字段值仍然会被存储到_source字段。

如果字段值是字符串数组,那么ignore_above属性会检查字符串数组中的每个元素。如果某个元素的长度超过 ignore_above 设置的阈值,该元素不会被索引,但数组中其他符合长度限制的元素仍然会被索引。

例如,创建索引并设置ignore_above属性:

txt
PUT my_index
{
  "mappings": {
    "properties": {
      "tags": {
        "type": "keyword",
        "ignore_above": 10
      }
    }
  }
}

插入数据:

txt
PUT my_index/_doc/1
{
  "tags": ["short", "medium tag", "very long string exceeding limit"]
}

那么查询"short"时,可以匹配文档1:

txt
GET my_index/_search
{
  "query": {
    "term": {
      "tags": "short"
    }
  }
}

如果查询"very long string exceeding limit",无法匹配文档1:

txt
GET my_index/_search
{
  "query": {
    "term": {
      "tags": "very long string exceeding limit"
    }
  }
}

2.4.4 index和index_options

index属性用于控制字段是否被索引,取值为truefalse,默认值是true。当index被设置为true时,会创建倒排索引结构加速查询。

index_options属性用于控制倒排列表中包含什么信息,该属性只支持keywordtext类型字段,属性取值如下:

  • docs:倒排列表中只包含文档ID(DocID);
  • freqs:倒排列表中包含文档ID和词频(Term Frequency);
  • positions:倒排列表中包含文档ID、词频和词元位置,这是默认值
  • offsets:倒排列表中包含文档ID、词频、词元位置以及在原始字符串中的字符偏移量(用于高亮功能快速定位需要高亮的文本片段);

2.4.5 doc_values

doc_values用于控制是否开启DocValue,对于大多数支持DocValue的类型(textannotated_text类型不支持DocValue),doc_values默认开启。

开启doc_values属性有助于加速排序、聚合操作。

对于某些类型,例如numericdatebooleankeyword类型,即使关闭了index属性,也可以在这些字段值上进行搜索,这是因为doc_values属性开启了,在这种情况下,搜索类似于全表扫描,所以效率较慢。这些字段称为doc_values_only字段。

参考资料

[1] https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/

[2] https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/