本地英文版地址: ../en/nested.html
nested
类型是object
数据类型的一个特殊版本,它允许以一种可以相互独立查询的方式对对象数组进行索引。
当摄入包含大量任意键的键值对时,可以考虑将每个键值对建模为包含key
和value
字段的嵌套文档。
相反,可以考虑使用flattened数据类型,它将整个对象映射为单个字段,并允许对其内容进行简单的搜索。
嵌套的文档及其查询的代价通常是很高的,因此对于这个用例使用flattened
数据类型是一个更好的选择。
Elasticsearch没有内部对象的概念。 因此,它将对象层次结构简化为字段名称和值的简单列表。 例如,考虑以下文档:
PUT my_index/_doc/1 { "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 AND smith
:
GET my_index/_search { "query": { "bool": { "must": [ { "match": { "user.first": "Alice" }}, { "match": { "user.last": "Smith" }} ] } } }
如果需要索引对象数组并保持数组中每个对象的独立性,请使用nested
数据类型而不是object
数据类型。
在内部,嵌套对象将数组中的每个对象作为单独的隐藏文档进行索引,这意味着可以使用nested
查询独立于其他对象来查询每个嵌套对象:
PUT my_index { "mappings": { "properties": { "user": { "type": "nested" } } } } PUT my_index/_doc/1 { "group" : "fans", "user" : [ { "first" : "John", "last" : "Smith" }, { "first" : "Alice", "last" : "White" } ] } GET my_index/_search { "query": { "nested": { "path": "user", "query": { "bool": { "must": [ { "match": { "user.first": "Alice" }}, { "match": { "user.last": "Smith" }} ] } } } } } GET my_index/_search { "query": { "nested": { "path": "user", "query": { "bool": { "must": [ { "match": { "user.first": "Alice" }}, { "match": { "user.last": "White" }} ] } }, "inner_hits": { "highlight": { "fields": { "user.first": {} } } } } } }
嵌套文档可以:
-
使用
nested
查询对其进行查询。 -
使用
nested
和reverse_nested
聚合对其进行分析 - 使用嵌套排序进行排序。
- 使用嵌套内部命中来获取并高亮。
因为嵌套文档是作为单独的文档进行索引的,所以只能在nested
查询、nested
/reverse_nested
聚合或嵌套内部命中的范围内访问它们。
例如,如果嵌套文档中的字符串字段将index_options
设置为offsets
以允许在高亮阶段使用发布,则这些 offsets 在高亮阶段(主要阶段之一)将不可用。
相反,高亮需要通过嵌套内部命中来执行。
在通过docvalue_fields
或stored_fields
进行搜索的过程中加载字段时,同样的注意事项也适用。
nested
字段接受下列参数:
-
dynamic
-
(可选,字符串)
新属性(
properties
)是否应该被动态的添加到一个已有的嵌套对象中。 接受true
(默认),false
及strict
。 -
properties
-
(可选,对象)
嵌套对象内的字段,可以认识任意一种数据类型,包含
nested
。 新属性可能会被添加到一个已有的嵌套对象。 -
include_in_parent
-
(可选,布尔)
如果为
true
,嵌套对象中的所有字段也将作为标准(扁平的)字段添加到父文档中。 默认为false
。 -
include_in_root
-
(可选,布尔)
如果为
true
,嵌套对象中的所有字段也将作为标准(扁平的)字段添加到根文档中。 默认为false
。
nested
映射和对象的限制
如前所述,每个嵌套对象都作为一个单独的 Lucene 文档进行索引。
接着前面的例子,如果我们索引一个包含 100 个user
对象的文档,那么将会创建 101 个 Lucene 文档:父文档一个,每个嵌套对象一个。
由于与nested
映射相关的开销,Elasticsearch 进行了一些设置来防止性能问题:
-
index.mapping.nested_fields.limit
-
一个索引中不同
nested
映射的最大数量。nested
类型应该只在特殊情况下使用,即当对象数组需要彼此独立地查询时。 为了防止映射设计不当,该设置限制了每个索引的唯一nested
类型的数量。 默认值为50
。
在前面的例子中,user
映射对这个限制只计为 1。
-
index.mapping.nested_objects.limit
-
单个文档在所有
nested
类型中可以包含的嵌套 JSON 对象的最大数量。 当文档包含太多嵌套对象时,此限制有助于防止内存不足错误。 默认值为10000
。
为了说明这个设置是如何工作的,考虑在前面的示例映射中添加另一个名为comments
的nested
类型。
对于每个文档,它包含的user
和comment
对象的总数必须低于该限制。
有关防止映射爆炸的其他设置,请参考防止映射爆炸的设置。