elasticsearch——Rest Client


https://www.jianshu.com/p/66b91bec12e3

 

elasticsearch——Rest Client

0.2372018.05.10 15:23:03字數 1287閱讀 8223

elasticsearch版本迭代太快,項目中用的5.X版本,java client使用了新推出的Rest Client。而網上的client大多是還是TransportClient。組里封裝的EsClient不滿足業務需求,只能自己研究下Rest Client。Rest Client為推薦使用,TransportClient將在未來版本中廢棄。新版本的很多api都發生了變化,改名了或者換地方了。。。

這里提供一個elasticsearch5.6 java rest client的中文文檔:https://legacy.gitbook.com/book/quanke/elasticsearch-java-rest/details。本文章只是簡單應用,詳細細節參考此文檔。

介紹

java rest client有兩個實現類,分別是RestClient和RestHighLevelClient。前者是一個低級客戶端,通過Http與elasticsearch集群進行通信,可以做到 負載均衡、故障轉移、持久化鏈接、自動發現集群節點等功能,同時支持所有elasticsearch版本,但是需要自己對請求和相應做編解碼(自己寫JSON);后者是一個高級客戶端,對增刪改差進行了封裝,不需要處理編解碼,類似之前的TransportClient,但是兼容性較差,對客戶端和集群版本要求較高。
因為RestClient沒有提供增刪改差方法,只能自己寫json並選擇Http請求的方法進行實現,一般使用較少,只有RestHighLevelClient無法滿足的情況下才會使用。這里主要介紹RestHighLevelClient。

RestHighLevelClient

RestHighLevelClient restHighLevelClient = new RestHighLevelClient(restClient);
RestHighLevelClient僅僅是對RestClinet的一個封裝。支持異步請求。

search api

請求

構造查詢主要用到兩個類:SearchRequest和SearchSourceBuilder。

SearchRequest searchRequest = new SearchRequest(); //穿件SeachRequest,Without arguments this runs against all indices.
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();// 大多數的搜索參數被添加到 SearchSourceBuilder 。它為每個進入請求體的每個東西都提供 setter 方法。
searchSourceBuilder.query(QueryBuilders.matchAllQuery()); // 添加一個 match_all 查詢到 searchSourceBuilder 。
searchRequest.source(searchSourceBuilder); //將searchSourceBuilder添加到searchRequest

這里構造了一個查詢請求,內容為一個match_all查詢。
SearchRequest為最終的查詢請求封裝,而查詢的大部分細節由SearchSourceBuilder指定。
首先來看一下常用的幾個SearchRequest方法

SearchRequest searchRequest = new SearchRequest("posts"); // 限制請求到某個索引上
searchRequest.indices("gets"); //設定索引
searchRequest.types("doc"); // 限制請求的類別

Es-java包中請求體封裝類,其屬性的setter和getter方法,都沒有相應的set和get標記,直接使用屬性名作為方法名,然后通過入參和返回值區分哪個是setter哪個是getter。之前版本中用的標准setter和getter在(至少在5.X)客戶端中已經不見了。

還有很多其他的配置參數,這里不再羅列。

然后是搜索細節——SearchSourceBuilder
SearchSourceBuilder可以配置大多數的搜索細節,以下為幾個實例,詳細參考文檔:

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //使用默認選項創建 SearchSourceBuilder 。 sourceBuilder.query(QueryBuilders.termQuery("user", "kimchy"));//設置查詢對象。可以使任何類型的 QueryBuilder sourceBuilder.from(0); //設置from選項,確定要開始搜索的結果索引。 默認為0。 sourceBuilder.size(5); //設置大小選項,確定要返回的搜索匹配數。 默認為10。 sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //設置一個可選的超時時間,用於控制搜索允許的時間。 

sourceBuilder.query:設置查詢對象。所有Query DSL支持的搜索類型都有對應的QueryBuilder。創建QueryBuilder有兩種方式:直接new和QueryBuilders工廠方法,我習慣后者(實際沒差別)。常見的QueryBuilder列幾個:

