[[mapping-parent-field]] === `_parent` field A parent-child relationship can be established between documents in the same index by making one mapping type the parent of another: [source,js] -------------------------------------------------- PUT my_index { "settings": { "mapping.single_type": false }, "mappings": { "my_parent": {}, "my_child": { "_parent": { "type": "my_parent" <1> } } } } PUT my_index/my_parent/1 <2> { "text": "This is a parent document" } PUT my_index/my_child/2?parent=1 <3> { "text": "This is a child document" } PUT my_index/my_child/3?parent=1&refresh=true <3> { "text": "This is another child document" } GET my_index/my_parent/_search { "query": { "has_child": { <4> "type": "my_child", "query": { "match": { "text": "child document" } } } } } -------------------------------------------------- // CONSOLE <1> The `my_parent` type is parent to the `my_child` type. <2> Index a parent document. <3> Index two child documents, specifying the parent document's ID. <4> Find all parent documents that have children which match the query. See the <> and <> queries, the <> aggregation, and <> for more information. The value of the `_parent` field is accessible in aggregations and scripts, and may be queried with the <>: [source,js] -------------------------- GET my_index/_search { "query": { "parent_id": { <1> "type": "my_child", "id": "1" } }, "aggs": { "parents": { "terms": { "field": "_parent", <2> "size": 10 } } }, "script_fields": { "parent": { "script": { "inline": "doc['_parent']" <3> } } } } -------------------------- // CONSOLE // TEST[continued] <1> Querying the id of the `_parent` field (also see the <> and the <>) <2> Aggregating on the `_parent` field (also see the <> aggregation) <3> Accessing the `_parent` field in scripts ==== Parent-child restrictions * The parent and child types must be different -- parent-child relationships cannot be established between documents of the same type. * The `_parent.type` setting can only point to a type that doesn't exist yet. This means that a type cannot become a parent type after it has been created. * Parent and child documents must be indexed on the same shard. The `parent` ID is used as the <> value for the child, to ensure that the child is indexed on the same shard as the parent. This means that the same `parent` value needs to be provided when <>, <>, or <> a child document. ==== Global ordinals Parent-child uses <> to speed up joins. Global ordinals need to be rebuilt after any change to a shard. The more parent id values are stored in a shard, the longer it takes to rebuild the global ordinals for the `_parent` field. Global ordinals, by default, are built eagerly: if the index has changed, global ordinals for the `_parent` field will be rebuilt as part of the refresh. This can add significant time the refresh. However most of the times this is the right trade-off, otherwise global ordinals are rebuilt when the first parent-child query or aggregation is used. This can introduce a significant latency spike for your users and usually this is worse as multiple global ordinals for the `_parent` field may be attempt rebuilt within a single refresh interval when many writes are occurring. When the parent/child is used infrequently and writes occur frequently it may make sense to disable eager loading: [source,js] -------------------------------------------------- PUT my_index { "settings": { "mapping.single_type": false }, "mappings": { "my_parent": {}, "my_child": { "_parent": { "type": "my_parent", "eager_global_ordinals": false } } } } -------------------------------------------------- // CONSOLE The amount of heap used by global ordinals can be checked as follows: [source,sh] -------------------------------------------------- # Per-index GET _stats/fielddata?human&fields=_parent # Per-node per-index GET _nodes/stats/indices/fielddata?human&fields=_parent -------------------------------------------------- // CONSOLE