es查询之nested(嵌套)查询

Published on 2023-05-12 13:14 in 分类: 随笔 with 狂盗一枝梅
分类: 随笔

一、出现的问题

这里有个教师索引teacher,其mapping信息如下

{
    "properties": {
        "name": {
            "type": "keyword"
        },
        "age": {
            "type": "integer"
        },
        "students": {
            "properties": {
                "name": {
                    "type": "keyword"
                },
                "age": {
                    "type": "integer"
                }
            }
        }
    }
}

新插入两条数据

{{es-host}}/teacher/_doc
{
    "name": "张三",
    "age": 34,
    "students":[
        {
            "name": "小明",
            "age": 13
        },
        {
            "name": "小红",
            "age": 14
        }
    ]
}
{
    "name": "李四",
    "age": 35,
    "students":[
        {
            "name": "小明",
            "age": 14
        },
        {
            "name": "小红",
            "age": 13
        }
    ]
}

张三老师和李四老师都有小明和小红两个学生,但是并非同一个人,其年龄是相反的,现在我想查询:姓名为小明,年龄14岁的学生,他的老师叫什么名字,查询方式如下:

{{es-host}}/teacher/_search

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "students.name": "小明"
                    }
                },
                {
                    "term": {
                        "students.age": 14
                    }
                }
            ]
        }
    }
}

查询结果如下:

{
    "took": 15,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 2,
            "relation": "eq"
        },
        "max_score": 1.2292043,
        "hits": [
            {
                "_index": "teacher",
                "_type": "_doc",
                "_id": "edDrDYgBF_FDuIInec6p",
                "_score": 1.2292043,
                "_source": {
                    "name": "张三",
                    "age": 34,
                    "students": [
                        {
                            "name": "小明",
                            "age": 13
                        },
                        {
                            "name": "小红",
                            "age": 14
                        }
                    ]
                }
            },
            {
                "_index": "teacher",
                "_type": "_doc",
                "_id": "etDrDYgBF_FDuIIn-84N",
                "_score": 1.2292043,
                "_source": {
                    "name": "李四",
                    "age": 35,
                    "students": [
                        {
                            "name": "小明",
                            "age": 14
                        },
                        {
                            "name": "小红",
                            "age": 13
                        }
                    ]
                }
            }
        ]
    }
}

可以看到,竟然把两个老师都查询出来了

二、如何解决

  1. 在创建mapping的时候将数据结构定义为nested类型
  2. 查询的时候使用nested查询

1. 创建nested类型

{{es-host}}/teacher/_mapping

{
    "properties": {
        "name": {
            "type": "keyword"
        },
        "age": {
            "type": "integer"
        },
        "students": {
            "type": "nested",
            "properties": {
                "name": {
                    "type": "keyword"
                },
                "age": {
                    "type": "integer"
                }
            }
        }
    }
}

2. 再次查询为空

新增之前的那两条数据之后,再次查询

{{es-host}}/teacher/_search

{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "students.name": "小明"
                    }
                },
                {
                    "term": {
                        "students.age": 14
                    }
                }
            ]
        }
    }
}

发现结果是空的

{
    "took": 7,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 0,
            "relation": "eq"
        },
        "max_score": null,
        "hits": []
    }
}

这是因为mapping定义是nested类型了,就必须使用nested查询方式

3. nested查询

{{es-host}}/teacher/_search

使用nested查询方式再次查询,查询句式

{
    "query": {
        "nested": {
            "path": "students",
            "query": {
                //原来的query
            }
        }
    }
}

其中的path指的是声明为nested类型的字段的path。

{
    "query": {
        "nested": {
            "path": "students",
            "query": {
                "bool": {
                    "must": [
                        {
                            "term": {
                                "students.name": "小明"
                            }
                        },
                        {
                            "term": {
                                "students.age": 14
                            }
                        }
                    ]
                }
            }
        }
    }
}

这时候就能查询出来结果了

{
    "took": 8,
    "timed_out": false,
    "_shards": {
        "total": 1,
        "successful": 1,
        "skipped": 0,
        "failed": 0
    },
    "hits": {
        "total": {
            "value": 1,
            "relation": "eq"
        },
        "max_score": 1.6931472,
        "hits": [
            {
                "_index": "teacher",
                "_type": "_doc",
                "_id": "fNAGDogBF_FDuIInL856",
                "_score": 1.6931472,
                "_source": {
                    "name": "李四",
                    "age": 35,
                    "students": [
                        {
                            "name": "小明",
                            "age": 14
                        },
                        {
                            "name": "小红",
                            "age": 13
                        }
                    ]
                }
            }
        ]
    }
}

正是我想要的查询结果


#es
目录