You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Elasticsearch RestHighLevelClient查询未取消成功交易的方案及效率问询

当然可以直接用Elasticsearch实现,效率还更高!

从你的交易数据和需求来看,你要的是那些交易ID不存在任何CANCELLED状态记录的SUCCESS交易(比如例子里的id=2的SUCCESS交易,而id=1的SUCCESS因为有对应的CANCELLED记录要被排除)。完全不需要先查两个列表再在客户端过滤——把逻辑推到Elasticsearch端处理,不管是性能还是代码简洁度都会更好。

为什么ES端方案效率更高?

你当前的客户端过滤方案有几个明显的性能瓶颈:

  • 需要传输所有SUCCESS和CANCELLED的交易数据到客户端,网络开销大
  • 客户端要在内存中存储两个完整列表,数据量越大内存压力越大
  • 循环过滤是单线程的本地计算,没法利用Elasticsearch的分布式并行处理能力

而ES端处理的话,会利用索引优化(比如status字段的倒排索引、id字段的聚合优化),分片并行计算,最后只返回符合条件的结果,整体效率提升非常明显。

具体实现方案

方案一:先聚合筛选有效ID,再查询对应SUCCESS交易

这种方案分两步,但都在ES端完成,逻辑清晰且高效:

  1. 第一步:聚合找出所有没有CANCELLED记录的交易ID
// 构建聚合请求:按id分组,过滤每个分组是否有CANCELLED记录
SearchSourceBuilder aggSource = new SearchSourceBuilder();
aggSource.aggregation(
    AggregationBuilders.terms("group_by_id")
        .field("id") // 按交易id分组
        .subAggregation(
            AggregationBuilders.filter("has_cancelled")
                .filter(QueryBuilders.matchQuery("status", "CANCELLED"))
        )
);

SearchRequest aggRequest = new SearchRequest("你的交易索引名");
aggRequest.source(aggSource);

// 执行聚合请求
SearchResponse aggResponse = restHighLevelClient.search(aggRequest, RequestOptions.DEFAULT);

// 解析聚合结果,收集没有CANCELLED记录的id
Terms groupByIdAgg = aggResponse.getAggregations().get("group_by_id");
List<String> validTradeIds = new ArrayList<>();
for (Terms.Bucket bucket : groupByIdAgg.getBuckets()) {
    Filter cancelledFilter = bucket.getAggregations().get("has_cancelled");
    if (cancelledFilter.getDocCount() == 0) {
        // 该id下没有任何CANCELLED交易,属于有效id
        validTradeIds.add(bucket.getKeyAsString());
    }
}
  1. 第二步:用有效ID查询SUCCESS交易
// 构建查询请求:只查有效id下的SUCCESS交易
SearchSourceBuilder querySource = new SearchSourceBuilder();
querySource.query(
    QueryBuilders.boolQuery()
        .must(QueryBuilders.matchQuery("status", "SUCCESS"))
        .must(QueryBuilders.termsQuery("id", validTradeIds))
);

SearchRequest queryRequest = new SearchRequest("你的交易索引名");
queryRequest.source(querySource);

// 执行查询并解析结果
SearchResponse queryResponse = restHighLevelClient.search(queryRequest, RequestOptions.DEFAULT);
// 这里解析queryResponse得到你需要的List<Trade>

方案二:用子查询直接排除已取消的ID(更简洁的单查询方案)

如果你想一步完成,可以结合子查询直接排除那些存在CANCELLED记录的ID:

// 先获取所有CANCELLED交易的id列表
SearchRequest cancelledIdsRequest = new SearchRequest("你的交易索引名");
cancelledIdsRequest.source(new SearchSourceBuilder()
    .query(QueryBuilders.matchQuery("status", "CANCELLED"))
    .fetchSource("id", null)); // 只返回id字段,减少数据传输

SearchResponse cancelledIdsResponse = restHighLevelClient.search(cancelledIdsRequest, RequestOptions.DEFAULT);
List<String> cancelledIds = Arrays.stream(cancelledIdsResponse.getHits().getHits())
    .map(hit -> hit.getSourceAsMap().get("id").toString())
    .collect(Collectors.toList());

// 构建主查询:SUCCESS交易,且id不在已取消的id列表中
BoolQueryBuilder finalQuery = QueryBuilders.boolQuery()
    .must(QueryBuilders.matchQuery("status", "SUCCESS"))
    .mustNot(QueryBuilders.termsQuery("id", cancelledIds));

SearchRequest finalRequest = new SearchRequest("你的交易索引名");
finalRequest.source(new SearchSourceBuilder().query(finalQuery));

SearchResponse finalResponse = restHighLevelClient.search(finalRequest, RequestOptions.DEFAULT);
// 解析结果得到目标交易列表

方案选择

如果你的交易数据量很大(比如百万级以上),方案一的聚合方式会更高效——因为ES的聚合是分布式并行处理的,比先查所有cancelled id再过滤的方式更优化。如果数据量不大,方案二的单查询写法更简洁。

不管选哪种,都比你当前的客户端过滤方案效率高得多。

内容的提问来源于stack exchange,提问作者Shashank Gandham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:19:38