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)
must(QueryBuilder queryBuilder)
should(QueryBuilder queryBuilder)
//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())); }
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測試一下,結果如下:
【end】