自定義elasticsearchRestHighLevelClient工具類

一、使用原因

1.由於客戶要求,es要是用官方推薦elasticsearch-rest-high-level-client,原來用的是spring集成的感覺用着挺方便,換了jar後兩個jar不兼容,所以全部換成了elasticsearch-rest-high-level-client-6.5.0.jar(我們目前用的ES版本),但是用起來不是很方便,所以寫了一個工具類;

 二、工具實例

1.1 client

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.Closeable;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 自定義es客戶端
 *
 * @author YanZhen
 * @date 2019/10/23 12:17
 **/
@Slf4j
public class CustomEsClient implements Closeable {
    /**
     * 默認超時時間
     */
    private long timeOut = 1L;

    /**
     * RestHighLevelClient
     */
    private RestHighLevelClient restHighLevelClient;

    public CustomEsClient(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    /**
     * RestHighLevelClient
     *
     * @return 獲取RestHighLevelClient實例
     */
    public RestHighLevelClient getRestHighLevelClient() {
        return restHighLevelClient;
    }

    @Override
    public void close() throws IOException {
        restHighLevelClient.close();
    }

    /**
     * 設置超時時間
     *
     * @param timeOut 超時時間,單位:秒
     */
    public void setTimeOut(long timeOut) {
        this.timeOut = timeOut;
    }

    /**
     * 單條數據插入
     *
     * @param t 放入的對象
     * @return 響應信息,放入es的基本信息(index、type、id)
     */
    public IndexResponse add(EsIndexTypeId t) {
        if (checkIndexTypeId(t)) {
            return null;
        }
        String index = t.index();
        String type = t.type();
        String id = String.valueOf(t.id());
        final String jsonString = JSONObject.toJSONString(t);
        final IndexRequest request = new IndexRequest(index, type, id)
                .source(jsonString, XContentType.JSON)
                .opType(DocWriteRequest.OpType.CREATE)
                .timeout(TimeValue.timeValueSeconds(timeOut));
        IndexResponse indexResponse = null;
        try {
            indexResponse = restHighLevelClient.index(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{},type:{},id:{})添加失敗:", index, type, id, e);
        }
        return indexResponse;
    }

    /**
     * 批量數據插入
     * 記錄是否有操作失敗的數據,請調用(BulkResponse.hasFailures)
     *
     * @param ts 放入的對象集合
     * @return 響應信息,放入es的基本信息(index、type、id)
     */
    public BulkResponse upsertAll(List<EsIndexTypeId> ts) {
        BulkRequest bulkRequest = new BulkRequest();
        IndexRequest request;
        for (EsIndexTypeId t : ts) {
            if (checkIndexTypeId(t)) {
                continue;
            }
            final String jsonString = JSONObject.toJSONString(t);
            request = new IndexRequest(t.index(), t.type(), String.valueOf(t.id()))
                    .source(jsonString, XContentType.JSON).timeout(TimeValue.timeValueSeconds(timeOut));
            bulkRequest.add(request);
        }
        BulkResponse response = null;
        try {
            response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es批量添加失敗:", e);
        }
        return response;
    }

    /**
     * 判斷索引是否存在
     *
     * @param t 與es存儲對應的對象
     * @return true存在,false不存在
     */
    public boolean existsIndex(EsIndexTypeId t) {
        return existsIndex(t.index());
    }

    /**
     * 判斷索引是否存在
     *
     * @param index 索引
     * @return true存在,false不存在
     */
    public boolean existsIndex(String index) {
        if (index == null) {
            return false;
        }
        GetIndexRequest request = new GetIndexRequest();
        request.indices(index);
        request.masterNodeTimeout(TimeValue.timeValueSeconds(timeOut));
        boolean exists = false;
        try {
            exists = restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{})查詢異常:", index, e);
        }
        return exists;
    }

    /**
     * 刪除單個數據
     *
     * @param t 與es存儲對應的對象,需要對象的(index、type、id)
     * @return 刪除對象的基本信息(index 、 type 、 id)
     */
    public DeleteResponse deleteById(EsIndexTypeId t) {
        if (checkIndexTypeId(t)) {
            return null;
        }
        DeleteRequest request = new DeleteRequest(t.index(), t.type(), String.valueOf(t.id()));
        //設置超時:等待主分片變得可用的時間
        request.timeout(TimeValue.timeValueMinutes(timeOut));

        //同步執行
        DeleteResponse deleteResponse = null;
        try {
            deleteResponse = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{},type:{},id:{})刪除異常:", t.index(), t.type(), t.id(), e);
        }

