程序员阿沛
发布于 2026-06-27 / 0 阅读
0
0

Elasticsearch入门系列一什么是ESES的安装和使用场景文档索引节点副本基本概念

Elasticsearch入门系列(一)什么是ES、ES的安装和使用场景、文档 & 索引 & 节点 & 副本基本概念

ES官方文档

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

先通过如何用数据库做模糊搜索引出ES的优势。

用数据库如何做搜索

一般会使用%关键词%进行模糊搜索。

select * from products where name like “%牙膏%”;

缺点:

1、无法使用索引,会全表扫描;

2、每一行扫描时,需要进行字符串查找,复杂度介于O(n+m)到O(mn)之间。如果母字符串很长,则每一行比对的成本也很大。

3、无法满足用户需求和容错场景。例如,数据表记录的是”生化危机大电影“,用户搜索”生化机“肯定无法搜索成功,而实际上用户希望能搜成功。

总结起来,数据库做搜索性能差且无法满足多数搜索场景和容错性。

全文检索、倒排索引和Lucene

倒排索引是指将数据表某一列或某几列的文本进行分词,建立分词与拥有该分词的行的主键之间的映射关系(一个分词可对应多个行id)。这样的映射关系表就是倒排索引。

全文检索指的是检索一个关键词的过程:

1、对表数据建立倒排索引;

2、对关键词分词;

3、根据关键词的分词(可能有多个)到倒排索引检索得到数据行id;

4、根据id回数据表搜索完整行数据。

优点:

1、倒排索引中的每次检索不是字符串查找,而是精准匹配。

2、由于是精准匹配,可以按一定结构组织倒排索引,检索关键词的分词时不再是全表扫描。

3、由于对要搜索的关键词进行分词后再对每个分词检索,容错性提高。

Lucene是一个封装了建立各种结构倒排索引和全文检索算法的jar包。

什么是Elastisearch

Elastisearch是基于Lucene开发的分布式、高性能、高可用、可伸缩的搜索和分析系统。

如果我们直接基于Lucene在项目中构建一个具有搜索功能的模块,假设建立的倒排索引大小超过单机磁盘容量,就需要在另一个机器上放新的倒排索引数据,变为一个分布式系统,开发者不得不关心更多分布式带来的问题,如一台机器宕机导致该机器的数据不可用,如客户端请求需要广播所有机器,如新索引应该放到哪一台机器上。

但使用ES,我们可以无需考虑这些问题,把全文检索的任务交给ES,开发者只关注业务即可。

ES的优点:

1、自带分布式节点集群,自动维护数据在多个节点的分布和搜索请求路由到多个节点的执行。

2、自动维护数据的冗余副本,实现高可用,一台机器挂掉,数据的完整副本依旧存在。

3、ES封装了更多高级搜索功能,开发者无需重复造轮子。

ES的功能

1、分布式的搜索和数据分析服务

数据分析例如查最近7天毛巾这个产品的销量排名前10的商家有哪些,每个商品分类下有多少商品等。

2、对海量数据进行近实时的处理

分布式以后,可以采用大量服务器进行检索和数据处理,自然就能做到高效的海量数据处理。

所谓的近实时是指数据搜索和分析是秒级别的,此外数据从写入到下次能读取有一个小延迟(大概需要相隔约1s)。

ES的使用场景:搜索和数据分析的场景。

1、电商商品检索、百度全文检索、站内搜索等。

2、日志数据分析:logstash采集日志,ES进行复杂的数据分析(ELK技术)。

3、GitHub,上亿行代码搜索。

ES本身不是什么新技术,而是将全文检索、数据分析和分布式技术合并在一起形成独一无二的服务。

数据库的优势在于提供事务操作,而ES的优势在于分布式服务、全文检索、数据分析和数据实时处理。

ES核心概念

1、Document:文档是ES中的最小数据单元。它可以是一条客户数据,一条商品数据,一条订单数据,通常用JSON表示,每个index的type中可以存储多个document。一个document中包含多个field(字段)。

如下所示是一个文档:

{    "product_id": 1,    "product_name": "xxxx",    "product_desc": "xxxx",    "category_id": 10,    "category_name": "xxxx"}

2、Index:索引,包含一堆具有相似结构的文档数据,比如一个商品索引用来存放所有商品文档。

3、Type:类型,每个Index可以包含一个或多个type,type是Index的一个逻辑分类,一个type下的document具有相同的field,不同type的field不同。

