ElasticSearch與SpringBoot集成-ElasticsearchRestTemplate


1. 簡介

  SpringBoot提供了與ElasticSearch的集成的starter包,並封裝了ElasticsearchRestTemplate類,還實現了與Java對象與ElasticSearch索引的映射關系,可以采用與JPA相似的Repository接口,來操作ES數據。

  需要使用maven引用以下依賴:

     <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.elasticsearch.client</groupId>
                    <artifactId>transport</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.elasticsearch.client</groupId>
                    <artifactId>elasticsearch-rest-high-level-client</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>6.5.0</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>6.5.0</version>
        </dependency>

  注意:以上的依賴版本可以根據你使用的ES的版本來定。比如我當前的ElasticSearch的版本是6.5.0,就需要手動替換成6.5.0版本的jar包。

 

2. 配置文件

2.1 application.yml

  在SpringBoot項目中application.yml文件中增加以下配置:

spring:
  elasticsearch:
    rest:
      uris: http://192.168.220.11:9200   ---ES的連接地址,多個地址用逗號分隔
      username:                          ---用戶名
      password:                          ---密碼
      connection-timeout: 1000           ---連接超時時間
      read-timeout: 1000                 ---讀取超時時間

 

2.2 創建映射對象

  我這里定義了一個員工類,並使用@Document定義員工類關聯的index索引、typeso因類型,shards主分區,replicas副分區。

  在@Document中有個屬性是createIndex,表示當索引不存在時,操作這個對象會默認創建索引,默認為true。如果你的索引設置比較多,就把createIndex設置為false,再通過其他接口手動觸發創建索引操作。

  @Id 表示索引的主鍵

  @Field 用來描述字段的ES數據類型,是否分詞等配置,等於Mapping描述

/**
 * 員工對象
 * <p>
 * 注解:@Document用來聲明Java對象與ElasticSearch索引的關系
 * indexName 索引名稱
 * type      索引類型
 * shards    主分區數量,默認5
 * replicas  副本分區數量,默認1
 * createIndex 索引不存在時,是否自動創建索引,默認true*/
@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@Document(indexName = "employee_index", type = "employee_type", shards = 1, replicas = 0,createIndex = true)
public class EmployeeBean {

    @Id
    private String id;

    /**
     * 員工編碼
     */
    @Field(type = FieldType.Keyword)
    private String studentCode;

    /**
     * 員工姓名
     */
    @Field(type = FieldType.Keyword)
    private String name;

    /**
     * 員工簡歷
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String desc;

    /**
     * 員工住址
     */
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private Integer type;

    /**
     * 手機號碼
     */
    @Field(type = FieldType.Keyword)
    private String mobile;

}

 

2.3 創建Repository接口

  Repository需要繼承ElasticsearchRepository接口,參數<映射對象,主鍵ID的數據類型>。之后Repository類就可以使用類似JPA的方法操作ElasticSearch數據。

@Component
public interface EmployeeRepository extends ElasticsearchRepository<EmployeeBean, String> {


}

  我們在操作索引和數據時,需要引用這2個類

    @Autowired
    private ElasticsearchRestTemplate restTemplate;
    @Autowired
    private EmployeeRepository repository;

 

3. 索引操作

3.1 判斷索引是否存在

    /**
     * 判斷索引是否存在
     * @return boolean
     */
    public boolean indexExists() {
        return restTemplate.indexExists(EmployeeBean.class);
    }

    /**
     * 判斷索引是否存在
     * @param indexName 索引名稱
     * @return boolean
     */
    public boolean indexExists(String indexName) {
        return restTemplate.indexExists(indexName);
    }

 

3.2 創建索引

    /**
     * 創建索引(推薦使用:因為Java對象已經通過注解描述了Setting和Mapping)
     * @return boolean
     */
    public boolean indexCreate() {
        return restTemplate.createIndex(EmployeeBean.class);
    }

    /**
     * 創建索引
     * @param indexName 索引名稱
     * @return boolean
     */
    public boolean indexCreate(String indexName) {
        return restTemplate.createIndex(indexName);
    }

 

 3.3 刪除索引

    /**
     * 索引刪除
     * @param indexName 索引名稱
     * @return boolean
     */
    public boolean indexDelete(String indexName) {
        return restTemplate.deleteIndex(indexName);
    }

 

4. 數據操作

4.1 新增數據

    /**
     * 新增數據
     * @param bean 數據對象
     */
    public void save(EmployeeBean bean) {
        repository.save(bean);
    }

    /**
     * 批量新增數據
     * @param list 數據集合
     */
    public void saveAll(List<EmployeeBean> list) {
        repository.saveAll(list);
    }

 

