✨建议收藏✨RestHighLevelClient操作大全✨

1,419 阅读20分钟

吃东西的小埋


前言

虽然Elasticsearch官方在7.15版本将RestHighLevelClient标记为了废弃状态,但是其7.17版本是可以和Elasticsearch8.x版本兼容使用的,同时可能有些公司的Elasticsearch版本还停留在6.x7.x,并不会很快升级到8.x,所以RestHighLevelClientApi的整理还是有必要的。

在本文,将对RestHighLevelClient的常用操作进行演示,Elasticsearch的版本是7.6.0,所有操作对应的DSL语句可以在如下两篇文章中找到说明。

超详细总结Elasticsearch的查询之上篇
超详细总结Elasticsearch的查询之下篇

当然,也可以通过如下方式来打印构建出来的DSL语句。

// SearchSourceBuilder用于构建DSL语句
// 其toString()可以打印其构建的DSL语句
String buildDsl = sourceBuilder.toString();
System.out.println(buildDsl);

正文

一. 数据准备

下面会演示如何通过RestHighLevelClient来创建索引和批量插入文档,但是在这之前,我们需要提前将索引信息和需要批量插入的文档写在JSON文件中。

将索引信息写到名为mappings.json的文件中,内容如下。

{
  "properties": {
    "name": {
      "type": "text",
      "fields": {
        "sortkey": {
          "type": "keyword"
        }
      },
      "fielddata": true
    },
    "description": {
      "type": "text"
    },
    "constellation": {
      "type": "keyword"
    },
    "age": {
      "type": "integer"
    },
    "sid": {
      "type": "keyword"
    },
    "sex": {
      "type": "text"
    },
    "status": {
      "type": "boolean"
    },
    "birthday": {
      "type": "date"
    }
  }
}

将需要批量插入的文档写入到名为demoentities.json的文件中,内容如下。

[{
  "name": "Bill",
  "description": "This Is Demo One Bill",
  "constellation": "Sagittarius",
  "age": 20,
  "sid": "0000",
  "sex": "男性",
  "status": true,
  "birthday": "1995-08-11"
}, {
  "name": "Tom",
  "description": "This Is Demo Two Tom",
  "constellation": "Libra",
  "age": 31,
  "sid": "0001",
  "sex": "男性",
  "status": true,
  "birthday": "1990-04-23"
}, {
  "name": "Jack",
  "description": "This Is Demo Three Jack",
  "constellation": "Aquarius",
  "age": 25,
  "sid": "0002",
  "sex": "男性",
  "status": true,
  "birthday": "1994-12-08"
}, {
  "name": "Mary",
  "description": "This Is Demo Four Mary",
  "constellation": "Gemini",
  "age": 33,
  "sid": "0003",
  "sex": "女性",
  "status": false,
  "birthday": "1988-01-23"
}, {
  "name": "Wendy",
  "description": "This Is Demo Five Wendy",
  "constellation": "Virgo",
  "age": 19,
  "sid": "0004",
  "sex": "女性",
  "status": true,
  "birthday": "2001-05-05"
}]

对于文档,我们定义一个实体类来表示。

@Getter
@Setter
public class DemoEntity {

    private String name;
    private String description;
    private String constellation;
    private int age;
    private String sid;
    private String sex;
    private boolean status;
    private String birthday;

}

所有的演示基于Junit4来运行,对应的setUp()tearDown() 方法如下所示。

public class DemoTest {

    private static final String HOST_NAME = "localhost";
    private static final int PORT = 9200;
    private static final String SCHEME = "http";

    private static final String MAPPINGS_FILENAME = "mappings.json";
    private static final String DEMOENTITIES_FILENAME = "demoentities.json";

    private ObjectMapper objectMapper;

    private String mappings;
    private List<DemoEntity> demoEntities;

    private RestHighLevelClient esClient;