例如一个博客系统拥有一个索引,这个索引可以分为用户数据的type,文章数据的type以及评论数据的type。

又例如,一个电商系统的客户模块是一个索引,订单是一个索引,商品是一个索引,库存也是一个索引。而订单索引根据不同的商品又可以分为不同的type,每个type的document的field如下所示:

普通商品的type:包含product_id、product_name、product_desc、category_id、category_name这5个字段。

电子商品的type:包含product_id、product_name、product_desc、category_id、category_name、service_period(保修期)这6个字段。

食用商品的type:… … 略;

4、节点和集群:ES默认初始只有一个名为elasticsearch的集群,该集群里只有一个节点,如果新增节点也会默认加入到名为elasticsearch的集群。

5、Shard:分片,单机无法存储所有数据,ES可以将一个索引的数据分为多份数据,每份数据就是一个shard,这些shard分布到多台服务器存储。shard的好处有2点:便于数据横向扩展;分布到多台服务器,相当于多台服务器并发响应请求(多台机器的cpu一起在运算,多台机器的磁盘并发读写),提高吞吐。

一个ES节点可以包含一个或多个shard分片。

6、Replica:副本,副本是一种副本分片,其本质也是分片。shard其实叫做primary
shard,简称为shard,replica其实叫做replica
shard,简称为replica。一般而言,每一个shard都需要冗余一份replica。副本的好处有2点:部分节点宕机时高可用;replica所在的节点也可以提供读服务,提高吞吐。

我们来看一个简单的示例:

ES默认一个Index初始会分为5个primary shard,每个primary shard都要冗余1份replica
shard。因此,创建一个Index就会创建10个shard,而且primary shard 和 replica
shard不应该都放在1台机器,最小的高可用配置需要2台服务器,每台服务器都包含一部分primary shard 和一部分replica shard。

一个node是指一个ES进程。

Index相当于数据库的库,type相当于数据库的表,document相当于数据库的行。

还需要说明的是,ES是面向文档的,或者说面向对象的,而关系型数据库则是面向行的,不同对象必须存在数据库的不同表,而ES的一个文档则可以保存多个有关系的对象。

ES服务端的安装和启动

_ 请参考如下链接 _

docker安装ES官方文档:

https://hub.docker.com/_/elasticsearch

使用docker安装和启动ES:

https://www.jianshu.com/p/8abecc27848e

docker ES外网访问:

https://blog.csdn.net/pyon_/article/details/122485435

docker ES设置密码:

https://www.codenong.com/cs106096987/

es客户端 elasticsearch-head安装和启动:

https://blog.csdn.net/weixin_42871989/article/details/123899321

我自己的做法:

# 启动docker ES,这里没有绑定容器卷,之后再绑定docker run -d -p 9200:9200 --name='es' -e discovery.type=single-node     
# ES单节点模式-e ES_JAVA_OPTS="-Xms128m -Xmx128m"     
# 限制分配内存128,不设置这个的话,默认会向系统申请4G内存,如果机器没那么大内存则会启动失败elasticsearch:7.4.2
# 拷贝ES的配置文件目录到本地docker cp es:/usr/share/elasticsearch/config /tmp/es
# 移除ES容器docker rm -f es
# 重新启动ES容器,并绑定容器卷docker run -d -p 9200:9200 --name='es' -e discovery.type=single-node -e ES_JAVA_OPTS="-Xms128m -Xmx128m" -v /tmp/es/config:/usr/share/elasticsearch/config  -v /tmp/es/data:/usr/share/elasticsearch/data --privileged=true elasticsearch:7.4.2
# 更改ES配置文件docker exec -it es /bin/bashvi config/elasticsearch.yml
# ES配置文件内容如下cluster.name: docker-clusternetwork.host: 0.0.0.0xpack.security.enabled: true        
# 这只xpack才能生成和使用密码xpack.security.transport.ssl.enabled: truehttp.cors.enabled: true            
# 这3条允许跨域,这样elasticsearch head才能访问ES服务http.cors.allow-origin: "*"http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type
# 重启ES容器docker restart es
# 设置密码(自动生成密码)并记录到文本文件中,该命令会生成多个ES服务的用户和每个用户对应的密码docker exec -it es /bin/bash./bin/elasticsearch-setup-passwords auto

注意点:

1、之所以要先以不绑定容器卷的形式启动一次,在手动将容器内config拷贝到本地,然后再重新run一个新ES容器绑定容器卷,是因为不这样做就会报如下错误。

