# \_parent,\_routing 元字段

| \_parent  | 用于创建两个映射类型之间的父子关系。 |
| --------- | ------------------ |
| \_routing | 将文档路由到特定分片的自定义路由值。 |

## \_parent field

通过使一个映射类型成为另一个映射类型的父类，可以在同一索引中的文档之间建立父子关系 :

```
curl -XPUT 'localhost:9200/my_index?pretty' -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "my_parent": {},
    "my_child": {
      "_parent": {
        "type": "my_parent" # 1
      }
    }
  }
}
'
curl -XPUT 'localhost:9200/my_index/1/1?pretty' -H 'Content-Type: application/json' -d' # 2
{
  "text": "This is a parent document"
}

'
curl -XPUT 'localhost:9200/my_index/my_child/2?parent=1&pretty' -H 'Content-Type: application/json' -d' # 2
{
  "text": "This is a child document"
}
'
curl -XPUT 'localhost:9200/my_index/my_child/3?parent=1&refresh=true&pretty' -H 'Content-Type: application/json' -d' # 4
{
  "text": "This is another child document"
}
'
curl -XGET 'localhost:9200/my_index/my_parent/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": {
    "has_child": { # 5
      "type": "my_child",
      "query": {
        "match": {
          "text": "child document"
        }
      }
    }
  }
}
'
```

| 1     | 该**my\_parent**类型是**my\_child**类型的**parent**（父节）。 |
| ----- | ------------------------------------------------- |
| 2     | 索引**parent**文档。                                   |
| 3 , 4 | 索引两个子文档，指定父文档的**ID**。                             |
| 5     | 查找具有与查询匹配的子项的所有父文档。                               |

通过使一个映射类型成为另一个映射类型的父类，可以在同一索引中的文档之间建立父子关系 :