    @Before
    public void setUp() throws Exception {
        esClient = new RestHighLevelClient(RestClient.builder(
                new HttpHost(HOST_NAME, PORT, SCHEME)));

        objectMapper = new ObjectMapper();
        InputStream mappingsInputstream = this.getClass().getClassLoader()
                .getResourceAsStream(MAPPINGS_FILENAME);
        mappings = objectMapper.writeValueAsString(objectMapper.readValue(
                mappingsInputstream, Map.class));
        InputStream demoentitiesInputstream = this.getClass().getClassLoader()
                .getResourceAsStream(DEMOENTITIES_FILENAME);
        demoEntities = objectMapper.readValue(demoentitiesInputstream,
                new TypeReference<List<DemoEntity>>() {});
    }

    @After
    public void tearDown() throws Exception {
        esClient.close();
    }
    
    ......
    
}

最后贴出整个演示工程需要的依赖。

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.14.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.14.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.14.0</version>
    </dependency>

    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.6.0</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.6.0</version>
    </dependency>

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.24</version>
    </dependency>
</dependencies>

二. 索引操作

1. 创建索引

创建索引主要依赖CreateIndexRequest,演示代码如下。(使用到的mappings我们已经提前在setUp() 方法里通过读取mappings.json文件得到了,这里不再重复贴出对应代码)。

@Test
public void 创建索引() throws Exception {
    CreateIndexRequest createIndexRequest = new CreateIndexRequest("testindex")
            .mapping(mappings, XContentType.JSON);

    CreateIndexResponse createIndexResponse = esClient.indices()
            .create(createIndexRequest, RequestOptions.DEFAULT);

    System.out.println(createIndexResponse.index());
    System.out.println(createIndexResponse.isAcknowledged());
}

打印如下。

testindex
true

此时名为testindex就已经创建成功。

2. 删除索引

删除索引主要依赖DeleteIndexRequest,演示代码如下。

@Test
public void 删除索引() throws Exception {
    DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("testindex");

    AcknowledgedResponse acknowledgedResponse = esClient.indices()
            .delete(deleteIndexRequest, RequestOptions.DEFAULT);

    System.out.println(acknowledgedResponse.isAcknowledged());
}

打印如下。

true

3. 查询索引

可以通过GetIndexRequest来查询索引的详细信息,如下所示。

@Test
public void 查询索引() throws Exception {
    GetIndexRequest getIndexRequest = new GetIndexRequest("testindex");

    GetIndexResponse getIndexResponse = esClient.indices()
            .get(getIndexRequest, RequestOptions.DEFAULT);

    System.out.println(getIndexResponse.getAliases());
    System.out.println(getIndexResponse.getMappings());
    System.out.println(getIndexResponse.getSettings());
}

打印如下。

{testindex=[]}
{testindex=org.elasticsearch.cluster.metadata.MappingMetaData@5e4051c7}
{testindex={"index.creation_date":"1717426229438","index.number_of_replicas":"1","index.number_of_shards":"1","index.provided_name":"testindex","index.uuid":"Mp-M0NkIT2qGQfin-NUkTw","index.version.created":"7060099"}}

三. 文档操作

1. 创建文档

通过IndexRequest可以插入一条文档,如下所示。

@Test
public void 创建文档() throws Exception {
    DemoEntity demoEntity = demoEntities.get(0);
    IndexRequest indexRequest = new IndexRequest();
    indexRequest.index("testindex").id(demoEntity.getSid())
            .source(objectMapper.writeValueAsString(demoEntity), XContentType.JSON);

    IndexResponse indexResponse = esClient.index(indexRequest,
            RequestOptions.DEFAULT);

    System.out.println(indexResponse.getResult());
}

打印如下。

CREATED

2. 查询文档

这里指的是通过文档Id进行的简单查询,如下所示。

@Test
public void 查询文档() throws Exception {
    GetRequest getRequest = new GetRequest();
    getRequest.index("testindex").id("0000");

    GetResponse getResponse = esClient.get(getRequest,
            RequestOptions.DEFAULT);

    System.out.println(getResponse.getSourceAsString());
}

打印如下。

{
    "name": "Bill",
    "description": "This Is Demo One Bill",
    "constellation": "Sagittarius",
    "age": 20,
    "sid": "0000",
    "sex": "男性",
    "status": true,
    "birthday": "1995-08-11"
}

