Elastic Search的映射(Mapping)用于在一个索引中把文档划分为具有逻辑关系的分组,类似于数据库的表结构,是一个不可获取的一部分。
自动生成
映射可以类似于MongoDB那样自动生成,例如我们首先插入一条数据。
PUT twitter/_doc/1
{
"user_name": "kimchy",
"age":25,
}
此时,可以通过API查看mapping设置
GET /twitter/_mapping
{
"twitter": {
"mappings": {
"properties": {
"age": { "type": "long" },
"user_name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } }
}
}
}
}
}
手动生成
自动生成可以省略我们创建mapping的步骤,但很多时候我们需要更精细化的设置,则是可以手动创建mapping:
PUT /twitter
{
"mappings": {
"properties": {
"age": { "type": "long" },
"user_name": { "type": "keyword", "ignore_above": 256 }
}
}
}
修改映射
Elasticsearch不允许对索引修改映射,我们再次执行创建mapping语句的时候会报错,对于修改映射的需求,ES提供了_reindex的api,具体的方式是:
-
创建一个新索引
-
通过_reindex API将数据从老索引移动到新索引
POST /_reindex
{
"source": { "index": "twitter" },
"dest": { "index": "twitter2" }
}
具体方法可以参考官方文档: Reindex is coming!
简单类型
对于映射设置,最常用的就是设置其字段类型,例如:
"properties": {
"age": { "type": "long" },
"user_name": { "type": "keyword" }
}
对于简单类型,ES对于其分类如下:
-
字符串:text 、 keyword
-
数字:long, integer, short, byte, double, float, half_float, scaled_float
-
日期:date
-
布尔值:boolean
-
二进制:binary
-
范围:integer_range, float_range, long_range, double_range, date_range
多字段
对于字符串类型,可以把它定义成两种类型: text和keyword。
-
text:只匹配其部分信息,内容会被分词,如文章。不支持聚合
-
keyword:必须完整匹配的内容,如邮箱,身份证号,部分匹配会导致错误的结果。支持聚合
这两种类型都是比较常用的,但有的时候,对于一个字符串字段,我们可能希望他两种都支持,此时,可以利用其多字段特性
"properties": {
"user_name": {
"type": "text",
"fields": {
"keyword": {
"type": "raw",
"ignore_above": 256
}
}
}
对于user_name这个字段,其类型是text,同时又定义了一个"raw"的keyword的关键字段,当需要完全匹配的时候,可以通过user_name.raw查询。
更多内容可以参考其官方文档:Field datatypes
复合类型
Elasticsearch支持三种复合类型:
-
Array 数组型: 支持数组形式,不需要一个专有的字段数据类型
-
Object 对象型: object数据类型:表现形式其实就是单一的JSON对象
-
Nested 嵌套型: nested数据类型:表现形式是多个Object型组成的一个数组
Array 数组型
在Elasticsearch中,没有特定的array类型。默认情况下,任何字段都可以包含0个或者更多值,但是,所有array中的值必须具有相同的数据类型,例如:
-
字符串数组:["one", "two"]
-
整数数组:[1,2]
-
数组的数组:[1, [2, 3]],等价于[1,2,3]
-
对象数组:[ { "name": "Mary", "age": 12 }, { "name": "John", "age": 10 }]
数组可以包含null值,这些值可以由配置的null_value替换或完全跳过。一个空的array []被视为不存在的字段-无值的字段。
Array类型是直接支持的,不需要特殊映射,如long类型的数组,直接映射成long即可。
Object 对象型
JSON文档本质上是分层的:文档包含内部对象,内部对象本身还包含内部对象。
PUT /account/_doc/1
{
"region": "US",
"manager": {
"age": 30,
"name": "John Smith"
}
}
}
在内部,这个文档被索引为一个简单的、扁平的键值对列表,如下所示:
{
"region": "US",
"manager.age": 30,
"manager.name ": "John Smith"
}
索引方法如下:
{
"mappings": {
"properties": {
"region": { "type": "keyword" },
"manager": {
"properties": {
"age": { "type": "integer" },
"name": { "type": "text" }
}
}
}
}
}
基本上是一个嵌套的方式,还是比较直观的。
Nested 嵌套型
由于对象扁平化存储,导致有的时候,对象数组并非你期望的那样工作,例如如下对象:
{
"group": "fans",
"user": [
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
]
}
在内部被转化成如下格式的文档:
{
"group": "fans",
"user.first": [
"alice",
"john"
],
"user.last": [
"smith",
"white"
]
}
user.first和 user.last 扁平化为多值字段,alice 和 white 的关联关系丢失了。导致这个文档错误地匹配对 alice 和 smith 的查询
如果想并且保持数组中每个对象的独立性,在ElasticSearch中应该将其映射为nested对象类型而不是默认的object类型。
{
"mappings": {
"my_type": {
"properties": {
"user": {
"type": "nested"
}
}
}
}
}