有关更多信息，请参阅[**has\_child**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-has-child-query.html) 和[**has\_parent**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-has-parent-query.html)查询，[**children aggregation**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/search-aggregations-bucket-children-aggregation.html)和[**inner hits**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/search-request-inner-hits.html#parent-child-inner-hits)。

&#x8BE5;**\_parent** 字段的值可以在**aggregations**（聚合）和**scripts**（脚本）中访问，并且可以使用 [**parent\_id**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-parent-id-query.html)查询进行查询

```
curl -XGET 'localhost:9200/my_index/_search?pretty' -H 'Content-Type: application/json' -d'
{
  "query": {
    "parent_id": {
      "type": "my_child",
      "id": "1"
    }
  },
  "aggs": {
    "parents": {
      "terms": {
        "field": "_parent",
        "size": 10
      }
    }
  },
  "script_fields": {
    "parent": {
      "script": {
         "inline": "doc[\u0027_parent\u0027]"
      }
    }
  }
}
'
```

| 1 | 查&#x8BE2;**\_parent**字段的**id**（参考[**has\_parent**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-has-parent-query.html)查询和[**has\_child**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-has-child-query.html)查询） |
| - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2 | &#x5728;**\_parent**字段上的聚合（参考[**children aggregation**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/search-aggregations-bucket-children-aggregation.html)）                                                                                        |
| 3 | 在脚本中访&#x95EE;**\_parent**字段                                                                                                                                                                                                                                       |

### Parent-child restrictionsedit （父子限制） <a href="#idparentfieldparentchildrestrictionsedit-fu-zi-xian-zhi" id="idparentfieldparentchildrestrictionsedit-fu-zi-xian-zhi"></a>

* 父类和子类型必须不同 - 不能在相同类型的文档之间建立父子关系。
* &#x8BE5;**\_parent.type**设置只能指向不存在的类型。 这意味着类型在创建后不能成为父类型。
* 父文档和子文档必须在相同的分片上索引。 父**ID**用作子节点的路由值，以确保子节点与父节点在同一分片上进行索引。 这意味着在获取，删除或更新子文档时需要提供相同的**parent**值。

### Global ordinals （全局序列） <a href="#idparentfieldglobalordinals-quan-ju-xu-lie" id="idparentfieldglobalordinals-quan-ju-xu-lie"></a>

父子使用 [**全局序列**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/fielddata.html#global-ordinals)来加快连接。 在对分片进行任何更改之后，需要重建全局序列。 分片中存储的父**ID**值越多，重建 **\_parent** 字段的全局序列所需的时间越长。

默认情况下，全局序列是高效的：如果索引已更改，则 **\_parent** 字段的全局序列将作为刷新的一部分进行重新构建。 这会增加刷新时间。 然而，大多数时候，这是正确的选择，否则，当使用第一个 **parent-child query**（父子查询）或**aggregation**（聚合）时，全局序列将被重建。 这可能会为您的用户带来较大的延迟，并且通常会更糟，因为在发生许多写入时，可能会在单个刷新间隔内重新创建 **\_parent** 字段的多个全局序列。

当 **parent/child**不频繁使用时，写入频繁发生，最好禁用预加载 :

```
curl -XPUT 'localhost:9200/my_index?pretty' -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "my_parent": {},
    "my_child": {
      "_parent": {
        "type": "my_parent",
        "eager_global_ordinals": false
      }
    }
  }
}
'
```

可以检查全局序列使用的堆数量，如下所示 :

```
# Per-index
curl -XGET 'localhost:9200/_stats/fielddata?human&fields=_parent&pretty'
# Per-node per-index
curl -XGET 'localhost:9200/_nodes/stats/indices/fielddata?human&fields=_parent&pretty'
```

## \_routing field

使用以下公式将文档路由到索引中的特定分片：

```
shard_num = hash(_routing) % num_primary_shards
```

用于 **\_routing** 的默认值是文档的\_id或文档的\_parent ID（如果存在）。

可以通过为每个文档指定自定义路由值来实现自定义路由模式。 例如：

```
curl -XPUT 'localhost:9200/my_index/my_type/1?routing=user1&refresh=true&pretty' -H 'Content-Type: application/json' -d' # 1
{
  "title": "This is a document"
}
'
curl -XGET 'localhost:9200/my_index/my_type/1?routing=user1&pretty' # 2
```

| 1 | 此文档使用**user1**作为其**routingvalue**（路由值），而不是其**ID**。                                                                                                                                                                                                                                                            |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2 | 在[**getting**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/docs-get.html)（获取），[**deleting**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/docs-delete.html)（删除）或[**updating**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/docs-update.html)（更新）文档时需要提供相同的路由值。 |

该

**\_routing** 字段的值可以在查询中访问 :

```
curl -XGET 'localhost:9200/my_index/_search?pretty' -H 'Content-Type: application/json' -d' # 1
{
  "query": {
    "terms": {
      "_routing": [ "user1" ]
    }
  }
}
'
```

| 1 | 在\_routing字段上查询（也可以参见[**ids query**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/query-dsl-ids-query.html)） |
| - | --------------------------------------------------------------------------------------------------------------------------- |

### Searching with custom routing（使用自定义路由搜索）

自定义路由可以减少搜索的影响。 搜索请求不必分散到索引中的所有分片，而是将该请求发送到与特定路由值（或值）匹配的分片 :

```
curl -XGET 'localhost:9200/my_index/_search?routing=user1,user2&pretty' -H 'Content-Type: application/json' -d' # 1
{
  "query": {
    "match": {
      "title": "document"
    }
  }
}
'
```

| 1 | 该搜索请求仅会在与user1和user2路由值相关联的分片上执行。 |
| - | --------------------------------- |

### Making a routing value required（路由值的要求） <a href="#idroutingfieldmakingaroutingvaluerequired-lu-you-zhi-de-yao-qiu" id="idroutingfieldmakingaroutingvaluerequired-lu-you-zhi-de-yao-qiu"></a>

当使用自定义路由时，重要的是在[**indexing**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/docs-index_.html)（索引）， [**getting**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/docs-get.html)（获取）， [**deleting**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/docs-delete.html)（删除）或 [**updating**](https://www.elastic.co/guide/en/elasticsearch/reference/5.3/docs-update.html)（更新）文档时提供路由值。

忘记路由值可能导致文档被索引在多个分片上。 作为保护措施，可以将 **\_routing** 字段配置为使所有CRUD操作都需要指定路由值 :

```
curl -XPUT 'localhost:9200/my_index2?pretty' -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "my_type": {
      "_routing": {
        "required": true # 1
      }
    }
  }
}
'
curl -XPUT 'localhost:9200/my_index2/my_type/1?pretty' -H 'Content-Type: application/json' -d' # 2
{
  "text": "No routing value provided"
}
'
```

| 1 | **my\_type**文档需要路由。                        |
| - | ------------------------------------------ |
| 2 | 此索引请求会引发一个**routing\_missing\_exception**。 |

### Unique IDs with custom routing（具有自定义路由的唯一ID） <a href="#idroutingfielduniqueidswithcustomrouting-ju-you-zi-ding-yi-lu-you-de-wei-yi-id" id="idroutingfielduniqueidswithcustomrouting-ju-you-zi-ding-yi-lu-you-de-wei-yi-id"></a>

在索引指定自定义 **\_routing** 的文档时，**\_id** 的唯一性不能保证在索引中的所有分片。

事实上，如果使用不同的 **\_routing** 值进行索引，那么具有相&#x540C;**\_id** 的文档可能会在不同的分片上出现。

由用户确定**ID** 在索引中是唯一的。

### Routing to an index partition（路由到索引分区） <a href="#idroutingfieldroutingtoanindexpartition-lu-you-dao-suo-yin-fen-qu" id="idroutingfieldroutingtoanindexpartition-lu-you-dao-suo-yin-fen-qu"></a>

可以配置索引，使得自定义路由值将转到分片的子集，而不是单个分片。这有助于减轻最终产生不平衡群集的风险，同时还可以减少搜索的影响。

这是通过在索引创建时提供索引级别设置 _**index.routing\_partition\_size**_ 来完成的。随着分区大小的增加，数据的分布越均匀，必须以每个请求搜索更多的分片为代价。

当存在此设置时，计算分片的公式为：

```
shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards
```

也就是说，**\_routing** 字段用于计算索引中的一组分片，然后使用 **\_id** 来选择该组内的分片。

要启用此功能，_**index.routing\_partition\_size**_ 应具有大于1且小于 _**index.number\_of\_shards**_ 的值。

一旦启用，分区索引将具有以下限制 :

* 具有父子关系的映射无法在其中创建。
*   索引中的所有映射必须设置&#x20;

    **\_routing** 字段。
