当前位置: 首页 > news >正文

玩转ElasticSearch

目录

一.初识ElasticSearch

1.认识和安装

2. Kibana的安装与界面

3.倒排索引

4.IK分词器

5.基础概念

二. 索引库操作

1. Mapping映射属性

2. 索引库操作

三. 文档操作

1. 文档CRUD

2.批量处理

四.RestAPI

1. 客户端初始化

2.索引库操作

3.文档操作 

五.DSL查询

1.快速入门

2.叶子查询

(1)全文检索

(2)精确查询

3.复合查询

4.排序和分页

5.高亮显示

六. RestClient查询

1. 快速入门

2.构建查询条件

3.数据聚合

(1)DSL聚合

(2)RestClient聚合


一.初识ElasticSearch

1.认识和安装

elasticsearch结合kibana、Logstash、Beats,是一整套技术栈,被叫做ELK。被广泛应用在日志数据分析、实时监控等领域。

Lucene是一个Java语言的搜索引擎类库,是Apache公司的顶级项目,由DougCutting于1999年研发 。官网地址:https://lucene.apache.org/

Lucene的优势:

  •    易扩展
  •    高性能(基于倒排索引)

Lucene的缺点:

  •    只限于Java语言开发
  •    学习曲线陡峭
  •    不支持水平扩展

2004年Shay Banon基于Lucene开发了Compass

2010年Shay Banon 重写了Compass,取名为Elasticsearch。

官网地址: https://www.elastic.co/cn/

相比与lucene,elasticsearch具备下列优势:

  • 支持分布式,可水平扩展
  • 提供Restful接口,可被任何语言调用

安装:

下载地址 : Download Elasticsearch | Elastic

下载后解压后点击 \bin\elasticsearch.bat

测试是否安装成功,浏览器输入 https://localhost:9200/

登录名是elastic,登录密码,第一次启动时控制台是会打印密码的

此时我的密码是:yb+QdTjfl*eUY39pcQUY

启动成功之后,浏览器显示:

2. Kibana的安装与界面

Kibana 是 ES的可视化工具

下载地址: Download Kibana Free | Get Started Now | Elastic

下载下来,解压,解压后找到bin目录下的 kibana.bat,点击执行(执行前一定要启动es)

出现地址表示启动成功

访问地址 :http://localhost:5601/, 提示需要密钥

到es的bin目录下执行执行指令:elasticsearch-create-enrollment-token.bat --scope kibana

此时我的密码是:

eyJ2ZXIiOiI4LjE0LjAiLCJhZHIiOlsiMTkyLjE2OC4xLjE4Nzo5MjAwIl0sImZnciI6IjllNGY1OTE5OTBjMzU2NTQ2Mzc2NDA4MWQwZTMzMjlhYTYyMDc2YTJiNTA1OWEyNDc1YzRhYjAzMTQ2YzUxOWQiLCJrZXkiOiI4V2FLSkprQnpPcHhVOEF4WW1mMTpMZ1VxQzFOazVDdkVTVFotOHJDVlBnIn0=

复制生成的密钥到浏览器, 点击配置密钥。之后跳出验证码确认

把指令 kibana.bat的控制台显示出来的复制到浏览器

接下来输入es的账户及密码:

成功进入:

3.倒排索引

倒排索引:记录词条在哪个文档出现几次及在文档中的位置

什么是文档和词条?

  •  每一条数据就是一个文档
  •  对文档中的内容分词,得到的词语就是词条

什么是正向索引?

  • 基于文档id创建索引。根据id查询快,但是查询词条时必须先找到文档,而后判断是否包含词条

什么是倒排索引? 

  • 对文档内容分词,对词条创建索引,并记录词条所在文档的id。 查询时先根据词条查询到文档id,而后根据文档id查询文档

4.IK分词器

分词器的作用是什么?

  •  创建倒排索引时,对文档分词
  •  用户搜索时,对输入的内容分词