NoSuchFileException: /usr/share/elasticsearch/config/jvm.options

原因很简单,我们本地的config目录是空的,而以bind方式挂载容器卷,会使得宿主机目录覆盖容器目录,因此容器内config目录被清空,因此无法启动ES服务。

2、自动生成密码后,密码配置已经被写入到data目录中,因此密码会永久有效

3、如需修改密码可以做如下操作:

# 创建一个临时超级用户./bin/elasticsearch-users useradd zbp -r superuser
# 用这个用户去修改elastic用户的密码curl -XPUT -u zbp:zbp的密码 http://localhost:9200/_xpack/security/user/elastic/_password -H "Content-Type: application/json" -d '{"password": "自定义密码"}'

ES客户端 elasticsearch-head 安装和启动

可参考:

https://blog.csdn.net/weixin_42871989/article/details/123899321

需要注意的是,使用 elasticsearch-head 连接一个有密码的ES服务时,需要访问这个链接去连:

http://ES服务的IP地址:9200/?auth_user=ES用户名&auth_password=密码

ES简单命令

ES提供了一套cat api能查看ES中的元数据。

查看集群健康状况(v参数表示显示表头)

 GET /_cat/health?v
epoch      timestamp cluster        status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent1653135582 12:19:42  docker-cluster green           1         1      1   1    0    0        0             0                  -                100.0%

分别展示了节点个数,primary
shard总数(pri),未分配的shard数量(unassign),活跃状态的分片和总分片占比(active_shards_percent)。

查看集群中有哪些索引

GET /_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size green open .security-7 C-62KLzFR0qKqljcVJHkbw 1 0 6 0 19.8kb 19.8kb

分别展示了索引名,该索引的状态(health),索引的主分片个数(pri),索引的副本分片个数(rep),文档个数(docs.count),索引占的大小。

关于集群的健康状态:

green:每个索引的primary shard 和replica shard都是active状态的。

yellow:每个索引的primary shard 都是active状态的,但部分replica shard是不可用状态的。

red:不是所有索引的primary shard都是active状态的,即当前主数据有部分不可访问。

一般我们在开发环境启动一个ES服务会发现其处于黄色状态,原因是我们创建一个index时,ES会为其创建5个primary shard 和 5个
replica shard,而且primary shard 和 replica shard不能同时放在一个node中。

因此实际上,我们开发环境可能只启动了一个ES node,因此5个primary shard都在这1个node中处于活跃状态,而其他5个replica
shard无法分配到其他node而处于不可用状态。

如果启动ES集群时指明以单节点模式启动,那么ES就不会创建和分配replica shard,集群状态也会是绿色的。

查看索引的文档个数

GET /_cat/count/index_name?v

简单索引操作

# 创建索引PUT /zbp_index?pretty

# 删除索引(慎用,相当于删除数据库)DELETE /zbp_index?pretty

文档CURD操作之新增一个文档

# PUT /索引名/type名/文档id

PUT /zbp_index/product/1{

插入的文档数据 “name”:“gaolujie yagao”, “desc”:“youxiao fangzhu”, “price”:25, “producer”:“zhonghua producer”, “tags”:[“fangzhu”]}

返回结果{ “_index”: “zbp_index”,

插入文档所在的index “_type”: “product”,

插入文档所在的type “_id”: “1”,

文档id “_version”: 1,

版本号,与乐观锁的并发控制有关 “result”: “created”, “_shards”: {

该文档涉及的分片信息 “total”: 2,

一个文档只能分别保存在一个primary shard和一个replica shard中,因此涉及的分配数量为2 “successful”: 1,

成功写入到1个分片中,因为此时只有1个node,replica shard根本没分配 “failed”: 0 }, “_seq_no”: 0, “_primary_term”: 1}

插入文档时,ES会自动创建index和type,无需提前创建,而且ES默认会对document中每个field都建立倒排索引,使其可以被搜索。

文档CURD操作之查询一个文档

# GET /索引名/type名/文档id
GET /zbp_index/product/1
# 返回结果{    "_index": "zbp_index",    "_type": "product",    "_id": "1",    "_version": 2,    "_seq_no": 1,    "_primary_term": 1,    "found": true,    "_source": {    
# _source是查询出来的原文档内容        "name": "gaolujie yagao",        "desc": "youxiao fangzhu",        "price": 25,        "producer": "zhonghua producer",        "tags": [            "fangzhu"        ]    }}

