Elasticsearch 基础教程

Elasticsearch 高级教程

Elasticsearch 插件

Elasticsearch 笔记

Elasticsearch FAQ

original icon
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.knowledgedict.com/tutorial/elasticsearch-index-mapping.html

Elasticsearch 索引映射类型及mapping属性详解


在 Elasticsearch 中,映射指的是 mapping,用来定义一个文档以及其所包含的字段如何被存储和索引,可以在映射中事先定义字段的数据类型、字段的权重、分词器等属性,就如同在关系型数据库中创建数据表时会设置字段的类型。

Elasticsearch 中一个字段可以是核心类型之一,如字符串或者数值型,也可以是一个从核心类型派生的复杂类型,如数值。

映射分类

在 Elasticsearch 中,映射可分为动态映射和静态映射。在关系型数据库中写入数据之前首先要建表,在建表语句中声明字段的属性,在 Elasticsearch 中,则不必如此,Elasticsearch 最重要的功能之一就是让你尽可能快地开始探索数据,文档写入 Elasticsearch 中,它会根据字段的类型自动识别,这种机制称为动态映射,而静态映射则是写入数据之前对字段的属性进行手工设置。

静态映射

静态映射是在创建索引时手工指定索引映射,和 SQL 中在建表语句中指定字段属性类似。相比动态映射,通过静态映射可以添加更详细、更精准的配置信息,例子如下:

PUT my_index
{
  "mappings": {
    "article": {
      "_all": {
        "enabled": false
      },
      "properties": {
        "title": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart",
          "similarity": "BM25",
          "store": true
        },
        "summary": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart",
          "similarity": "BM25"
        },
        "content": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart",
          "similarity": "BM25",
          "store": true
        }
      }
    },
    "question_and_anwser": {
      "_all": {
        "enabled": false
      },
      "properties": {
        "question": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart",
          "similarity": "BM25"
        },
        "anwser": {
          "type": "text",
          "analyzer": "ik_max_word",
          "search_analyzer": "ik_smart",
          "similarity": "BM25"
        },
        "question_user_id": {
          "type": "long"
        },
        "anwser_user_id": {
          "type": "long"
        },
        "create_time": {
          "type": "date",
          "format": "strict_date_optional_time || epoch_mills"
        }
      }
    }
  }
}

动态映射

动态映射是一种偷懒的方式,可直接创建索引并写入文档,文档中字段的类型是 Elasticsearch 自动识别的,不需要在创建索引的时候设置字段的类型。在实际项目中,如果遇到的业务在导入数据之前不确定有哪些字段,也不清楚字段的类型是什么,使用动态映射非常合适。当 Elasticsearch 在文档中碰到一个以前没见过的字段时,它会利用动态映射来决定该字段的类型,并自动把该字段添加到映射中,根据字段的取值自动推测字段类型的规则见下表:

Elasticsearch 自动推测字段类型的规则
JSON 格式的数据 自动推测的字段类型
null 没有字段被添加
true or false boolean 类型
浮点类型数字 float 类型
数字 long 类型
JSON 对象 object 类型
数组 由数组中第一个非空值决定
string 有可能是 date 类型(若开启日期检测)、double 或 long 类型、text 类型、keyword 类型

下面举一个例子认识动态 mapping,在 Elasticsearch 中创建一个新的索引并查看它的 mapping,命令如下:

PUT books
GET books/_mapping

此时 books 索引的 mapping 是空的,返回结果如下:

{
  "books": {
    "mappings": {}
  }
}

再往 books 索引中写入一条文档,命令如下:

PUT books/it/1
{
  "id": 1,
  "publish_date": "2019-11-10",
  "name": "master Elasticsearch"
}

文档写入完成之后,再次查看 mapping,返回结果如下:

{
  "books": {
    "mappings": {
      "it": {
        "properties": {
          "id": {
            "type": "long"
          },
          "name": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "publish_date": {
            "type": "date"
          }
        }
      }
    }
  }
}

id、publish_date、name 三个字段分别被推测为 long 类型、date 类型和 text 类型,这就是动态 mapping 的功劳。

使用动态 mapping 要结合实际业务需求来综合考虑,如果将 Elasticsearch 当作主要的数据存储使用,并且希望出现未知字段时抛出异常来提醒你注意这一问题,那么开启动态 mapping 并不适用。在 mapping 中可以通过 dynamic 设置来控制是否自动新增字段,接受以下参数:

  • true:默认值为 true,自动添加字段。
  • false:忽略新的字段。
  • strict:严格模式,发现新的字段抛出异常。

