目录

JPA编程,去重查询ES索引中的字段,对已有数据的去重过滤,而非全部字典数据

JPA编程,去重查询ES索引中的字段,对已有数据的去重过滤,而非全部字典数据

一、背景

课程管理界面,查询前,需要把查询元数据给出。 学科列表、学段列表和分类列表,我们把它定义为查询元数据。 https://i-blog.csdnimg.cn/direct/0f9f5873d86840f9a5e3595d950a2569.png 一般的业务需求是: 系统维护好多个字典,比如学科、学段等等,相当于属性库。 但是,这有一个不友好的地方,字典列表数据过多,比如学段字典包括了幼儿园和大学等,而实际上,课程只有初中或高中,连小学学段也没有。 这样展示的学段列表,就显得数据冗余,增加选择的干扰。 修改后的需求: 基于已有课程的属性,进行去重查询出学科列表等数据,也即上文提到的查询元数据。(已非原始字典) 比如说,我创建了一个课程,它是数学科目,初中学段,那么查询列表中的学科列表就只有数学一个值,学段列表只有初中一个值。 后期创建了一个化学科目的高中课程,此时学科列表就有数学和化学两个学科,学段包括初中和高中。

二、es索引

@Data @Document(indexName = “#{commonConfig.courseIdx}”, type = “_doc”, shards = 1, refreshInterval = “-1”) public class CourseIndex implements Serializable { @Id private String id; /**

  • 课程编号 / @Field(type = FieldType.Keyword) private String courseNo; /*
  • 创建者ID / @Field(type = FieldType.Long) private long creatorId; /*
  • 课程名称 / @Field(type = FieldType.Text) private String name; /*
  • 科目 / @Field(type = FieldType.Integer) private int subject; /*
  • 学段 */ @Field(type = FieldType.Integer) private int stage; }

三、es聚合查询

import lombok.RequiredArgsConstructor; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.Aggregation; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.List; @Component @RequiredArgsConstructor public class CourseIndexAggrService { private final ElasticsearchRestTemplate elasticsearchRestTemplate; private static final String UNIQUE_FIELD = “unique_field”; public static final String SUBJECT = “subject”; public static final String STAGE = “stage”; public List findUniqueField(String uniqueField) { NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder(); BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); boolQueryBuilder.filter(QueryBuilders.termQuery(“deleted”, LogicDeleteEnum.OK.ordinal())); queryBuilder.withQuery(boolQueryBuilder); TermsAggregationBuilder termsAgg = AggregationBuilders.terms(UNIQUE_FIELD).field(uniqueField); queryBuilder.addAggregation(termsAgg); queryBuilder.withIndices(“course_index”); AggregatedPage resultPage = elasticsearchRestTemplate.queryForPage(queryBuilder.build(), CourseIndex.class); Aggregation aggregation = resultPage.getAggregation(UNIQUE_FIELD); ParsedLongTerms terms = (ParsedLongTerms) aggregation; // 获取桶 final List extends Terms.Bucket buckets = terms.getBuckets(); // 提取唯一值 List uniqueUserIds = new ArrayList<>(); for (Terms.Bucket bucket : buckets) { uniqueUserIds.add(bucket.getKeyAsString()); } return uniqueUserIds; } }

四、调用示例

// 科目列表 final List subjects = courseIndexAggrService.findUniqueField(SUBJECT).stream().map(v -> Integer.parseInt(v)).collect(Collectors.toList()); // 学段列表 final List stages = courseIndexAggrService.findUniqueField(STAGE).stream().map(v -> Integer.parseInt(v)).collect(Collectors.toList());