// 創建一個字段“user”與文本“kimchy”相匹配的的全文匹配查詢。
MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("user", "kimchy");
// 創建一個字段date的范圍查詢。
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("date").lte(time);

每個QueryBuilder都根據各自的查詢提供了對應的方法,同時支持鏈式創建並初始化。
QueryBuilder支持像curl一樣進行查詢嵌套,比如一個bool的must里套一個bool,should里放一個bool一個range。
無論怎么嵌套,最終得到的QueryBuilder結構就像傳統的search json一樣。最后把這個QueryBuilder添加到SearchSourceBuilder中:

searchSourceBuilder.query(queryBuilder); 

每個SearchSourceBuilder只能設定一個QueryBuilder,即一個Query DSL中只有一個query元素。

在傳統Query DSL中,還有一些在結構上與query並列的,比如sort,在java中表示如下:

FieldSortBuilder sortBuilder = SortBuilders.fieldSort(sortField).order(sortOrder);
searchSourceBuilder.sort(sortBuilder);

可以控制一次返回文檔的個數、返回文檔的字段:

searchSourceBuilder.size(num); searchSourceBuilder.fetchSource(includeFields, excludeFields); 

實現高亮:

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
HighlightBuilder highlightBuilder = new HighlightBuilder(); //創建一個HighlightBuilder
HighlightBuilder.Field highlightTitle =new HighlightBuilder.Field("title"); //指定高亮字段1
highlightBuilder.field(highlightTitle); //指定高亮字段2
highlightBuilder.preTags(preTags); //修改高亮前綴(默認http標簽)
highlightBuilder.postTags(postTags); //修改高亮后綴(默認http標簽)
searchSourceBuilder.highlighter(highlightBuilder);

然后可以從結果中獲取高亮顯示的文本字段。

實現聚合:

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_company").field("company.keyword");
aggregation.subAggregation(AggregationBuilders.avg("average_age").field("age"));
searchSourceBuilder.aggregation(aggregation);

詳細方法參考聚合api。

響應
SearchResponse searchResponse = client.search(searchRequest);

通過SearchResponse獲得所有的相應數據。

無論請求還是相應,想要構造或者解析都需要按照DSL的格式,一層一層去做。

可以遍歷返回的文檔:

SearchHits hits = searchResponse.getHits(); //獲得hits數組 long totalHits = hits.getTotalHits(); //獲取檢索的文檔總數(不是這次返回的數量) for (SearchHit hit : hits) { String index = hit.getIndex(); //獲取文檔的index String type = hit.getType(); //獲取文檔的type String id = hit.getId(); //獲取文檔的id Map<String, Object> sourceMap = hit.getSource(); //獲取文檔內容,封裝為map String sourceString = hit.getSourceAsString(); //獲取文檔內容,轉換為json字符串。 } 

這里遍歷,官方使用了

SearchHit[] searchHits = hits.getHits();
for (SearchHit hit : searchHits) {
    // do something with the SearchHit
}

其實SearchHits實現了Iterable接口,可以直接進行迭代。
hit中除了source之外的字段,也可以進行獲取,以高亮為例:

Map<String, HighlightField> highlightFields = hit.getHighlightFields(); HighlightField highlight = highlightFields.get("title"); //獲取該title領域 的突出顯示 Text[] fragments = highlight.fragments(); //獲取包含突出顯示的字段內容的一個或多個片段 String fragmentString = fragments[0].string(); 

聚合的話不在Hits中,需要從SearchResponse中獲取Aggregations對象:

Aggregations aggregations = searchResponse.getAggregations(); Terms byCompanyAggregation = aggregations.get("by_company"); //Get the by_company terms aggregation Bucket elasticBucket = byCompanyAggregation.getBucketByKey("Elastic"); // Avg averageAge = elasticBucket.getAggregations().get("average_age"); //Get the average_age sub-aggregation from that bucket double avg = averageAge.getValue(); 

其他參考官方API。

游標

5.X版本中的游標使用也跟之前有了不同,下面簡單介紹:

final Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1L)); // 創建游標對象 SearchRequest searchRequest = new SearchRequest("posts"); searchRequest.scroll(scroll); // 為查詢設置游標,注意是在SearchRequest中配置 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.query(matchQuery("title", "Elasticsearch")); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = client.search(searchRequest); //通過發送初始化 SearchRequest 來初始化搜索上下文 String scrollId = searchResponse.getScrollId(); // 獲取scrollId SearchHit[] searchHits = searchResponse.getHits().getHits(); while (searchHits != null && searchHits.length > 0) { //在一個循環中通過調用 Search Scroll api 檢索所有搜索命中結果,知道沒有文檔返回為止。 //創建一個新的SearchScrollRequest,持有最近一次返回的滾動標識符和滾動間隔 SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); scrollRequest.scroll(scroll); //重新設置游標ID searchResponse = client.searchScroll(scrollRequest); //游標查詢,這里使用searchScroll,與第一次查詢不同 scrollId = searchResponse.getScrollId(); //獲取新的游標ID searchHits = searchResponse.getHits().getHits(); //處理返回的搜索結果 } ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); //一旦查詢全部完成,清除游標 clearScrollRequest.addScrollId(scrollId); ClearScrollResponse clearScrollResponse = client.clearScroll(clearScrollRequest); boolean succeeded = clearScrollResponse.isSucceeded(); 

delete api

在RestHighLevelClient中,刪除只支持按照index/type/id進行精確刪除,不支持delete by query的操作。普通的TransportClient支持delete by query。

DeleteRequest request = new DeleteRequest(indexName, type, id); //創建DeleteRequest對象 DeleteResponse response = client.delete(request); //執行刪除操作 

DeleteRequest除了以上三個值,還有很多可選參數:

request.routing("routing"); // 路由值 request.parent("parent"); //Parent 值 request.timeout(TimeValue.timeValueMinutes(2)); // TimeValue 類型的等待主分片可用的超時時間 request.timeout("2m"); // 字符串類型的等待主分片可用的超時時間 request.setRefreshPolicy(WriteRequest.RefreshPolicy.WAIT_UNTIL);// Refresh policy as a WriteRequest.RefreshPolicy instance request.setRefreshPolicy("wait_for"); // Refresh policy as a String request.version(2); // Version request.versionType(VersionType.EXTERNAL); // Version type 

相應DeleteResponse可以獲得操作結果的各種信息:

String index = deleteResponse.getIndex(); // index String type = deleteResponse.getType(); // type String id = deleteResponse.getId(); // id long version = deleteResponse.getVersion(); .// version 

index api

IndexRequest request = new IndexRequest(
    "posts", //Index
    "doc", //Type
    "1"); //Document id
String jsonString = "{" +
    "\"user\":\"kimchy\"," +
    "\"postDate\":\"2013-01-30\"," +
    "\"message\":\"trying out Elasticsearch\"" +
    "}";
request.source(jsonString, XContentType.JSON); /以字符串提供的 Document source

這里使用IndexRequest做index請求。包括index\type\id信息,然后創建了index文檔,這里采用字符串方式。
文檔可以使用多種方式提供,包括字符串、Map、XContentBuilder、Object數組、BytesReference、鍵值對數組等方式:

Map<String, Object> jsonMap = new HashMap<>(); jsonMap.put("user", "kimchy"); jsonMap.put("postDate", new Date()); jsonMap.put("message", "trying out Elasticsearch"); IndexRequest indexRequest = new IndexRequest("posts", "doc", "1").source(jsonMap); //Map 作為文檔源,它可以自動轉換為 JSON 格式。 XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject(); { builder.field("user", "kimchy"); builder.field("postDate", new Date()); builder.field("message", "trying out Elasticsearch"); } builder.endObject(); IndexRequest indexRequest = new IndexRequest("posts", "doc", "1").source(builder); //XContentBuilder 對象作為文檔源,由 Elasticsearch 內置的幫助器生成 JSON 內容 IndexRequest indexRequest = new IndexRequest("posts", "doc", "1") .source("user", "kimchy", "postDate", new Date(), "message", "trying out Elasticsearch"); //以鍵值對對象作為文檔來源,它自動轉換為 JSON 格式 

other api

待續。。。(各種api以官方rest client文檔為准)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM