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

大家在工作中想必也接触过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文本,但目前还未实现。

如果原来类型不是nested,可以使用elasticsearch动态模板设置字段类型nested

{
  "index_patterns": [
    "*"
  ],
  "order": 0,
  "version": 1,
  "mappings": {
    "dynamic_templates": [
      {
        "nested_fields": {
          "match": "*_nested",
          "mapping": {
            "type": "nested"
          }
        }
      }
    ]
  }
}

原文:https://www.cnblogs.com/just84/p/10936034.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现 Elasticsearch嵌套聚合查询,你可以使用 Elasticsearch 的 AggregationBuilders 类来创建嵌套聚合查询。具体实现步骤如下: 1. 创建一个嵌套聚合查询,用于组合多个子聚合查询。 2. 在嵌套聚合查询添加多个子聚合查询,分别对应不同的聚合方式。 3. 如果你需要对子聚合查询进行分组,可以在子聚合查询添加 terms 聚合查询。 4. 如果你需要对子聚合查询进行计数,可以在子聚合查询添加 count 聚合查询。 5. 执行查询并处理结果。 以下是一个示例 Java 代码,用于实现 Elasticsearch嵌套聚合查询: ``` SearchResponse response = client.prepareSearch("index_name") .addAggregation( AggregationBuilders.nested("nested_agg", "nested_field") .subAggregation(AggregationBuilders.terms("term_agg") .field("term_field")) .subAggregation(AggregationBuilders.count("count_agg") .field("count_field"))) .execute() .actionGet(); Nested nestedAgg = response.getAggregations().get("nested_agg"); Terms termAgg = nestedAgg.getAggregations().get("term_agg"); long totalCount = nestedAgg.getAggregations().get("count_agg").getDocCount(); ``` 其,"index_name" 是你要查询的索引名称,"nested_field" 是你要进行嵌套聚合查询的字段名称,"term_field" 和 "count_field" 分别是你要进行分组和计数的字段名称。你可以根据实际情况进行修改。执行完查询后,你可以从查询结果获取嵌套聚合对象,并进一步获取子聚合对象的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值