下面通过例子和实际操作来学习 dynamic 控制新增字段的方法。创建一个 books 索引并指定 mapping,设置 it 类型下 dynamic 属性的取值为 strict,也就是说,it 类型下的文档中出现 mapping 中没有定义的字段会抛出异常,命令如下:

PUT books
{
  "mappings": {
    "it": {
      "dynamic": "strict",
      "properties": {
        "title": {
          "type": "text"
        },
        "publish_date": {
          "type": "date"
        }
      }
    }
  }
}

写入三个文档:

PUT books/it/1
{
  "title": "master Elasticsearch",
  "publish_date": "2017-06-01"
}
PUT books/it/2
{
  "title": "master Elasticsearch"
}
PUT books/it/3
{
  "title": "master Elasticsearch",
  "publish_date": "2017-06-01",
  "author":"Tom"
}

文档 books/it/1 和 books/it/2 会创建成功,books/it/3 中出现了新的字段 author,该字段在 mapping 中并没有定义,会抛出 strict_dynamic_mapping_exception 异常。

核心类型

Elasticsearch 字段类型的核心类型有字符串类型、数字类型、日期类型、布尔类型、二进制类型、范围类型等。

Elasticsearch 字段核心类型
一级分类 二级分类 具体类型
核心类型 字符串类型 string、text、keyword
数字类型 long、integer、short、byte、double、float、half_float、scaled_float
日期类型 date
布尔类型 boolean
二进制类型 binary
范围类型 range

字符串类型

字符串是最直接的,如果在索引字符,字段就应该是 text 类型。它们也是最有趣,因为在映射中有很多选项来分析它们。解析文本、转变文本、将其分解为基本元素使得搜索更为相关,这个过程叫作分析

Elasticsearch 5.X 之后的字段类型不再支持 string,由 text 或 keyword 取代。如果仍使用 string,会给出警告。

  • text

    如果一个字段是要被全文搜索的,比如邮件内容、产品描述、新闻内容,应该使用 text 类型。设置 text 类型以后,字段内容会被分析,在生成倒排索引以前,字符串会被分词器分成一个一个词项(term)。text 类型的字段不用于排序,且很少用于聚合(Terms Aggregation 除外)。

  • keyword

    keyword 类型适用于索引结构化的字段,比如 email 地址、主机名、状态码和标签,通常用于过滤(比如,查找已发布博客中 status 属性为 published 的文章)、排序、聚合。类型为 keyword 的字段只能通过精确值搜索到,区别于 text 类型。

如上所提到的,text 类型字段可以在映射中指定相关的分析选项,通过 index 选项指定。

index 选项可以设置为 analyzed (默认)、 not_analyzedno

  • analyzed

    默认情况下,index 被设置为 analyzed,并产生了如下行为:分析器将所有字符转为小写,并将字符串分解为单词。当期望每个单词完整匹配时,请使用这种选项。举个例子,如果用户搜索 “elasticsearch”,他们希望在结果列表里看到 “Principles and Practice of Elasticsearch”。

  • not_analyzed

    将 index 设置为 not_analyzed,将会产生相反的行为:分析过程被略过,整个字符串被当作单独的词条进行索引。当进行精准的匹配时,请使用这个选项,如搜索标签。你可能希望 “big data” 出现在搜索 “big data” 的结果中,而不是出现在搜索 “data” 的结果中。同样,对于多数的词条计数聚集,也需要这个。如果想知道最常出现的标签,可能需要 “big data” 作为一整个词条统计,而不是 “big” 和 “data” 分开统计。

  • no

    如果将 index 设置为 no,索引就被略过了,也没有词条产生,因此无法在那个字段上进行搜索。当无须在这个字段上搜索时,这个选项节省了存储空间,也缩短了索引和搜索的时间。例如,可以存储活动的评论。尽管存储和展示这些评论是很有价值的,但是可能并不需要搜索它们。在这种情况下,关闭那个字段的索引,使得索引的过程更快,并节省了存储空间。

数字类型

数字类型支持 byte、short、integer、long、float、double、half_float 和 scaled_float,它们的取值范围如下表:

