java RestHighLevelClient方式操作es

我是浣熊的微笑發表於2020-12-07

之前有寫過一篇文章,介紹使用繼承ElasticsearchRepository類或者使用ElasticSearchTemplate的方式進行CRUD,但是因為API更新不及時,逐漸不用了。目前還是推薦使用官方的API,即RestHighLevelClient的方式查詢。使用過程中遇到一些坑,記錄下

maven依賴

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>${elasticsearch.version}</version>
</dependency>
<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>${elasticsearch.version}</version>
</dependency>

 

使用例子在下面,有兩點需要注意的地方

1.查詢預設會進行分頁,根據業務需要設定返回資料的數量, searchSourceBuilder.size(10000),否則只會返回10條資料

2.本來想用mget提高查詢效率,但是在使用時發現用索引別名查詢的時候,如果是多個索引共用別名會查詢不到資料

package com.example.demo.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;

import java.io.IOException;

/**
 * es配置工廠類
 */
public class ESClientSpringFactory {
    public static int CONNECT_TIMEOUT_MILLIS = 1000;
    public static int SOCKET_TIMEOUT_MILLIS = 30000;
    public static int CONNECTION_REQUEST_TIMEOUT_MILLIS = 500;
    public static int MAX_CONN_PER_ROUTE = 10;
    public static int MAX_CONN_TOTAL = 30;

    private static HttpHost[] HTTP_HOST;
    private RestClientBuilder builder;
    private RestClient restClient;
    private RestHighLevelClient restHighLevelClient;

    private static ESClientSpringFactory esClientSpringFactory = new ESClientSpringFactory();

    private ESClientSpringFactory(){}

    public static ESClientSpringFactory build(HttpHost[] httpHost,
                                              Integer maxConnectNum, Integer maxConnectPerRoute){
        HTTP_HOST = httpHost;
        MAX_CONN_TOTAL = maxConnectNum;
        MAX_CONN_PER_ROUTE = maxConnectPerRoute;
        return  esClientSpringFactory;
    }

    public static ESClientSpringFactory build(HttpHost[] httpHost, Integer connectTimeOut, Integer socketTimeOut,
                                              Integer connectionRequestTime, Integer maxConnectNum, Integer maxConnectPerRoute){
        HTTP_HOST = httpHost;
        CONNECT_TIMEOUT_MILLIS = connectTimeOut;
        SOCKET_TIMEOUT_MILLIS = socketTimeOut;
        CONNECTION_REQUEST_TIMEOUT_MILLIS = connectionRequestTime;
        MAX_CONN_TOTAL = maxConnectNum;
        MAX_CONN_PER_ROUTE = maxConnectPerRoute;
        return  esClientSpringFactory;
    }


    public void init(){
        builder = RestClient.builder(HTTP_HOST);
        setConnectTimeOutConfig();
        setMutiConnectConfig();
        restClient = builder.build();
        restHighLevelClient = new RestHighLevelClient(builder);
        System.out.println("init factory");
    }
    // 配置連線時間延時
    public void setConnectTimeOutConfig(){
        builder.setRequestConfigCallback(requestConfigBuilder -> {
            requestConfigBuilder.setConnectTimeout(CONNECT_TIMEOUT_MILLIS);
            requestConfigBuilder.setSocketTimeout(SOCKET_TIMEOUT_MILLIS);
            requestConfigBuilder.setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT_MILLIS);
            return requestConfigBuilder;
        });
    }
    // 使用非同步httpclient時設定併發連線數
    public void setMutiConnectConfig(){
        builder.setHttpClientConfigCallback(httpClientBuilder -> {
            httpClientBuilder.setMaxConnTotal(MAX_CONN_TOTAL);
            httpClientBuilder.setMaxConnPerRoute(MAX_CONN_PER_ROUTE);
            return httpClientBuilder;
        });
    }

    public RestClient getClient(){
        return restClient;
    }

    public RestHighLevelClient getRhlClient(){
        return restHighLevelClient;
    }

    public void close() {
        if (restClient != null) {
            try {
                restClient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("close client");
    }
}

 

package com.example.demo.config;

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * es配置類
 * 
 * @author : chenpeng36
 * @version : 2020/1/15 14:24
 */
@Configuration
public class EsConfiguration {
   @Value("${elasticSearch.host}")
   private String host;

   @Value("${elasticSearch.port}")
   private int port;

   @Value("${elasticSearch.client.connectNum}")
   private Integer connectNum;

   @Value("${elasticSearch.client.connectPerRoute}")
   private Integer connectPerRoute;

   @Bean
   public HttpHost[] httpHost() {
      String[] array = host.split(",");
      HttpHost[] hosts = new HttpHost[array.length];
      for (int i = 0; i < array.length; i++) {
         hosts[i] = new HttpHost(array[i], port, "http");
      }
      return hosts;
   }

   @Bean(initMethod = "init", destroyMethod = "close")
   public ESClientSpringFactory getFactory() {
      return ESClientSpringFactory.build(httpHost(), connectNum, connectPerRoute);
   }

   @Bean
   @Scope("singleton")
   public RestClient getRestClient() {
      return getFactory().getClient();
   }

   @Bean("rhlClient")
   @Scope("singleton")
   public RestHighLevelClient getRHLClient() {
      return getFactory().getRhlClient();
   }
}

 

用的比較多的一個是範圍查詢,一個是精確查詢

package com.example.demo;

import org.elasticsearch.action.get.*;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;

import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.util.Map;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {DemoApplication.class})
class DemoApplicationTests {

    @Autowired
    private RestHighLevelClient rhlClient;


 //分頁查詢
    @Test
    public void searchByPage() throws IOException {
        //構建搜尋請求物件
        SearchRequest searchRequest = new SearchRequest("index_name");
        //設定搜尋物件的型別,不需要設定
        //searchRequest.types("ads_peer_info_community_type");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        int page = 1;
        //每頁記錄數
        int size = 2;
        //計算出記錄起始下標
        int from = (page - 1) * size;
        searchSourceBuilder.from(from);//起始記錄下標,從0開始
        searchSourceBuilder.size(size);//每頁顯示的記錄數
        //搜尋源搜尋方式
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = rhlClient.search(searchRequest, RequestOptions.DEFAULT);
        //搜尋結果
        SearchHits hits = searchResponse.getHits();
        //獲得匹配總記錄
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : searchHits) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            String name= (String) sourceAsMap.get("name");
            System.out.println(name);
        }
    }

//mget方式查詢
    @Test
    public void mgetSearch() throws IOException {
        try {
            MultiGetRequest request = new MultiGetRequest();
            list.forEach(item -> {
                request.add(Index, type, item);
            });
            MultiGetResponse result = restHighLevelClient.mget(request, RequestOptions.DEFAULT);
            for (MultiGetItemResponse respons : result.getResponses()) {
                if (respons.getResponse()!= null){
                    Map<String, Object> sourceAsMap = respons.getResponse().getSourceAsMap();
                    if (sourceAsMap != null) {
                        InfoEntity infoEntity = new InfoEntity();
                        Long time = (Long) sourceAsMap.get("time");
                        String name= (String) sourceAsMap.get("name");
                        infoEntity.setTime(time);
                        infoEntity.setName(name);
                    }
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

    /**
     * 精確搜尋
     * 設定搜尋源物件的查詢方式為  termQuery("id","111")  表示查詢欄位為id的關鍵字為111
     *
     * @throws IOException
     */
    @Test
    public void termQuery() throws IOException {
        //構建搜尋請求物件
        SearchRequest searchRequest = new SearchRequest("index");
        //設定搜尋物件的型別,不需要設定
        //searchRequest.types("type");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        searchSourceBuilder.query(QueryBuilders.termQuery("rowkey", "eb3cddde-f745-4360-bd7c-c271e2087a31"));
        //設定源欄位過慮,第一個引數結果集包括哪些欄位,第二個參數列示結果集不包括哪些欄位
//        searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
        //向搜尋請求物件中設定搜尋源
        searchRequest.source(searchSourceBuilder);
        //執行搜尋,向ES發起http請求
        SearchResponse searchResponse = rhlClient.search(searchRequest);
        //搜尋結果
        SearchHits hits = searchResponse.getHits();
        //匹配到的總記錄數
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : searchHits) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            String id = (String) sourceAsMap.get("id");
            System.out.println(id);
        }
    }

    @Test
    public void queryById() throws IOException {
        //構建搜尋請求物件
        SearchRequest searchRequest = new SearchRequest("index_name");
        //設定搜尋物件的型別,不需要設定
        //searchRequest.types("type");

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //搜尋方式  根據id查詢
        String[] ids = new String[]{"d136fc82-f458-4ba2-96a8-e83c4f621571", "6051bcaf-d587-44cd-86ba-b4c5c39da08f"};
        searchSourceBuilder.query(QueryBuilders.termsQuery("_id", ids));
        //設定源欄位過慮,第一個引數結果集包括哪些欄位,第二個參數列示結果集不包括哪些欄位
//        searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
        //向搜尋請求物件中設定搜尋源
        searchRequest.source(searchSourceBuilder);
        //執行搜尋,向ES發起http請求
        SearchResponse searchResponse = rhlClient.search(searchRequest);
        //搜尋結果
        SearchHits hits = searchResponse.getHits();
        //匹配到的總記錄數
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : searchHits) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            String id = (String) sourceAsMap.get("id");
            System.out.println(id);
        }
    }


    @Test
    public void searchBySingleId() throws IOException {
        GetRequest getRequest = new GetRequest("index");
        getRequest.id("6051bcaf-d587-44cd-86ba-b4c5c39da08f");
        String[] includes = new String[]{"*", "birthday"};
        String[] excludes = Strings.EMPTY_ARRAY;
        FetchSourceContext fetchSourceContext = new FetchSourceContext(true);
        getRequest.fetchSourceContext(fetchSourceContext);
        GetResponse response = rhlClient.get(getRequest);
        Map<String, Object> sourceAsMap = response.getSourceAsMap();
        String id = (String) sourceAsMap.get("id");
        System.out.println(id);
        System.out.println(response.getSource().keySet().toString());
    }

    @Test
    public void searchByMutiId() throws IOException {
//        String[] includes = new String[]{"*", "birthday"};
//        String[] excludes = Strings.EMPTY_ARRAY;
        FetchSourceContext fetchSourceContext = new FetchSourceContext(true);
        MultiGetRequest multiGetRequest = new MultiGetRequest();
        multiGetRequest.add(new MultiGetRequest.Item("ads_peer_info_community_index", "ads_peer_info_community_type", "d136fc82-f458-4ba2-96a8-e83c4f621571").fetchSourceContext(fetchSourceContext)); //通過Item新增查詢條件
        multiGetRequest.add("ads_peer_info_community_index", "ads_peer_info_community_type", "6051bcaf-d587-44cd-86ba-b4c5c39da08f");  //直接新增查詢條件
        MultiGetResponse multiGetItemResponses = rhlClient.multiGet(multiGetRequest);
        MultiGetItemResponse[] responses = multiGetItemResponses.getResponses();
        for (MultiGetItemResponse response : responses) {
            System.out.println(response.getResponse().getSource().keySet().toString());
        }
    }