3. 修改文档

基于UpdateRequest并指定文档Id可以完成文档字段修改,如下所示。

@Test
public void 修改文档() throws Exception {
    UpdateRequest updateRequest = new UpdateRequest();
    updateRequest.index("testindex").id("0000").doc(XContentType.JSON,
            "age", "20");

    UpdateResponse updateResponse = esClient.update(updateRequest,
            RequestOptions.DEFAULT);

    System.out.println(updateResponse.getResult());
}

打印如下。

UPDATED

4. 删除文档

基于DeleteRequest并指定文档Id可以删除指定文档,如下所示。

@Test
public void 删除文档() throws Exception {
    DeleteRequest deleteRequest = new DeleteRequest();
    deleteRequest.index("testindex").id("0000");

    DeleteResponse deleteResponse = esClient.delete(deleteRequest,
            RequestOptions.DEFAULT);

    System.out.println(deleteResponse.getResult());
}

打印如下。

DELETED

5. 批量创建文档

指一次HTTP请求,创建多条文档,依赖于BulkRequest,如下所示。

@Test
public void 批量新增() throws Exception {
    BulkRequest bulkRequest = new BulkRequest();
    for (DemoEntity demoEntity : demoEntities) {
        bulkRequest.add(new IndexRequest().index("testindex").id(demoEntity.getSid()).source(XContentType.JSON,
                "name", demoEntity.getName(), "description", demoEntity.getDescription(),
                "constellation", demoEntity.getConstellation(), "age", demoEntity.getAge(),
                "sid", demoEntity.getSid(), "sex", demoEntity.getSex(),
                "status", demoEntity.isStatus(), "birthday", demoEntity.getBirthday()));
    }

    BulkResponse bulkResponse = esClient.bulk(bulkRequest, RequestOptions.DEFAULT);

    System.out.println(bulkResponse.getTook());
    System.out.println(Arrays.toString(bulkResponse.getItems()));
}

打印如下。

52ms
[org.elasticsearch.action.bulk.BulkItemResponse@2e5c7f0b, org.elasticsearch.action.bulk.BulkItemResponse@21d5c1a0, org.elasticsearch.action.bulk.BulkItemResponse@4de025bf, org.elasticsearch.action.bulk.BulkItemResponse@538613b3, org.elasticsearch.action.bulk.BulkItemResponse@1eef9aef]

6. 批量删除文档

通过BulkRequest指定多个文档Id,可以进行批量文档删除,如下所示。

@Test
public void 批量删除() throws Exception {
    BulkRequest bulkRequest = new BulkRequest();
    for (DemoEntity demoEntity : demoEntities) {
        bulkRequest.add(new DeleteRequest().index("testindex").id(demoEntity.getSid()));
    }

    BulkResponse bulkResponse = esClient.bulk(bulkRequest, RequestOptions.DEFAULT);

    System.out.println(bulkResponse.getTook());
    System.out.println(Arrays.toString(bulkResponse.getItems()));
}

打印如下。

5ms
[org.elasticsearch.action.bulk.BulkItemResponse@55f3c410, org.elasticsearch.action.bulk.BulkItemResponse@11acdc30, org.elasticsearch.action.bulk.BulkItemResponse@770d4269, org.elasticsearch.action.bulk.BulkItemResponse@4a8ab068, org.elasticsearch.action.bulk.BulkItemResponse@1922e6d]

三. Match查询

1. match_all

匹配索引下所有文档,默认返回10条数据。

@Test
public void match_all() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery()));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

5 hits
1ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}
{"name":"Tom","description":"This Is Demo Two Tom","constellation":"Libra","age":31,"sid":"0001","sex":"男性","status":true,"birthday":"1990-04-23"}
{"name":"Jack","description":"This Is Demo Three Jack","constellation":"Aquarius","age":25,"sid":"0002","sex":"男性","status":true,"birthday":"1994-12-08"}
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}
{"name":"Wendy","description":"This Is Demo Five Wendy","constellation":"Virgo","age":19,"sid":"0004","sex":"女性","status":true,"birthday":"2001-05-05"}

2. 分页查询

from表示从第几条数据开始(首条数据是第0),size表示查询多少条数据回来。

@Test
public void 分页查询() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .from(3)
                    .size(2));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

5 hits
1ms
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}
{"name":"Wendy","description":"This Is Demo Five Wendy","constellation":"Virgo","age":19,"sid":"0004","sex":"女性","status":true,"birthday":"2001-05-05"}

3. 指定返回某些字段

可以在查询时,通过SearchSourceBuilderfetchSource() 方法指定返回文档的哪些字段(第一个参数)。

@Test
public void 指定返回某些字段() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .fetchSource(new String[] {"name", "sid"}, new String[] {}));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

5 hits
1ms
{"name":"Bill","sid":"0000"}
{"name":"Tom","sid":"0001"}
{"name":"Jack","sid":"0002"}
{"name":"Mary","sid":"0003"}
{"name":"Wendy","sid":"0004"}

4. 指定排除某些字段

可以在查询时,通过SearchSourceBuilderfetchSource() 方法指定不要返回文档的哪些字段(第二个参数)。

@Test
public void 指定排除某些字段() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .fetchSource(new String[] {}, new String[] {"sex", "birthday"}));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

5 hits
1ms
{"constellation":"Sagittarius","name":"Bill","description":"This Is Demo One Bill","age":20,"sid":"0000","status":true}
{"constellation":"Libra","name":"Tom","description":"This Is Demo Two Tom","age":31,"sid":"0001","status":true}
{"constellation":"Aquarius","name":"Jack","description":"This Is Demo Three Jack","age":25,"sid":"0002","status":true}
{"constellation":"Gemini","name":"Mary","description":"This Is Demo Four Mary","age":33,"sid":"0003","status":false}
{"constellation":"Virgo","name":"Wendy","description":"This Is Demo Five Wendy","age":19,"sid":"0004","status":true}

5. 脚本自定义字段

SearchSourceBuilderscriptField() 方法可以添加自定义脚本字段,第一个参数是自定义的字段名,第二个参数是配置的脚本用于指定字段的拼装规则。

@Test
public void 脚本字段() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .scriptField("hello_filed", new Script("doc['name'].value+'_hello'"))
                    .scriptField("world_filed", new Script("doc['name'].value+'_world'")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        Map<String, DocumentField> fields = searchHit.getFields();
        fields.forEach((filed, value) -> {
            System.out.println(value.getName() + ": " + value.getValue());
        });
    }
}

打印如下。

5 hits
14ms
hello_filed: bill_hello
world_filed: bill_world
hello_filed: tom_hello
world_filed: tom_world
hello_filed: jack_hello
world_filed: jack_world
hello_filed: mary_hello
world_filed: mary_world
hello_filed: wendy_hello
world_filed: wendy_world

6. match

通过查询条件来匹配文档,但是注意查询条件会分词

@Test
public void match() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchQuery("description", "One")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
2ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

7. match_phrase

按照短语去匹配文档,查询条件会分词,在匹配中文短语的场景下比较好用。

@Test
public void match_phrase_noslop() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchPhraseQuery("description", "Demo One")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
5ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

8. slop指定间隔

match_phrase可以搭配slop来指定间隔,示例如下。

@Test
public void match_phrase_useslop() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchPhraseQuery("description", "Is Bill")
                            .slop(2)));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

上面意思就是isbill之间如果间隔两个词就算作匹配,打印如下。

1 hits
2ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

9. match_phrase_prefix

先结合下面示例解释一下match_phrase_prefix,我们对description字段的查询条件Is Demo On会被分词为isdemoon这三个Token,此时进行match_phrase_prefix查询,就是将上述三个Token的最后一个Token之前的Tokenisdemo)去进行一个match_phrase查询,然后最后一个Tokenon)进行前缀匹配。

@Test
public void match_phrase_prefix() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchPhrasePrefixQuery("description", "Is Demo On")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
4ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

10. multi_match

匹配文档时需要多个字段满足查询条件,注意查询条件是会分词的。

@Test
public void multi_match() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.multiMatchQuery("Bill Good", "name", "description")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
0s
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

四. Term查询

1. term

通过查询条件来匹配文档,并且查询条件不会分词

@Test
public void term() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.termQuery("description", "one")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
1ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

2. terms

根据查询条件集合匹配文档,文档匹配任意查询条件就返回,不分词

@Test
public void terms() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.termsQuery("description", Arrays.asList("one", "two"))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

2 hits
0s
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}
{"name":"Tom","description":"This Is Demo Two Tom","constellation":"Libra","age":31,"sid":"0001","sex":"男性","status":true,"birthday":"1990-04-23"}

五. 布尔查询

1. must

文档满足所有条件时才会被返回。

@Test
public void must() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.boolQuery()
                            .must(QueryBuilders.matchQuery("name", "Mary"))
                            .must(QueryBuilders.matchPhraseQuery("sex", "女性"))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
6ms
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}

2. should

文档满足任意查询条件就返回。

@Test
public void should() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.boolQuery()
                            .should(QueryBuilders.matchQuery("name", "Bill"))
                            .should(QueryBuilders.matchPhraseQuery("name", "Mary"))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

2 hits
1ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}

3. must_not

文档不满足所有条件时才返回。

@Test
public void must_not() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.boolQuery()
                            .mustNot(QueryBuilders.matchPhraseQuery("sex", "男性"))
                            .mustNot(QueryBuilders.rangeQuery("age")
                                    .gte(25))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
2ms
{"name":"Wendy","description":"This Is Demo Five Wendy","constellation":"Virgo","age":19,"sid":"0004","sex":"女性","status":true,"birthday":"2001-05-05"}

4. filter

功能同must,只不过不参与记分(must参与)。

@Test
public void filter() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.boolQuery()
                            .filter(QueryBuilders.matchPhraseQuery("sex", "男性"))
                            .filter(QueryBuilders.rangeQuery("age")
                                    .gte(25))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

2 hits
0s
{"name":"Tom","description":"This Is Demo Two Tom","constellation":"Libra","age":31,"sid":"0001","sex":"男性","status":true,"birthday":"1990-04-23"}
{"name":"Jack","description":"This Is Demo Three Jack","constellation":"Aquarius","age":25,"sid":"0002","sex":"男性","status":true,"birthday":"1994-12-08"}

5. 布尔查询嵌套

布尔嵌套是boolQuery() 里面嵌一个boolQuery(),本质就是将一个布尔条件当作外层布尔查询的一个条件,示例如下。

@Test
public void 布尔查询嵌套() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.boolQuery()
                            .must(QueryBuilders.matchQuery("description", "This People"))
                            .must(QueryBuilders.termsQuery("age", new int[] {30, 33}))
                            .must(QueryBuilders.boolQuery()
                                    .should(QueryBuilders.matchQuery("status", true))
                                    .should(QueryBuilders.rangeQuery("birthday")
                                            .gte("1980-01-01")))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
3ms
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}

六. 排序查询

1. 简单排序

下面演示对日期进行升序排序。

@Test
public void 排序查询() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .sort("birthday", SortOrder.ASC));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

5 hits
1ms
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}
{"name":"Tom","description":"This Is Demo Two Tom","constellation":"Libra","age":31,"sid":"0001","sex":"男性","status":true,"birthday":"1990-04-23"}
{"name":"Jack","description":"This Is Demo Three Jack","constellation":"Aquarius","age":25,"sid":"0002","sex":"男性","status":true,"birthday":"1994-12-08"}
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}
{"name":"Wendy","description":"This Is Demo Five Wendy","constellation":"Virgo","age":19,"sid":"0004","sex":"女性","status":true,"birthday":"2001-05-05"}

2. 多级排序

下面演示当birthday相等时,再根据age来排序。

@Test
public void 多级排序() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .sort("birthday", SortOrder.ASC)
                    .sort("age", SortOrder.DESC));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

