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

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