数字类型及取值范围
类型 取值范围
long -2^63 至 2^63-1
integer -2^31 至 2^31-1
short -32768 至 32767
byte -128 至 127
double 64 位双精度 IEEE 754 浮点类型
float 32 位单精度 IEEE 754 浮点类型
half_float 16 位半精度 IEEE 754 浮点类型
scaled_float 缩放类型的浮点数

对于 float、half_float 和 scaled_float,-0.0 和 +0.0 是不同的值,使用 term 查询查找 -0.0 不会匹配 +0.0,同样 range 查询中上边界是 -0.0,也不会匹配 +0.0,下边界是 +0.0,也不会匹配 -0.0。

对于数字类型的字段,在满足需求的情况下,要尽可能选择范围小的数据类型。比如,某个字段的取值最大值不会超过 100,那么选择 byte 类型即可。迄今为止,吉尼斯世界记录的人类的年龄的最大值为 134 岁,对于年龄字段,short 类型足矣。字段的长度越短,索引和搜索的效率越高。

处理浮点数时,优先考虑使用 scaled_float 类型。scaled_float 是通过缩放因子把浮点数变成 long 类型,比如价格只需要精确到分,price 字段的取值为 57.34,设置放大因子为 100,存储起来就是 5734。所有的 API 都会把 price 的取值当作浮点数,事实上 Elasticsearch 底层存储的是整数类型,因为压缩整数比压缩浮点数更加节省存储空间。

数字类型配置映射的例子如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "number_of bytes": {
          "type": "integer"
        },
        "time_in_seconds": {
          "type": "float"
        },
        "price": {
          "type": "scaled_float",
          "scaling_factor": 100
        }
      }
    }
  }
}

日期类型

JSON 中没有日期类型,所以在 Elasticsearch 中的日期可以是以下几种形式:

  • 格式化日期的字符串,如 “2015-01-01” 或 “2015/01/01 12:10:30”。
  • 代表 milliseconds-since-the-epoch 的长整型数(epoch 指的是一个特定的时间:1970-01-01 00:00:00 UTC)。
  • 代表 seconds-since-the-epoch 的整型数。

Elasticsearch 内部会把日期转换为 UTC(世界标准时间),并将其存储为表示 milliseconds-since-the-epoch 的长整型数,这样做的原因是和字符串相比,数值在存储和处理时更快。日期格式可以自定义,如果没有自定义,默认格式如下:

"strict_date_optional_time||epoch_millis"

日期类型配置映射的例子如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "dt": {
          "type": "date"
        }
      }
    }
  }
}

写入 3 个文档:

PUT my_index/my_type/1
{
  "dt": "2019-11-14"
}
PUT my_index/my_type/2
{
  "dt": "2019-11-14T13:16:302"
}
PUT my_index/my_type/3
{
  "dt": 1573664468000
}

默认情况下,以上 3 个文档的日期格式都可以被解析,内部存储的是毫秒计时的长整型数。

布尔类型

如果一个字段是布尔类型,可接受的值为 truefalse。Elasticsearch 5.4 版本以前,可以接受被解释为 true 或 false 的字符串和数字,5.4 版本以后只接受 true、false、"true"、"false"。

布尔类型配置映射的例子如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "is_published": {
          "type": "boolean"
        }
      }
    }
  }
}

写入 3 条文档:

PUT my_index/my_type/1
{
  "is_published": true
}
PUT my_index/my_type/2
{
  "is_published": "true"
}
PUT my_index/my_type/3
{
  "is_published": false
}

执行以下搜索,文档 1 和文档 2 都可以被搜索:

GET my_index/_search
{
  "query": {
    "term": {
      "is_published": true
    }
  }
}

binary 类型

binary 类型接受 base64 编码的字符串,默认不存储(这里的不存储是指 store 属性取值为 false),也不可搜索。

布尔类型配置映射的例子如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "name": {
          "type": "text"
        },
        "blob": {
          "type": "binary"
        }
      }
    }
  }
}

写入一条文档,其中 blob 的值为字符串 "Some binary blob" 的 Base64 编码:

PUT my_index/my_type/1
{
  "name": "Some binary blob",
  "blob": "U29t2SBiaW5hcnkgYmxvYg=="
}

range 类型

range 类型的使用场景包括网页中的时间选择表单、年龄范围选择表单等,range 类型支持的类型和取值范围如下表:

range 类型及取值范围
类型 范围
integer_range -2^31 至 2^31-1
float_range 32-bit IEEE 754
long_range -2^63 至 2^63-1
double_range 64-bit IEEE 754
date_range 64 位整数,毫秒计时