5 hits
0s
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}
{"name":"Tom","description":"This Is Demo Two Tom","constellation":"Libra","age":31,"sid":"0001","sex":"男性","status":true,"birthday":"1990-04-23"}
{"name":"Jack","description":"This Is Demo Three Jack","constellation":"Aquarius","age":25,"sid":"0002","sex":"男性","status":true,"birthday":"1994-12-08"}
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}
{"name":"Wendy","description":"This Is Demo Five Wendy","constellation":"Virgo","age":19,"sid":"0004","sex":"女性","status":true,"birthday":"2001-05-05"}

3. 对分词字段进行排序

正常是不能对会分词的字段进行排序以及桶聚合的,但是可以为分词的字段添加一个类型为keyword的字段,就可以排序了(我们在创建索引时已经为name添加好了类型为keyword的字段)。

@Test
public void 对分词字段进行排序() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .sort("name", SortOrder.ASC));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

5 hits
0s
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}
{"name":"Jack","description":"This Is Demo Three Jack","constellation":"Aquarius","age":25,"sid":"0002","sex":"男性","status":true,"birthday":"1994-12-08"}
{"name":"Mary","description":"This Is Demo Four Mary","constellation":"Gemini","age":33,"sid":"0003","sex":"女性","status":false,"birthday":"1988-01-23"}
{"name":"Tom","description":"This Is Demo Two Tom","constellation":"Libra","age":31,"sid":"0001","sex":"男性","status":true,"birthday":"1990-04-23"}
{"name":"Wendy","description":"This Is Demo Five Wendy","constellation":"Virgo","age":19,"sid":"0004","sex":"女性","status":true,"birthday":"2001-05-05"}

七. 模糊查询

1. fuzzy

fuzzy查询中可以通过fuzziness来指定编辑距离,即查询条件如果与文档对应字段分词后的Token的编辑距离满足fuzziness,则匹配,注意查询条件不分词

编辑距离就是将一个字符串变成另外一个字符串需要的最小变更次数

下面示例中,boll通过一次编辑可以变成bill,故description字段分词后的Tokenbill的文档会被匹配出来。

@Test
public void fuzzy() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.fuzzyQuery("description", "boll")
                            .fuzziness(Fuzziness.ONE)));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
10ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

2. wildcard

查询条件不分词)支持如下两种通配符。

  • *匹配任意字符序列
  • ?匹配任意单字符
@Test
public void 通配符查询() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.wildcardQuery("description", "bi*")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    SearchHits searchHits = searchResponse.getHits();
    System.out.println(searchHits.getTotalHits());
    System.out.println(searchResponse.getTook());
    for (SearchHit searchHit : searchHits) {
        System.out.println(searchHit.getSourceAsString());
    }
}

打印如下。

1 hits
2ms
{"name":"Bill","description":"This Is Demo One Bill","constellation":"Sagittarius","age":20,"sid":"0000","sex":"男性","status":true,"birthday":"1995-08-11"}

八. 指标聚合

1. max,min,avgsum

这四种指标的说明如下。

指标项说明
max最大值
min最小值
avg平均值
sum累加值

聚合主要使用SearchSourceBuilderaggregation() 方法来添加聚合内容,如下所示。

@Test
public void max_min_avg_sum() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.max("test_max")
                            .field("age"))
                    .aggregation(AggregationBuilders.min("test_min")
                            .field("age"))
                    .aggregation(AggregationBuilders.avg("test_avg")
                            .field("age"))
                    .aggregation(AggregationBuilders.sum("test_sum")
                            .field("age")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Sum) {
            System.out.println(((Sum) aggregation).getValue());
        } else if (aggregation instanceof Max) {
            System.out.println(((Max) aggregation).getValue());
        } else if (aggregation instanceof Avg) {
            System.out.println(((Avg) aggregation).getValue());
        } else if (aggregation instanceof Min) {
            System.out.println(((Min) aggregation).getValue());
        }
    }
}

打印如下。

128.0
33.0
25.6
19.0

2. value_count

统计指定字段出现的次数。

@Test
public void value_count() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.count("test_value_count")
                            .field("name")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof ValueCount) {
            System.out.println(((ValueCount) aggregation).getValue());
        }
    }
}