默认分词器:标准分词器,对中文会一个个字切分,没有中文语义,形成不了有效的词条

例如:

语法说明:

     POST:请求方式

     /_analyze:请求路径,这里省略了http://192.168.12.168:9200,有kibana帮我们补充

     请求参数,json风格:  analyzer:分词器类型,这里是默认的standard分词器

                                          text:要分词的内容

中文分词器(ik分词器):

  •  ik_smart(最大粒度:按照最长的词条进行分词;更适合搜索的时候)
  •  ik_max_word:(最细粒度:按照最短的词条进行分词,分的词条会比较多;更适合在创建索引的时候使用)

官网下载:https://release.infinilabs.com/analysis-ik/stable/

注意:IK分词器插件的版本要和ElasticSearch的版本一致

把解压后的文件放在ES 的所在目录下的的 plugins文件里然后重启ES

测试:

自定义词库:

找到ik 中的 config 文件夹的IKAnalyzer.cfg.xml文件并打开

在config文件创建ext.dic文件并添加词

重启ES并测试:

5.基础概念

二. 索引库操作

1. Mapping映射属性

2. 索引库操作

语法:

查看索引库语法: GET /索引库名示例: GET /heima删除索引库的语法: DELETE /索引库名示例: DELETE /heima索引库和mapping一旦创建无法修改,但是可以添加新的字段,语法如下:
PUT /索引库名/_mapping
{"properties": {"新字段名":{"type": "integer"}}
}
示例:
PUT /heima/_mapping
{"properties": {"age":{"type": "integer"}}
}

三. 文档操作

1. 文档CRUD

查看文档语法: GET /索引库名/_doc/文档id 示例:GET /heima/_doc/1
删除索引库的语法:DELETE /索引库名/_doc/文档id  示例:DELETE /heima/_doc/1

修改:

2.批量处理

四.RestAPI

ES官方提供了各种不同语言的客户端,用来操作ES。这些客户端的本质就是组装DSL语句,通过http请求发送给ES。

我们选择使用早期的JavaRestClient客户端来学习

官方文档地址:

https://www.elastic.co/guide/en/elasticsearch/client/index.html

1. 客户端初始化

添加依赖:

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

初始化RestHighLevelClient:

public class IndexTest {//es的操作客户端对象;执行任何与es有关的操作都需要//说明接下来测试的每个方法都要先初始化该对象private RestHighLevelClient client;//执行每个方法之前先执行的方法@BeforeEachpublic void init() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.12.168:9200")));}//测试cLient是否有效@Testpublic void testGetConnection() {System.out.println(client);}//每次执行完之后要关闭client客户端的连接@AfterEachpublic void close() throws Exception {client.close();}
}

运行测试类:

2.索引库操作

创建索引库:

//索引库名称
private static final String INDEX_NAME = "items";
//索引库映射结构
private  static final String MAPPING_TEMPLATE="{\n" +"  \"mappings\": {\n" +"    \"properties\": {\n" +"      \"id\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"name\":{\n" +"        \"type\": \"text\",\n" +"        \"analyzer\": \"ik_max_word\"\n" +"      },\n" +"      \"price\":{ \n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"stock\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"image\":{\n" +"        \"type\":\"keyword\",\n" +"        \"index\": false\n" +"      },\n" +"      \"category\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"brand\":{\n" +"        \"type\": \"keyword\"\n" +"      },\n" +"      \"sold\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"commentCount\":{\n" +"        \"type\": \"integer\"\n" +"      },\n" +"      \"isAD\":{\n" +"        \"type\": \"boolean\"\n" +"      },\n" +"      \"updateTime\":{\n" +"        \"type\": \"date\"\n" +"      }\n" +"    }\n" +"  }\n" +"}";
//创建索引库
@Test
public void createIndex() throws Exception {//创建索引库对象;--->创建索引--->创建索引的请求CreateIndexRequest request = new CreateIndexRequest(INDEX_NAME);//设置请求参数request.source(MAPPING_TEMPLATE, XContentType.JSON);//发送请求client.indices().create(request, RequestOptions.DEFAULT);
}

