【问题标题】:Get all different values for a certain field in elasticsearch with spring data使用弹簧数据获取弹性搜索中某个字段的所有不同值
【发布时间】:2025-12-13 03:35:01
【问题描述】:

我正在尝试使用 SpringData 在 ElasticSearch 中获取某个字段(例如“名称”)的所有不同值。

作为第一种方法,我有这个 JSON 可以满足我的要求:

{
    "aggs" : {
        "nameAgg" : {
            "terms" : { "field" : "name.key", "size":10000 }
        }
    },
    "size":0
}

如果我在索引上执行 GET,它会正常工作,检索如下数据:

"aggregations": {
        "nameAgg": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
                {
                    "key": "Paul",
                    "doc_count": 12
                },
                {
                    "key": "John",
                    "doc_count": 7
                }
]
}
}

由于我只需要该字段的所有不同值,这符合我的需要。 现在,我正在尝试使用 spring-data-elasticsearch 在 Java 中实现这一点。

我做过的最接近的尝试是这样的:

AbstractAggregationBuilder<TermsAggregationBuilder> agBuilder = AggregationBuilders.terms("name.key").field("name.key").size(10000);
    
Query query = new NativeSearchQueryBuilder().withQuery(QueryBuilders.matchAllQuery()).addAggregation(agBuilder).build();

但输出包含每个索引文档的所有数据,它与我的预期输出不匹配。 如何使用 spring-data-elasticsearch 执行这种类型的请求?

更新: 我试图为查询指定一个 Pageable 参数,就像这样:

AbstractAggregationBuilder<TermsAggregationBuilder> agBuilder = AggregationBuilders.terms("name.key").field("name.key");
    
    Query query = new NativeSearchQueryBuilder()   
        .withPageable(PageRequest.of(0, 0))
        .withQuery(QueryBuilders.matchAllQuery())
        .addAggregation(agBuilder).build();

但后来我收到了这个异常:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Page size must not be less than one!
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:497)
Caused by: java.lang.IllegalArgumentException: Page size must not be less than one!
    at org.springframework.data.domain.AbstractPageRequest.<init>(AbstractPageRequest.java:50)
    at org.springframework.data.domain.PageRequest.<init>(PageRequest.java:43)
    at org.springframework.data.domain.PageRequest.of(PageRequest.java:70)
    at org.springframework.data.domain.PageRequest.of(PageRequest.java:58)

【问题讨论】:

  • 您使用哪个版本的 Spring Data Elasticsearch?以及如何执行显示的Query
  • 我正在使用:版本 Spring Data Elasticsearch:4.0.3.RELEASE 版本 Elasticsearch 客户端:7.6.2

标签: elasticsearch spring-data spring-data-elasticsearch elasticsearch-aggregation


【解决方案1】:

我找到了解决办法。

如果你尝试使用大小为 0 的页面,spring data 会抛出异常,我做了一个解决方法,创建一个实现 Pageable 接口的类:

public class CustomBlankPage implements Pageable {
  
  public static final CustomBlankPage PAGE = new CustomBlankPage();

  @Override
  public int getPageNumber() {
    return 0;
  }

  @Override
  public int getPageSize() {
    return 0;
  }

  @Override
  public long getOffset() {
    return 0;
  }

  @Override
  public Sort getSort() {
    return null;
  }

  @Override
  public Pageable next() {
    return null;
  }

  @Override
  public Pageable previousOrFirst() {
    return null;
  }

  @Override
  public Pageable first() {
    return null;
  }

  @Override
  public boolean hasPrevious() {
    return false;
  }
}

搜索的实现如下:

AbstractAggregationBuilder<TermsAggregationBuilder> agBuilder = AggregationBuilders.terms("name.key").field("name.key").size(10000);
    
Query query = new NativeSearchQueryBuilder()   
        .withPageable(CustomBlankPage.PAGE)
        .withQuery(QueryBuilders.matchAllQuery())
        .addAggregation(agBuilder).build(); 

然后我探索使用此代码检索到的结果:

SearchHits<Person> hits = operations.search(query, Person.class);
Aggregations aggs = hits.getAggregations();
ParsedStringTerms namesTerm = (ParsedStringTerms) aggs.get("name.key");
List<String> keys = namesTerm.getBuckets()
      .stream()
      .map(b -> b.getKeyAsString())
      .collect(Collectors.toList());

【讨论】:

    【解决方案2】:

    您已在 JSON 中设置 size: 0,因此您需要在 spring:

    Query query = new NativeSearchQueryBuilder()   
                         .withPageable(PageRequest.of(0, 0)    //  <-- (page = 0, size = 0) <--
                         .withQuery(QueryBuilders.matchAllQuery())
                         .addAggregation(agBuilder).build();
    
    

    【讨论】:

    • 嗨乔。我以前试过,就像你说的那样。但后来我有一个弹簧数据异常:org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Page size must not be less than one! at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) at javax.servlet.http.HttpServlet.service(HttpServlet.java:497) 使用此信息更新的问题。
    【解决方案3】:

    NativeSearchQueryBuilder 有一个 withMaxResults(Integer) 方法,可以满足您的需求。

    【讨论】: