ElasticSearch入门及进阶实战(2) SpringBoot 整合 elasticsearch

 

Spring项目 提供SpringData子模块,为各种数据访问提供统一编程接口,包括关系数据库(Mysql)、非关系数据库(Redis)或者类似Elasticsearch这样的分布式索引数据库。从而简化代码开发,提高开发效率。

Spring Data Elasticsearch 基于Spring Data API简化elasticsearch操作,将elasticsearch原始客户端API进行封装。Spring Data Elasticsearch为elasticsearch项目提供集成搜索引擎,提供了Spring Data风格的操纵数据方式,避免大量样板代码。

常用注解说明

@Document

@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
//标示映射到Elasticsearch文档上的领域对象
public @interface Document {
    //索引库名===>关系数据库中数据库概念
    String indexName();
    //类型=====》关系数据库表的概念
    String type() default "";
    //创建索引是使用服务端设置-默认false
    boolean useServerConfiguration() default false;
    //分片数-默认5
    short shards() default 5;
    //副本数量-默认1
    short replicas() default 1;
    //刷新时间
    String refreshInterval() default "1s";
    //索引存储类型
    String indexStoreType() default "fs";
    //配置是否在存储库上创建索引
    boolean createIndex() default true;
    //版本管理配置
    VersionType versionType() default VersionType.EXTERNAL;
}

@Id

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
//Document中的id========>关系数据库表行的概念
public @interface Id {
}

@Field

@Field(type = FieldType.Keyword)
@Field(analyzer = "ik_max_word",type = FieldType.Text)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
@Documented
@Inherited
public @interface Field {
    //文章中字段类型
    FieldType type() default FieldType.Auto;
    //是否建立倒排索引
    boolean index() default true;

    DateFormat format() default DateFormat.none;

    String pattern() default "";
    //是否存储数据
    boolean store() default false;

    boolean fielddata() default false;

    String searchAnalyzer() default "";
    //分词器名次
    String analyzer() default "";

    String normalizer() default "";

    String[] ignoreFields() default {};

    boolean includeInParent() default false;

    String[] copyTo() default {};
}
@Field注解中为文章自动指定元数据类型
public enum FieldType {
    Text,//会进行分词并建了索引的字符类型
    Integer,
    Long,
    Date,
    Float,
    Double,
    Boolean,
    Object,
    Auto,//自动判断对象类型
    Nested,//嵌套对象类型
    Ip,
    Attachment,
    Keyword;//不会进行分词建立索引的类型

    private FieldType() {
    }
}

Spring Data风格的操作数据

1. 通过继承ElasticsearchRepository,来完成ES普通的CRUD和分页查询和普通JPA没什么区别

ElasticsearchRepository里有几个特殊的search方法,是ES独有的,是区别与其他普通JPA的地方,用来构建ES查询的。

<S extends T> S index(S var1);

Iterable<T> search(QueryBuilder var1);

Page<T> search(QueryBuilder var1, Pageable var2);

Page<T> search(SearchQuery var1);

Page<T> searchSimilar(T var1, String[] var2, Pageable var3);

void refresh();

Class<T> getEntityClass();

普通操作:

List<Order> findByNameAndPrice(String name, Integer price);  
  
List<Order> findByNameOrPrice(String name, Integer price);  
          
Page<Order> findByName(String name,Pageable page);  
  
Page<Order> findByNameNot(String name,Pageable page);  
  
Page<Order> findByPriceBetween(int price,Pageable page);  
  
Page<Order> findByNameLike(String name,Pageable page);  

//使用@query注解可以直接使用elasticsearch的DSL语句进行查询  
@Query("{\"bool\" : {\"must\" : {\"term\" : {\"message\" : \"?0\"}}}}")  
Page<Order> findByMessage(String message, Pageable pageable); 

//批量插入
List<order> orderList = orderDao.getAllOrderList(null);
Iterable<EsProduct> esProductIterable = orderRepository.saveAll(orderList);

从ElasticsearchRepository API中我们主要关注QueryBuilder 和SearchQuery 对象,要完成一些特殊查询就主要看这两个参数。

从接口关系图中可以看到SearchQuery是个接口,其实现类是NativeSearchQuery。实际使用中,我们主要是通过构建NativeSearchQuery来完成一些复杂查询。

从NativeSearchQuery源码查看,NativeSearchQuery构造函数主要需要两个参数:QueryBuilder 和 SortBuilder。

 public NativeSearchQuery(QueryBuilder query) {
        this.query = query;
    }

    public NativeSearchQuery(QueryBuilder query, QueryBuilder filter) {
        this.query = query;
        this.filter = filter;
    }

    public NativeSearchQuery(QueryBuilder query, QueryBuilder filter, List<SortBuilder> sorts) {
        this.query = query;
        this.filter = filter;
        this.sorts = sorts;
    }

    public NativeSearchQuery(QueryBuilder query, QueryBuilder filter, List<SortBuilder> sorts, Field[] highlightFields) {
        this.query = query;
        this.filter = filter;
        this.sorts = sorts;
        this.highlightFields = highlightFields;
    }

当然,实际使用过程基本不直接New NativeSearchQuery,而是通过NativeSearchQueryBuilder 的build方法来构建查询。

QueryBuilder 主要用来构建查询条件和过滤条件和 SortBuilder主要构建排序。我们可以通过NativeSearchQueryBuilder 来组合这些QueryBuilder和SortBuilder,在组合分页参数,最后得到一个SearchQuery。

NativeSearchQuery实现:

Pageable pageable = PageRequest.of(pageNum, pageSize);
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //分页
        nativeSearchQueryBuilder.withPageable(pageable);
        //过滤
        if (brandId != null || productCategoryId != null) {
            BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
            if (brandId != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery("brandId", brandId));
            }
            if (productCategoryId != null) {
                boolQueryBuilder.must(QueryBuilders.termQuery("productCategoryId", productCategoryId));
            }
            nativeSearchQueryBuilder.withFilter(boolQueryBuilder);
        }
        //搜索
        if (StringUtils.isEmpty(keyword)) {
            nativeSearchQueryBuilder.withQuery(QueryBuilders.matchAllQuery());
        } else {
            List<FunctionScoreQueryBuilder.FilterFunctionBuilder> filterFunctionBuilders = new ArrayList<>();
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("name", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(10)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("subTitle", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(5)));
            filterFunctionBuilders.add(new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.matchQuery("keywords", keyword),
                    ScoreFunctionBuilders.weightFactorFunction(2)));
            FunctionScoreQueryBuilder.FilterFunctionBuilder[] builders = new FunctionScoreQueryBuilder.FilterFunctionBuilder[filterFunctionBuilders.size()];
            filterFunctionBuilders.toArray(builders);
            FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(builders)
                    .scoreMode(FunctionScoreQuery.ScoreMode.SUM)
                    .setMinScore(2);
            nativeSearchQueryBuilder.withQuery(functionScoreQueryBuilder);
        }
        //排序
        if(sort==1){
            //按新品从新到旧
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("id").order(SortOrder.DESC));
        }else if(sort==2){
            //按销量从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("sale").order(SortOrder.DESC));
        }else if(sort==3){
            //按价格从低到高
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.ASC));
        }else if(sort==4){
            //按价格从高到低
            nativeSearchQueryBuilder.withSort(SortBuilders.fieldSort("price").order(SortOrder.DESC));
        }else{
            //按相关度
            nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        }
        nativeSearchQueryBuilder.withSort(SortBuilders.scoreSort().order(SortOrder.DESC));
        NativeSearchQuery searchQuery = nativeSearchQueryBuilder.build();
        LOGGER.info("DSL:{}", searchQuery.getQuery().toString());
        return productRepository.search(searchQuery);

ElasticsearchTemplate使用

ElasticsearchTemplate是ElasticsearchRepository的补充,提供更多底层操作方法。比如通过ElasticsearchRepository的saveAll方法能够实现批量插入,但是只支持小量数据查询,如果是超大数据插入就需要使用ES原生的API bulk 了,可以实现百万级数据迅速插入。

在ElasticsearchTemplate中提供了对应方法:

 

SpringBoot 整合 elasticsearch

1、在pom.xml中添加相关依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

2、修改SpringBoot配置文件,添加elasticsearch相关配置

data:
    elasticsearch:
      repositories:
        enabled: true
      cluster-nodes: 127.0.0.1:9300
      cluster-name: elasticsearch

3、构建Elasticsearch POJO,使用注解@Document创建ES 文章对象。

4、继承ElasticsearchRepository接口,同时添加自定义衍生查询,用于操作ES数据

5、创建Service实现ES操作

6、定义API

7、测试API

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章