Elasticsearch——RestHighLevelClient

介紹

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

 

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); //執行刪除操作
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


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



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 格式








 

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