删除索引库:

//测试删除索引库
@Test
public void testDeleteIndex() throws Exception {//1、创建删除索引库请求对象DeleteIndexRequest request = new DeleteIndexRequest(INDEX_NAME);//2、发送请求client.indices().delete(request, RequestOptions.DEFAULT);
}

判断索引库是否存在:

//测试查询索引库items是否存在
@Test
public void testExistsIndex() throws Exception {//1、创建查询索引库请求对象GetIndexRequest request = new GetIndexRequest(INDEX_NAME);//2、发送请求boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);//3、打印结果System.out.println(exists ? "索引库已经存在" : "索引库不存在");
}

索引库操作的基本步骤:

  • 初始化RestHighLevelClient
  • 创建XxxIndexRequest。XXX是Create、Get、Delete
  • 准备请求参数(Create时需要)
  • 发送请求。调用RestHighLevelClient#indices().xxx()方法 ,xxx是create、exists、delete

3.文档操作 

文档操作的基本步骤:

  • 初始化RestHighLevelClient
  • 创建XxxRequest。XXX是Index、Get、Update、Delete
  • 准备参数(Index和Update时需要)
  • 发送请求。调用RestHighLevelClient#.xxx()方法,xxx是 index、get、update、delete
  • 解析结果(Get时需要)

新增文档的JavaAPI如下:

新增商品:

public class DocumentTest {//索引库名称private static final String INDEX_NAME = "items";//es的操作客户端对象;执行任何与es有关的操作都需要//说明接下来测试的每个方法都要先初始化该对象private RestHighLevelClient client;//执行每个方法之前先执行的方法@BeforeEachpublic void init() {client = new RestHighLevelClient(RestClient.builder(HttpHost.create("http://192.168.12.168:9200")));}//每次执行完之后要关闭client客户端的连接@AfterEachpublic void close() throws Exception {client.close();}//根据商品id查询mysql数据库中的商品,并将该商品保存es@Testpublic void testCreateIndex() throws IOException{//1、根据商品id查询mysql数据库中的商品Item item = itemService.getById(317578L);//2、将Item对象转换为es可接受的对象ItemDocItemDoc itemDoc = BeanUtils.copyBean(item, ItemDoc.class);//3、创建文档的请求对象IndexRequest request = new IndexRequest("items").id(itemDoc.getId().toString());//4、设置请求参数String jsonStr = JSONUtil.toJsonStr(itemDoc);request.source(jsonStr, XContentType.JSON);//3、发送请求client.index(request, RequestOptions.DEFAULT);}
}

查询:

查询文档包含查询和解析响应结果两部分。对应的JavaAPI如下:

修改:

删除:

4.批量操作

批处理代码流程与之前类似,只不过构建请求会用到一个名为BulkRequest的类

批处理的API示例:

由于商品数量达到数十万,因此不可能一次性全部导入。建议采用循环遍历方式,每次导入1000条左右的数据。

@Test
public void importDocuments() throws IOException {//页号int pageNo = 1;//页大小int pageSize = 1000;while (true) {//1、根据页号、页大小(1000);每次查询1000条数据//分页查询状态为1的商品数据Page<Item> page = itemService.lambdaQuery().eq(Item::getStatus, 1).page(new Page<>(pageNo, pageSize));List<Item> itemList = page.getRecords();if (CollUtils.isEmpty(itemList)) {break;}//创建批量请求BulkRequest bulkRequest = new BulkRequest();for (Item item : itemList) {//2.将每条数据转换为ItemDoc:并设置到IndexRequestItemDoc itemEsDTO = BeanUtils.copyBean(item, ItemDoc.class);//将ItemDoc转换为json字符串String jsonStr = JSONUtil.toJsonStr(itemEsDTO);//创建requestIndexRequest request = new IndexRequest("items").id(itemEsDTO.getId().toString());//设置请求参数request.source(jsonStr, XContentType.JSON);//添加到批量请求中bulkRequest.add(request);}//3、发送批量请求,提交BuLkRequestclient.bulk(bulkRequest, RequestOptions.DEFAULT);//4、继续分页查询;直到数据没有为止pageNo++;}
}

