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測試一下,結果如下: