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)));

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Docker基于ElasticSearch全文搜索引擎的旅游景点搜索网设计 开发环境: Idea + Mysql + ubuntu + Docker + RabbitMQ + ElasticSearch + kibana 本项目主要是学习利用全文检索引擎框架ElasticSearch实现一个中文旅游网站搜索设计,通过建立一个hotel的索引库关联对应的mysql表数据,实现高效率的查询,解决了传统关系型数据因为数据量大导致的查询瓶颈问题。查询业务是crud中最复杂的业务,涉及到多种条件的组合,查询结果的分页和排序,搜索引擎查询结果的解析;根据查询条件的设置对结果某些信息字段进行聚合分析方便用户的筛选;还有就是试下用户输入查询拼音关键字也可以下拉自动补全功能,这就需要引入拼音分词器以及它和ik分词器的各种组合形成自定义的复合分词器。 项目实现的功能页面不多,主要包括前台用户查询酒店结果和后台管理员对酒店信息添加和维护。其中管理员对酒店维护的时候,因为修改了mysql数据库里面酒店的信息,这样就需要把酒店的最新信息同步到全文搜索引擎中,这里采用了RabbitMQ作为消息中间件实现了它们之间的解耦合。 -------- <项目介绍> 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 --------
实现 ES 聚合分页,可以使用 ElasticsearchJava API 来编写代码。下面是一个简单的示例: ```java import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.metrics.sum.Sum; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.transport.client.PreBuiltTransportClient; import java.net.InetAddress; import java.util.List; import java.util.Map; public class AggregationPaginationExample { public static void main(String[] args) throws Exception { TransportClient client = new PreBuiltTransportClient(Settings.EMPTY) .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName("localhost"), 9300)); int pageSize = 5; int pageNumber = 1; SearchResponse response = client.prepareSearch("my_index") .setQuery(QueryBuilders.matchAllQuery()) .addAggregation( AggregationBuilders.terms("my_terms_agg") .field("my_field") .subAggregation(AggregationBuilders.sum("my_sum_agg").field("my_other_field")) .order(Terms.Order.aggregation("my_sum_agg", false)) .size(pageSize) .from((pageNumber - 1) * pageSize) ) .setSize(0) .get(); Terms termsAgg = response.getAggregations().get("my_terms_agg"); for (Terms.Bucket bucket : termsAgg.getBuckets()) { String key = bucket.getKeyAsString(); long docCount = bucket.getDocCount(); Sum sumAgg = bucket.getAggregations().get("my_sum_agg"); double sumValue = sumAgg.getValue(); System.out.println(key + ": " + docCount + " documents, sum = " + sumValue); } client.close(); } } ``` 这个示例使用了 ElasticsearchJava API,查询一个名为 `my_index` 的索引,按照 `my_field` 字段进行分组,并计算每组中 `my_other_field` 字段的总和。然后按照总和排序,并使用分页参数进行分页。最后打印出每个分组的结果。 需要注意的是,聚合分页实现方式与普通的分页略有不同,具体可以参考上面的代码示例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值