打印如下。

5

3. cardinality

统计指定字段不同的值的个数。

@Test
public void cardinality() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.cardinality("test_cardinality")
                            .field("status")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Cardinality) {
            System.out.println(((Cardinality) aggregation).getValue());
        }
    }
}

打印如下。

2

4. stats

方便的计算出统计信息minmaxavgsumcount

@Test
public void stats() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.stats("test_stats")
                            .field("age")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Stats) {
            System.out.println(((Stats) aggregation).getCount());
            System.out.println(((Stats) aggregation).getMin());
            System.out.println(((Stats) aggregation).getMax());
            System.out.println(((Stats) aggregation).getAvg());
            System.out.println(((Stats) aggregation).getSum());
        }
    }
}

打印如下。

5
19.0
33.0
25.6
128.0

5. extended_stats

stats基础上增加了平方和方差标准差平均值加减标准差的统计信息。

@Test
public void extended_stats() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.extendedStats("test_extended_stats")
                            .field("age")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof ExtendedStats) {
            System.out.println(((ExtendedStats) aggregation).getCount());
            System.out.println(((ExtendedStats) aggregation).getMin());
            System.out.println(((ExtendedStats) aggregation).getMax());
            System.out.println(((ExtendedStats) aggregation).getAvg());
            System.out.println(((ExtendedStats) aggregation).getSum());
            System.out.println(((ExtendedStats) aggregation).getSumOfSquares());
            System.out.println(((ExtendedStats) aggregation).getVariance());
            System.out.println(((ExtendedStats) aggregation).getStdDeviation());
            System.out.println(((ExtendedStats) aggregation).getStdDeviationBound(ExtendedStats.Bounds.UPPER));
            System.out.println(((ExtendedStats) aggregation).getStdDeviationBound(ExtendedStats.Bounds.LOWER));
        }
    }
}

打印如下。

5
19.0
33.0
25.6
128.0
3436.0
31.839999999999964
5.642694391866351
36.8853887837327
14.3146112162673

6. percentiles

用于统计指定字段不同值区间下的文档数占总文档数的百分比。

@Test
public void percentiles() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.percentiles("test_percentiles")
                            .field("age")
                            .percentiles(1, 5, 25, 50, 75, 95, 100)));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Percentiles) {
            for (Percentile percentile : (Percentiles) aggregation) {
                System.out.println(percentile.getPercent() + ": " + percentile.getValue());
            }
        }
    }
}

打印如下。

1.0: 19.0
5.0: 19.0
25.0: 19.75
50.0: 25.0
75.0: 31.5
95.0: 33.0
100.0: 33.0

意思age < 25的文档,占总命中文档数的50%。

九. 桶聚合

1. terms

字段的一个唯一值就是一个桶。

@Test
public void terms桶聚合() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.terms("test_terms")
                            .field("status")));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Terms) {
            System.out.println(((Terms) aggregation).getDocCountError());
            System.out.println(((Terms) aggregation).getSumOfOtherDocCounts());
            List<? extends Terms.Bucket> buckets = ((Terms) aggregation).getBuckets();
            for (Terms.Bucket bucket : buckets) {
                System.out.println(bucket.getKeyAsString() + ":" + bucket.getDocCount());
            }
        }
    }
}

打印如下。

0
0
true:4
false:1

示例中聚合字段是status,为布尔类型,可以进行terms聚合,如果是text类型,则不能,除非为text字段添加keyword字段。

在桶里面还能再聚合,如下所示。

@Test
public void 桶聚合基础上进一步聚合() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.terms("test_terms")
                            .field("status")
                            .subAggregation(AggregationBuilders.stats("test_stats")
                                    .field("age"))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Terms) {
            System.out.println(((Terms) aggregation).getDocCountError());
            System.out.println(((Terms) aggregation).getSumOfOtherDocCounts());
            List<? extends Terms.Bucket> buckets = ((Terms) aggregation).getBuckets();
            for (Terms.Bucket bucket : buckets) {
                System.out.println(bucket.getKeyAsString() + ":" + bucket.getDocCount());
                Aggregations subAggregations = bucket.getAggregations();
                Stats stats = subAggregations.get("test_stats");
                System.out.println(stats.getCount());
                System.out.println(stats.getMin());
                System.out.println(stats.getMax());
                System.out.println(stats.getAvg());
                System.out.println(stats.getSum());
            }
        }
    }
}