下面代码创建了一个 range_index 索引,expected_attendees 字段为 integer_range 类型,time_frame 字段为 date_range 类型。

PUT range_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "expected_attendees": {
          "type": "integer_range"
        },
        "time_frame": {
          "type": "date_range",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
        }
      }
    }
  }
}

索引一条文档,expected_attendees 的取值为 10 到 20,time_frame 的取值是 2015-10-31 12:00:00 至 2015-11-01,命令如下:

PUT my_index/my_type/1
{
  "expected_attendees": {
    "gte": 10,
    "lte": 20
  },
  "time_frame": {
    "gte": "2019-10-31 12:00:00",
    "lte": "2019-11-01"
  }
}

复合类型

Elasticsearch 字段类型的复合类型有数组类型对象类型嵌套类型

Elasticsearch 字段 - 复合类型
一级分类 二级分类 具体类型
核心类型 数组类型 array
对象类型 object
嵌套类型 nested

数组类型

Elasticsearch 没有专用的数组类型,默认情况下任何字段都可以包含 0 个或者多个值,但是一个数组中的值必须是同一种类型。例如:

  1. 字符数组["one","two"]
  2. 整型数组[1,3]
  3. 嵌套数组[1,[2,3]],等价于 [1,2,3]
  4. 对象数组[{"city":"amsterdam","country":"nederland"},{"city":"brussels","country":"belgium"}]

动态添加数据时,数组的第一个值的类型决定整个数组的类型。混合数组类型是不支持的,比如: [1,"abc"]。数组可以包含 null 值,空数组 [ ] 会被当作 missing field 对待。

在文档中使用 array 类型不需要提前做任何配置,默认支持。例如写入一条带有数组类型的文档,命令如下:

PUT my_index/my_type/1
{
  "message": "some arrays in this document...",
  "tags": ["elasticsearch", "wow"],
  "lists": [{
    "name": "prog_list",
    "description": "programming list"
  },
  {
    "name": "cool_list",
    "description": "cool stuff list"
  }]
}

搜索 lists 字段下的 name,命令如下:

GET my_index/_search
{
  "query": {
    "match": {
      "lists.name": "cool_list"
    }
  }
}

object 类型

JSON 本质上具有层级关系,文档包含内部对象,内部对象本身还包含内部对象,请看下面的例子:

{
  "region": "US",
  "manager": {
    "age": 30,
    "name": {
      "first": "John",
      "last": "Smith"
    }
  }
}

上面的文档中,整体是一个 JSON 对象,JSON 中包含一个 manager 对象,manager 对象又包含名为 name 的内部对象。写入到 Elasticsearch 之后,文档会被索引成简单的扁平 key-value 对,格式如下:

{
  "region": "US",
  "manager.age": 30,
  "manager.name.first": "John",
  "manager.name.last": "Smith"
}

上面文档结构的显式映射如下:

{
  "mappings": {
    "my_type": {
      "properties": {
        "region": {
          "type": "keyword"
        },
        "manager": {
          "properties": {
            "age": {
              "type": "integer"
            },
            "name": {
              "properties": {
                "first": {
                  "type": "text"
                },
                "last": {
                  "type": "text"
                }
              }
            }
          }
        }
      }
    }
  }
}

nested 类型

nested 类型是 object 类型中的一个特例,可以让对象数组独立索引和查询。Lucene 没有内部对象的概念,所以 Elasticsearch 将对象层次扁平化,转化成字段名字和值构成的简单列表。

使用 Object 类型有时会出现问题,比如文档 my_index/my_type/1 的结构如下:

PUT my_index/my_type/1
{
  "group": "fans",
  "user": [{
    "first": "John",
    "last": "Smith"
  }, {
    "first": "Alice",
    "last": "White"
  }]
}

user 字段会被动态添加为 Object 类型,最后会被转换为以下平整的形式:

{
  "group": "fans",
  "user.first": ["alice", "john"],
  "user.last": ["smith", "white"]
}

user.first 和 user.last 扁平化以后变为多值字段,alice 和 white 的关联关系丢失了。执行以下搜索会搜索到上述文档:

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [{
        "match": {
          "user.first": "Alice"
        }
      },
      {
        "match": {
          "user.last": "Smith"
        }
      }]
    }
  }
}

