中間件:ES組件RestHighLevelClient用法詳解

2021-02-24 知了一笑
一、基礎API簡介1、RestHighLevelClient

RestHighLevelClient的API作為ElasticSearch備受推薦的客戶端組件,其封裝系統操作ES的方法,包括索引結構管理,數據增刪改查管理,常用查詢方法,並且可以結合原生ES查詢原生語法,功能十分強大。

在使用RestHighLevelClient的語法時,通常涉及上面幾個方面,在掌握基礎用法之上可以根據業務特點進行一些自定義封裝,這樣可以更優雅的解決業務需求。

2、核心依賴

使用RestHighLevelClient需要依賴rest-high-level-client包,和ES相關基礎依賴。

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-client</artifactId>
</dependency>
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>

二、索引管理

這裡不做過多描述,注意一點:因為ES的數據結構特點,所以不需要索引更新方法,新的欄位在更新數據時直接寫入即可,不需要提前更新索引結構。

@Service
public class EsIndexOperation {

    @Resource
    private RestHighLevelClient client ;
    private final RequestOptions options = RequestOptions.DEFAULT;

    /**
     * 判斷索引是否存在
     */
    public boolean checkIndex (String index) {
        try {
            return client.indices().exists(new GetIndexRequest(index), options);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Boolean.FALSE ;
    }

    /**
     * 創建索引
     */
    public boolean createIndex (String indexName ,Map<String, Object> columnMap){
        try {
            if(!checkIndex(indexName)){
                CreateIndexRequest request = new CreateIndexRequest(indexName);
                if (columnMap != null && columnMap.size()>0) {
                    Map<String, Object> source = new HashMap<>();
                    source.put("properties", columnMap);
                    request.mapping(source);
                }
                this.client.indices().create(request, options);
                return Boolean.TRUE ;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Boolean.FALSE;
    }

    /**
     * 刪除索引
     */
    public boolean deleteIndex(String indexName) {
        try {
            if(checkIndex(indexName)){
                DeleteIndexRequest request = new DeleteIndexRequest(indexName);
                AcknowledgedResponse response = client.indices().delete(request, options);
                return response.isAcknowledged();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Boolean.FALSE;
    }
}

三、數據管理

這裡在更新數據時,可以直接修改索引結構,在dataMap中放進新的欄位即可。

@Service
public class EsDataOperation {

    @Resource
    private RestHighLevelClient client ;
    private final RequestOptions options = RequestOptions.DEFAULT;

    /**
     * 寫入數據
     */
    public boolean insert (String indexName, Map<String,Object> dataMap){
        try {
            BulkRequest request = new BulkRequest();
            request.add(new IndexRequest(indexName,"doc").id(dataMap.remove("id").toString())
                    .opType("create").source(dataMap,XContentType.JSON));
            this.client.bulk(request, options);
            return Boolean.TRUE ;
        } catch (Exception e){
            e.printStackTrace();
        }
        return Boolean.FALSE;
    }

    /**
     * 批量寫入數據
     */
    public boolean batchInsert (String indexName, List<Map<String,Object>> userIndexList){
        try {
            BulkRequest request = new BulkRequest();
            for (Map<String,Object> dataMap:userIndexList){
                request.add(new IndexRequest(indexName,"doc").id(dataMap.remove("id").toString())
                        .opType("create").source(dataMap,XContentType.JSON));
            }
            this.client.bulk(request, options);
            return Boolean.TRUE ;
        } catch (Exception e){
            e.printStackTrace();
        }
        return Boolean.FALSE;
    }

    /**
     * 更新數據,可以直接修改索引結構
     */
    public boolean update (String indexName, Map<String,Object> dataMap){
        try {
            UpdateRequest updateRequest = new UpdateRequest(indexName,"doc", dataMap.remove("id").toString());
            updateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
            updateRequest.doc(dataMap) ;
            this.client.update(updateRequest, options);
            return Boolean.TRUE ;
        } catch (Exception e){
            e.printStackTrace();
        }
        return Boolean.FALSE;
    }

    /**
     * 刪除數據
     */
    public boolean delete (String indexName, String id){
        try {
            DeleteRequest deleteRequest = new DeleteRequest(indexName,"doc", id);
            this.client.delete(deleteRequest, options);
            return Boolean.TRUE ;
        } catch (Exception e){
            e.printStackTrace();
        }
        return Boolean.FALSE;
    }
}

四、查詢操作

注意:查詢總數的CountRequest語法,SearchRequest查詢結果中數據轉換語法,分頁查詢中需要指定偏移位置和分頁大小。

@Service
public class EsQueryOperation {

    @Resource
    private RestHighLevelClient client ;
    private final RequestOptions options = RequestOptions.DEFAULT;

    /**
     * 查詢總數
     */
    public Long count (String indexName){
        // 指定創建時間
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("createTime", 1611378102795L));

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(queryBuilder);

        CountRequest countRequest = new CountRequest(indexName);
        countRequest.source(sourceBuilder);
        try {
            CountResponse countResponse = client.count(countRequest, options);
            return countResponse.getCount();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0L;
    }

    /**
     * 查詢集合
     */
    public List<Map<String,Object>> list (String indexName) {
        // 查詢條件,指定時間並過濾指定欄位值
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("createTime", 1611378102795L));
        queryBuilder.mustNot(QueryBuilders.termQuery("name","北京-李四"));
        sourceBuilder.query(queryBuilder);
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResp = client.search(searchRequest, options);
            List<Map<String,Object>> data = new ArrayList<>() ;
            SearchHit[] searchHitArr = searchResp.getHits().getHits();
            for (SearchHit searchHit:searchHitArr){
                Map<String,Object> temp = searchHit.getSourceAsMap();
                temp.put("id",searchHit.getId()) ;
                data.add(temp);
            }
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null ;
    }

    /**
     * 分頁查詢
     */
    public List<Map<String,Object>> page (String indexName,Integer offset,Integer size) {
        // 查詢條件,指定時間並過濾指定欄位值
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(offset);
        sourceBuilder.size(size);
        sourceBuilder.sort("createTime", SortOrder.DESC);
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResp = client.search(searchRequest, options);
            List<Map<String,Object>> data = new ArrayList<>() ;
            SearchHit[] searchHitArr = searchResp.getHits().getHits();
            for (SearchHit searchHit:searchHitArr){
                Map<String,Object> temp = searchHit.getSourceAsMap();
                temp.put("id",searchHit.getId()) ;
                data.add(temp);
            }
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null ;
    }
}

五、排序方式

排序除了常規的指定欄位升序降序規則之外,還可以基於原生的腳本語法,基於自定義規則排序讓一些特定的數據沉底或者置頂。

@Service
public class EsSortOperation {

    @Resource
    private RestHighLevelClient client ;
    private final RequestOptions options = RequestOptions.DEFAULT;

    /**
     * 排序規則
     */
    public List<Map<String,Object>> sort (String indexName) {
        // 先升序時間,在倒序年齡
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.sort("createTime", SortOrder.ASC);
        sourceBuilder.sort("age",SortOrder.DESC) ;
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResp = client.search(searchRequest, options);
            List<Map<String,Object>> data = new ArrayList<>() ;
            SearchHit[] searchHitArr = searchResp.getHits().getHits();
            for (SearchHit searchHit:searchHitArr){
                Map<String,Object> temp = searchHit.getSourceAsMap();
                temp.put("id",searchHit.getId()) ;
                data.add(temp);
            }
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null ;
    }

    /**
     * 自定義排序規則
     */
    public List<Map<String,Object>> defSort (String indexName) {
        // 指定置換順序的規則
        // [age 12-->60]\[age 19-->10]\[age 13-->30]\[age 18-->40],age其他值忽略為1
        Script script = new Script("def _ageSort = doc['age'].value == 12?60:" +
                                                            "(doc['age'].value == 19?10:" +
                                                            "(doc['age'].value == 13?30:" +
                                                            "(doc['age'].value == 18?40:1)));" + "_ageSort;");
        ScriptSortBuilder sortBuilder = SortBuilders.scriptSort(script,ScriptSortBuilder.ScriptSortType.NUMBER);
        sortBuilder.order(SortOrder.ASC);
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.sort(sortBuilder);
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(sourceBuilder);
        try {
            SearchResponse searchResp = client.search(searchRequest, options);
            List<Map<String,Object>> data = new ArrayList<>() ;
            SearchHit[] searchHitArr = searchResp.getHits().getHits();
            for (SearchHit searchHit:searchHitArr){
                Map<String,Object> temp = searchHit.getSourceAsMap();
                temp.put("id",searchHit.getId()) ;
                data.add(temp);
            }
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null ;
    }
}

六、原始碼地址

GitHub·地址
https://github.com/cicadasmile/data-manage-parent
GitEE·地址
https://gitee.com/cicadasmile/data-manage-parent

相關焦點

  • Elasticsearch High Level Rest Client
    >elasticsearch-rest-high-level-client</artifactId> <version>7.9.1</version> <exclusions> <exclusion> <groupId>org.elasticsearch
  • ES實戰系列01:基於SpringBoot和RestHighLevelClient 快速搭建博客搜索系統
    本文知識導航01 項目簡介本項目基於SpringBoot 2.3,ElasticSearch 7.7.1,同時使用es官網提供的 elasticsearch-rest-high-level-client
  • 使用Java Rest Client操作Elasticsearch
    官網沒支持,但是個人開發者也有一些開源的,具體的可在es官網clients地址查看:https://www.elastic.co/guide/en/elasticsearch/client/index.html開發過程中,基本最常用的就是Java和curl的方式了,因為es本身就是使用java語言開發的,所以對Java的支持應該是最到位了,此外es也支持rest
  • springboot接入多個ES啟動時候自檢報錯
    ;import org.apache.http.impl.client.BasicCredentialsProvider;import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;import org.elasticsearch.client.RestClient;import org.elasticsearch.client.RestClientBuilder
  • Elasticsearch SQL用法詳解
    /bin/elasticsearch-plugin install file:/elasticsearch-sql-5.6.3.0.zip3.重啟ES服務 執行完上述三步,你就可以使用SQL探索數據了,以kibana中的使用為例:二、6.4 Elasticsearch SQL用法
  • client-go功能詳解
    首先是Discovery:type DiscoveryInterface interface {RESTClient() restclient.Interface ServerGroupsInterface ServerResourcesInterface ServerVersionInterface
  • 中間件mysql-proxy的一些細節
    mysql的中間件有mysql-proxy\Atlas等。
  • Spring Data REST 與 Spring RestTemplate 實戰詳解
    org.springframework.web.client.RestTemplate 位於 spring-web 的核心項目裡面。如下圖所示:我們看源碼會發現 restTemplate 幫我們實現了大部分通用的情況,如果遇到特殊情況,我們也可以類似 Servlet 一樣的思路直接調用 restTemplate 的 execute 方法。代碼如下。
  • VSCode的REST Client指南,超好用的HTTP客戶端工具
    2 基本功能我先新建一個文件pkslow.http,後綴要是http或rest才可以被識別。2.1 連結即請求只要一個連結就可以了:結果如下:curl --request GET \  --url https://www.pkslow.com/ \  --header 'user-agent: vscode-restclient
  • 學會 IDEA REST Client 後就可以丟掉 postman 了
    構建HTTP請求腳本上面的歷史記錄就是一個完整的IDEA REST Client請求腳本,如果你是從控制臺觸發的,那麼可以直接複製歷史請求記錄的文件放到項目裡作為HTTP請求的腳本,給其他成員共享,如果不是,也可以直接新建一個.http或者.rest結尾的文件,IDEA會自動識別為HTTP請求腳本。
  • 公司ES升級帶來的坑怎麼填?
    elasticsearch-rest-client:spring.elasticsearch.rest.uris=http:spring.elasticsearch.rest.username=userspring.elasticsearch.rest.password=secret
  • 消息中間件 RabbitMQ 入門篇
    常用的主流消息中間件都有哪些?如何安裝、啟動一個 RabbitMQ 服務?如何構建一個簡單的生產者與消費者模型?為什麼要使用 RabbitMQ?近兩年談的很多的一個概念微服務,在一個大型業務系統架構中,會被拆分成很多小的業務系統,這些業務系統之間如何建立通信呢?
  • linux kernel的中斷子系統之(四):High level irq event handler
    level irq event handler,在這個high level的handler中,會通過和interupt controller交互,進行中斷處理的flow control(處理中斷的嵌套、搶佔等),當然最終會遍歷該中斷描述符的IRQ action list,調用外設的specific handler來處理該中斷4、具體CPU architecture相關的模塊會進行現場恢復
  • Springboot -- 用更優雅的方式發HTTP請求(RestTemplate詳解)
    1.簡述RestTemplate是Spring用於同步client端的核心類,簡化了與http服務的通信,並滿足RestFul原則,程序代碼可以給它提供URL,並提取結果。默認情況下,RestTemplate默認依賴jdk的HTTP連接工具。
  • MySQL如何實時同步數據到ES?試試這款阿里開源的神器!
    組件下載首先我們需要下載canal的各個組件canal-server、canal-adapter、canal-admin,下載地址:https://github.com/alibaba/canal/releases
  • Pgbackrest 實踐
    openssl rand -base64 48Dpy3iBVyfoAsDH+OQyApvpNT5ijs3jPI3fuVgTRKKbckN9HZe74ObGtsdkrhaa7T修改配置文件。vim /home/postgres/pg/data/postgresql.confarchive_command = 'pgbackrest --stanza=postgres archive-push %p'archive_mode = onlisten_addresses = '*'log_line_prefix
  • 使用Python調用Power BI REST API刷新工作區所有報告(國內版)
    分享個使用Python調用Power BI REST API來刷新指定工作區中所有報告的方法,全程只需2步:在"應用註冊"的主界面可以看到剛註冊號的應用"pbiRefresh"這樣應用程式就創建並配置好啦,下面就可以調API接口啦~~https://docs.microsoft.com/en-us/rest
  • 簡單粗暴的RestTemplate
    import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.http.client.ClientHttpRequestFactory;import