嵌套字段类型
嵌套字段类型是一种特殊的对象字段类型。
任何对象字段都可以接受对象数组。数组中的每个对象都会动态映射为对象字段类型,并以扁平化形式存储。这意味着数组中的对象被拆分为单独的字段,并且所有对象中每个字段的值被存储在一起。有时,为了将嵌套对象作为一个整体保留以便对其进行搜索,需要使用嵌套类型。
扁平化形式
默认情况下,每个嵌套对象都会动态映射为对象字段类型。任何对象字段都可以接受对象数组。
PUT testindex1/_doc/100
{
"patients": [
{"name" : "John Doe", "age" : 56, "smoker" : true},
{"name" : "Mary Major", "age" : 85, "smoker" : false}
]
}
当这些对象被存储时,它们会被扁平化处理,因此它们的内部表示形式是每个字段的所有值组成的数组:
{
"patients.name" : ["John Doe", "Mary Major"],
"patients.age" : [56, 85],
"patients.smoker" : [true, false]
}
在这种表示形式下,某些查询可以正常工作。例如,如果您搜索年龄大于 75 岁 或者 吸烟的患者,文档 100 应该匹配。
GET testindex1/_search
{
"query": {
"bool": {
"should": [
{
"term": {
"patients.smoker": true
}
},
{
"range": {
"patients.age": {
"gte": 75
}
}
}
]
}
}
}
该查询正确返回了文档 100:
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.3616575,
"hits" : [
{
"_index" : "testindex1",
"_type" : "_doc",
"_id" : "100",
"_score" : 1.3616575,
"_source" : {
"patients" : [
{
"name" : "John Doe",
"age" : "56",
"smoker" : true
},
{
"name" : "Mary Major",
"age" : "85",
"smoker" : false
}
]
}
}
]
}
}
反之,如果您搜索年龄大于 75 岁 并且 吸烟的患者,文档 100 则不应匹配。
GET testindex1/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"patients.smoker": true
}
},
{
"range": {
"patients.age": {
"gte": 75
}
}
}
]
}
}
}
然而,此查询仍然错误地返回了文档 100。这是因为在为各个字段创建值数组时,年龄与吸烟状态之间的关系丢失了。
嵌套字段类型
嵌套对象被存储为独立的文档,父对象持有对其子对象的引用。要将对象标记为嵌套,需创建一个包含嵌套字段类型的映射。
PUT testindex1
{
"mappings" : {
"properties": {
"patients": {
"type" : "nested"
}
}
}
}
然后,索引一个包含嵌套字段类型的文档:
PUT testindex1/_doc/100
{
"patients": [
{"name" : "John Doe", "age" : 56, "smoker" : true},
{"name" : "Mary Major", "age" : 85, "smoker" : false}
]
}
您可以使用以下嵌套查询来搜索年龄大于 75 岁 或者 吸烟的患者:
GET testindex1/_search
{
"query": {
"nested": {
"path": "patients",
"query": {
"bool": {
"should": [
{
"term": {
"patients.smoker": true
}
},
{
"range": {
"patients.age": {
"gte": 75
}
}
}
]
}
}
}
}
}
该查询正确地返回了两位患者:
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.8465736,
"hits" : [
{
"_index" : "testindex1,
"_id" : "100",
"_score" : 0.8465736,
"_source" : {
"patients" : [
{
"name" : "John Doe",
"age" : 56,
"smoker" : true
},
{
"name" : "Mary Major",
"age" : 85,
"smoker" : false
}
]
}
}
]
}
}
您可以使用以下嵌套查询来搜索年龄大于 75 岁 并且 吸烟的患者:
GET testindex1/_search
{
"query": {
"nested": {
"path": "patients",
"query": {
"bool": {
"must": [
{
"term": {
"patients.smoker": true
}
},
{
"range": {
"patients.age": {
"gte": 75
}
}
}
]
}
}
}
}
}
如预期,上一个查询没有返回任何结果:
{
"took" : 7,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}
参数
下表列出了对象字段类型接受的参数。所有参数均为可选。
| 参数 | 描述 |
|---|---|
dynamic |
指定是否可以向对象动态添加新字段。有效值为 true、false、strict 和 strict_allow_templates。默认值为 true。 |
include_in_parent |
一个布尔值,指定是否应将子嵌套对象中的所有字段也以扁平化形式添加到父文档中。默认值为 false。 |
include_in_root |
一个布尔值,指定是否应将子嵌套对象中的所有字段也以扁平化形式添加到根文档中。默认值为 false。 |
properties |
此对象的字段,可以是任何支持的类型。如果 dynamic 设置为 true,则可以动态向此对象添加新属性。 |