代码改变世界

Elasticsearch中的嵌套查询介绍及实例

2019-05-28 11:15  14174  阅读(11738)  评论(0编辑  收藏  举报

大家在工作中想必也接触过Elasticsearch,今天介绍一下es中的嵌套对象及对应的查询方式。

 

从考虑一个业务场景开始吧,业务上需要把某些类似的商品聚合成为一个关联组,需要支持根据某个商品的特征,查询到它所在的关联组,es中的存储结构如下:

{
    "memberGoods":[
        {
            "title":"商品A",
            "brand":"a"
        },
        {
            "title":"商品B",
            "brand":"b"
        }
    ],
    "groupId":"A"
}

那么问题来了,如果memberGoods是一个普通的Object类型,对于下面的查询条件:

{
    "query":{
        "bool":{
            "must":[
                {
                    "match":{
                        "title":"商品A"
                    }
                },
                {
                    "match":{
                        "brand":"b"
                    }
                }
            ]
        }
    }
}

上面的数据依然会匹配上,但是商品A的品牌应该是a,而不是b呀,造成这种现象的原因是结构性的JSON文档会平整成索引内的一个简单键值格式,就像这样:

{
    "memberGoods.title":[
        "商品A",
        "商品B"
    ],
    "memberGoods.brand":[
        "a",
        "b"
    ],
    "groupId":"A"
}

显然,如上的数据损失了同一商品数据之间的关联性,从而出现了交叉匹配的现象,为解决这一问题,nested Object应运而生,它保留了子文档数据中的关联性,如果memberGoods的数据格式被定义为nested,那么每一个nested object 将会作为一个隐藏的单独文本建立索引。如下:

{
     "groupId":"A"
},
{
     "memberGoods.title":"商品A",
     "memberGoods.brand":"a"
},
{
     "memberGoods.title":"商品B",
     "memberGoods.brand":"b"
}

通过分开给每个nested object建索引,object内部的字段间的关系就能保持。当执行查询时,只会匹配’match’同时出现在相同的nested object的结果。

不仅如此,由于nested objects 建索引的方式,在查询的时候将根文本和nested文档拼接是很快的,就跟把他们当成一个单独的文本一样的快。

 

nested object作为一个独立隐藏文档单独建索引,因此,我们不能直接查询它们。取而代之,我们必须使用nested查询或者nested filter来接触它们,java语言描述如下:

 

               queryBuilder.must(QueryBuilders.nestedQuery("memberGoods"/** nested 字段*/,
                        QueryBuilders.matchPhraseQuery("memberGoods.title", "商品A"), ScoreMode.Avg));

 

其中memberGoods是父字段,memberGoods.title是子字段,以上已有提及,最后的参数ScoreMode.Avg是父文档匹配分数的设定,(Parent hit's score is the average/max/sum/min of all child scores.)

 

此外,nested形式的查询也有一些需要注意的缺点:

1.增加,改变或者删除一个nested文本,整个文本必须重新建索引。nested文本越多,代价越大。

2.检索请求会返回整个文本,而不仅是匹配的nested文本。尽管有计划正在执行以能够支持返回根文本的同时返回最匹配的nested文本,但目前还未实现。

 

--------------------------------------------

更多详细内容,请参考es官方文档:

https://www.elastic.co/guide/en/elasticsearch/guide/master/nested-objects.html

https://www.elastic.co/guide/en/elasticsearch/guide/master/index.html