文档CURD操作之修改一个文档

# 以覆盖的方式修改一个文档,用PUT和POST都可以PUT /zbp_index/product/1{    
# 我要修改name字段,但是其他字段也要带上,这是覆盖方式的一个坏处    "name":"better gaolujie yagao",    "desc":"youxiao fangzhu",    "price":25,    "producer":"zhonghua producer",    "tags":["fangzhu"]}
# 返回结果{    "_index": "zbp_index",    "_type": "product",    "_id": "1",    "_version": 2,    
# 版本号发生更新    "result": "updated",    
# 操作结果是"更新"而非"新增"    "_shards": {        "total": 2,        "successful": 1,        "failed": 0    },    "_seq_no": 1,    "_primary_term": 1}
# 使用_update这个api以部分更新的方式修改一个文档,只能使用POST请求POST /zbp_index/product/1/_update{    "doc":{        "name":"gaolujie yagao!",    
# 要更改的字段        "price": 30,        "more_info":"no more"    
# 新增一个之前不存在的字段也行    }}
# 返回结果{    "_index": "zbp_index",    "_type": "product",    "_id": "1",    "_version": 11,    "result": "updated",    "_shards": {        "total": 2,        "successful": 1,        "failed": 0    },    "_seq_no": 10,    "_primary_term": 1}

覆盖一个id=1的文档时,其实并非对id=1的文档的每个字段都进行修改。而是将原文档标记为deleted,并创建一个新的id=1的文档。

当ES的数据逐渐变多时,会自动删除标记为deleted的文档。

如果用户希望明确一个 PUT|POST /索引/类型/id号
是一个创建文档操作而非覆盖操作(也就是说你不知道当前这个文档是否存在),则可以使用_create API。如果文档已存在,则该操作会报错。

PUT|POST /zbp_index/product/6/_create

文档CURD操作之删除一个文档

DELETE /索引名/type名/文档id

删除操作也是将文档标记为deleted,而非真的删除文档。

如果需要根据条件删除可以使用_delete_by_query API。

# /索引名/_delete_by_query/outbound_invoice/_delete_by_query{    "query": {        "bool": {            "filter": [                {                    "term": {                        "client_id": 14119  
# 删除client_id为14119的文档                    }                }            ]        }    }}

文档查询方式之query string search

# GET /索引名/type名/_search
# 直接查询该index/type的所有文档(不加任何参数即可)GET /zbp_index/product/_search
# 查询name字段包含yagao的文档,并按price字段降序排序GET /zbp_index/product/_search?q=name:yagao&sort=price:desc
# 返回结果{    "took": 294,    
# 耗费多少毫秒    "timed_out": false,    
# 是否超时    "_shards": {            "total": 1, 
# 请求发向了多少个分片,对于搜索请求,会发送到所有的primary shard(如果有某个primary shard down掉,则发送到顶替的replica shard上)        "successful": 1,        "skipped": 0,        "failed": 0    },    "hits": {        "total": {    
# 查询结果数量(document的数量)            "value": 1,            "relation": "eq"        },        "max_score": null, 
# 最高匹配相关度,最高是1        "hits": [{    
# 包含匹配的document的详细数据            "_index": "zbp_index",            "_type": "product",            "_id": "1",            "_score": null,    本文档的匹配相关度,越匹配,分数越高。如果要求按某字段排序,则分数为null            "_source": {                "name": "better gaolujie yagao",                "desc": "youxiao fangzhu",                "price": 25,                "producer": "zhonghua producer",                "tags": [                    "fangzhu"                ]            },            "sort": [ 
# 本文档的排序值                25            ]        }]    }}

query string search方式适用于临时的、在命令行中查询的简单场景,如果查询请求复杂是很难构建的,因此在生产环境中很少用query
string search查询。

顺便再介绍一下query的+ 和 - 语法。

GET /zbp_index/product/_search?q=+name:yagao    // 查询name字段包含yagao的文档GET /zbp_index/product/_search?q=-name:yagao    // 查询name字段不包含yagao的文档

_all metadata

GET /index/type/_search?q=test

搜索所有的field,任一个field包含指定关键字的文档都能搜索出来。

实际上,在创建文档时,ES会默认将所有字段作为字符串拼接起来作为一个 _all
字段,并对其建立倒排索引。如果遇到上面这样的不指定field的关键词搜索,就会可以用到_all字段的倒排索引进行检索。

