nested类型是object数据类型的一个专门版本,它允许对对象数组进行索引,以便它们可以相互独立地查询。
当用大的任意键值集合键入键值对时,可以考虑将每个键值对建模为具有键和值字段的自己嵌套文档。相反,考虑使用扁平化数据类型,它将整个对象映射为单个字段,并允许对其内容进行简单搜索。嵌套文档和查询通常比较昂贵,因此在这个用例中使用扁平化数据类型是一个更好的选择。
对象阵列的展平方式
Elasticsearch没有内部对象的概念。因此,它将对象层次结构展平为字段名和值的简单列表。例如:
PUT my-index-000001/_doc/1
{
"group" : "fans",
"user" : [ (1)
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}
(1)用户字段被动态添加为object类型的字段。
以前的文档将在内部转换为更像以下内容的文档:
{
"group" : "fans",
"user.first" : [ "alice", "john" ],
"user.last" : [ "smith", "white" ]
}
user.first和user.last字段被展平为多值字段,alice和white之间的关联将丢失。此文档与alice和smith的查询不匹配:
GET my-index-000001/_search
{
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }}
]
}
}
}
对objects数组使用nested字段
如果需要为对象数组编制索引并保持数组中每个对象的独立性,请使用nested数据类型而不是object数据类型。
在内部,nested对象将数组中的每个对象作为单独的隐藏文档进行索引,这意味着每个嵌套对象都可以通过嵌套查询独立于其他对象进行查询:
PUT my-index-000001
{
"mappings": {
"properties": {
"user": {
"type": "nested" (1)
}
}
}
}
PUT my-index-000001/_doc/1
{
"group" : "fans",
"user" : [
{
"first" : "John",
"last" : "Smith"
},
{
"first" : "Alice",
"last" : "White"
}
]
}
GET my-index-000001/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "Smith" }} (2)
]
}
}
}
}
}
GET my-index-000001/_search
{
"query": {
"nested": {
"path": "user",
"query": {
"bool": {
"must": [
{ "match": { "user.first": "Alice" }},
{ "match": { "user.last": "White" }} (3)
]
}
},
"inner_hits": { (4)
"highlight": {
"fields": {
"user.first": {}
}
}
}
}
}
}
(1)user字段映射为nested类型,而不是object类型。
(2)此查询不匹配,因为Alice和Smith不在同一嵌套对象中。
(3)此查询匹配,因为Alice和White位于同一嵌套对象中。
(4)内部点击允许我们突出显示匹配的嵌套文档。
nested映射和objects的限制
如前所述,每个嵌套对象都作为单独的Lucene文档编制索引。继续上一个示例,如果我们为包含100个用户对象的单个文档编制索引,那么将创建101个Lucene文档:一个用于父文档,一个用于每个嵌套对象。由于嵌套映射的相关费用,Elasticsearch将设置放在适当的位置以防止性能问题:
index.mapping.nested_fields.limit
索引中不同嵌套映射的最大数目。嵌套类型只应在特殊情况下使用,即需要相互独立地查询对象数组时。为了防止映射设计不当,此设置限制每个索引的唯一嵌套类型数。默认值为50。
在上一个示例中,user映射将仅计算为1,以达到此限制。
index.mapping.nested_objects.limit
单个文档可以跨所有嵌套类型包含的最大嵌套JSON对象数。当文档包含太多嵌套对象时,此限制有助于防止内存不足错误。默认值为10000。
为了说明这个设置是如何工作的,请考虑在前面的示例映射中添加另一个嵌套类型,称为commenrs。对于每个文档,其包含的user和comment对象的总数必须低于限制。