ElasticSearch High Level REST API【2】搜索查询
如下为一段带有分页的简单搜索查询示例
在search搜索中大部分的搜索条件添加都可通过设置SearchSourceBuilder来实现,然后将SearchSourceBuilder
RestHighLevelClient client = ElasticClient.getRestHighLevelClient(); SearchRequest searchRequest = new SearchRequest(); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.termQuery("user", "kimchy")); sourceBuilder.from(0); sourceBuilder.size(5); sourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS)); //设置一个可选的超时,控制允许搜索的时间 searchRequest.source(sourceBuilder); try { SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT); Long total = search.getHits().getTotalHits(); //获取匹配的总数量 System.out.println("总记录数:" + total); for (SearchHit hit : search.getHits().getHits()) { float score = hit.getScore(); //获得分数,即匹配度 String source = hit.getSourceAsString(); System.out.println(source); } } catch (IOException e) { e.printStackTrace(); }
search查询的返回值为SearchResponse,调用SearchResponse的getHits()方法会获取SearchHits对象,然后再通过SearchHits的getHits()方法即返回一个SearchHit[]数组。
遍历SearchHit[]数组获取每一个对象,通过hit.getScore()可获取分数,即搜索匹配度。通过hit.getSourceAsString()可得到对象的json字符串。
备注:在上述查询中用到了termQuery查询,ES还提供了matchQuery查询,不同的查询需求中需要选择不同的查询,在此需要了解这两个查询的区别:
- termQuery : term为不使用分词器查找,类似精确查找。
- matchQuery : mactch为使用分词器进行查找,会查询到一些近似匹配的内容。
SearchHit使用汇总
要获取返回的内容,需要获得SearchHit,下面总结下SearchHit的一些使用:
SearchHits hits = searchResponse.getHits(); long totalHits = hits.getTotalHits(); //查询命中总数 float maxScore = hits.getMaxScore(); //查询命中的最高分数 //嵌套在SearchHits可以迭代获取单个搜索结果中 SearchHit[] searchHits = hits.getHits(); for (SearchHit hit : searchHits) { //使用SearchHit做一些事情 } //通过SearchHit还可以获取 返回数据 的索引、类型、docId和得分等基本信息 String index = hit.getIndex(); String type = hit.getType(); String id = hit.getId(); float score = hit.getScore(); //hit还可以以Json字符串或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");
指定排序
sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC)); //按分数(即匹配度)排序 sourceBuilder.sort(new FieldSortBuilder("_uid").order(SortOrder.ASC)); //通过指定字段来排序
排序有两种排序方式,第一通过ScoreSortBuilder实现按分数(即匹配度)排序
第二种方式通过指定字段来排序,如上图所示通过“_uid”字段排序
关闭检索
有时候我们只想要知道到底匹配了多少条具体,但不关系具体每条记录的内容,这个时候我们可以选择关闭检索,不去查询每天数据的内容,可通过如下方式实现:
sourceBuilder.fetchSource(false);
关闭检索后,运行程序输出如下
只返回了总记录数,遍历输出每条数据均为 null
另外还可以通过sourceBuilder接受一个或多个数组,来控制要要返回哪些字段,排除哪些字段。具体实现如下,第一个数组参数为要接受的字段,第二个数组参数为要排除的内容:
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"); highlightTitle.highlighterType("unified"); //字段高亮显示类型,默认用标签包裹高亮字词 highlightBuilder.field(highlightTitle); searchSourceBuilder.highlighter(highlightBuilder);
以上只是在查询中加入高亮显示的功能,那么我们如何在查询结果中获取呢,通过SearchHit的getHighlightFields()方法获取我们需要关键内容:
SearchHits hits = searchResponse.getHits(); for (SearchHit hit : hits.getHits()) { Map highlightFields = hit.getHighlightFields(); HighlightField highlight = highlightFields.get("title"); Text[] fragments = highlight.fragments(); String fragmentString = fragments[0].string(); }
聚合操作
public void aggregation(){ RestHighLevelClient client = elasticClient.getRestHighLevelClient(); SearchRequest searchRequest = new SearchRequest(); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_sex") .field("sex.keyword"); //若不加keyword,在text类型上进行聚合操作时会报错 aggregation.subAggregation(AggregationBuilders.avg("avg_age") .field("age")); //avg_age 为子聚合名称,名称可随意 searchSourceBuilder.aggregation(aggregation); searchRequest.source(searchSourceBuilder); SearchResponse searchResponse = null; try { searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); } catch (IOException e) { e.printStackTrace(); } Aggregations aggregations = searchResponse.getAggregations(); Terms byCompanyAggregation = aggregations.get("by_sex"); Terms.Bucket elasticBucket = byCompanyAggregation.getBucketByKey("女性"); Avg averageAge = elasticBucket.getAggregations().get("avg_age"); double avg = averageAge.getValue(); System.out.println("女性平均年龄:"+avg); }