五.DSL查询

Elasticsearch的查询可以分为两大类:

  • 叶子查询(Leaf query clauses):一般是在特定的字段里查询特定值,属于简单查询,很少单独使用。
  • 复合查询(Compound query clauses):以逻辑方式组合多个叶子查询或者更改叶子查询的行为方式。

在查询以后,还可以对查询的结果做处理,包括:

  • 排序:按照1个或多个字段值做排序
  • 分页:根据from和size做分页,类似MySQL
  • 高亮:对搜索结果中的关键字添加特殊样式,使其更加醒目
  • 聚合:对搜索结果做数据统计以形成报表

1.快速入门

基于DSL的查询语法如下:

GET /indexName/_search
{"query": {"查询类型": {"查询条件": "条件值"}}
}// 查询所有
GET /indexName/_search
{"query": {"match_all": {}}
}

2.叶子查询

叶子查询还可以进一步细分,常见的有:

  • 全文检索(full text)查询:利用分词器对用户输入内容分词,然后去倒排索引库中匹配。例如:    match_query      multi_match_query
  • 精确查询:不对用户输入内容分词,直接精确匹配,一般是查找keyword、数值、日期、布尔等类型。例如: ids    range    term

(1)全文检索

match查询:全文检索查询的一种,会对用户输入内容分词,然后去倒排索引库检索,语法:

GET /indexName/_search
{"query": {"match": {"FIELD": "TEXT"}}
}#单个字符中分词查询
GET /items/_search
{"query": {"match": {"name": "脱脂牛奶"}}
}

multi_match:与match查询类似,只不过允许同时查询多个字段,语法:

GET /indexName/_search
{"query": {"multi_match": {"query": "TEXT","fields": ["FIELD1", " FIELD12"]}}
}#多个字段中分词搜索
GET /indexName/_search
{"query": {"multi_match": {"query": "手机","fields": ["name", "category"]}}
}

match和multi_match的区别是什么?

  • match:根据一个字段查询
  • multi_match:根据多个字段查询,参与查询字段越多,查询性能越差

(2)精确查询

精确查询,英文是Term-level query,顾名思义,词条级别的查询。也就是说不会对用户输入的搜索条件再分词,而是作为一个词条,与搜索的字段内容精确值匹配。

因此推荐查找keyword、数值、日期、boolean类型的字段。例如id、price、城市、地名、人名等作为一个整体才有含义的字段。

词条查询:

//term查询
GET /indexName/_search
{"query": {"term": {"FIELD": {"value": "VALUE"}}}
}例如:
GET /items/_search
{"query": {"term": {"brand": {"value": "锤子"}}}
}

范围查询:

// range查询
GET /indexName/_search
{"query": {"range": {"FIELD": {"gte": 10,"lte": 20}}}
}例如:
GET /items/_search
{"query": {"range": {"price": {"gte": 10000,"lte": 20000}}}
}

精确查询常见的有哪些?

  • term查询:根据词条精确匹配,一般搜索keyword类型、数 值类型、布尔类型、日期类型字段
  • range查询:根据数值范围查询,可以是数值、日期的范围

3.复合查询

复合查询大致可以分为两类:

  • 第一类:基于逻辑运算组合叶子查询,实现组合条件,例如  bool
  • 第二类:基于某种算法修改查询时的文档相关性算分,从而改变文档排名。例如:  function_score     dis_max