4.2 修改數據

    /**
     * 修改數據
     * @param indexName 索引名稱
     * @param type      索引類型
     * @param bean 修改數據對象,ID不能為空
     */
    public void update(String indexName, String type, EmployeeBean bean) {
        UpdateRequest updateRequest = new UpdateRequest();
        updateRequest.retryOnConflict(1);//沖突重試
        updateRequest.doc(JSONUtil.toJsonStr(bean), XContentType.JSON);
        updateRequest.routing(bean.getId());//默認是_id來路由的,用來路由到不同的shard,會對這個值做hash,然后映射到shard。所以分片
        UpdateQuery query = new UpdateQueryBuilder().withIndexName(indexName).withType(type).withId(bean.getId())
                .withDoUpsert(true)//不加默認false。true表示更新時不存在就插入
                .withClass(EmployeeBean.class).withUpdateRequest(updateRequest).build();
        UpdateResponse updateResponse = restTemplate.update(query);
    }

 

4.3 刪除數據

    /**
     * 根據ID,刪除數據
     * @param id 數據ID
     */public void deleteById(String id) {
        repository.deleteById(id);
    }

    /**
     * 根據對象刪除數據,主鍵ID不能為空
     * @param bean 對象
     */public void deleteByBean(EmployeeBean bean) {
        repository.delete(bean);
    }

    /**
     * 根據對象集合,批量刪除
     * @param beanList 對象集合
     */public void deleteAll(List<EmployeeBean> beanList) {
        repository.deleteAll(beanList);
    }

    /**
     * 刪除所有
     */public void deleteAll() {
        repository.deleteAll();
    }
    
    /**
     * 根據條件,自定義刪除(在setQuery中的條件,可以根據需求自由拼接各種參數,與查詢方法一樣)
     * @param indexName 索引
     * @param type      索引類型
     */public void delete(String indexName, String type) {
        DeleteQuery deleteQuery = new DeleteQuery();
        deleteQuery.setIndex(indexName);
        deleteQuery.setType(type);//建index沒配置就是類名全小寫
        deleteQuery.setQuery(new BoolQueryBuilder().must(QueryBuilders.termQuery("mobile","13526568454")));
        restTemplate.delete(deleteQuery);
    }

 

4.4 批量操作

    /**
     * 批量新增
     * @param indexName  索引名稱
     * @param type       索引類型
     * @param beanList 新增對象集合
     */public void batchSave(String indexName, String type, List<EmployeeBean> beanList) {
        List<IndexQuery> queries = new ArrayList<>();
        IndexQuery indexQuery;
        int counter = 0;
        for (EmployeeBean item : beanList) {
            indexQuery = new IndexQuery();
            indexQuery.setId(item.getId());
            indexQuery.setSource(JSONUtil.toJsonStr(item));
            indexQuery.setIndexName(indexName);
            indexQuery.setType(type);
            queries.add(indexQuery);
            //分批提交索引
            if (counter != 0 && counter % 1000 == 0) {
                restTemplate.bulkIndex(queries);
                queries.clear();
                System.out.println("bulkIndex counter : " + counter);
            }
            counter++;
        }
        //不足批的索引最后不要忘記提交
        if (queries.size() > 0) {
            restTemplate.bulkIndex(queries);
        }
        restTemplate.refresh(indexName);
    }

    /**
     * 批量修改
     * @param indexName 索引名稱
     * @param type      索引類型
     * @param beanList 修改對象集合
     */public void batchUpdate(String indexName, String type, List<EmployeeBean> beanList) {
        List<UpdateQuery> queries = new ArrayList<>();
        UpdateQuery updateQuery;
        UpdateRequest updateRequest;
        int counter = 0;
        for (EmployeeBean item : beanList) {
            updateRequest = new UpdateRequest();
            updateRequest.retryOnConflict(1);//沖突重試
            updateRequest.doc(item);
            updateRequest.routing(item.getId());

            updateQuery = new UpdateQuery();
            updateQuery.setId(item.getId());
            updateQuery.setDoUpsert(true);
            updateQuery.setUpdateRequest(updateRequest);
            updateQuery.setIndexName(indexName);
            updateQuery.setType(type);
            queries.add(updateQuery);
            //分批提交索引
            if (counter != 0 && counter % 1000 == 0) {
                restTemplate.bulkUpdate(queries);
                queries.clear();
                System.out.println("bulkIndex counter : " + counter);
            }
            counter++;
        }
        //不足批的索引最后不要忘記提交
        if (queries.size() > 0) {
            restTemplate.bulkUpdate(queries);
        }
        restTemplate.refresh(indexName);
    }

 

