Appearance
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字节)有符号整数,取值范围为
; long:64位(8字节)有符号整数,取值范围为
; unsigned_long:64位(8字节)无符号整数,取值范围为
; 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中,布尔值只有两种取值:true或false。分别取值如下:
- False values:
false,"false",""(空字符串) - True values:
true,"true"
1.5 二进制数据
binary类型用于存储任意的二进制数据,输入时需要将数据编码为 Base64 字符串。Elasticsearch 将这些数据存储为字节数组,但不解析其内容,仅将其视为原始数据。它适合存储非文本的原始字节数据,例如图像、文件或其他二进制内容。
核心特点:
- 不支持搜索、排序或聚合,仅用于存储和检索。
- 数据以 Base64 编码字符串形式输入,解码后存储为字节数组。
- 适合存储无法直接索引的二进制内容,如图像、PDF 文件或加密数据。
- 常用于需要保存原始数据但不进行分析的场景。
1.6 空间数据类型
空间数据类型包括如下几类:
point:表示笛卡尔坐标系中的一个点
https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/point
shape:表示笛卡尔坐标系中的一个或多个点
https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/shape
geo_point:表示地理中的一个经纬度点
https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/geo-point
geo_shape:表示地理中的一个或多个经纬度点
https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/geo-shape
1.7 对象与对象数组
在ES中,对象类型是object,这是 ES 中最基本、最常用的复杂数据类型。当索引一个包含 JSON 对象的文档时,默认情况下 ES 就会将其映射为 object 类型。
例如,现有一个文档:
json
{
"title": "Document A",
"user": {
"name": "Alice",
"age": 30
}
}那么,对于属性user,ES自动将其映射为object类型。
object的核心特点是扁平化(Flattening):将 JSON 对象中的所有字段拉平到顶层。
例如,如果有一个 user 字段,其中包含 name 和 age,ES 实际上会将它们索引为 user.name 和 user.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 type | Elasticsearch data type ("dynamic":"true") |
|---|---|
null | No field added |
true or false | boolean |
double | float |
long | long |
object | object |
array | Depends on the first non-null value in the array |
string that passes date detection | date |
string that passes numeric detection | float or long |
string that doesn’t pass date detection or numeric detection | text 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/_mapping2.3.3 更新Mapping
可以添加新字段,但不能修改已有字段的类型。例如,添加"email"字段:
txt
PUT my_index/_mapping
{
"properties": {
"email": { "type": "keyword" }
}
}如果需要修改字段类型,通常需要创建一个新索引并迁移数据。
2.3.4 删除Mapping
Mapping 无法单独删除,只能通过删除整个索引来移除:
txt
DELETE my_index2.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 listIK 分词器有两种模式:
- 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属性用于控制字段是否被索引,取值为true或false,默认值是true。当index被设置为true时,会创建倒排索引结构加速查询。
index_options属性用于控制倒排列表中包含什么信息,该属性只支持keyword或text类型字段,属性取值如下:
docs:倒排列表中只包含文档ID(DocID);freqs:倒排列表中包含文档ID和词频(Term Frequency);positions:倒排列表中包含文档ID、词频和词元位置,这是默认值;offsets:倒排列表中包含文档ID、词频、词元位置以及在原始字符串中的字符偏移量(用于高亮功能快速定位需要高亮的文本片段);
2.4.5 doc_values
doc_values用于控制是否开启DocValue,对于大多数支持DocValue的类型(text和annotated_text类型不支持DocValue),doc_values默认开启。
开启doc_values属性有助于加速排序、聚合操作。
对于某些类型,例如numeric、date、boolean、keyword类型,即使关闭了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/