布尔查询是一个或多个查询子句的组合。子查询的组合方式有:

  • must:必须匹配每个子查询,类似“与”
  • should:选择性匹配子查询,类似“或”
  • must_not:必须不匹配,不参与算分,类似“非”
  • filter:必须匹配,不参与算分

 例如:我们要搜索"智能手机",但品牌必须是华为,价格必须是900~1599

GET /items/_search
{"query": {"bool": {"must": [{"match": {"name": "手机"}}],"filter": [{"term": {"brand": { "value": "华为" }}},{"range": {"price": {"gte": 90000, "lt": 159900}}}]}}
}

4.排序和分页

排序:

elasticsearch支持对搜索结果排序 ,默认是根据相关度算分(_score)来排序,也可以指定字段排序。可以排序字段类 型有:keyword类型、数值类型、地理坐标类型、日期类型等。

语法:

GET /indexName/_search
{"query": {"match_all": {}},"sort": [{"排序字段": {"order": "排序方式asc和desc"}}]
}

例如:

搜索商品,按照销量排序,销量一样则按照价格升序

GET /indexName/_search
{"query": {"match_all": {}},"sort": [{"sold":{"order": "desc"}},{"price":{"order":"asc"}}]
}

分页:

elasticsearch 默认情况下只返回top10的数据。而如果要查询更多数据就需要修改分页参数了。elasticsearch中通过修改from、size参数来控制要返回的分页结果:

  • from:从第几个文档开始
  • size:总共查询几个文档

语法:

GET /items/_search
{"query": {"match_all": {}},"from": 0, // 分页开始的位置,默认为0"size": 10, // 期望获取的文档总数"sort": [{"price": "asc"}]
}

例如:搜索商品,查询出销量排名前10的商品,销量一样时按照价格升序

GET /indexName/_search
{"query": {"match_all": {}},"from": 0, // 分页开始的位置,默认为0"size": 10, // 期望获取的文档总数"sort": [{"sold":{"order": "desc"}},{"price":{"order":"asc"}}]
}

深度分页问题:

elasticsearch的数据一般会采用分片存储,也就是把一个索引中的数据分成N份,存储到不同节点上。这种存储方式比较有利于数据扩展,但给分页带来了一些麻烦。

比如一个索引库中有100000条数据,分别存储到4个分片,每个分片25000条数据。现在每页查询10条,查询第99页。那么分页查询的条件如下:

GET /items/_search
{"from": 990, // 从第990条开始查询"size": 10, // 每页查询10条"sort": [{"price": "asc"}]
}

从语句来分析,要查询第990~1000名的数据。

从实现思路来分析,肯定是将所有数据排序,找出前1000名,截取其中的990~1000的部分。但问题来了,我们如何才能找到所有数据中的前1000名呢?

要知道每一片的数据都不一样,第1片上的第900~1000,在另1个节点上并不一定依然是900~1000名。所以我们只能在每一个分片上都找出排名前1000的数据,然后汇总到一起,重新排序,才能找出整个索引库中真正的前1000名,此时截取990~1000的数据即可。

如图:

试想一下,假如我们现在要查询的是第999页数据呢,是不是要找第9990~10000的数据,那岂不是需要把每个分片中的前10000名数据都查询出来,汇总在一起,在内存中排序?如果查询的分页深度更深呢,需要一次检索的数据岂不是更多?

由此可知,当查询分页深度较大时,汇总数据过多,对内存和CPU会产生非常大的压力。

因此elasticsearch会禁止from+ size超过10000的请求。

针对深度分页,elasticsearch提供了两种解决方案:

  • search after:分页时需要排序,原理是从上一次的排序值开始,查询下一页数据。(意思是要记录上一次查询的最后一条记录的排序值,然后携带到下一次查询。)官方推荐使用的方式。

  • scroll:原理将排序后的文档id形成快照,保存下来,基于快照做分页。官方已经不推荐使用