事实上是不应该匹配的,如果需要索引对象数组并避免上述问题的产生,应该使用 nested 对象类型而不是 object 类型,nested 对象类型可以保持数组中每个对象的独立性。Nested 类型将数组中每个对象作为独立隐藏文档来索引,这意味着每个嵌套对象都可以独立被搜索,映射中指定 user 字段为 nested 类型:

PUT /my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "user": {
          "type": "nested"
        }
      }
    }
  }
}

再次执行上述查询语句,文档不会被匹配。

索引一个包含 100 个 nested 字段的文档实际上就是索引 101 个文档,每个嵌套文档都作为一个独立文档来索引。为了防止过度定义嵌套字段的数量,每个索引可以定义的嵌套字段被限制在 50 个。

地理类型

Elasticsearch 的地理相关类型有地理坐标类型地理图形类型

Elasticsearch 字段地理类型
一级分类 二级分类 具体类型
地理类型 地理坐标类型 geo_point
地理图形类型 geo_shape

geo_point 地理坐标

geo point 类型用于存储地理位置信息的经纬度,可用于以下几种场景:

  • 查找一定范围内的地理位置。
  • 通过地理位置或者相对中心点的距离来聚合文档。
  • 把距离因素整合到文档的评分中。
  • 通过距离对文档排序。

指定 location 字段为 geo_point 类型,映射如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "location": {
          "type": "geo_point"
        }
      }
    }
  }
}

geo_point 字段接收以下 4 种类型的地理位置数据,分别介绍如下:

  1. 经纬度坐标键值对。

    PUT my_index/my_type/1
    {
      "text": "geo_point as an object",
      "location": {
        "lat": 41.12,
        "lon": -71.34
      }
    }
  2. 字符串格式的地理坐标参数。

    PUT my_index/my_type/2
    {
      "text": "geo_point as a string",
      "location": "41.12,-71.34"
    }
  3. 地理坐标的哈希值。

    PUT my_index/my_type/3
    {
      "text": "geo_point as a geohash",
      "location": "u1269qu5dcgp"
    }
  4. 数组形式的地理坐标。

    PUT my_index/my_type/4
    {
      "text": "geo_point as an array",
      "location": [-71.34, 41.12]
    }

geo_shape 地理图形

geo_point 类型可以存储一个坐标点,geo_shape 类型可以存储一块区域,比如矩形、三角形或者其他多边形。GeoJSON 是一种对各种地理数据结构进行编码的格式,对象可以表示几何、特征或者特征集合,支持点、线、面、多点、多线、多面等几何类型。GeoJSON 里的特征包含一个几何对象和其他属性,特征集合表示一系列特征。

Elasticsearch 地理形状说明
GeoJSON 类型 Elasticsearch 类型 说明
Point point 一个单独的经纬度坐标点
LineString linestring 任意的线条,由两到多个点组成
Polygon polygon 由 N+1 个点组成的封闭 N 边形
MultiPoint multipoint 一组不连续但有可能相关联的点
MultiLineString multilinestring 多条不关联的线
MultiPolygon multipolygon 多个不关联的多边形
GeometryCollection geometrycollection 几何对象的集合
N/A envelop 由左上角坐标或右下角坐标确定的封闭矩形
N/A circle 由圆心和半径确定的圆,默认单位为米

下面通过实例演示如何使用 geo_shape 类型。首先创建一个索引,映射中指定 location 字段为 geo_shape 类型,命令如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "location": {
          "type": "geo_shape"
        }
      }
    }
  }
}

写入一条由经纬度组成的点:

PUT my_index/city/1
{
  "location": {
    "type": "point",
    "coordinates": [-77.03653, 38.897676]
  }
}

写入一条由多个点组成的线:

PUT my_index/city/2
{
  "location": {
    "type": "linestring",
    "coordinates": [
      [-77.03653, 38.897676],
      [-77.009051, 38.889939]
    ]
  }
}

写入一条首尾封闭的多边形:

PUT my_index/city/3
{
  "location": {
    "type": "polygon",
    "coordinates": [
      [
        [100.0, 0.0],
        [101.0, 0.0],
        [101.0, 1.0],
        [100.0, 1.0],
        [100.0, 0.0]
      ]
    ]
  }
}

写入多个多边形:

PUT my_index/city/4
{
  "location": {
    "type": "polygon",
    "coordinates": [
      [
        [100.0, 0.0],
        [101.0, 0.0],
        [101.0, 1.0],
        [100.0, 1.0],
        [100.0, 0.0]
      ],
      [
        [100.2, 0.2],
        [100.8, 0.2],
        [100.8, 0.8],
        [100.2, 0.8],
        [100.2, 0.2]
      ]
    ]
  }
}

