Elasticsearch 使用 Java High Level REST Client 查询文档

上一篇我们学习了如何使用 Java High Level REST Client 的相关 API 来操作索引、文档,在此基础上,今天我们来学习如何文档查询。如果你之前已经掌握了如何使用 RESTful API 来实现文档查询,那么使用 Java High Level REST Client 相关的 API 进行文档查询时,你会发现似曾相似,简直就是一个模式,下边我们具体来看。

1、QueryBuilders

我们先认识一个类QueryBuilders,它提供了许多构建文档查询条件的静态方法,例如:

public static MatchQueryBuilder matchQuery(String name, Object text) {}

public static MatchPhraseQueryBuilder matchPhraseQuery(String name, Object text) {}

public static TermQueryBuilder termQuery(String name, String value) {}

public static RangeQueryBuilder rangeQuery(String name) {}

public static BoolQueryBuilder boolQuery() {}
......
......

可以看到这些静态方法都返回了一个 Builder 类型,其实我们也可以自己new对应的 Builder 类,QueryBuilders的相关静态方法就是这么做的,只是简化了我们的操作。通过这些 Builder 类就可以来构建我们的查询条件了,单从它们的名字来看就和我们之前学习 RESTful API 时的matchmatch_phrasetermrangebool很类似,其实就是一回事。

例如,查询school北大,并且age大于等于10小于等于50的数据,可以使用如下方式构建查询条件:

BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
        .must(new TermQueryBuilder("school.keyword", "北大"))
        .must(new RangeQueryBuilder("age").gte(10).lte(50));

2、SearchSourceBuilder

前边我们已经可以构建查询条件了,那么接下来就是如何去接收已有的查询条件了。这里需要使用SearchSourceBuilder类了:

SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
...省略boolQueryBuilder的构建...
searchSourceBuilder.query(boolQueryBuilder);

SearchSourceBuilderquery方法用来接收一个查询条件的对象。SearchSourceBuilder除了接收查询条件,还可以对查询结果排序、分页、查询结果包含文档的那些字段、超时、高亮等等,下边我们来看几个常用的功能:

  • 排序
    按照age降序排列查询结果:
searchSourceBuilder.sort("age", SortOrder.DESC);
  • 分页
    从第0行开始查询20条数据:
searchSourceBuilder.from(0);
searchSourceBuilder.size(20);
  • 字段过滤
    只返回文档中nameageschool三个字段:
String[] includeFields = new String[]{"name", "age", "school"};
searchSourceBuilder.fetchSource(includeFields, new String[]{});
  • 高亮
    设置高亮的字段以及高亮包裹的 html 标签:
HighlightBuilder highlightBuilder = new HighlightBuilder()
        .field("name")
        .preTags("")
        .postTags("");
searchSourceBuilder.highlighter(highlightBuilder);
  • 超时时间
    设置查询的超时时间为10秒:
searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));

3、SearchRequest

通过QueryBuildersSearchSourceBuilder类,我们已经可以构建出复杂的查询了,接下就是去查询了:

SearchRequest request = new SearchRequest("user");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
...省略查询的构建过程...
request.source(searchSourceBuilder);
SearchResponse response = client.search(request, RequestOptions.DEFAULT);

4、实例

在编写实例之前,先根据上一篇的内容准备好如下数据:


数据有了,就开始我们的查询吧。下边的查询代码基本用到了我们上边介绍的内容,关键的都有注释:

public void searchDocument() throws IOException {
    SearchRequest request = new SearchRequest("user");
    SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    // school 是清华或北大的
    BoolQueryBuilder schoolQueryBuilder = QueryBuilders.boolQuery()
            .should(QueryBuilders.termQuery("school.keyword", "北大"))
            // .should(QueryBuilders.matchPhraseQuery("school", "北大"))
            .should(QueryBuilders.termQuery("school.keyword", "清华"));

    BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
            .must(schoolQueryBuilder)
            // name 以王开头的
            .must(QueryBuilders.matchPhrasePrefixQuery("name", "王"))
            // age 大于等于10小于等于70
            .must(QueryBuilders.rangeQuery("age").gte(10).lte(70));

    // 设置查询条件
    searchSourceBuilder.query(boolQueryBuilder);
    // 字段过滤
    String[] includeFields = new String[]{"name", "age", "school"};
    searchSourceBuilder.fetchSource(includeFields, new String[]{});
    // 设置高亮
    HighlightBuilder highlightBuilder = new HighlightBuilder()
            .field("name")
            .preTags("")
            .postTags("");
    searchSourceBuilder.highlighter(highlightBuilder);
    // 排序
    searchSourceBuilder.sort("age", SortOrder.DESC);
    // 分页
    searchSourceBuilder.from(0);
    searchSourceBuilder.size(20);
    // 超时时间
    searchSourceBuilder.timeout(new TimeValue(10, TimeUnit.SECONDS));
    request.source(searchSourceBuilder);
    // 发起查询请求
    SearchResponse response = client.search(request, RequestOptions.DEFAULT);
    for (SearchHit hit : response.getHits()) {
        // 提取高亮的字段内容,因为查询出来的文档数据和高亮字段的数据是分开的
        String highlightName = hit.getHighlightFields().get("name").fragments()[0].toString();
        // 提取查询出的文档数据,并转成对象
        User user = JSONObject.parseObject(hit.getSourceAsString(), User.class);
        // 用高亮的字段内容覆盖覆盖原文档字段
        user.setName(highlightName);
        System.out.println(JSON.toJSONString(user));
    }
}

查询结果如下:


上边分页时每次的开始数据行数是一个固定值0,并不能真正的分页,要分页我们就要先通过总数据条数计算出总页数,总数数据条数可通过如下方法获得:

long totalHits = response.getHits().getTotalHits().value;

接下来具体的分页操作就简单了。

关于文档的查询就先介绍这么多了,下一篇介绍文档的聚合查询。

你可能感兴趣的:(Elasticsearch 使用 Java High Level REST Client 查询文档)