        return deleteResponse;
    }

    /**
     * 檢驗必要的值
     *
     * @param t 與es存儲對應的對象
     * @return true不符合,false符合
     */
    private boolean checkIndexTypeId(EsIndexTypeId t) {
        return t == null || t.index() == null || t.type() == null || t.id() == null;
    }

    /**
     * 刪除索引
     *
     * @param t 與es存儲對應的對象,需要對象的(index)
     * @return 刪除索引的基本信息(index 、 type 、 id)
     */
    public AcknowledgedResponse deleteIndex(EsIndexTypeId t) {
        if (t == null || t.index() == null) {
            return null;
        }
        return deleteIndex(t.index());
    }

    /**
     * 刪除索引
     *
     * @param index 索引
     * @return 刪除索引的基本信息(index 、 type 、 id)
     */
    public AcknowledgedResponse deleteIndex(String index) {
        if (index == null) {
            return null;
        }
        DeleteIndexRequest request = new DeleteIndexRequest(index);
        //設置超時:等待主分片變得可用的時間
        request.timeout(TimeValue.timeValueMinutes(timeOut));

        //同步執行
        AcknowledgedResponse acknowledgedResponse = null;
        try {
            acknowledgedResponse = restHighLevelClient.indices().delete(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{})刪除索引異常:", index, e);
        }

        return acknowledgedResponse;
    }

    /**
     * 根據ids批量刪除指定信息
     * 記錄是否有操作失敗的數據,請調用(BulkResponse.hasFailures)
     *
     * @param index 索引
     * @param type  索引指定的類型
     * @param ids   要刪除的Id
     * @return 刪除後響應信息
     */
    public BulkResponse deleteByIds(String index, String type, List<Long> ids) {
        if (index == null || type == null || ids == null || ids.isEmpty()) {
            return null;
        }

        final BulkRequest request = new BulkRequest();
        request.timeout(TimeValue.timeValueSeconds(timeOut));
        DeleteRequest deleteRequest;
        for (Long id : ids) {
            deleteRequest = new DeleteRequest();
            deleteRequest.index(index);
            deleteRequest.type(type);
            deleteRequest.id(id + "");
            request.add(deleteRequest);
        }

        BulkResponse response = null;
        try {
            response = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{},type:{},ids:{})刪除索引異常:", index, type, ids.toString(), e);
        }
        return response;
    }

    /**
     * 根據不同的索引和類型和id批量刪除指定信息
     * 記錄是否有操作失敗的數據,請調用(BulkResponse.hasFailures)
     *
     * @param ts 與es存儲對應的對象
     * @return 刪除後響應信息
     */
    public BulkResponse deleteByIndexAndTypeAndIds(List<EsIndexTypeId> ts) {
        final BulkRequest request = new BulkRequest();
        request.timeout(TimeValue.timeValueSeconds(timeOut));
        DeleteRequest deleteRequest;
        for (EsIndexTypeId t : ts) {
            if (checkIndexTypeId(t)) {
                continue;
            }
            deleteRequest = new DeleteRequest();
            deleteRequest.index(t.index());
            deleteRequest.type(t.type());
            deleteRequest.id(t.id() + "");
            request.add(deleteRequest);
        }

        BulkResponse response = null;
        try {
            response = restHighLevelClient.bulk(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es根據不同類型的索引刪除數據異常:", e);
        }
        return response;
    }

    /**
     * 修改單條數據
     *
     * @param t 與es存儲對應的對象
     * @return 響應修改對象的基本信息(index 、 type 、 id)
     */
    public UpdateResponse update(EsIndexTypeId t) {
        if (checkIndexTypeId(t)) {
            return null;
        }
        UpdateRequest request = new UpdateRequest(t.index(), t.type(), String.valueOf(t.id()));
        String jsonString = JSONObject.toJSONString(t);
        request.upsert(jsonString, XContentType.JSON);

        //設置超時:等待主分片變得可用的時間
        request.timeout(TimeValue.timeValueSeconds(timeOut));
        // 刷新
        request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);
        //如果要更新的文檔在獲取或者索引階段已被另一操作更改,則重試更新操作的次數
        request.retryOnConflict(3);
        // 禁用noop檢測
        request.detectNoop(false);
        // 無論文檔是否存在,腳本都必須運行,即如果腳本尚不存在,則腳本負責創建文檔。
         request.scriptedUpsert(false);
        // 如果不存在,則表明部分文檔必須用作upsert文檔。
        request.docAsUpsert(false);
        request.doc(jsonString, XContentType.JSON);
        //設置在繼續更新操作之前必須激活的分片副本的數量。
//        request.waitForActiveShards(2);
        //使用ActiveShardCount方式,可以是ActiveShardCount.ALL,ActiveShardCount.ONE或ActiveShardCount.DEFAULT(默認值)
//        request.waitForActiveShards(ActiveShardCount.ALL);

        //同步執行
        UpdateResponse updateResponse = null;
        try {
            updateResponse = restHighLevelClient.update(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{},type:{},id:{})更新異常:", t.index(), t.type(), t.id(), e);
        }
        return updateResponse;
    }

    /**
     * 根據Id查詢數據
     *
     * @param t      與es存儲對應的對象
     * @param tClass 與es存儲對應的對象的類型
     * @return 響應信息
     */
    public <T> T queryById(EsIndexTypeId t, Class<T> tClass) {
        // 檢查參數
        if (checkIndexTypeId(t)) {
            return null;
        }

        // 根據ID查詢數據
        final GetRequest getRequest = new GetRequest().index(t.index()).type(t.type()).id(String.valueOf(t.id()));
        GetResponse documentFields = null;
        try {
            documentFields = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{},type:{},id:{})根據文件Id查詢異常:", t.index(), t.type(), t.id(), e);
        }

        if (documentFields == null) {
            return null;
        }
        return JSONObject.parseObject(documentFields.getSourceAsString(), tClass);
    }

    /**
     * 查詢數據,帶分頁,且不指定分頁啓用默認值
     * @param sourceBuilder 查詢條件
     * @param index 索引
     * @param type 索引類型
     * @param tClass 返回對象類型
     * @param <T> 返回對象類型
     * @return 分頁數據
     */
    public <T> PageEsData<T> searchPage(SearchSourceBuilder sourceBuilder, String index, String type, Class<T> tClass) {
        // 校驗參數
        if (sourceBuilder == null) {
            return PageEsData.newPageData();
        }

        // 默認第0條開始
        if (sourceBuilder.from() < 0) {
            sourceBuilder.from(0);
        }
        // 默認一頁展示10條
        if (sourceBuilder.size() < 1) {
            sourceBuilder.size(10);
        }

        SearchResponse search = null;
        try {
            final SearchRequest request = new SearchRequest(index);
            if (type != null) {
                request.types(type);
            }
            sourceBuilder.timeout(TimeValue.timeValueSeconds(timeOut));
            request.source(sourceBuilder);
            search = restHighLevelClient.search(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("es(index:{},type:{})根據條件查詢異常:", index, type, e);
        }

        if (search == null) {
            return null;
        }

        if (RestStatus.OK.getStatus() != search.status().getStatus()) {
            log.warn("es(index:{},type:{})根據條件查詢失敗(狀態碼:{})", index, type, search.status().getStatus());
            return PageEsData.newPageData();
        }

        // 響應數據
        final SearchHits hits = search.getHits();
        if (hits == null) {
            return PageEsData.newPageData();
        }

        return new PageEsData<>(Arrays.stream(hits.getHits()).filter(Objects::nonNull)
                .map(documentFields -> JSONObject.parseObject(documentFields.getSourceAsString(), tClass))
                .collect(Collectors.toList()), hits.getTotalHits());
    }
}