特殊类型

Elasticsearch 特殊类型有 IP 类型、范围类型、令牌计数类型、附件类型和抽取类型。

Elasticsearch 字段特殊类型
一级分类 二级分类 具体类型
地理类型 IP 类型 ip
范围类型 completion
令牌计数类型 token_count
附件类型 attachment
抽取类型 percolator

ip 类型

ip 类型的字段用于存储 IPv4 或者 IPv6 的地址。在映射中指定字段为 ip 类型的映射和查询语句如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "id_addr": {
          "type": "ip"
        }
      }
    }
  }
}
PUT my_index/my_type/1
{
  "ip_addr": "192.168.1.1"
}
GET my_index/_search
{
  "query": {
    "term": {
      "ip_addr": "192.168.0.0/16"
    }
  }
}

token_count 类型

token_count 用于统计字符串分词后的词项个数,本质上是一个整数型字段。举个例子,映射中指定 name 为 text 类型,增加 name.length 字段用于统计分词后词项的长度,类型为 token_count,分词器为标准分词器,命令如下:

PUT my_index
{
  "mappings": {
    "my_type": {
      "properties": {
        "name": {
          "type": "text",
          "fields": {
            "length": {
              "type": "token_count",
              "analyzer": "standard"
            }
          }
        }
      }
    }
  }
}

写入两条文档做测试,解析后第一条文档的 name.length 值为 2,第二条文档的 name.length 值为 3,命令如下:

PUT my_index/my_type/1
{
  "name": "John Smith"
}
PUT my_index/my_type/2
{
  "name": "Rachel Alice Williams"
}

搜索测试:

GET my_index/_search
{
  "query": {
    "term": {
      "name.length": 3
    }
  }
}

mapping 属性

elasticsearch 的 mapping 中的字段属性非常多,具体如下表格:

字段属性
属性名 描述
type 字段类型,常用的有 text、integer 等等。
store 是否存储指定字段,可选值为 true|false,设置 true 意味着需要开辟单独的存储空间为这个字段做存储,而且这个存储是独立于 _source 的存储的。
norms 是否使用归一化因子,可选值为 true|false,不需要对某字段进行打分排序时,可禁用它,节省空间;typetext 时,默认为 true;而 typekeyword 时,默认为 false
index_options

索引选项控制添加到倒排索引(Inverted Index)的信息,这些信息用于搜索(Search)和高亮显示:

  • docs :只索引文档编号(Doc Number);
  • freqs :索引文档编号和词频率(term frequency);
  • positions :索引文档编号,词频率和词位置(序号);
  • offsets :索引文档编号,词频率,词偏移量(开始和结束位置)和词位置(序号)。

默认情况下,被分析的字符串(analyzed string)字段使用 positions,其他字段默认使用 docs

此外,需要注意的是 index_option 是 elasticsearch 特有的设置属性;临近搜索和短语查询时,index_option 必须设置为 offsets,同时高亮也可使用 postings highlighter。

term_vector

索引选项控制词向量相关信息:

  • no :默认值,表示不存储词向量相关信息;
  • yes :只存储词向量信息;
  • with_positions :存储词项和词项位置;
  • with_offsets :存储词项和字符偏移位置;
  • with_positions_offsets :存储词项、词项位置、字符偏移位置。

term_vector 是 lucene 层面的索引设置。

similarity

指定文档相似度算法(也可以叫评分模型):

  • BM25 :es 5 之后的默认设置。
copy_to 复制到自定义 _all 字段,值是数组形式,即表明可以指定多个自定义的字段。
analyzer 指定索引和搜索时的分析器,如果同时指定 search_analyzer 则搜索时会优先使用 search_analyzer
search_analyzer 指定搜索时的分析器,搜索时的优先级最高。
fielddata

默认是 false,因为 doc_values 不支持 text 类型,所以有了 fielddata,fielddata 是 text 版本的 doc_values,也是为了优化字段进行排序、聚合和脚本访问。

和 doc_values 不同的是,fielddata 使用的是内存,而不是磁盘;因为 fielddata 会消耗大量的堆内存,fielddata 一旦加载到堆中,在 segment 的生命周期之内都将一致保持在堆中,所以谨慎使用。