Elasticsearch Java Rest Client API 整理總結 (二) —— SearchAPI


引言

上一篇 中主要介紹了 Document API,本節中講解 search API

Search APIs

Java High Level REST Client 支持下面的 Search API:

Search API

Search Request

searchRequest 用來完成和搜索文檔,聚合,建議等相關的任何操作同時也提供了各種方式來完成對查詢結果的高亮操作。

最基本的查詢操作如下

SearchRequest searchRequest = new SearchRequest(); 
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); 
searchSourceBuilder.query(QueryBuilders.matchAllQuery()); // 添加 match_all 查詢
searchRequest.source(searchSourceBuilder); // 將 SearchSourceBuilder  添加到 SeachRequest 中

可選參數

SearchRequest searchRequest = new SearchRequest("posts");  // 設置搜索的 index
searchRequest.types("doc");  // 設置搜索的 type

除了配置 indextype 外,還有一些其他的可選參數

searchRequest.routing("routing"); // 設置 routing 參數
searchRequest.preference("_local");  // 配置搜索時偏愛使用本地分片,默認是使用隨機分片

什么是 routing 參數?

當索引一個文檔的時候,文檔會被存儲在一個主分片上。在存儲時一般都會有多個主分片。Elasticsearch 如何知道一個文檔應該放置在哪個分片呢?這個過程是根據下面的這個公式來決定的:

shard = hash(routing) % number_of_primary_shards
  • routing 是一個可變值,默認是文檔的 _id ,也可以設置成一個自定義的值
  • number_of_primary_shards 是主分片數量

所有的文檔 API 都接受一個叫做 routing 的路由參數,通過這個參數我們可以自定義文檔到分片的映射。一個自定義的路由參數可以用來確保所有相關的文檔——例如所有屬於同一個用戶的文檔——都被存儲到同一個分片中。

使用 SearchSourceBuilder

對搜索行為的配置可以使用 SearchSourceBuilder 來完成,來看一個實例

SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();  // 默認配置
sourceBuilder.query(QueryBuilders.termQuery("user", "kimchy")); // 設置搜索,可以是任何類型的 QueryBuilder
sourceBuilder.from(0); // 起始 index
sourceBuilder.size(5); // 大小 size
sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); // 設置搜索的超時時間

設置完成后,就可以添加到 SearchRequest 中。

SearchRequest searchRequest = new SearchRequest();
searchRequest.source(sourceBuilder);

構建查詢條件

查詢請求是通過使用 QueryBuilder 對象來完成的,並且支持 Query DSL

DSL (domain-specific language) 領域特定語言,是指專注於某個應用程序領域的計算機語言。

— 百度百科

可以使用構造函數來創建 QueryBuilder

MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("user", "kimchy"); 

QueryBuilder 創建后,就可以調用方法來配置它的查詢選項:

matchQueryBuilder.fuzziness(Fuzziness.AUTO);  // 模糊查詢
matchQueryBuilder.prefixLength(3); // 前綴查詢的長度
matchQueryBuilder.maxExpansions(10); // max expansion 選項,用來控制模糊查詢

也可以使用QueryBuilders 工具類來創建 QueryBuilder 對象。這個類提供了函數式編程風格的各種方法用來快速創建 QueryBuilder 對象。

QueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("user", "kimchy")
                                        .fuzziness(Fuzziness.AUTO)
                                                .prefixLength(3)
                                                .maxExpansions(10);

fuzzy-matching 拼寫錯誤時的匹配:

好的全文檢索不應該是完全相同的限定邏輯,相反,可以擴大范圍來包括可能的匹配,從而根據相關性得分將更好的匹配放在前面。

例如,搜索 quick brown fox 時會匹配一個包含 fast brown foxes 的文檔

