Spring Boot 2.x实战75 - Spring Data 19 - Spring Data Elasticsearch的search查询(SearchQuery)与统计分析

3.6.2 search查询

ElasticsearchRepository除了给我们提供了CRUD和分页排序功能以外,还给我们提供了支持Elasticsearch API的search方法:

@NoRepositoryBean
public interface ElasticsearchRepository<T, ID> extends ElasticsearchCrudRepository<T, ID> {
	 //...
   Iterable<T> search(QueryBuilder query);

   Page<T> search(QueryBuilder query, Pageable pageable);

   Page<T> search(SearchQuery searchQuery);
	 //...
}

org.springframework.data.elasticsearch.core.query.SearchQuery可使用org.elasticsearch.index.query.QueryBuilder构造查询条件,所以三个search方法是类似的。如下面的验证代码:

@Bean
CommandLineRunner queryBuilderAndSearchQuery(PersonRepository personRepository){
   return args -> {
      QueryBuilder queryBuilder = QueryBuilders.matchAllQuery(); //1
      
      SearchQuery searchQuery = new NativeSearchQueryBuilder() //2
            .withQuery(queryBuilder) // 3
            .withPageable(PageRequest.of(0, 3, Sort.by("age"))) //4
            .build(); //5
     
      Page<Person> personPage1 = personRepository.search(queryBuilder, PageRequest.of(0, 3, Sort.by("age"))); //6
      Page<Person> personPage2 = personRepository.search(searchQuery); //7
			System.out.println("personPage1总数为: " + personPage1.getTotalElements()
					+ " 总页数为:" + personPage1.getTotalPages());
			personPage1.forEach(System.out::println);
			System.out.println("personPage2总数为: " + personPage2.getTotalElements()
					+ " 总页数为:" + personPage2.getTotalPages());
			personPage2.forEach(System.out::println);
   };
}
  1. QueryBuilders有大量的静态方法构造QueryBuilder

    • matchAllQuery():查询所有的数据,返回值是QueryBuilder的子类MatchAllQueryBuilder
    • matchQuery(String name, Object text):匹配属性值,返回值是QueryBuilder的子类MatchQueryBuilder
    • fuzzyQuery(String name, String value):模糊匹配属性值,返回值是QueryBuilder的子类FuzzyQueryBuilder
    • rangeQuery(String name):范围查询,返回值是QueryBuilder的子类RangeQueryBuilder
  2. 通过NativeSearchQueryBuilder构造SearchQuery

  3. 使用withQuery(QueryBuilder queryBuilder),通过QueryBuilder设置查询;

  4. 设置分页和排序信息;

  5. 建造SearchQuery;

  6. 使用Page<T> search(QueryBuilder query, Pageable pageable)方法查询;

  7. 使用Page<T> search(SearchQuery searchQuery)方法查询,两次查询的结果是一致的。
    在这里插入图片描述
    使用SearchQuery更友好易读性更强,我们再演示几个查询的例子:

@Bean
CommandLineRunner search(PersonRepository personRepository){
   return args -> {
      SearchQuery queryByAgeRangeAndNameRegex = new NativeSearchQueryBuilder()
            .withQuery(rangeQuery("age").from(30).to(35)) // 1
            .withFilter(matchQuery("name", "wyf")) // 2
            .build();

      SearchQuery fuzzyQuery = new NativeSearchQueryBuilder()
            .withQuery(fuzzyQuery("address.city", "shang").fuzziness(Fuzziness.AUTO)) //3
            .build(); 

      SearchQuery anotherFuzzyQuery = new NativeSearchQueryBuilder()
            .withQuery(matchQuery("address.city", "jing") 
                       .fuzziness(Fuzziness.AUTO))//4
            .build();


      Page<Person> personPage1 = personRepository.search(queryByAgeRangeAndNameRegex);
      Page<Person> personPage2 = personRepository.search(fuzzyQuery);
      Page<Person> personPage3 = personRepository.search(anotherFuzzyQuery);

      personPage1.forEach(System.out::println);
      System.out.println("--------------");
      personPage2.forEach(System.out::println);
      System.out.println("--------------");
      personPage3.forEach(System.out::println);
      System.out.println("--------------");

   };
}
  1. 构造范围查询,formtoRangeQueryBuilder的方法;
  2. withFilter(QueryBuilder filterBuilder)的入参也为QueryBuilder
  3. 构造模糊查询,fuzzinessFuzzyQueryBuilder的方法;
  4. 使用匹配查询构造模糊查询,fuzzinessMatchQueryBuilder的方法。
    在这里插入图片描述
3.6.3 统计查询

我们还可以使用SearchQuery构造聚合查询统计,如总数、最大值、最小值、平均值、统计信息等;我们需要通过ElasticsearchOperations(由AbstractElasticsearchConfiguration提供的Bean)来执行查询统计。

@Bean
CommandLineRunner aggregateQuery(ElasticsearchOperations elasticsearchOperations){

   return args -> {

      SearchQuery aggregateQuery = new NativeSearchQueryBuilder().withIndices("person") //1
            .addAggregation(AggregationBuilders.sum("sumAge").field("age")) //2
            .addAggregation(AggregationBuilders.max("maxAge").field("age")) 
            .addAggregation(AggregationBuilders.min("minAge").field("age")) 
            .addAggregation(AggregationBuilders.count("countAge").field("age")) 
            .addAggregation(AggregationBuilders.avg("avgAge").field("age")) 
            .addAggregation(AggregationBuilders.stats("ageInfo").field("age")) //3
            .addAggregation(AggregationBuilders.range("ageRange")
                                             .field("age")
                                             .addRange(30,35)) //4
            .addAggregation(AggregationBuilders.filter("leftPerson",
                                           rangeQuery("age").from(30).to(35))
                                        	.subAggregation(AggregationBuilders.sum("leftSum").field("age"))) //5
            .build();

      Aggregations aggs = elasticsearchOperations.query(aggregateQuery, searchResponse -> {
         Aggregations aggregations = searchResponse.getAggregations();
         return aggregations;
      }); //6

      double sum = ((ParsedSum)aggs.get("sumAge")).getValue(); //7
      System.out.println("sum age is " + sum);
      double max = ((ParsedMax)aggs.get("maxAge")).getValue();
      System.out.println("max age is " + max);
      double min = ((ParsedMin)aggs.get("minAge")).getValue();
      System.out.println("min age is " + min);
      double count = ((ParsedValueCount)aggs.get("countAge")).getValue();
      System.out.println("count is " + count);
      double avg = ((ParsedAvg)aggs.get("avgAge")).getValue();
      System.out.println("avg age is " + avg);

      ParsedStats stats = ((ParsedStats)aggs.get("ageInfo")); //8
      System.out.println("stats sum age is " + stats.getSumAsString());
      System.out.println("stats max age is " + stats.getMaxAsString());
      System.out.println("stats min age is " + stats.getMinAsString());
      System.out.println("stats avg age is " + stats.getAvgAsString());
      System.out.println("stats count is " + stats.getCount());

      ((ParsedRange)aggs.get("ageRange")).getBuckets().forEach(bucket -> { //9
         System.out.println(bucket.getFromAsString()
                        + "到" + bucket.getToAsString()
                          + "数量为: " + bucket.getDocCount());
      });

			Aggregations filterAggs = ((ParsedFilter)aggs.get("leftPerson")).getAggregations();//10
			double leftSum = ((ParsedSum)filterAggs.get("leftSum")).getValue();
			System.out.println("left sum is " + leftSum);
   };
}
  1. 通过withIndices方法指定索引名称,若不调用此方法会统计整个Elasticsearch所有属性为age的索引。

  2. 通过addAggregation添加聚合统计;使用AggregationBuilders的静态方法来构造聚合统计,如sum()max()min()avg()count()等;静态方法接受的参数是聚合统计的名称;通过field方法设置需要统计的属性。

  3. 构造统计查询,stats()方法包含的信息有sum、max、min、avg、count;

  4. 使用range()构造范围统计;

  5. 先用filter方法过滤人员,再通过subAggregation构造子聚合来统计剩下来的人员的岁数总和;

  6. 通过ElasticsearchOperationsquery(SearchQuery query, ResultsExtractor<T> resultsExtractor)方法执行查询,聚合是通过ResultsExtractor函数接口获得:

    public interface ResultsExtractor<T> {
       T extract(SearchResponse response);
    }
    
  7. 不同的聚合有不同的类型,可用Aggregationsget("聚合名称")来获得聚合并强制转换成ParsedSumParsedMaxParsedMinParsedValueCountParsedAvg等,再使用用getValue()方法获取实际的值。

  8. ParsedStats包含了sum、max、min、avg、count;

  9. ParsedRange可通过BucketgetDocCount()方法获得符合范围的数量;

  10. 我们可以从ParsedFilter聚合里获得它的子聚合ParsedSum

新书推荐:

我的新书《从企业级开发到云原生微服务:Spring Boot 实战》已出版,内容涵盖了丰富Spring Boot开发的相关知识
购买地址:https://item.jd.com/12760084.html
在这里插入图片描述
主要包含目录有:

第一章 初识Spring Boot(快速领略Spring Boot的美丽)
第二章 开发必备工具(对常用开发工具进行介绍:包含IntelliJ IDEA、Gradle、Lombok、Docker等)
第三章 函数式编程
第四章 Spring 5.x基础(以Spring 5.2.x为基础)
第五章 深入Spring Boot(以Spring Boot 2.2.x为基础)
第六章 Spring Web MVC
第七章 数据访问(包含Spring Data JPA、Spring Data Elasticsearch和数据缓存)
第八章 安全控制(包含Spring Security和OAuth2)
第九章 响应式编程(包含Project Reactor、Spring WebFlux、Reactive NoSQL、R2DBC、Reactive Spring Security)
第十章 事件驱动(包含JMS、RabbitMQ、Kafka、Websocket、RSocket)
第11章 系统集成和批处理(包含Spring Integration和Spring Batch)
第12章 Spring Cloud与微服务
第13章 Kubernetes与微服务(包含Kubernetes、Helm、Jenkins、Istio)
多谢大家支持。

猜你喜欢

转载自blog.csdn.net/wiselyman/article/details/106759469
今日推荐