​​​​​详情见文档:

https://www.elastic.co/guide/en/elasticsearch/reference/7.12/paginate-search-results.html

总结:大多数情况下,我们采用普通分页就可以了。查看百度、京东等网站,会发现其分页都有限制。例如百度最多支持77页,每页不足20条。京东最多100页,每页最多60条。

因此,一般我们采用限制分页深度的方式即可,无需实现深度分页

5.高亮显示

高亮显示就是在搜索结果中把搜索关键字突出显示

语法:

GET /{索引库名}/_search
{"query": {"match": {"搜索字段": "搜索关键字"}},"highlight": {"fields": {  //指定要高亮的字段"高亮字段名称": {"pre_tags": "<em>",  //高亮的前置标签"post_tags": "</em>" //高亮的前置标签}}}
}

注意

  • 搜索必须有查询条件,而且是全文检索类型的查询条件,例如match

  • 参与高亮的字段必须是text类型的字段

  • 默认情况下参与高亮的字段要与搜索字段一致,除非添加:required_field_match=false

例如:

GET /items/_search
{"query": {"match": {"name": "手机"}},"highlight": {"fields": {  //指定要高亮的字段"name": {"pre_tags": "<em cloor='red'>",  //高亮的前置标签"post_tags": "</em>" //高亮的前置标签}}}
}

六. RestClient查询

1. 快速入门

数据搜索的Java代码我们分为两部分: 构建请求参数和解析查询结果

@Test
public void testMatchAll() throws IOException {//创建请求对象SearchRequest searchRequest = new SearchRequest(INDEX_NAME);//设置请求参数searchRequest.source().query(QueryBuilders.matchAllQuery());//发送请求并获取结果SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//解析响应结果SearchHits searchHits = searchResponse.getHits();//符合本次搜索的总文档 数(最多10000条)long total = searchHits.getTotalHits().value;System.out.println("本次搜索命中的总文档数:"+total);SearchHit[] hits = searchHits.getHits();if(hits!= null&&hits.length>0){for (SearchHit hit:hits){//获取原文的json字符串String jsonStr = hit.getSourceAsString();ItemDoc itemDoc = JSONUtil.toBean(jsonStr,ItemDoc.class);System.out.println(itemDoc);}}
}

查询的基本步骤是:

1. 创建SearchRequest对象

2. 准备Request.source(),也就是DSL。

    ① QueryBuilders来构建查询条件

    ② 传入Request.source() 的query() 方法

3. 发送请求,得到结果

4. 解析结果(参考JSON结果,从外到内,逐层解析)

2.构建查询条件

全文检索的查询条件构造API如下:

// 单字段查询
QueryBuilders.matchQuery("name", "脱脂牛奶");
// 多字段查询
QueryBuilders.multiMatchQuery("脱脂牛奶", "name", "category");

精确查询的查询条件构造API如下:

// 词条查询
QueryBuilders.termQuery("category", "牛奶");
// 范围查询
QueryBuilders.rangeQuery("price").gte(100).lte(150);

布尔查询的查询条件构造API如下:

// 创建布尔查询
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
// 添加must条件
boolQuery.must(QueryBuilders.termQuery("brand", "华为"));
// 添加filter条件
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(2500));

排序和分页:

ES中通过Restful请求操作索引库、文档。请求内容用DSL语句来表示。创建索引库和mapping的DSL语法如下:

// 查询
request.source().query(QueryBuilders.matchAllQuery());
// 分页
request.source().from(0).size(5);
// 价格排序
request.source().sort("price", SortOrder.ASC);

高亮显示:

 request.source().highlighter(SearchSourceBuilder.highlight().field("name").preTags("<em>").postTags("</em>"));

代码如下:

//测试高亮
@Test
public void testHighlight() throws IOException {//1、创建搜索请求SearchRequest request = new SearchRequest(INDEX_NAME);//2、设置查询参数request.source().query(QueryBuilders.matchQuery("name", "华为"));//设置高亮request.source().highlighter(SearchSourceBuilder.highlight().field("name").preTags("<em>").postTags("</em>"));//3、发送请求获取响应结果SearchResponse response = client.search(request, RequestOptions.DEFAULT);//4、解析响应结果handleResponse(response);
}
private static void handleResponse(SearchResponse response) {System.out.println("共搜索到 " + response.getHits().getTotalHits().value + " 条数据");//获取查询数组SearchHit[] hits = response.getHits().getHits();for (SearchHit hit : hits) {//获取_source(原始json数据)String jsonStr = hit.getSourceAsString();ItemDoc itemDoc = JSONUtil.toBean(jsonStr, ItemDoc.class);//解析高亮结果Map<String, HighlightField> highlightFields = hit.getHighlightFields();if (CollUtils.isNotEmpty(highlightFields)) {HighlightField highlightField = highlightFields.get("name");if (highlightField != null) {String highlightStr = highlightField.getFragments()[0].string();itemDoc.setName(highlightStr);}}System.out.println(itemDoc);}
}

3.数据聚合

聚合(aggregations可以实现对文档数据的统计、分析、运算。聚合常见的有三类:

桶(Bucket)聚合:用来对文档做分组

       TermAggregation:按照文档字段值分组

       Date Histogram:按照日期阶梯分组,例如一周为一组,或者一月为一组

度量(Metric)聚合:用以计算一些值,比如:最大值、最小值、平均值等

       Avg:求平均值

       Max:求最大值

       Min:求最小值

       Stats:同时求maxminavgsum

管道(pipeline)聚合:其它聚合的结果为基础做聚合

注意:参与聚合的字段必须是Keyword、数值、日期、布尔的类型的字段

(1)DSL聚合

我们要统计所有商品中共有哪些商品分类,其实就是以分类(category)字段对数据分组。category值一样的放在同一组,属于Bucket聚合中的Term聚合。

GET /items/_search
{"size": 0,  // 设置size为0,结果中不包含文档,只包含聚合结果"aggs": { // 定义聚合"cateAgg": { //给聚合起个名字“terms”: { // 聚合的类型,按照品牌值聚合,所以选择term"field": “category", // 参与聚合的字段"size": 20 // 希望获取的聚合结果数量}}}
}

默认情况下,Bucket聚合是对索引库的所有文档做聚合,我们可以限定要聚合的文档范围,只要添加query条件即可

GET /items/_search
{"query": {"bool": {"filter": [{ "term": {"category": "手机"}},{ "range": { "price": { "gte": 300000}}}]}}, "size": 0, "aggs": {"brand_agg": {"terms": {"field": "brand","size": 20}}}
}

除了对数据分组(Bucket)以外,我们还可以对每个Bucket内的数据进一步做数据计算和统计。例如:我想知道手机有哪些品牌,每个品牌的价格最小值、最大值、平均值。

GET /items/_search
{"query": {"term": {"category": "手机"}}, "size": 0, "aggs": {"brand_agg": {"terms": {"field": "brand"},"aggs": {"stats_metric": {"stats": {"field": "price"}}}}}
}

aggs代表聚合,与query同级,此时query的作用是?

     限定聚合的的文档范围

聚合必须的三要素:

     聚合名称
     聚合类型
     聚合字段

聚合可配置属性有:

     size:指定聚合结果数量
     field:指定聚合字段

(2)RestClient聚合

 //聚合统计@Testpublic void testAggs() throws IOException {SearchRequest searchRequest=new SearchRequest(INDEX_NAME);//不返回文件searchRequest.source().size(0);//设置品牌的聚合统计searchRequest.source().aggregation(AggregationBuilders.terms("brand_agg").field("brand").size(20).subAggregation(AggregationBuilders.stats(name:"stat_metric").field("price")));SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);//解析聚合统计结果Aggregations aggregations = searchResponse.getAggregations();Terms brandAgg = aggregations.get("brand_agg");if(brandAgg!=null){List<? extends Terms.Bucket> buckets = brandAgg.getBuckets();for (Terms.Bucket bucket : buckets){System.out.println(bucket.getKeyAsString()+"."+bucket.getDocCount());Aggregations statAgg=bucket.getAggregations();Stats statMetric=statAgg.get("stat_metric");System.out.println("平均值:"+statMetric.getAvg());System.out.println("最大值:"+statMetric.getMax());System.out.println("最小值:"+statMetric.getMin());System.out.println("总和:"+statMetric.getSum());}}
}


文章转载自:

http://ucypfPhP.rfpxq.cn
http://X2hikNEp.rfpxq.cn
http://OYNwkM8i.rfpxq.cn
http://TmYyw4ig.rfpxq.cn
http://ST1wgALK.rfpxq.cn
http://wln6nFeU.rfpxq.cn
http://yV2xN28S.rfpxq.cn
http://kBRh6t4M.rfpxq.cn
http://k4S9Buj4.rfpxq.cn
http://f40Xn1FE.rfpxq.cn
http://a7NDJLc0.rfpxq.cn
http://LjVr4ZUs.rfpxq.cn
http://o09NdSNT.rfpxq.cn
http://o2eWx8vB.rfpxq.cn
http://YZ6Weyn2.rfpxq.cn
http://Vlp2Zmrp.rfpxq.cn
http://3W2ihfc0.rfpxq.cn
http://t2kAcNIw.rfpxq.cn
http://V5AHLMyz.rfpxq.cn
http://ZBPMqp1p.rfpxq.cn
http://x6ax0aXg.rfpxq.cn
http://TFHMYlXp.rfpxq.cn
http://MBAofJW9.rfpxq.cn
http://4E7HxaML.rfpxq.cn
http://HmajTgQJ.rfpxq.cn
http://P8KRkfbw.rfpxq.cn
http://hkxLyfkY.rfpxq.cn
http://34PiH36m.rfpxq.cn
http://pNJ2np9u.rfpxq.cn
http://G81fk3No.rfpxq.cn
http://www.dtcms.com/a/383624.html

相关文章:

  • 设计模式-模板模式详解
  • GDB调试技巧实战--揪出内存泄漏元凶
  • LLM基础-工程化
  • Ubuntu系统下交叉编译Android的Lame库
  • AI 重构医疗:辅助诊断、药物研发、健康管理的三大落地场景实践
  • MySQL的日志系统(redolog、binlog、WAL技术)
  • 贪心算法应用:半导体晶圆生产问题详解
  • 按键精灵解决重复性点击
  • 索引-分类
  • webrtc弱网-IntervalBudget类源码分析与算法原理
  • 第20课:数据治理与合规
  • 模型训练中的数据泄露:原理解析与实战防范指南
  • 凌晨0-3点不睡,你熬的不是夜,是人生!
  • [哈希表]966. 元音拼写检查器
  • 密码库的轻量化定制裁剪:技术原理与实践指南
  • Tomcat vs JBoss:轻量级与重型Java服务器对比
  • v-model与-sync的演变和融合
  • Vue的快速入门
  • 26考研——进程与线程(2)
  • Java基础 9.14
  • Node.js核心模块介绍
  • 认识集合框架
  • DMA 控制器核心组件作用与使用解读
  • 卫星通信天线的指向精度,含义、测量和计算
  • [数据结构——Lesson11排序的概念及直接插入排序(还可以)]
  • VTK基础(03):VTK中数据的读和写
  • Spring AI(五) 文生图,图生图(豆包)
  • 数据分析需要掌握的数学知识(易理解)
  • 正则表达式详解:从基础到扩展的全面指南
  • 数据分析:排序