欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringBoot使用Elasticsearch高级查询

程序员文章站 2022-07-05 14:40:05
...

前言:本文为原创 若有错误欢迎评论!

一.基本整合与操作

1.依赖:

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-elasticsearch</artifactId>
    <version>3.1.2.RELEASE</version>
</dependency>

2.配置文件

spring:   
    data:     
        elasticsearch:       
            cluster-name: elasticsearch       
            cluster-nodes: 192.168.56.101:9300

3.新建es的实体类

  1. @Document:作用在类,标记实体类为文档对象

四个属性
indexName:对应索引库名称
type:对应在索引库中的类型
shards:分片数量,默认5
replicas:副本数量,默认1

  1. @Id: 作用在成员变量,标记一个字段作为id主键

  2. @Filed: 作用在成员变量,标记为文档的字段

字段映射属性
type:字段类型,取值是枚举:FieldType.?
index:是否索引,布尔类型,默认是true
store:是否存储,布尔类型,默认是false
analyzer:分词器名称:ik_max_word

示例

  @Document(indexName = "item",type = "test", shards = 1, replicas = 0)
  public class Item {
    @Id
    private Long id;

    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String title; //标题
    
    @Field(type = FieldType.Keyword)
    private String category;// 分类

    @Field(type = FieldType.Keyword)
    private String brand; // 品牌

    @Field(type = FieldType.Double)
    private Double price; // 价格

    @Field(index = false, type = FieldType.Keyword)
    private String images; // 图片地址
 }

4.Spring Data Elasticsearch基本操作
( 注入ElasticsearchTemplate进行使用)

创建索引

// 创建索引,会根据Item类的@Document注解信息来创建
elasticsearchTemplate.createIndex(Item.class);

创建映射

//配置映射,会根据Item类中的id、Field等字段来自动完成映射
elasticsearchTemplate.putMapping(Item.class);

删除索引

elasticsearchTemplate.deleteIndex(“heima”);

二.Spring Data Elasticsearch的文档操作(即crud)

  • 先完成五的全部操作 并建好索引库和类型

1.准备工作

  1. 新建一个interface 然后extends ElasticsearchRepository

public interface ItemRepository extends ElasticsearchRepository<Item,Long> { }

  1. 新建一个类 并注入刚才那个接口

@Autowired private
ItemRepository itemRepository;

2.基本操作

  1. 新增文档
Item item = new Item(1L, "小米手机7", " 手机","小米", 3499.00, "test.png")
    itemRepository.save(item);
  1. 批量新增
	List<Item> list = new ArrayList<>();
    list.add(new Item(2L, "坚果手机R1", " 手机", "锤子", 3699.00, "test.png")
    list.add(new Item(3L, "华为META10", " 手机", "华为", 4499.00, "test.png")

           // 接收对象集合,实现批量新增
    itemRepository.saveAll(list);
  1. 修改文档
    //修改和新增是同一个接口,区分的依据就是id,这一点跟我们在页面发起PUT请求是类似的
    itemRepository.save(item);
  1. 基本查询
  • 根据id查询
   Optional<Item> optional = this.itemRepository.findById(1l);
   Item item=optional.get();
  • 查询全部并排序
   Iterable<Item> items =itemRepository.findAll(Sort.by(Sort.Direction.DESC, "price"));
   items.forEach(item-> System.out.println(item));
  • 根据自动生成的每个字段的查询方法
    类似mybatis的**** 生成entity每个字段的各种查询方法
 List<Item> list = itemRepository.findByPriceBetween(2000.00, 3500.00);

三.高级查询(QueryBuilders)

  • QueryBuilders:
    Repository的search方法需要QueryBuilder参数,通过QueryBuilders的静态方法可获得多个不同QueryBuilder对象 如MatchQueryBuilder、TermQueryBulider等)

//如:词条查询:
MatchQueryBuilder queryBuilder = QueryBuilders.matchQuery(“title”, “小米”);
//执行查询
Iterable items = this.itemRepository.search(queryBuilder);
items.forEach(System.out::println);

四.高级查询(NativeSearchQueryBuilder 最常用查询)

  • NativeSearchQueryBuilder:Spring提供的一个查询条件构建器,帮助构建json格式的请求体

1.自定义查询

	 // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

    // 添加基本的分词查询
    queryBuilder.withQuery(QueryBuilders.matchQuery("title", "小米"));

    // 执行搜索,获取结果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
        
            Page<item> :默认是分页查询,因此返回的是一个分页的结果对象
                常用属性:
                page.getTotalElements():总条数 
                page.getTotalPages():总页数 
                page.getSize():每页文档大小(每页文档数量)
                page.getNumber():当前第几页
                page.forEach():page实现了Iterator可以直接用forEach遍历每条数据
                page.iterator():返回迭代器,不常用 因为Page本身实现了Iterator接口

2.分页查询(Elasticsearch中的分页是从第0页开始)

    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

    // 添加基本的分词查询
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
    // 初始化分页参数
    int page = 0;
    int size = 3;
    // 设置分页参数
    queryBuilder.withPageable(PageRequest.of(page, size));

    //执行查询
    Page<Item> items = this.itemRepository.search(queryBuilder.build());
    items.forEach(System.out::println);

3.排序

    // 构建查询条件
    NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

    // 添加基本的分词查询
    queryBuilder.withQuery(QueryBuilders.termQuery("category", "手机"));
    // 排序
    queryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));

    // 执行搜索,获取结果
    Page<Item> items = this.itemRepository.search(queryBuilder.build());