4.5 數據查詢

    /**
     * 數據查詢,返回List
     * @param field 查詢字段
     * @param value 查詢值
     * @return List<EmployeeBean>
     */
    @Override
    public List<EmployeeBean> queryMatchList(String field, String value) {
        MatchQueryBuilder builder = QueryBuilders.matchQuery(field, value);
        SearchQuery searchQuery = new NativeSearchQuery(builder);
        return restTemplate.queryForList(searchQuery, EmployeeBean.class);
    }

    /**
     * 數據查詢,返回Page
     * @param field 查詢字段
     * @param value 查詢值
     * @return AggregatedPage<EmployeeBean>
     */
    @Override
    public AggregatedPage<EmployeeBean> queryMatchPage(String field, String value) {
        MatchQueryBuilder builder = QueryBuilders.matchQuery(field, value);
        SearchQuery searchQuery = new NativeSearchQuery(builder).setPageable(PageRequest.of(0, 100));
        AggregatedPage<EmployeeBean> page = restTemplate.queryForPage(searchQuery, EmployeeBean.class);

        long totalElements = page.getTotalElements(); // 總記錄數
        int totalPages = page.getTotalPages();  // 總頁數
        int pageNumber = page.getPageable().getPageNumber(); // 當前頁號
        List<EmployeeBean> beanList = page.toList();  // 當前頁數據集
        Set<EmployeeBean> beanSet = page.toSet();  // 當前頁數據集
        return page;
    }

  QueryBuilders對象是用於創建查詢方法的,支持多種查詢類型,常用的查詢API包括以下方法:

    /**
     * 關鍵字匹配查詢
     *
     * @param name 字段的名稱
     * @param value 查詢值
     */
    public static TermQueryBuilder termQuery(String name, String value) {
        return new TermQueryBuilder(name, value);
    }

    public static TermQueryBuilder termQuery(String name, int value) {
        return new TermQueryBuilder(name, value);
    }

    public static TermQueryBuilder termQuery(String name, long value) {
        return new TermQueryBuilder(name, value);
    }

    public static TermQueryBuilder termQuery(String name, float value) {
        return new TermQueryBuilder(name, value);
    }

    public static TermQueryBuilder termQuery(String name, double value) {
        return new TermQueryBuilder(name, value);
    }

    public static TermQueryBuilder termQuery(String name, boolean value) {
        return new TermQueryBuilder(name, value);
    }

    public static TermQueryBuilder termQuery(String name, Object value) {
        return new TermQueryBuilder(name, value);
    }

    /**
     * 關鍵字查詢,同時匹配多個關鍵字
     *
     * @param name   字段名稱
     * @param values  查詢值
     */
    public static TermsQueryBuilder termsQuery(String name, String... values) {
        return new TermsQueryBuilder(name, values);
    }

    /**
     * 創建一個匹配多個關鍵字的查詢,返回boolean
     *
     * @param fieldNames 字段名稱
     * @param text           查詢值
     */
    public static MultiMatchQueryBuilder multiMatchQuery(Object text, String... fieldNames) {
        return new MultiMatchQueryBuilder(text, fieldNames); // BOOLEAN is the default
    }

    /**
     * 關鍵字,精確匹配
     *
     * @param name 字段名稱
     * @param text    查詢值
     */
    public static MatchQueryBuilder matchQuery(String name, Object text) {
        return new MatchQueryBuilder(name, text);
    }

    /**
     * 關鍵字范圍查詢(后面跟范圍條件)
     *
     * @param name 字段名稱
     */
    public static RangeQueryBuilder rangeQuery(String name) {
        return new RangeQueryBuilder(name);
    }

    /**
     * 判斷字段是否有值
     *
     * @param name 字段名稱
     */
    public static ExistsQueryBuilder existsQuery(String name) {
        return new ExistsQueryBuilder(name);
    }

    /**
     * 模糊查詢
     *
     * @param name  字段名稱
     * @param value  查詢值
     */
    public static FuzzyQueryBuilder fuzzyQuery(String name, String value) {
        return new FuzzyQueryBuilder(name, value);
    }

    /**
     * 組合查詢對象,可以同時引用上面的所有查詢對象
     */
    public static BoolQueryBuilder boolQuery() {
        return new BoolQueryBuilder();
    }

 

4.6 聚合查詢

  AggregationBuilders對象是用於創建聚合方法的,支持多種查詢類型,常用的查詢API包括以下方法: 

    /**
     * 根據字段聚合,統計該字段的每個值的數量
     */
    public static TermsAggregationBuilder terms(String name) {
        return new TermsAggregationBuilder(name, null);
    }

    /**
     * 統計操作的,過濾條件
     */
    public static FilterAggregationBuilder filter(String name, QueryBuilder filter) {
        return new FilterAggregationBuilder(name, filter);
    }

    /**
     * 設置多個過濾條件
     */
    public static FiltersAggregationBuilder filters(String name, KeyedFilter... filters) {
        return new FiltersAggregationBuilder(name, filters);
    }

    /**
     * 統計該字段的數據總數
     */
    public static ValueCountAggregationBuilder count(String name) {
        return new ValueCountAggregationBuilder(name, null);
    }

    /**
     * 計算平均值
     */
    public static AvgAggregationBuilder avg(String name) {
        return new AvgAggregationBuilder(name);
    }

    /**
     * 計算最大值
     */
    public static MaxAggregationBuilder max(String name) {
        return new MaxAggregationBuilder(name);
    }

    /**
     * 計算最小值
     */
    public static MinAggregationBuilder min(String name) {
        return new MinAggregationBuilder(name);
    }

    /**
     * 計算總數
     */
    public static SumAggregationBuilder sum(String name) {
        return new SumAggregationBuilder(name);
    }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM