ElasticSearch 聚合分页查询实现方案

1 需求分析

最近接到需求,需要对聚合后的商铺信息进行分页查询,同时还要查询商铺下面的商品

大体结构如下

[{
    shop1:[
        {
            spuinfo1
        },
          {
            spuinfo2
        }
    ]
},
 {
    shop1:[
        {
            spuinfo1
        },
          {
            spuinfo2
        }
    ]
}   
]
​
​

这种结构可以通过es的Aggregation来实现,还要对结果进行排序及分页。我们需要返回的数据有:聚合后的数据总数,用于前端展示分页信息,以及分页查询的起始位置。

2 实现方案

结果总数可以通过 cardinality类似SQL中distinct某个字段后,再count,于是使用cardinality获取相关聚合结果的total:

用bucket_sort实现分页

在terms中使用bucket_sort功能的时候,terms中分组的size大小设置应该大于bucket_sort中的from+size的大小,否则会因为terms中size的大小限制了返回的数据。bucket_sort的sort排序是针对父聚合返回的结果进行排序的,比如上述terms返回的结果为1000条,那么bucket_sort仅对这1000条进行排序。

3 query 查询

GET /productinfos/_search
{
  "aggs": {
    "shoppes": {
      "terms": {
        "field": "shoppeId",
        "order": {
          "shoppe_sort": "desc"
        },
        "size": 4
      },
      "aggs": {
        "shop_sort": {
          "sum": {
            "field": "salecount"
          }
        },
        "shoppe_spu": {
          "order": {
            "max": "spuid"
          }
        },
        "shop_bucket": {
          "bucket_sort": {
            "from": 0,
            "size": 5,
            "gap_policy": "SKIP"
          }
        }
      }
    }
  },
  "size": 0
}

4 代码实现

Map<String, SortOrder> orderMap2 = new HashMap<>();
        orderMap2.put("salecount_sort",SortOrder.Desc);
        Aggregation salecount_sort = Aggregation.of(a -> a.max(v -> v.field(param.getOrder())));
​
        int bucketFrom = (param.getPageNum()-1)*param.getPageSize();
        int bucketSize = bucketFrom + param.getPageSize();
Aggregation shoppes = Aggregation.of(
        a -> a.terms(v -> v.field("shoppeId").size(bucketSize).order(orderMap))
                .aggregations("shop_sort", s -> param.getOrder().equals("salecount")? s.sum(v -> v.field(param.getOrder())):s.max(v -> v.field(param.getOrder())))
                .aggregations("shop_bucketSort", b ->b.bucketSort(s -> s.from(bucketFrom).size(param.getPageSize()).gapPolicy(GapPolicy.Skip)))
                .aggregations("shop_spu", b -> b.terms(v -> v.field("spuId").size(param.getSpuNum()).order(orderMap2))
                                .aggregations("salecount_sort",salecount_sort)));
Aggregation shoppeCount = Aggregation.of(c -> c.cardinality(v -> v.field(SearchParamConfig.SHOPPEID)));

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值