ES 基础用法
创建索引
# 创建索引
# "dynamic": "strict"====》不允许动态添加字段,如果遇到新的字段,就抛出异常。
# "dynamic": "true"===》允许动态添加新的字段。这是默认值
# "dynamic": "false"===》忽略新的字段。在原有的映射基础上,当有新的字段时,不会主动的添加新的映射关系,只作为查询结果出现在查询中。
PUT my_blogs
{
"mappings": {
"dynamic": "strict",
"properties": {
"author": {
"type": "keyword"
},
"title": {
"type": "keyword"
},
"content": {
"type": "text"
},
"views": {
"type": "integer"
},
"created": {
"type": "date",
"format":"yyyy-MM-dd HH:mm:ss"
}
}
}
}
keyword与text的区别:text会被分词;
date类型的默认格式为:”strict_date_optional_time||epoch_millis”,文档
查看索引信息
GET my_blogs/_mapping
删除索引
DELETE /test_blogs
新增文档
# 指定文档id为blog1,如果未指定则会自动生成
# 新增
POST my_blogs/_doc/blog1
{
"author": "lzc",
"title":"Learning ElasticSearch",
"content":"学习ElasticSearch技术",
"views": 0,
"created": "2020-05-06 08:44:00"
}
POST my_blogs/_doc/blog2
{
"author": "lzc",
"title":"Learning Java",
"content":"学习java技术",
"views": 0,
"created": "2020-05-06 08:44:00"
}
POST my_blogs/_doc/
{
"author": "lzc",
"title":"Learning RocketMQ",
"content":"学习RocketMQ技术",
"views": 0,
"created": "2020-05-06 08:56:00"
}
# 查询所有
GET /my_blogs/_search
{
"query": {
"match_all": {}
}
}
查询
term、terms
term查询、terms查询会去倒排索引中寻找确切的term,它并不知道分词器的存在,这种查询适合keyword、numeric、date等明确值的。
# term查询:查询 author 字段里有某个关键词的文档
GET /my_blogs/_search
{
"query": {
"term": {
"author": "lzc"
}
}
}
# terms 查询:查询 author 字段里有多个关键词的文档
GET /my_blogs/_search
{
"query": {
"terms": {
"author": [
"zhangsan",
"lzc"
]
}
}
}
match、multi_match
match查询知道分词器的存在,会对field进行分词操作,然后再查询
# 它和term区别可以理解为term是精确查询,match是模糊查询;
# match会对"学习RocketMQ"分词,分词规则跟分词器有关,可能会被分为"学习"与"RocketMQ"
# term 可以认为这是一个单词
GET /my_blogs/_search
{
"query": {
"match": {
"content": "学习RocketMQ"
}
}
}
# 查询多个字段
GET /my_blogs/_search
{
"query": {
"multi_match": {
"query": "RocketMQ",
"fields": ["content","xxxx"]
}
}
}
_source
指定需要返回的字段
# 只返回author、title字段
GET /my_blogs/_search
{
"_source": ["author","title"],
"query": {
"match_all": {}
}
}
Bool查询
must
返回的文档必须满足must子句的条件,并且参与计算分值。
# term查询:查询 author 字段里有某个关键词的文档
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{"term":{"author":"lzc"}}
]
}
}
}
# 匹配多个字段
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{"term":{"title":"java"}},
{"term":{"author":"zhangsan"}}
]
}
}
}
# terms 查询:查询某个字段里有多个关键词的文档
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{"terms":{"author":["lzc","zhangsan"]}}
]
}
}
}
must_not
返回的文档必须不满足must_not定义的条件。
GET /my_blogs/_search
{
"query": {
"bool": {
"must_not": [
{"term":{"author":"zhangsan"}}
]
}
}
}
should
返回的文档可能满足should子句的条件。在一个Bool查询中,如果没有must或者filter,有一个或者多个should子句,那么只要满足一个就可以返回。minimum_should_match
参数定义了至少满足几个子句。
# 相当于or语句
GET /my_blogs/_search
{
"query": {
"bool": {
"should": [
{"term":{"author":"lzc"}},
{"term":{"author":"zhangsan"}}
]
}
}
}
filter
返回的文档必须满足filter子句的条件。但是不会像Must一样,参与计算分值。
# 类似于and语句
GET /my_blogs/_search
{
"query": {
"bool": {
"filter": [
{"term":{"title":"java"}},
{"term":{"author":"zhangsan"}}
]
}
}
}
exists
# 查询字段为author的值不为null或者不为[]
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{
"exists": {
"field": "author"
}
}
]
}
}
}
高亮查询
单字段查询
GET /my_blogs/_search
{
"query": {
"match": {
"content": "RocketMQ"
}
},
"highlight": {
"pre_tags": [
"<tag1>"
],
"post_tags": [
"</tag1>"
],
"fields": {
"content": {}
}
}
}
查询结果:
{
"_index" : "my_blogs",
"_type" : "_doc",
"_id" : "Bfh853EBC1bB8l9gL99x",
"_score" : 1.092264,
"_source" : {
"author" : "lzc",
"title" : "Learning RocketMQ",
"content" : "学习RocketMQ技术",
"views" : 0,
"created" : "2020-05-06 08:56:00"
},
"highlight" : {
"content" : [
"学习<tag1>RocketMQ</tag1>技术"
]
}
}
多字段查询
GET /my_blogs/_search
{
"query" : {
"multi_match": {
"query": "RocketMQ" ,
"fields" : [ "content", "title" ]
}
},
"highlight" : {
"pre_tags" : ["<tag1>"],
"post_tags" : ["</tag1>"],
"fields" : {
"title": {},
"content" : {}
}
}
}
删除文档
# 通过id删除
DELETE my_blogs/_doc/blog9
# 通过条件删除
POST my_blogs/_delete_by_query
{
"query": {
"bool": {
"must": [
{
"term": {
"author": {
"value": "zhangsan"
}
}
}
]
}
}
}
修改文档
# 根据id修改
POST my_blogs/_update/blog1
{
"doc": {
"author":"lizc"
}
}
# doc_as_upsert 设置 true, 如果id不存在就新增
POST my_blogs/_update/blog2
{
"doc": {
"author":"lizhencheng",
"title":"好好学习"
},
"doc_as_upsert" : true
}
连接查询
ElasticSerch 的连接查询有两种方式实现
- nested
- parent和child关联查询
nested
创建索引
# 假设用来存储博客与博客评论
PUT my_blogs
{
"mappings": {
"properties": {
"author": {
"type": "keyword"
},
"title": {
"type": "keyword"
},
"content": {
"type": "text"
},
"views": {
"type": "integer"
},
"created": {
"type": "date",
"format":"yyyy-MM-dd HH:mm:ss"
},
"comment": {
"type": "nested",
"properties": {
"commentName":{
"type":"keyword"
},
"commentContent":{
"type":"keyword"
},
"commentCreated":{
"type": "date",
"format":"yyyy-MM-dd HH:mm:ss"
}
}
}
}
}
}
新增数据
POST my_blogs/_doc/blog1
{
"author": "lzc",
"title":"Learning ElasticSearch",
"content":"学习ElasticSearch技术",
"views": 0,
"created": "2020-05-06 08:00:00",
"comment":[
{
"commentName":"zhangsan",
"commentContent":"commentContent1",
"commentCreated":"2020-05-07 08:00:00"
},
{
"commentName":"lisi",
"commentContent":"commentContent2",
"commentCreated":"2020-05-07 10:00:00"
},
{
"commentName":"wangwu",
"commentContent":"commentContent3",
"commentCreated":"2020-05-08 08:00:00"
}
]
}
POST my_blogs/_doc/blog2
{
"author": "xiaoli",
"title":"Learning Java",
"content":"学习Java技术",
"views": 0,
"created": "2020-05-07 08:00:00",
"comment":[
{
"commentName":"zhangsan",
"commentContent":"commentContent4",
"commentCreated":"2020-05-08 08:00:00"
}
]
}
查询
# 查询 author = lzc 并且 commentName = zhangsan
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"author": {
"value": "lzc"
}
}
},
{
"nested": {
"path": "comment",
"query": {
"bool": {
"must": [
{
"term": {
"comment.commentName": {
"value": "zhangsan"
}
}
}
]
}
}
}
}
]
}
}
}
parent-child
创建索引
PUT my_blogs
{
"mappings": {
"properties": {
"blog_comment_relation": {
"type": "join",
"relations": {
"blog": [
"comment"
]
}
},
"author": {
"type": "keyword"
},
"title": {
"type": "keyword"
},
"content": {
"type": "text"
},
"views": {
"type": "integer"
},
"created": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"commentName": {
"type": "keyword"
},
"commentContent": {
"type": "keyword"
},
"commentCreated": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
新增数据
# 新增父节点
POST my_blogs/_doc/blog1
{
"author": "lzc",
"title":"Learning ElasticSearch",
"content":"学习ElasticSearch技术",
"views": 0,
"created": "2020-05-06 08:55:00",
"blog_comment_relation": {
"name":"blog"
}
}
POST my_blogs/_doc/blog2
{
"author": "zhangsan",
"title":"Learning Java",
"content":"学习java技术",
"views": 0,
"created": "2020-05-06 08:58:00",
"blog_comment_relation": {
"name":"blog"
}
}
# 新增子节点记录
# 需要指定routing为父节点的id,使得他们处于同一个分片。无论是子节点还是孙子节点,routing都是指向父节点id
# parent 指定父元素id
PUT my_blogs/_doc/comment1?routing=blog1
{
"commentUserName": "lili",
"commentContent": "I am learning ElasticSearch",
"commentCreated":"2020-05-07 08:00:00",
"blog_comment_relation": {
"name": "comment",
"parent": "blog1"
}
}
PUT my_blogs/_doc/comment2?routing=blog1
{
"commentUserName": "jack",
"commentContent": "I am learning Java",
"commentCreated":"2020-05-07 09:00:00",
"blog_comment_relation": {
"name": "comment",
"parent": "blog1"
}
}
PUT my_blogs/_doc/comment3?routing=blog2
{
"commentUserName": "jackma",
"commentContent": "so easy",
"commentCreated":"2020-05-08 09:00:00",
"blog_comment_relation": {
"name": "comment",
"parent": "blog2"
}
}
查询
# Has Child查询,返回父文档
# "inner_hits": {} ==> 加了这个会将子文档一起查询出来, 默认只会返回三条数据
# "inner_hits"里面有四个属性
# from: 返回结果的偏移量, 如"from": 2 ==> 从索引为2的位置返回size条数据
# size: inner_hits返回的最大数量。默认值为3。
# size: inner_hits => 默认情况最大可设置为100,可通过index.max_inner_result_window来设置
# sort: 如何对内部命中进行排序,如 "sort": [{"commentCreated":"desc"}]
# name: 用于响应中特定内部命中定义的名称
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"_id": {
"value": "blog1"
}
}
},
{
"has_child": {
"type": "comment",
"query": {
"bool": {
"must": [
{
"match_all": {}
}
]
}
},
"inner_hits": {
"size": 10,
"sort": [{"commentCreated":"desc"}]
}
}
}
]
}
}
}
# Has Parent查询,返回子文档
# "inner_hits": {} ==> 加了这个会将父文档一起查询出来
POST /my_blogs/_search
{
"query": {
"bool": {
"must": [
{
"has_parent": {
"parent_type": "blog",
"query": {
"match": {
"_id": "blog1"
}
},
"inner_hits": {}
}
}
]
}
}
}
比较
nested | parent/child | |
---|---|---|
优点 | 读取性能高 | 父子文档可以独立更新 |
缺点 | 每次更新需要更新整个文档 | 关联关系,需要额外的内存,查询效率相对较差 |
场景 | 频繁查询 | 频繁更新 |
聚合
# size为0则不会返回文档信息,只会返回聚合信息
GET /my_blogs/_search
{
"size" : 0,
"aggs" : {
"author_blog_counts" : {
"terms" : {
"field" : "author"
}
}
}
}
返回结果
{
"took" : 6,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
},
"aggregations" : {
"author_blog_counts" : {
"doc_count_error_upper_bound" : 0,
"sum_other_doc_count" : 0,
"buckets" : [
{
"key" : "lzc",
"doc_count" : 2
},
{
"key" : "zhangsan",
"doc_count" : 1
}
]
}
}
}
Reindex
将文档从一个索引复制到另一个索引。
# 将my_blogs中的数据复制到my_blogs_copy
POST _reindex
{
"source": {
"index": "my_blogs"
},
"dest": {
"index": "my_blogs_copy"
}
}
# 设置数量, 默认情况, size为1000
POST _reindex
{
"size": 1,
"source": {
"index": "my_blogs"
},
"dest": {
"index": "my_blogs_copy"
}
}
# 根据条件进行复制
POST _reindex
{
"size": 1000,
"source": {
"index": "my_blogs",
"query": {
"bool": {
"must": [
{
"term": {
"author": {
"value": "lzc"
}
}
}
]
}
}
},
"dest": {
"index": "my_blogs_copy"
}
}
自动匹配
www.elastic.co/guide/en/elasticsea...
分页
scroll
www.elastic.co/guide/en/elasticsea...
www.elastic.co/guide/en/elasticsea...
Java操作
配置
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>7.1.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.1.1</version>
</dependency>
与SpringBoot进行整合
elasticsearch.ip=localhost:9200
配置类
@Configuration
public class ESConfig {
/**
* 超时时间设为5分钟
*/
private static final int TIME_OUT = 5 * 60 * 1000;
private static final int ADDRESS_LENGTH = 2;
private static final String HTTP_SCHEME = "http";
@Value("${elasticsearch.ip}")
String[] ipAddress;
@Bean
public RestClientBuilder restClientBuilder() {
HttpHost[] hosts = Arrays.stream(ipAddress)
.map(this::makeHttpHost)
.filter(Objects::nonNull)
.toArray(HttpHost[]::new);
return RestClient.builder(hosts);
}
@Bean(name = "restHighLevelClient")
public RestHighLevelClient highLevelClient(@Autowired RestClientBuilder restClientBuilder) {
restClientBuilder.setRequestConfigCallback(
new RestClientBuilder.RequestConfigCallback() {
@Override
public RequestConfig.Builder customizeRequestConfig(
RequestConfig.Builder requestConfigBuilder) {
return requestConfigBuilder.setSocketTimeout(TIME_OUT);
}
});
return new RestHighLevelClient(restClientBuilder);
}
private HttpHost makeHttpHost(String s) {
assert !StringUtils.isEmpty(s);
String[] address = s.split(":");
if (address.length == ADDRESS_LENGTH) {
String ip = address[0];
int port = Integer.parseInt(address[1]);
System.err.println(ip + "+" + port);
return new HttpHost(ip, port, HTTP_SCHEME);
} else {
return null;
}
}
}
创建索引
PUT my_blogs
{
"mappings": {
"properties": {
"blog_comment_relation": {
"type": "join",
"relations": {
"blog": [
"comment"
]
}
},
"author": {
"type": "keyword"
},
"title": {
"type": "keyword"
},
"content": {
"type": "text"
},
"views": {
"type": "integer"
},
"created": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
},
"commentName": {
"type": "keyword"
},
"commentContent": {
"type": "keyword"
},
"commentCreated": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss"
}
}
}
}
编写代码
官方文档:www.elastic.co/guide/en/elasticsea...
新增
www.elastic.co/guide/en/elasticsea...
@Autowired
private RestHighLevelClient restHighLevelClient;
@Test
public void insert() throws IOException {
Map<String, Object> blog = new HashMap();
blog.put("author","lzc");
blog.put("title","Learning ElasticSearch12");
blog.put("content","学习ElasticSearch技术");
Map<String, Object> blogCommentRelation1 = new HashMap();
blogCommentRelation1.put("name","blog");
blog.put("blog_comment_relation",blogCommentRelation1);
IndexResponse indexResponse1 = insert("my_blogs", "blog1", null, blog);
Map<String, Object> comment1 = new HashMap();
comment1.put("commentName","commentName1");
comment1.put("commentContent","commentContent1");
Map<String, Object> blogCommentRelation2 = new HashMap();
blogCommentRelation2.put("name","comment");
blogCommentRelation2.put("parent","blog1");
comment1.put("blog_comment_relation",blogCommentRelation2);
IndexResponse indexResponse2 = insert("my_blogs", "comment1", "blog1", comment1);
Map<String, Object> comment2 = new HashMap();
comment2.put("commentName","commentName2");
comment2.put("commentContent","commentContent2");
Map<String, Object> blogCommentRelation3 = new HashMap();
blogCommentRelation3.put("name","comment");
blogCommentRelation3.put("parent","blog1");
comment1.put("blog_comment_relation",blogCommentRelation2);
IndexResponse indexResponse3 = insert("my_blogs", "comment2", "blog1", comment2);
}
/**
* @param index 索引名
* @param id 主键id, 如果传入null则会自动生成
* @param routing
* @param doc 文档内容
*/
public IndexResponse insert(String index, String id, String routing, Map<String, Object> doc) throws IOException {
IndexRequest indexRequest = new IndexRequest(index).source(doc);
if (id != null) {
indexRequest = indexRequest.id(id);
}
if (routing != null) {
indexRequest = indexRequest.routing(routing);
}
IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
return indexResponse;
}
新增or修改
www.elastic.co/guide/en/elasticsea...
@Autowired
private RestHighLevelClient restHighLevelClient;
@Test
public void updateOrInsert() throws IOException {
Map<String, Object> blog = new HashMap();
blog.put("author","lzc");
blog.put("title","Learning ElasticSearch");
blog.put("content","学习ElasticSearch技术");
Map<String, Object> blogCommentRelation1 = new HashMap();
blogCommentRelation1.put("name","blog");
blog.put("blog_comment_relation",blogCommentRelation1);
UpdateResponse updateResponse = updateOrInsert("my_blogs", "blog2", null, blog);
Map<String, Object> comment = new HashMap();
comment.put("commentName","commentName3");
comment.put("commentContent","commentContent3");
Map<String, Object> blogCommentRelation2 = new HashMap();
blogCommentRelation2.put("name","comment");
blogCommentRelation2.put("parent","blog2");
comment.put("blog_comment_relation",blogCommentRelation2);
IndexResponse indexResponse2 = insert("my_blogs", "comment2", "blog2", comment);
}
/**
* 新增或修改
* @param index 文档索引
* @param id 文档id
* @param routing
* @param doc 文档字段
*/
public UpdateResponse updateOrInsert(String index, String id, String routing, Map<String, Object> doc) throws IOException {
UpdateRequest request = new UpdateRequest(index,id);
if (routing != null) {
request = request.routing(routing);
}
request.doc(doc).docAsUpsert(true).retryOnConflict(5);
return restHighLevelClient.update(request, RequestOptions.DEFAULT);
}
通过id查找
www.elastic.co/guide/en/elasticsea...
@Autowired
private RestHighLevelClient restHighLevelClient;
@Test
public void getDocumentById() throws IOException {
Map<String, Object> blogMap = getDocumentById("my_blogs", "comment1");
}
/**
* @param index 索引名
* @param id 文档id
*/
public Map<String, Object> getDocumentById(String index, String id) throws IOException {
GetRequest getRequest = new GetRequest(index, id);
GetResponse getResponse = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
if (getResponse.isExists()) {
return getResponse.getSourceAsMap();
}
return null;
}
通过id删除
www.elastic.co/guide/en/elasticsea...
@Autowired
private RestHighLevelClient restHighLevelClient;
@Test
public void deleteDocumentById() throws IOException {
deleteDocumentById("my_blogs", "comment1");
}
/**
* @param index 索引名
* @param id 文档id
*/
public DeleteResponse deleteDocumentById(String index, String id) throws IOException {
DeleteRequest deleteRequest = new DeleteRequest(index, id);
DeleteResponse deleteResponse = restHighLevelClient.delete(deleteRequest, RequestOptions.DEFAULT);
return deleteResponse;
}
条件查询
www.elastic.co/guide/en/elasticsea...
@Test
public void searchRequest() throws IOException {
SearchRequest searchRequest = new SearchRequest("my_blogs");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery(); // 构造查询条件
searchSourceBuilder.query(queryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
System.out.println();
}
QueryBuilders.matchAllQuery()
相当于如下查询
GET /my_blogs/_search
{
"query": {
"match_all": {}
}
}
term查询
// 构造查询条件
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
// 构造term
queryBuilder.must(QueryBuilders.termQuery("title", "Learning ElasticSearch"));
相当于如下查询
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{
"term": {
"title": {
"value": "Learning ElasticSearch"
}
}
}
]
}
}
}
has_child
@Test
public void searchRequest() throws IOException {
SearchRequest searchRequest = new SearchRequest("my_blogs");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery(); // 构造查询条件
QueryBuilder childQueryBuilder = JoinQueryBuilders
.hasChildQuery(
"comment",
QueryBuilders.matchAllQuery(),
ScoreMode.None).innerHit(new InnerHitBuilder().setSize(100));
queryBuilder.must(childQueryBuilder);
searchSourceBuilder.query(queryBuilder);
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 下面是对结果进行解析
SearchHits searchHits = searchResponse.getHits();
SearchHit[] hits = searchHits.getHits();
for (SearchHit hit : hits) {
System.out.println("index = " + hit.getIndex());
Map<String, Object> blogAsMap = hit.getSourceAsMap();
System.out.println("id:" + hit.getId());
for (Map.Entry<String, Object> kv : blogAsMap.entrySet()) {
System.out.println(kv.getKey() + ":" + kv.getValue().toString());
}
System.out.println("[InnerHits]");
Map<String, SearchHits> innerHits = hit.getInnerHits();
for (Map.Entry<String, SearchHits> commentHit : innerHits.entrySet()) {
String key = commentHit.getKey(); // 这个例子里面, key = comment,因为InnerHits里面只有comment类型的
for (SearchHit commentSource : commentHit.getValue().getHits()) {
if (commentSource != null) {
System.out.println("index = " + commentSource.getIndex());
System.out.println("id = " + commentSource.getId());
Map<String, Object> commentAsMap = commentSource.getSourceAsMap();
for (Map.Entry<String, Object> kv2 : commentAsMap.entrySet()) {
System.out.println(kv2.getKey() + ":" + kv2.getValue().toString());
}
}
}
}
System.out.println("------------------------------------------------------");
}
}
相当于如下查询语句
GET /my_blogs/_search
{
"query": {
"bool": {
"must": [
{
"has_child": {
"query": {
"match_all": {}
},
"type": "comment",
"score_mode": "none",
"inner_hits": {
"size": 100
}
}
}
]
}
}
}
聚合
@Test
public void aggs() throws IOException {
SearchRequest searchRequest = new SearchRequest("my_blogs");
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
QueryBuilder queryBuilder = QueryBuilders.matchAllQuery(); // 构造查询条件
searchSourceBuilder.query(queryBuilder);
// 设置为0后只返回聚合结果
searchSourceBuilder.size(0);
// 设置聚合字段
List<String> aggKeys = new ArrayList<>();
aggKeys.add("author");
aggKeys.add("commentName");
aggKeys.forEach(aggKey -> {
searchSourceBuilder.aggregation(
AggregationBuilders.terms(aggKey).field(aggKey)
.size(10) // 针对这个字段的聚合结果, 最多返回的个数
);
});
searchRequest.source(searchSourceBuilder);
SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
// 获取聚合结果
Aggregations aggregations = searchResponse.getAggregations();
// 解析聚合结果
aggKeys.forEach(aggKey -> {
Terms terms = aggregations.get(aggKey);
if (terms.getBuckets().size() > 0) {
for (Terms.Bucket bucket : terms.getBuckets()) {
String name = bucket.getKeyAsString(); // 聚合字段
long count = bucket.getDocCount();
System.out.println(name + ":" + count);
}
}
});
}
相当于如下查询语句
GET /my_blogs/_search
{
"size": 0,
"query": {
"match_all": {
"boost": 1
}
},
"aggregations": {
"author": {
"terms": {
"field": "author",
"size": 10,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
},
"commentName": {
"terms": {
"field": "commentName",
"size": 10,
"order": [
{
"_count": "desc"
},
{
"_key": "asc"
}
]
}
}
}
}
本作品采用《CC 协议》,转载必须注明作者和本文链接