打印如下。

0
0
true:4
4
19.0
31.0
23.75
95.0
false:1
1
33.0
33.0
33.0
33.0

上面演示的是在桶里面又进行了一次status指标聚合。

2. filter

表示对查询结果进行过滤,如下所示。

@Test
public void filter桶聚合() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.filter("test_filter", QueryBuilders.boolQuery()
                            .filter(QueryBuilders.matchQuery("status", true)))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Filter) {
            System.out.println(((Filter) aggregation).getDocCount());
        }
    }
}

打印如下。

4

3. filters

filters用于对查询结果进行多个条件过滤,一个过滤条件对应一个桶,每个条件的过滤结果之间是相互独立的,所以同一条文档可能会进入多个桶。

下面演示将statustrue的文档放入一个桶,将age大于等于30的文档放入一个桶。

@Test
public void filters桶聚合() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.filters("test_filters",
                            QueryBuilders.matchQuery("status", true),
                            QueryBuilders.rangeQuery("age")
                                    .gte(30))));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Filters) {
            List<? extends Filters.Bucket> buckets = ((Filters) aggregation).getBuckets();
            for (Filters.Bucket bucket : buckets) {
                System.out.println(bucket.getDocCount());
            }
        }
    }
}

打印如下。

4
2

4. range

range用于在查询结果上基于范围来聚合,一个范围就是一个桶,并且范围区间是前闭后开,被聚合的字段类型需要是数字类型

@Test
public void range桶聚合() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.range("test_range")
                            .field("age")
                            .addRange(10, 20)
                            .addRange(20, 30)
                            .addRange(30, 40)));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Range) {
            List<? extends Range.Bucket> buckets = ((Range) aggregation).getBuckets();
            for (Range.Bucket bucket : buckets) {
                System.out.println("key: " + bucket.getKeyAsString());
                System.out.println("doc_count: " + bucket.getDocCount());
            }
        }
    }
}

打印如下。

key: 10.0-20.0
doc_count: 1
key: 20.0-30.0
doc_count: 2
key: 30.0-40.0
doc_count: 2

5. histogram

histogram用于在查询结果上基于固定间隔来聚合,一个间隔就是一个桶,聚合的字段类型需要是数字类型

@Test
public void histogram桶聚合() throws Exception {
    SearchRequest searchRequest = new SearchRequest();
    searchRequest.indices("testindex").source(
            new SearchSourceBuilder()
                    .query(QueryBuilders.matchAllQuery())
                    .aggregation(AggregationBuilders.histogram("test_histogram")
                            .field("age")
                            .interval(5)
                            .extendedBounds(10, 34)));

    SearchResponse searchResponse = esClient
            .search(searchRequest, RequestOptions.DEFAULT);

    Aggregations aggregations = searchResponse.getAggregations();
    for (Aggregation aggregation : aggregations) {
        if (aggregation instanceof Histogram) {
            List<? extends Histogram.Bucket> buckets = ((Histogram) aggregation).getBuckets();
            for (Histogram.Bucket bucket : buckets) {
                System.out.println("key: " + bucket.getKeyAsString());
                System.out.println("doc_count: " + bucket.getDocCount());
            }
        }
    }
}

打印如下。

key: 10.0
doc_count: 0
key: 15.0
doc_count: 1
key: 20.0
doc_count: 1
key: 25.0
doc_count: 1
key: 30.0
doc_count: 2

总结

原始的DSL内容可以参加下面两篇文档。

超详细总结Elasticsearch的查询之上篇
超详细总结Elasticsearch的查询之下篇

官方7.17RestHighLevelClient文档地址如下。

Java REST Client-7.17


总结不易,如果本文对你有帮助,烦请点赞,收藏加关注,谢谢帅气漂亮的你。

傻笑的小埋