1.2 指定 索引、類型、ID的實體模板,存入es的實體需要實現這個接口模板

**
 * @param <T> 對應實現類對象的ID類型,建議類型(Number、String)
 * @author YanZhen
 * @date 2019/10/23 13:50
 **/
public interface EsIndexTypeId<T> {

    /**
     * 類型名,必須指定
     * @return 該對象的索引
     */
    String index();
    /**
     * 類型名,必須指定
     * @return 該對象的類型
     */
    String type();
    /**
     * 索引唯一id,必須指定
     * @return 該對象的Id
     */
    T id();
}

1.3 分頁對象,存放從es取出的實體並進行分頁

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;

import java.util.ArrayList;
import java.util.List;

/**
 * ES分頁
 *
 * @author YanZhen
 * @date 2019/10/24 13:47
 **/
@ToString
@Data
@AllArgsConstructor
public class PageEsData<T> {
    /**
     * 響應信息
     */
    private List<T> data;

    /**
     * 總數據數
     */
    private long totalRows;

    /**
     * 獲取記錄開始行碼
     *
     * @param pageNum  當前頁數,從1開始
     * @param pageSize 每頁顯示數
     * @return 記錄開始行碼
     */
    public static int getDataStartNum(int pageNum, int pageSize) {
        return (pageNum - 1) * pageSize + 1;
    }

    /**
     * 初始化分頁對象
     *
     * @param <T> 返回值類型
     * @return 初始化分頁對象
     */
    public static <T> PageEsData<T> newPageData() {
        return new PageEsData<>(new ArrayList<>(), 0);
    }
}

三、總結

1.存取方便,對象存,對象取;

 轉載註明出處,看到缺點,請留言,謝謝先!

 

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