ElasticSearch使用RestHighLevelClient進行搜索查詢

Elasticsearch Java API有四類client連接方式:TransportClient、 RestClient 、Jest、 Spring_Data_Elasticsearch。其中TransportClient、 RestClient是Elasticsearch原生的api,TransportClient會在8.0版本中完成刪除,替代的是HighLevelRestClient,它使用HTTP請求而不是Java序列化請求。Spring_Data_Elasticsearch是spring集成的Elasticsearch開發包。在博客園 Elasticsearch 6.4基本操作 - Java版 一文中有簡單的描述,不再過多引述。本文主要記錄一下HighLevelRestClient在spingboot項目中的使用。

使用es主要是做一些非關係型數據文檔的檢索,公司用的最多的是配合kibana進行可視化的日誌檢索,非常方便。elasticsearch、kibana安裝,配置和使用,有大量博客記錄,此處不再說明。

@Configuration配置sping並啓動容器 @Bean註冊Bean

import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.elasticsearch.client.RestClientBuilder.RequestConfigCallback;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import java.util.ArrayList;
 
@Configuration
public class ESConfig {
 
    private static String hosts = "127.0.0.1"; // 集羣地址,多個用,隔開
    private static int port = 9200; // 使用的端口號
    private static String schema = "http"; // 使用的協議
    private static ArrayList<HttpHost> hostList = null;
 
    private static int connectTimeOut = 1000; // 連接超時時間
    private static int socketTimeOut = 30000; // 連接超時時間
    private static int connectionRequestTimeOut = 500; // 獲取連接的超時時間
 
    private static int maxConnectNum = 100; // 最大連接數
    private static int maxConnectPerRoute = 100; // 最大路由連接數
    static {
        hostList = new ArrayList<>();
        String[] hostStrs = hosts.split(",");
        for (String host : hostStrs) {
            hostList.add(new HttpHost(host, port, schema));
        }
    }
    @Bean
    public RestHighLevelClient client(){
        RestClientBuilder builder = RestClient.builder(hostList.toArray(new HttpHost[0]));
        // 異步httpclient連接延時配置
        builder.setRequestConfigCallback(new RequestConfigCallback() {
            @Override
            public Builder customizeRequestConfig(Builder requestConfigBuilder) {
                requestConfigBuilder.setConnectTimeout(connectTimeOut);
                requestConfigBuilder.setSocketTimeout(socketTimeOut);
                requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeOut);
                return requestConfigBuilder;
            }
        });
        // 異步httpclient連接數配置
        builder.setHttpClientConfigCallback(new HttpClientConfigCallback() {
            @Override
            public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
                httpClientBuilder.setMaxConnTotal(maxConnectNum);
                httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
                return httpClientBuilder;
            }
        });
        RestHighLevelClient client = new RestHighLevelClient(builder);
        return client;
    }
}

寫一個service。

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.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import java.io.IOException;
import java.util.Arrays;
 
@Service
public class ElasticSearchService {
    private static final Logger log = LoggerFactory.getLogger(ElasticSearchService.class);
 
    @Autowired
    private RestHighLevelClient client;
 
    public String search() throws IOException {
        BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("fields.entity_id", "319");//這裏可以根據字段進行搜索,must表示符合條件的,相反的mustnot表示不符合條件的
       // RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("fields_timestamp"); //新建range條件
       // rangeQueryBuilder.gte("2019-03-21T08:24:37.873Z"); //開始時間
       // rangeQueryBuilder.lte("2019-03-21T08:24:37.873Z"); //結束時間
       // boolBuilder.must(rangeQueryBuilder);
        boolBuilder.must(matchQueryBuilder);
        sourceBuilder.query(boolBuilder); //設置查詢,可以是任何類型的QueryBuilder。
        sourceBuilder.from(0); //設置確定結果要從哪個索引開始搜索的from選項,默認爲0
        sourceBuilder.size(100); //設置確定搜素命中返回數的size選項,默認爲10
      sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //設置一個可選的超時,控制允許搜索的時間。


        sourceBuilder.fetchSource(new String[] {"fields.port","fields.entity_id","fields.message"}, new String[] {}); //第一個是獲取字段,第二個是過濾的字段,默認獲取全部
        SearchRequest searchRequest = new SearchRequest("customer"); //索引
        searchRequest.types("doc"); //類型
        searchRequest.source(sourceBuilder);
        SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();  //SearchHits提供有關所有匹配的全局信息,例如總命中數或最高分數:
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit hit : searchHits) {
            log.info("search -> {}",hit.getSourceAsString());
        }
        return Arrays.toString(searchHits);
    }
}