//複合條件查詢,時間範圍和精確匹配
    @Test
    public void test3() {
        SearchRequest searchRequest = new SearchRequest(snapInfoIndex);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(10000);
        TermQueryBuilder queryBuilder = QueryBuilders.termQuery("name", name);
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("time");
        rangeQueryBuilder.gte(startTime);
        rangeQueryBuilder.lt(endTime);
        BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
        boolBuilder.must(queryBuilder);
        boolBuilder.must(rangeQueryBuilder);
        searchSourceBuilder.query(boolBuilder);
        searchRequest.source(searchSourceBuilder);
        List<InfoEntity> list = new ArrayList<>();
        try {
             SearchResponse searchResponse = client.search(searchRequest,                 
             RequestOptions.DEFAULT);
             SearchHits hits = searchResponse.getHits();
             SearchHit[] searchHits = hits.getHits();
             for (SearchHit searchHit : searchHits) {
                InfoEntity infoEntity = new InfoEntity();
                Map<String, Object> sourceAsMap = searchHit.getSourceAsMap();
                Long time = (Long) sourceAsMap.get("time");
                String name= (String) sourceAsMap.get("name");
                infoEntity.setName(name);
                infoEntity.setTime(time);
                snapList.add(infoEntity);
             }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
}

 

相關文章