4.聚合(不增加其他任何查询)

	NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

    // 不查询任何结果(因为没有size所以操作sourceFilter 但是include和exclude不可以同时使用 若同时为null无法设置展示字段 所以要想一个字段都没有必须include为new string[]{""} exclude为null)
    queryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{""}, null));

    // 1、添加一个新的聚合,聚合类型为terms,聚合名称为brands,聚合字段为brand
    queryBuilder.addAggregation(
        AggregationBuilders.terms("brands").field("brand")
        // 在品牌聚合桶内通过" . "进行连续调用嵌套聚合,求平均值
        .subAggregation(AggregationBuilders.avg("priceAvg").field("price"))
    );

    // 2、查询,需要把结果强转为AggregatedPage类型
    AggregatedPage<Item> aggPage = (AggregatedPage<Item>)this.itemRepository.search(queryBuilder.build());

    // 3、解析
    // 3.1、从结果中取出名为brands的那个聚合,
    // 因为是利用String类型字段来进行的term聚合,所以结果要强转为StringTerm类型
    StringTerms agg = (StringTerms) aggPage.getAggregation("brands");
    // 3.2、获取桶
    List<StringTerms.Bucket> buckets = agg.getBuckets();

    // 3.3、遍历
    for (StringTerms.Bucket bucket : buckets) {
        // 3.4、获取桶中的key,即品牌名称 3.5、获取桶中的文档数量
        System.out.println(bucket.getKeyAsString() + ",共" + bucket.getDocCount() + "台");

        // 3.6.获取子聚合结果:
        InternalAvg avg = (InternalAvg) bucket.getAggregations().asMap().get("priceAvg");
        System.out.println("平均售价:" + avg.getValue());
    }

聚合查询小结:

    AggregationBuilders:聚合工厂
    常用静态方法:
       桶:
            terms、dateHistogram、histogram
        度量:
            avg、max、min、stats
        AggregatedPage :聚合查询的结果类( Page<T> 的子接口)
        包装的方法:
            bool hasAggregations():判断查询结果是否有聚合
            Aggregations getAggregations():把所有聚合变成map 对应的key是聚合的名称(用于度量类型这种聚合里面没有多个子类 只有一个value)
            Aggregations getAggregation(String name):根据指定聚合名称获取聚合

    返回的Aggregation类型对象:
        不同对象
              由terms聚合:
                InternalTerms(由字段聚合就有三种key的类型):LongTerms、StringTerms、DoubleTerms
              由histogram聚合
                InternalHistogram(由数值分段 只有一种key的类型)
              由dateHistogram聚合
                InternalDateHistogram(由日期分段聚合 也只有一种key的类型)
        方法
            .getKeyAsString():获取key的值
            .getDocCount():获得doc的个数
            .getAggregations():获得所有集合的map形式(和".asMap().get(String name)"连续调用可以获得度量聚合的"Internal"对象)
            .getAggregation(Stirng name):通过名字获得聚合