本地英文版地址: ../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对象的总数必须低于该限制。
有关防止映射爆炸的其他设置,请参考防止映射爆炸的设置。