上面的ElasticSearchService 有幾個常用的Builder類和方法需要了解下。

BoolQueryBuilder 用來拼裝查詢條件。一般來說must的性能要低一些,因爲他要進行打分評估,也就是說要進行_score,而filter則不會。

  • filter(QueryBuilder queryBuilder)

Adds a query that must appear in the matching documents but will not contribute to scoring.

  • must(QueryBuilder queryBuilder)
    Adds a query that must appear in the matching documents and will contribute to scoring.

  • should(QueryBuilder queryBuilder)
    Adds a query that should appear in the matching documents.

簡單來說:must 相當於 與 & = ;must not 相當於 非 ~ !=;should 相當於 或 | or ;filter 過濾

//filter 效率比 must高的多 
 if (StringUtils.isNotBlank(query.getRouterDatabaseNo())) {
   boolQueryBuilder.filter(QueryBuilders.termQuery("routerDatabaseNo", query.getRouterDatabaseNo()));
 }

//時間段 一定要有頭有尾 不然會出現慢查詢
 if (null != query.getCreateTime() && null != query.getUpdateTime()) {
     boolQueryBuilder.filter(QueryBuilders.rangeQuery("createTime").from( query.getCreateTime()).to(query.getUpdateTime()));
 }

SearchSourceBuilder

SearchRequest searchRequest = new SearchRequest("customer"); //將請求限制爲一個索引
 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
 searchRequest.types("doc"); //將請求限制爲一個類型。
 searchRequest.source(sourceBuilder); //將SearchSourceBuilder添加到SeachRequest

創建SeachRequest,沒有參數,這將針對所有索引運行。有參數,則按參數所傳值爲索引,此處“customer”爲索引值。大多數搜索參數都添加到SearchSourceBuilder中,它爲搜索請求body中的所有內容提供了setter。

SearchSourceBuilder的排序:允許添加一個或多個SortBuilder實例,有四種特殊的實現(Field-,Score-,GeoDistance-和ScriptSortBuilder)。

sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); //按_score降序排序(默認值)。
sourceBuilder.sort(new FieldSortBuilder("_uid").order(SortOrder.ASC));//也可以按_id字段進行升序排序

SearchSourceBuilder的源過濾:默認情況下,搜索請求會返回文檔_source的內容,但與Rest API中的內容一樣,你可以覆蓋此行爲,例如,你可以完全關閉_source檢索:

sourceBuilder.fetchSource(false);

該方法還接受一個或多個通配符模式的數組,以控制以更精細的方式包含或排除哪些字段

String[] includeFields = new String[] {"title", "user", "innerObject.*"};
String[] excludeFields = new String[] {"_type"};
sourceBuilder.fetchSource(includeFields, excludeFields);

SearchSourceBuilder的請求結果高亮顯示:通過在SearchSourceBuilder上設置HighlightBuilder,可以實現高亮搜索結果,通過將一個或多個HighlightBuilder.Field實例添加到HighlightBuilder,可以爲每個字段定義不同的高亮行爲。

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
HighlightBuilder highlightBuilder = new HighlightBuilder(); //創建一個新的HighlightBuilder。
HighlightBuilder.Field highlightTitle = new HighlightBuilder.Field("title");  //爲title字段創建字段高光色。
highlightTitle.highlighterType("unified"); // 設置字段高光色類型。
highlightBuilder.field(highlightTitle);   //將字段高光色添加到高亮構建器。
HighlightBuilder.Field highlightUser = new HighlightBuilder.Field("user");
highlightBuilder.field(highlightUser);
searchSourceBuilder.highlighter(highlightBuilder);

SearchSourceBuilder 更多api可以參考鏈接文章,歸納的很詳細了,不再過多引述。


寫一個controller用於測試

import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.slowcity.admin.service.ElasticSearchService;

@RestController 
@RequestMapping("/test")
public class TestResource {
    
    @Autowired
    private ElasticSearchService elasticSearchService;
    private static final Logger log = LoggerFactory.getLogger(TestResource.class);
    //條件 查詢 
    @PostMapping("/v1/test")
    public String query( ) {
        String queryResult =null;
        try {
            queryResult = elasticSearchService.search();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return queryResult;
    }
}

首先在es中維護幾條數據,如下:
在這裏插入圖片描述
postman測試一下,結果如下:
在這裏插入圖片描述

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