文档查询方式之query DSL

DSL方式可以在请求的body体中构建json格式的搜索信息,相比于query search方式可以支持更复杂的搜索需求。

例1:查询所有文档

GET|POST /zbp_index/product/_search
# 请求body{    "query":{    
# 表示这是一个DSL查询            "match_all":{}    
# 查询所有文档    }}

例2:查询name字段包含yagao的所有文档,并按价格降序排序

GET|POST /zbp_index/product/_search
# 请求body{    "query":{    
# 表示这是一个DSL查询            "match":{                "name": "yagao"                        }    },    "sort":{          "price":"desc"              }}

例子3:查询所有文档并分页

GET|POST /zbp_index/product/_search
# 请求body{    "query":{    
# 表示这是一个DSL查询            "match_all":{}    
# 查询所有文档    },    "from":1,    
# 偏移量    "size":2    
# 每页大小}

例子4:查询所有文档,只显示name和price字段

 GET|POST /zbp_index/product/_search
# 请求body{    "query":{        "match_all":{}        },    "_source":["name","price"]}

文档查询方式之query filter

查询商品名中包含yagao,且售价大于25元的商品

GET|POST /zbp_index/product/_search{  "query": {    "bool": {    
# 可以组合多个条件      "must": {        "match": {          "name": "yagao"        }      },      "filter": {        "range": {          "price": {"gt": 20}        }      }    }  }}

如果需要多个条件组合可以使用must

{    "query": {        "bool": {            "must": [                {                    "term": {                        "name": "wali"                    }                },                {                    "term": {                        "country": "chinas"                    }                }            ]        }    },    "from": 0,    "size": 10}

term是精确查询,上面的语句相当于where name=“wali” and country=“chinas”。

文档查询方式之全文检索 full-text search

查询包含 yagao producer 关键字相关的文档。

GET|POST /zbp_index/product/_search{    "query":{        "match":{            "producer":"yagao producer"                }        }}

全文检索的语法和前面的例2没有任何区别。唯一区别在于例2的搜索值只有1个单词,而本例有2个单词。此时ES就会将用户提供的检索值进行分词,并对每个分词从倒排索引进行检索。只要有任何1个单词能从倒排索引中找到,都会出现在返回结果中,某一个文档涵盖的搜索值分词越多,该搜索值在倒排索引命中该文档的次数越多,该文档的分数也越高。

文档查询方式之全文检索 phrase search(短语搜索)

GET|POST /zbp_index/product/_search{    "query":{        "match_phrase":{            "producer":"yagao producer"                }        }}

短语搜索要求某个字段必须完全包含检索值才能匹配成功,这和全文搜索相反。

文档查询方式之全文检索 highlight search(高亮搜索)

GET|POST /zbp_index/product/_search{    "query":{        "match":{            "producer":"yagao"                }    },    "highlight":{        "fields":{            "producer" : {}       
# 只对producer中命中的关键字进行高亮显示             }        }}

高亮搜索和普通的DSL搜索什么区别,但是会在返回结果中多返回一个hightlights属性,里面包含了producer字段中的“yagao”字样会被添加一个高亮的html标签。

再看一个高亮显示的例子:

GET|POST /zbp_index/product/_search{    "query":{        "bool":{            "must":[                {                    "match_phrase":{                        "producer": "yagao producer"                    }                 },                 {                    "match_phrase":{                        "name": "yagao"                    }                 }            ]        }    },    "_source":["name","producer"],    "highlight":{        "fields":{            "producer":{},            "name":{}        }    }}
# 查询结果{    "took": 4,    "timed_out": false,    "_shards": {        "total": 1,        "successful": 1,        "skipped": 0,        "failed": 0    },    "hits": {        "total": {            "value": 1,            "relation": "eq"        },        "max_score": 1.0078249,        "hits": [            {                "_index": "zbp_index",                "_type": "product",                "_id": "2",                "_score": 1.0078249,                "_source": {                    "name": "special yagao",                    "producer": "special yagao producer"                },                "highlight": {                    "name": [                        "special <em>yagao</em>"                    ],                    "producer": [                        "special <em>yagao</em> <em>producer</em>"                    ]                }            }        ]    }}

注意:

上述6中查询方式可以组合使用,不是独立的。

对于ES 7以上的版本,DSL等带body的请求方式只能用post请求,而不能用get请求,否则会忽略body的内容直接返回所有文档。

聚合分析实例(聚合可用于数据分析)

开始之前先插入如下数据:

PUT /zbp_index/product/1{    "name": "better gaolujie yagao",    "desc": "youxiao fangzhu",    "price": 20,    "producer": "gaolujie producer",    "tags": [        "fangzhu",        "meibai"    ]}
PUT /zbp_index/product/2{    "name": "zhonghua yagao",    "desc": "guochan product",    "price": 25,    "producer": "zhonghua producer",    "tags": [        "xiahuo"    ]}
PUT /zbp_index/product/3{    "name": "heiren yagao",    "desc": "dajia douyong",    "price": 35,    "producer": "heiren producer",    "tags": [        "meibai",        "qingxin"    ]}
PUT /zbp_index/product/4{    "name": "yunnan baiyao yagao",    "desc": "yunnan baiyao",    "price": 50,    "producer": "yunnan baiyao producer",    "tags": [        "xiahuo",        "meibai",        "changqi youxiao"    ]}
PUT /zbp_index/product/5{    "name": "special yagao",    "desc": "zhizao xuannian",    "price": 55,    "producer": "special yagao producer",    "tags": [        "special",        "xiahuo",        "meibai",        "fangzhu"    ]}

我们要根据tags字段进行聚合,此时需要将该字段的fielddata属性置为true。

PUT /zbp_index/_mapping/product?include_type_name=true    
# 更改product这个type的字段属性,可以理解为和mysql中更改字段信息是一样的{    "properties":{        "tags":{            "type":"text",            "fielddata":true                }        }}

需求1:对商品按tags(中的每个元素)分组

POST /zbp_index/product/_search{    "size":0,        // 如果加上size=0,表示不显示查找出来的文档的结果,只显示aggs聚合的结果    "aggs":{        "group_by_tags":{    // 自定义的聚合任务名             "terms":{    // 以terms方式聚合,可以简单理解为“分组”                        "field":"tags"              }        }        }}
# 结果{    "took": 14,    "timed_out": false,    "_shards": {        "total": 1,        "successful": 1,        "skipped": 0,        "failed": 0    },    "hits": {        "total": {            "value": 5,            "relation": "eq"        },        "max_score": null,        "hits": []    },    "aggregations": {        "group_by_tags": {            "doc_count_error_upper_bound": 0,            "sum_other_doc_count": 0,            "buckets": [    // buckets的一个元素表示一类分组                {                    "key": "meibai",                    "doc_count": 4    // tags为美白的文档有4条                },                {                    "key": "xiahuo",                    "doc_count": 3                },                {                    "key": "fangzhu",                    "doc_count": 2                },                {                    "key": "changqi",                    "doc_count": 1                },                {                    "key": "qingxin",                    "doc_count": 1                },                {                    "key": "special",                    "doc_count": 1                },                {                    "key": "youxiao",                    "doc_count": 1                }            ]        }    }}

需求2:对名称中包含yagao的商品,对每个tag的商品分组。很简单,只需加上query属性表示筛选条件即可。

POST /zbp_index/product/_search{    "size":0,    "query":{        "match":{            "name":"yagao"        }    },    "aggs":{        "group_by_tags":{            "terms":{                        "field":"tags"            }        }        }}

需求3:对每个tag的商品分组,计算每个tag的商品平均价格。

 {    "size":0,    "aggs":{        "group_by_tags":{   // 自定义的聚合任务名            "terms":{   // 以terms方式聚合,可以简单理解为“分组”                "field":"tags"            },            "aggs":{    // 在group_by_tags聚合下计算平均价格                "avg_price":{    // 聚合任务名                    "avg":{    // 聚合方式:计算平均值                        "field":"price"                    }                }            }        }        }}
# 结果{    "took": 21,    "timed_out": false,    "_shards": {        "total": 1,        "successful": 1,        "skipped": 0,        "failed": 0    },    "hits": {        "total": {            "value": 5,            "relation": "eq"        },        "max_score": null,        "hits": []    },    "aggregations": {        "group_by_tags": {            "doc_count_error_upper_bound": 0,            "sum_other_doc_count": 0,            "buckets": [                {                    "key": "meibai",                    "doc_count": 4,                    "avg_price": {                        "value": 40.0                    }                },                {                    "key": "xiahuo",                    "doc_count": 3,                    "avg_price": {                        "value": 43.333333333333336                    }                },                {                    "key": "fangzhu",                    "doc_count": 2,                    "avg_price": {                        "value": 37.5                    }                },                {                    "key": "changqi",                    "doc_count": 1,                    "avg_price": {                        "value": 50.0                    }                },                {                    "key": "qingxin",                    "doc_count": 1,                    "avg_price": {                        "value": 35.0                    }                },                {                    "key": "special",                    "doc_count": 1,                    "avg_price": {                        "value": 55.0                    }                },                {                    "key": "youxiao",                    "doc_count": 1,                    "avg_price": {                        "value": 50.0                    }                }            ]        }    }}

需求4:在需求3的基础上,按平均价格降序排序

{    "size":0,    "aggs":{        "group_by_tags":{            "terms":{                "field":"tags",                "order":{"avg_price":"desc"}            },            "aggs":{                "avg_price":{                    "avg":{                        "field":"price"                    }                }            }        }        }}

需求5:先按价格范围区间分组,再在每组内按照tag分组,计算价格分组每组平均价格和tag分组的魅族平均价格。

{    "size":0,    "aggs":{        "group_by_price":{            "range":{                "field":"price",                "ranges":[                    {                        "from":20,                        "to":25                    },                    {                        "from":25,                        "to":40                    },                    {                        "from":40,                        "to":60                    }                ]            },            "aggs":{    // 在上一维度聚合的基础上再对另一个维度(或者说字段)聚合,这种嵌套聚合分组称为“下钻分析”                "group_by_tags":{                    "terms":{"field":"tags"},                    "aggs":{                        "avg_price":{                            "avg":{                                "field":"price"                            }                        }                    }                },                "avg_price":{                    "avg":{                        "field":"price"                    }                }            }        }        }}
# 结果{    "took": 5,    "timed_out": false,    "_shards": {        "total": 1,        "successful": 1,        "skipped": 0,        "failed": 0    },    "hits": {        "total": {            "value": 5,            "relation": "eq"        },        "max_score": null,        "hits": []    },    "aggregations": {        "group_by_price": {            "buckets": [                {                    "key": "20.0-25.0",                    "from": 20.0,                    "to": 25.0,                    "doc_count": 1,                    "avg_price": {                        "value": 20.0                    },                    "group_by_tags": {                        "doc_count_error_upper_bound": 0,                        "sum_other_doc_count": 0,                        "buckets": [                            {                                "key": "fangzhu",                                "doc_count": 1,                                "avg_price": {                                    "value": 20.0                                }                            },                            {                                "key": "meibai",                                "doc_count": 1,                                "avg_price": {                                    "value": 20.0                                }                            }                        ]                    }                },                {                    "key": "25.0-40.0",                    "from": 25.0,                    "to": 40.0,                    "doc_count": 2,                    "avg_price": {                        "value": 30.0                    },                    "group_by_tags": {                        "doc_count_error_upper_bound": 0,                        "sum_other_doc_count": 0,                        "buckets": [                            {                                "key": "meibai",                                "doc_count": 1,                                "avg_price": {                                    "value": 35.0                                }                            },                            {                                "key": "qingxin",                                "doc_count": 1,                                "avg_price": {                                    "value": 35.0                                }                            },                            {                                "key": "xiahuo",                                "doc_count": 1,                                "avg_price": {                                    "value": 25.0                                }                            }                        ]                    }                },                {                    "key": "40.0-60.0",                    "from": 40.0,                    "to": 60.0,                    "doc_count": 2,                    "avg_price": {                        "value": 52.5                    },                    "group_by_tags": {                        "doc_count_error_upper_bound": 0,                        "sum_other_doc_count": 0,                        "buckets": [                            {                                "key": "meibai",                                "doc_count": 2,                                "avg_price": {                                    "value": 52.5                                }                            },                            {                                "key": "xiahuo",                                "doc_count": 2,                                "avg_price": {                                    "value": 52.5                                }                            },                            {                                "key": "changqi",                                "doc_count": 1,                                "avg_price": {                                    "value": 50.0                                }                            },                            {                                "key": "fangzhu",                                "doc_count": 1,                                "avg_price": {                                    "value": 55.0                                }                            },                            {                                "key": "special",                                "doc_count": 1,                                "avg_price": {                                    "value": 55.0                                }                            },                            {                                "key": "youxiao",                                "doc_count": 1,                                "avg_price": {                                    "value": 50.0                                }                            }                        ]                    }                }            ]        }    }}

评论