# 3.2.Mapping

## Mapping

> 字段的类型可以通过手动mapping创建,但是不能修改已经mapping过的字段,但可以新增字段数据类型的mapping.

## Mapping（映射） <a href="#mapping-ying-she-mapping-ying-she" id="mapping-ying-she-mapping-ying-she"></a>

Mapping是用来定义一个文档（document），以及它所包含的属性（field）是如何存储和索引的。比如，使用mapping来定义：

* 哪些字符串属性应该被看做全文本属性（full text fields）。
* 哪些属性包含数字，日期或者地理位置。
* 文档中的所有属性是否都能被索引（\_all 配置）。
* 日期的格式。
* 自定义映射规则来执行动态添加属性。

### Mapping Types（映射类型） <a href="#mapping-ying-she-mappingtypes-ying-she-lei-xing" id="mapping-ying-she-mappingtypes-ying-she-lei-xing"></a>

每一个索引都有一个或多个映射类型，用于在一个索引中把文档划分为具有逻辑关系的分组。比如，用户文档应该存储为user 类型，博客应该放置于blogpost类型下。

每一个映射类型包含：

[Meta\_fields](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/mapping-fields.html)（元数据）

元标签用于制定如何处理文档相关的元数据。例如元标签包含文档的 [\_index](http://www.sohu.wiki/display/Elasticsearch/_index+field), [\_type](http://www.sohu.wiki/display/Elasticsearch/_type+field),[\_id](http://www.sohu.wiki/display/Elasticsearch/_id+field), 和[\_source](http://www.sohu.wiki/display/Elasticsearch/_source+field) 字段。

[Fields ](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/mapping-types.html)or properties（字段或属性）

每一个映射类型包含有一些与该类型相关的字段或者属性。比如一个user类型也许包含title，name，age属性，而blogpost类型也许包含title, body, user\_id 和 created属性。在同一索引中，不同的映射类型下具有相同名称的属性具有相同的映射。

> 注意: 如果两个字段或者多个字段在不同type(表)的mapping中,但是这些type(表)都在相同的同一个index下,字段的映射的数据类型必须一致.

#### 字段的数据类型

每个字段有一个typed 属性,也就是字段的数据类型.

* 简单类型:[`text`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/text.html),[`keyword`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/keyword.html),[`date`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/date.html),[`long`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/number.html),[`double`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/number.html),[`boolean`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/boolean.html)或[`ip`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/ip.html)
* 支持jason层级的类型: [`object`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/object.html)或[`nested`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/nested.html)
* 特殊类型: [`geo_point`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/geo-point.html),[`geo_shape`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/geo-shape.html), 或[`completio`](https://www.elastic.co/guide/en/elasticsearch/reference/5.2/search-suggesters-completion.html)

不同的场景使用不通的类型.如: 如果是一个字符串类型的字段,可以使用 `text`类型,用于全文索引. 使用 keyword 类型用于排序(sort) 或者聚合(aggregations).另外，你可以通过（分词器）标准分词英文分词，法文分词以及来索引一个字符串。

这就是进行multi-fields的目的。大多数数据类型都能通过fields配置来支持multi-fields。

#### 相关设置

接下来的设置用于限制通过人为或者动态创建field映射的数量，为了防止bad文档引起mapping explosion。

```
index.mapping.total_fields.limit
```

一个索引(index)中可拥有的最大的字段(field)数量, 默认值: 1000.

```
index.mapping.depth.limit
```

field(属性）的最大深度（嵌套），如果对象均在root下就是1，如果存在属性含有一个内部对象（object,nested），则2，默认20

直白理解就是嵌套的层数，如果超过了默认的20，则报下错误

```
{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[7bJsCFK][127.0.0.1:9300][indices:data/write/index[p]]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "Limit of mapping depth [20] in index [my_index11] has been exceeded due to object field [manager.name.first.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last.last]"
  },
  "status": 400
}
```

```
index.mapping.nested_fields.limit
```

一个index的type（表）中mapping时使用 `nested` 类型的字段最大数量默认50。

> 注意是type lavel ，并不是index lavel

如果超出会报如下错误

```
{
  "error": {
    "root_cause": [
      {
        "type": "illegal_argument_exception",
        "reason": "Limit of nested fields [50] in index [myindex33] has been exceeded"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "Limit of nested fields [50] in index [myindex33] has been exceeded"
  },
  "status": 400
}
```

### Dynamic mapping（动态映射） <a href="#mapping-ying-she-dynamicmapping-dong-tai-ying-she" id="mapping-ying-she-dynamicmapping-dong-tai-ying-she"></a>

字段和映射在被使用前是不需要定义的。可以通过索引一个文档来自动添加新的映射和字段名。可以向顶层映射类型和内部对象以及嵌套字段中添加新的字段。

通过配置[动态映射](http://www.sohu.wiki/pages/viewpage.action?pageId=9405268)规则来定制映射，用于新的类型和字段。

### Explicit mappings（显示映射） <a href="#mapping-ying-she-explicitmappings-xian-shi-ying-she" id="mapping-ying-she-explicitmappings-xian-shi-ying-she"></a>

你可以在[创建索引](http://www.sohu.wiki/pages/viewpage.action?pageId=4882789)的时候创建映射类型和字段映射，并且你可以通过[PUT mapping API](http://www.sohu.wiki/pages/viewpage.action?pageId=4882803)添加映射类型和字段到一个已经存在的索引中。

### Updating existing mappings（更新已存在的映射） <a href="#mapping-ying-she-updatingexistingmappings-geng-xin-yi-cun-zai-de-ying-she" id="mapping-ying-she-updatingexistingmappings-geng-xin-yi-cun-zai-de-ying-she"></a>

除了documented的地方，存在的类型和字段映射不能被更新。改变映射意味着让已经索引的文档失效。相反，你应该使用正确的映射以及重新索引数据来创建新的索引。

### Fields are shared across mapping types（映射类型中共享字段） <a href="#mapping-ying-she-fieldsaresharedacrossmappingtypes-ying-she-lei-xing-zhong-gong-xiang-zi-duan" id="mapping-ying-she-fieldsaresharedacrossmappingtypes-ying-she-lei-xing-zhong-gong-xiang-zi-duan"></a>

映射类型用于给字段分组，但是每个映射类型中的字段不是相互独立的。以下情况下的字段具有相同的映射。

* 相同名称
* 在同一索引中
* 不同的映射类型
* 映射到同一字段内部

如果title字段同时存在于user和blogpost映射类型中，那么title字段在每个类型中都有相同的映射。除了[copy\_to](http://www.sohu.wiki/pages/viewpage.action?pageId=10027040),[dynamic](http://www.sohu.wiki/pages/viewpage.action?pageId=10028289),[enabled](http://www.sohu.wiki/pages/viewpage.action?pageId=10028302),[ignore\_above](http://www.sohu.wiki/pages/viewpage.action?pageId=10028661),[include\_in\_all](http://www.sohu.wiki/pages/viewpage.action?pageId=9405298), 和[properties](http://www.sohu.wiki/pages/viewpage.action?pageId=10027013)，这些属性在每个字段中可能会有不同的设置。

通常，具有相同名称的字段也包含同样的数据类型，所以具有相同的映射不是问题。通过选择更多的描述名称能够解决冲突，如`user_title` 和`blog_title.`

### Example mapping（举例） <a href="#mapping-ying-she-examplemapping-ju-li" id="mapping-ying-she-examplemapping-ju-li"></a>

可以在创建索引的时候指定映射：

```
PUT my_index 
{
  "mappings": {
    "user": { 
      "_all":       { "enabled": false  }, 
      "properties": { 
        "title":    { "type": "text"  }, 
        "name":     { "type": "text"  }, 
        "age":      { "type": "integer" }  
      }
    },
    "blogpost": { 
      "_all":       { "enabled": false  }, 
      "properties": { 
        "title":    { "type": "text"  }, 
        "body":     { "type": "text"  }, 
        "user_id":  {
          "type":   "keyword" 
        },
        "created":  {
          "type":   "date", 
          "format": "strict_date_optional_time||epoch_millis"
        }
      }
    }
  }
}
```

* 创建了一个名为my\_index的索引
* 添加了两个type的mapping，user type（表）  和 blogpost type （表）&#x20;
* 禁用一个`meta field 类型的字段 _all`
* 每个字段映射了字段类型或属性。
