Skip to content

ElasticsearchRepository 查询时返回指定的字段

🏷️ Elasticsearch Spring Boot

索引中的字段太多,但是只需要其中的部分字段时,可以通过 ElasticsearchRepository 中的 Page<T> search(SearchQuery searchQuery); 方法配合 NativeSearchQueryBuilder 来实现。

通过 NativeSearchQueryBuilder.withFields 方法指定需要返回的字段,其定义如下:

java
public NativeSearchQueryBuilder withFields(String... fields) {
    this.fields = fields;
    return this;
}

查询示例:

java
SearchQuery searchQuery = new NativeSearchQueryBuilder()
    .withFilter(filterBuilder)
    .withQuery(queryBuilder)
    .withPageable(PageRequest.of(0, 1, Sort.by("createTime").descending()))
    .withFields("id", "novelIds", "position")
    .build();

Page<RecommendStrategyEo> page = this.recommendStrategyRepository.search(searchQuery);

附一下完整的示例代码。

  1. 添加 spring-boot-starter-data-elasticsearch 依赖

    xml
    <!-- ElasticSearch -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
        <version>2.2.13.RELEASE</version>
    </dependency>
  2. 添加配置

    yaml
    spring:
      elasticsearch:
        rest:
          uris: ["http://172.0.0.1:9200"]
          username: guest
          password: guest
  3. 定义索引模型

    使用 @Document 注解指定索引名。
    使用 @Id 注解标记索引主键字段。
    使用 @Field 注解指定字段的类型,如下面代码中的 @Field(type = FieldType.Date) 指定字段为日期型(否则默认是 long 型)。

    注意:

    应用启动时,若索引还未创建,默认会自动创建,此时索引的 mapping 中只有使用 @Field 注解指定了类型的字段,其它字段会在保存索引文档时自动创建。
    索引未创建时查询,若ES未开启查询时自动创建索引,则会报 index_not_found_exception 异常;若开启了查询时自动创建索引,则会自动创建索引(不太确定此时字段的类型是否和注解中一致,印象中是不一致的)。
    如果应用运行过程中删除了索引,此时往索引中添加数据时,其字段的类型和注解是不一致的。所以在应用运行过程中,最好不要删除索引。

    java
    import lombok.Data;
    import org.springframework.data.annotation.Id;
    import org.springframework.data.elasticsearch.annotations.Document;
    import org.springframework.data.elasticsearch.annotations.Field;
    import org.springframework.data.elasticsearch.annotations.FieldType;
    
    import java.util.Date;
    import java.util.List;
    
    @Data
    @Document(indexName = "recommend-strategy")
    public class RecommendStrategyEo {
    
        @Id
        private Integer id;
    
        private String appId;
    
        private Integer dimension;
    
        private Integer userSource;
    
        private Integer module;
    
        private Integer position;
    
        private Integer status;
    
        @Field(type = FieldType.Date)
        private Date createTime;
    
        @Field(type = FieldType.Date)
        private Date updateTime;
    
        private List<Integer> novelIds;
    
        private List<String> userCodes;
    }
  4. 创建一个继承自 ElasticsearchRepository 的接口,并添加 @Repository 注解

    ElasticsearchRepository 接口有两个泛型类型,第一个是索引对应的实体类型,第二是索引主键的类型。

    java
    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
    import org.springframework.stereotype.Repository;
    
    @Repository
    public interface RecommendStrategyRepository
        extends ElasticsearchRepository<RecommendStrategyEo, Integer> {
    
    }
  5. 查询示例

    java
    BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
    
    queryBuilder.should(
        QueryBuilders.boolQuery()
            .must(QueryBuilders.matchQuery("dimension", RecommendStrategyDimension.Customize.getValue()))
            .must(QueryBuilders.matchQuery("userCodes", userCode))
    );
    
    queryBuilder.should(
        QueryBuilders.boolQuery()
            .must(QueryBuilders.matchQuery("dimension", RecommendStrategyDimension.UserSource.getValue()))
            .must(QueryBuilders.matchQuery("userSource", userSource))
    );
    
    BoolQueryBuilder filterBuilder = QueryBuilders.boolQuery();
    filterBuilder.must(QueryBuilders.matchQuery("appId", appId));
    filterBuilder.must(QueryBuilders.matchQuery("module", module));
    
    SearchQuery searchQuery = new NativeSearchQueryBuilder()
        .withFilter(filterBuilder)
        .withQuery(queryBuilder)
        .withPageable(PageRequest.of(0, 1, Sort.by("createTime").descending()))
        .withFields("id", "novelIds", "position")
        .build();
    
    Page<RecommendStrategyEo> page = this.recommendStrategyRepository.search(searchQuery);
    if (page == null
            || page.getContent() == null
            || page.getContent().size() == 0) {
        return null;
    }
    
    RecommendStrategyEo eo = page.getContent().get(0);
    RecommendStrategyVo vo = new RecommendStrategyVo();
    vo.setNovelIds(eo.getNovelIds());
    vo.setPosition(eo.getPosition());
    return vo;