不論什么方式創建的 QueryBuilder ,最后都需要添加到 ``SearchSourceBuilder` 中

searchSourceBuilder.query(matchQueryBuilder);

構建查詢 文檔中提供了一個豐富的查詢列表,里面包含各種查詢對應的QueryBuilder 對象以及QueryBuilder helper 方法,大家可以去參考。

關於構建查詢的內容會在下篇文章中講解,敬請期待。

指定排序

SearchSourceBuilder 允許添加一個或多個SortBuilder 實例。這里包含 4 種特殊的實現, (Field-, Score-, GeoDistance-ScriptSortBuilder)

sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); // 根據分數 _score 降序排列 (默認行為)
sourceBuilder.sort(new FieldSortBuilder("_uid").order(SortOrder.ASC));  // 根據 id 降序排列

過濾數據源

默認情況下,查詢請求會返回文檔的內容 _source ,當然我們也可以配置它。例如,禁止對 _source 的獲取

sourceBuilder.fetchSource(false);

也可以使用通配符模式以更細的粒度包含或排除特定的字段:

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

高亮請求

可以通過在 SearchSourceBuilder 上設置 HighlightBuilder 完成對結果的高亮,而且可以配置不同的字段具有不同的高亮行為。

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
HighlightBuilder highlightBuilder = new HighlightBuilder(); 
HighlightBuilder.Field highlightTitle =
        new HighlightBuilder.Field("title"); // title 字段高亮
highlightTitle.highlighterType("unified");  // 配置高亮類型
highlightBuilder.field(highlightTitle);  // 添加到 builder
HighlightBuilder.Field highlightUser = new HighlightBuilder.Field("user");
highlightBuilder.field(highlightUser);
searchSourceBuilder.highlighter(highlightBuilder);

聚合請求

要實現聚合請求分兩步

  1. 創建合適的 ``AggregationBuilder`
  2. 作為參數配置在 ``SearchSourceBuilder` 上
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_company")
        .field("company.keyword");
aggregation.subAggregation(AggregationBuilders.avg("average_age")
        .field("age"));
searchSourceBuilder.aggregation(aggregation);

建議請求 Requesting Suggestions

SuggestionBuilder 實現類是由 SuggestBuilders 工廠類來創建的。

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
SuggestionBuilder termSuggestionBuilder =
    SuggestBuilders.termSuggestion("user").text("kmichy"); 
SuggestBuilder suggestBuilder = new SuggestBuilder();
suggestBuilder.addSuggestion("suggest_user", termSuggestionBuilder); 
searchSourceBuilder.suggest(suggestBuilder);

對請求和聚合分析

分析 API 可用來對一個特定的查詢操作中的請求和聚合進行分析,此時要將SearchSourceBuilder 的 profile標志位設置為 true

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.profile(true);

只要 SearchRequest 執行完成,對應的 SearchResponse 響應中就會包含 分析結果

同步執行

同步執行是阻塞式的,只有結果返回后才能繼續執行。

SearchResponse searchResponse = client.search(searchRequest);

異步執行

異步執行使用的是 listener 對結果進行處理。

ActionListener<SearchResponse> listener = new ActionListener<SearchResponse>() {
    @Override
    public void onResponse(SearchResponse searchResponse) {
        // 查詢成功
    }

    @Override
    public void onFailure(Exception e) {
        // 查詢失敗
    }
};

查詢響應 SearchResponse

查詢執行完成后,會返回 SearchResponse 對象,並在對象中包含查詢執行的細節和符合條件的文檔集合。

歸納一下, SerchResponse 包含的信息如下

  • 請求本身的信息,如 HTTP 狀態碼,執行時間,或者請求是否超時
RestStatus status = searchResponse.status(); // HTTP 狀態碼
TimeValue took = searchResponse.getTook(); // 查詢占用的時間
Boolean terminatedEarly = searchResponse.isTerminatedEarly(); // 是否由於 SearchSourceBuilder 中設置 terminateAfter 而過早終止
boolean timedOut = searchResponse.isTimedOut(); // 是否超時
  • 查詢影響的分片數量的統計信息,成功和失敗的分片
int totalShards = searchResponse.getTotalShards();
int successfulShards = searchResponse.getSuccessfulShards();
int failedShards = searchResponse.getFailedShards();
for (ShardSearchFailure failure : searchResponse.getShardFailures()) {
    // failures should be handled here
}

檢索 SearchHits

要訪問返回的文檔,首先要在響應中獲取其中的 SearchHits

SearchHits hits = searchResponse.getHits();

SearchHits 中包含了所有命中的全局信息,如查詢命中的數量或者最大分值:

long totalHits = hits.getTotalHits();
float maxScore = hits.getMaxScore();

查詢的結果嵌套在 SearchHits 中,可以通過遍歷循環獲取

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

SearchHit 提供了如 indextypedocId 和每個命中查詢的分數

String index = hit.getIndex();
String type = hit.getType();
String id = hit.getId();
float score = hit.getScore();

而且,還可以獲取到文檔的源數據,以 JSON-String 形式或者 key-value map 對的形式。在 map 中,字段可以是普通類型,或者是列表類型,嵌套對象。

String sourceAsString = hit.getSourceAsString();
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String documentTitle = (String) sourceAsMap.get("title");
List<Object> users = (List<Object>) sourceAsMap.get("user");
Map<String, Object> innerObject =
        (Map<String, Object>) sourceAsMap.get("innerObject");

Search API 查詢關系

上面的 QueryBuilderSearchSourceBuilderSearchRequest 之間都是嵌套關系,為此我專門整理了一個關系圖,以便更清楚的確認它們之間的關系。感興趣的同學可用此圖與前面的 API 進行對應,以加深理解。

search API 關系圖

結語

本篇包含了 Java High level Rest Client 的 SearchAPI 部分,獲取高亮,聚合,分析的結果並沒有在本文涉及,需要的同學可參考官方文檔,下篇會包含查詢構建,敬請期待~

系列文章列表

  1. Elasticsearch Java Rest Client API 整理總結 (一)——Document API
  2. Elasticsearch Java Rest Client API 整理總結 (二) —— SearchAPI
  3. Elasticsearch Java Rest Client API 整理總結 (三)——Building Queries


免責聲明!

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



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