Elasticsearch Java Rest Client API 整理总结 (二) —— SearchAPI

引言

上一篇 中主要介绍了 Document API,本节中讲解 search APIjava

Search APIs

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

Search API

Search Request

searchRequest 用来完成和搜索文档,聚合,建议等相关的任何操做同时也提供了各类方式来完成对查询结果的高亮操做。api

最基本的查询操做以下dom

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 如何知道一个文档应该放置在哪一个分片呢?这个过程是根据下面的这个公式来决定的:elasticsearch

shard = hash(routing) % number_of_primary_shards
  • routing 是一个可变值,默认是文档的 _id ,也能够设置成一个自定义的值
  • number_of_primary_shards 是主分片数量

全部的文档 API 都接受一个叫作 routing 的路由参数,经过这个参数咱们能够自定义文档到分片的映射。一个自定义的路由参数能够用来确保全部相关的文档——例如全部属于同一个用户的文档——都被存储到同一个分片中。ide

使用 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
相关文章
相关标签/搜索