java 在Double elasticSearch中按范围计数使用聚合的Sping Boot

6l7fqoea  于 2023-09-28  发布在  Java
关注(0)|答案(2)|浏览(120)

我正在尝试从ElasticSearch中计数特定范围内的记录。我有3个范围,代表不同的值在双。

low (0-4]
medium (4-7]
high (7-10]

这个物体就像

{

"company":"companyName", // string

"score": 6.2 // double

}

假设对于公司1,我想要获得得分值的所有计数。
返回一个像下面这样的对象{“high”:20,“medium”:10,“low”:3}
我找到了一种使用API的方法,

public interface ItemRepository extends ElasticsearchRepository<Item, String> {

    @Query("{\"bool\":{\"must\":[{\"match\":{\"userId\":100}},{\"range\":{\"score\":{\"gte\":?0,\"lt\":?1}}}]}}")
    long countByScoreRangeAndUserId(int lowerBound, int upperBound);
}

@Service
public class ItemService {

    @Autowired
    private ItemRepository itemRepository;

    public void getScoreCountRanges() {
        long range1Count = itemRepository.countByScoreRangeAndUserId(0, 40);
        long range2Count = itemRepository.countByScoreRangeAndUserId(40, 70);
        long range3Count = itemRepository.countByScoreRangeAndUserId(70, 101); // inclusive lower bound, exclusive upper bound
        System.out.println("Range 0-39 Count: " + range1Count);
        System.out.println("Range 40-69 Count: " + range2Count);
        System.out.println("Range 70-100 Count: " + range3Count);
    }
}

但我想这样做,在一个单一的滑动超过数据库,而不是计数在3次。哪条路更好更快
多谢

ddrv8njm

ddrv8njm1#

尝试使用NativeSearchQueryBuilder

@Service
public class ItemService {

@Autowired
private ElasticsearchOperations elasticsearchOperations;

public void getScoreCountRanges() {
    SearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.matchQuery("userId", 100))
            .addAggregation(AggregationBuilders.range("score_ranges")
                    .field("score")
                    .addUnboundedTo("low", 4)
                    .addRange("medium", 4, 7)
                    .addUnboundedFrom("high", 7)
            )
            .build();

    Aggregations aggregations = elasticsearchOperations.query(searchQuery, SearchResponse::getAggregations);
    Range rangeAggregation = aggregations.get("score_ranges");

    long lowCount = rangeAggregation.getBucketByKey("low").getDocCount();
    long mediumCount = rangeAggregation.getBucketByKey("medium").getDocCount();
    long highCount = rangeAggregation.getBucketByKey("high").getDocCount();

    System.out.println("Low Range Count: " + lowCount);
    System.out.println("Medium Range Count: " + mediumCount);
    System.out.println("High Range Count: " + highCount);
  }
}
krcsximq

krcsximq2#

我会用工作代码来回答这个问题,如果将来有人会发现它有用的话。

@Override
public Scores getScoreCountRanges() {
    Scores scores = new Scores();
    String aggregationName = "score_ranges";
    NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.matchQuery("userId", "DESIRED-USER-ID")
            .withAggregations(AggregationBuilders.range(aggregationName)
                    .field("scores")
                    .addRange(LOW, LOW_LOWER_BOUND,MEDIUM_LOWER_BOUND)    
                    .addRange(MEDIUM, MEDIUM_LOWER_BOUND, HIGH_LOWER_BOUND)   
                    .addRange(HIGH, HIGH_LOWER_BOUND, HIGH_UPPER_BOUND)  
            )
            .build();

    SearchHits<?> searchHits = operations.search(searchQuery, ClassOfData.class);
    if (!searchHits.hasAggregations())
        return scores;
    AggregationsContainer<?> aggregationsContainer = searchHits.getAggregations();
    if (aggregationsContainer == null) {
        return scores;
    }
    Aggregations aggregations = (Aggregations) aggregationsContainer.aggregations();
    ParsedRange rangeAggregation = aggregations.get(aggregationName);
    rangeAggregation.getBuckets().forEach(bucket -> fillScores(scores, bucket.getKey().toString(), bucket.getDocCount()));
    return scores;
}

这段代码将执行所谓的rangeAggregation,并将返回包含响应matchQuery的记录的桶,这些记录在您决定的范围内找到。
我们将使用该存储桶的文档计数来了解每个特定范围内有多少条记录符合条件。
你可以根据自己的意愿使用填充分数,或者做其他任何事情,返回一个包含键和值的map也是一个不错的选择。
希望对你有帮助。

相关问题