nested
类型是一种特殊的对象object数据类型,允许对象数组彼此独立的进行索引和查询
_
对象数组如何扁平化
内部对象object字段的数组不能像我们所期望的那样工作。Lucene内部没有对象的概念,所以ES将对象层次结构扁平化为一个字段名称和值的简单列表:
PUT /my_index/_doc/1?pretty
{
"group": "fans",
"user": [
{"first":"John", "last":"Smith"},
{"first":"Alice", "last":"White"}
]
}
user字段被动态的添加为
object
类型的字段,在其内部转化为一个看起来像下面这样的文档:
{
"group":"fans",
"user.first":["John","Alice"],
"user.last":["Smith","White"]
}
user.first和user.last字段被扁平化为多值字段,并且alice和white质检的关联已经丢失。
以下文本文档将错误的匹配user.first和user.last为smith查询:
GET /my_indx/_doc
{
"query":{
"bool":{
"must":[
{"match":{"user.first":"Alice"}},
{"match":{"user.last":"Smith"}}
]
}
}
}
//响应
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 0.5753642,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": 0.5753642,
"_source": {
"group": "fans",
"user": [
{
"first": "john",
"last": "smith"
},
{
"first": "alice",
"last": "white"
}
]
}
}
]
}
}
解释:可以看到,我们原本是想要查询用户名为Alice Smith的用户,实际文档中并不存在此用户,但是搜索还是错误的命中了此文档。
对对象数组使用嵌套字段
上面的例子描述了我们日常搜索的一些错误场景,但是我们要如何解决上面例子描述的问题呢?
如果需要索引对象数组并维护每个对象的独立性,则应对字段使用nested
类型而不是使用object
类型。
在内部,嵌套对象将数组中的每个对象作为单独的隐藏文档进行索引,这意味着每个嵌套对象都可以使用嵌套查询nested query
独立于其他对象进行查询。
要实现netsted查询,我们首先要为文档设置正确的映射(mapping
):
DELETE /my_index
PUT /my_index
{
"mappings": {
"properties": {
"user": {
"type":"nested"
}
}
}
}
PUT /my_index/_doc/1?pretty
{
"group": "fans",
"user": [
{"first":"John", "last":"Smith"},
{"first":"Alice", "last":"White"}
]
}
说明:此时user字段映射为nested类型,而不是默认的object类型
此时需要对bool查询进行一定的更改,再使用nested
查询:
GET /my_index/_serach?pretty
{
"query": {
"nested": {
"path":"user",
"query": {
"bool": {
"must": [
{"match":{"user.first":"Alice"}},
{"match":{"user.last":"White"}},
]
}
}
}
}
}
//响应
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 1,
"successful": 1,
"skipped": 0,
"failed": 0
},
"hits": {
"total": {
"value": 1,
"relation": "eq"
},
"max_score": 1.3862942,
"hits": [
{
"_index": "my_index",
"_type": "_doc",
"_id": "1",
"_score": 1.3862942,
"_source": {
"group": "fans",
"user": [
{
"first": "John",
"last": "Smith"
},
{
"first": "Alice",
"last": "White"
}
]
}
}
]
}
}
可以发现。此时Alice White用户文档则被正确的命中。