Elasticsearch学习整理
基本概念:
- 集群(Cluster)
- 节点(Node)
- 索引(Index)
- 文档(Document)
- 分片和复制(Sshards & Replicas)
探索集群 The REST API:
- 检查集群,节点和索引运行状况,状态和统计信息
GET /_cat/health?v #查看集群健康状态检查
GET /_cat/nodes?v #查看集群中的节点列表
GET /_cat/indices?v #查看集群索引列表
- 索引的创建、插入、检索和删除
PUT /customer?pretty #创建索引
PUT /customer/doc/1?pretty #插入文档,需要指定header:-H'Content-Type: application/json'
{
"name": "John Doe"
}
GET /customer/doc/1?pretty #检索文档
DELETE /customer?pretty #删除索引
- 修改数据
PUT /customer/doc/1?pretty #索引文档,指定header
{
"name": "John Doe"
}
POST /customer/doc?pretty #未指定ID使用POST,指定header
{
"name": "Jane Doe"
}
POST /customer/doc/1/_update?pretty #更新文档,同时新加age字段,指定header
{
"doc": { "name": "Jane Doe", "age": 20 }
}
POST /bank/account/_bulk?pretty&refresh --data-binary "@accounts.json" #批处理,加载本地accounts.json到集群
# 运行搜索的两种方式
GET /bank/_search?q=*&pretty #请求URI
POST /bank/_search?pretty #请求主体,指定header:-H'Content-Type: application/json'
{
"query": {
"match_all": {} }
}
# 查询语句介绍
{
"query": { "match_all": {} }, #query部分:查询的定义;match_all部分:想要运行的查询的类型
"from": 10, #from参数(0-based)从哪个文档开始,size参数指明从from参数开始,要返回多少个文档,对分页搜索非常有用。
"size": 10, #如果没有指定size的值,那么它默认就是10
"sort": {
"balance": {
"order":"desc"}} #降序排序
}
#查询
{ "query": {
"match":{
"address": "mill"}} } #匹配地址中包含mill的
{ "query": {
"match":{
"address": "mill lane"}} } #匹配地址中包含mill或lane的
{ "query": {
"match_phrase":{
"address": "mill lane"}} } #配短语“mill lane”
#bool查询:must、should、must_not
#包含“mill”和“lane”
{
"query": {
"bool": {
"must": [
{
"match": { "address": "mill"}},
{
"match": { "address": "lane"}}
]
}
}
}
#过滤器
#查找大于或等于20000且小于等于30000的帐户
{
"query": {
"bool": {
"must":{
"match_all":{}},
"filter":{
"range":{
"balance":{
"gte": 20000,
"lte": 30000
}
}
}
}
}
}
#聚合
#按状态对所有账户分组
{
"size": 0,
"aggs": {
"group_by_state": {
"terms": {
"field": "state.keyword"
}
}
}
}
......
基本概念
集群(Cluster)
群集是一个或多个节点(服务器)的集合,它们一起保存整个数据,并在所有节点上提供联合索引和搜索功能。 一个集群由一个唯一的名字来标识,默认是“elasticsearch”。确保不要在不同的环境中重复使用相同的群集名称,否则可能会导致节点加入错误的群集。
节点(Node)
节点是作为集群一部分的单个服务器,存储数据并参与集群的索引和搜索功能。就像一个集群一样,一个节点由一个名字来标识,默认情况下它是一个在启动时分配给节点的随机通用唯一标识符(UUID)。如果您不需要默认值,您可以定义任何您想要的节点名称。此名称对于管理目的非常重要,您需要确定网络中的哪些服务器对应于Elasticsearch群集中的哪些节点。
可以将节点配置为按集群名称加入特定的集群。默认情况下,每个节点都设置为加入一个名为elasticsearch的集群,这意味着如果启动网络中的许多节点,并假设它们可以互相发现,它们将自动形成并加入一个名为elasticsearch的集群。
在单个群集中,您可以拥有任意数量的节点。而且,如果网络中没有其他Elasticsearch节点正在运行,则默认情况下启动单个节点会形成一个名为elasticsearch的新单节点群集。
索引(Index)
索引是具有相似特征的文档的集合。 例如,您可以拥有客户数据的索引,产品目录的另一个索引以及订单数据的另一个索引。 索引由名称标识(必须全部为小写),该名称用于在对索引文档进行索引,搜索,更新和删除操作时引用索引。在单个群集中,可以根据需要定义多个索引。
文档(Document)
文档是可被索引的基本信息单元。 例如,您可以为单个客户提供文档,为单个产品提供另一个文档,为单个订单提供另一个文档。 这个文档是用JSON(JavaScript Object Notation)表示的,它是一个无处不在的互联网数据交换格式。
在索引/类型中,您可以根据需要存储多个文档。 请注意,尽管文档实际上驻留在索引中,但实际上文档必须被索引/分配给索引内的类型。
分片和复制(Shards & Replicas)
Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
分片之所以重要,主要有两方面的原因:
- 允许你水平分割/扩展你的内容量
- 允许你在分片(可能在多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
复制之所以重要,有两个主要原因:
- 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。
- 扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行
总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你事后不能改变分片的数量。
默认情况下,Elasticsearch中的每个索引都分配了5个主分片和1个副本,这意味着如果您的集群中至少有两个节点,则索引将包含5个主分片和另外5个副本分片(1个完全拷贝) 每个索引10个分片。
可以使用_cat/shards
API监视分片大小
Elasticsearch 提供了优化好的默认配置。除非你明白这些配置的行为和为什么要这么做,请不要修改这些配置。
两个最重要的设置:
number_of_shards #定义一个索引的主分片个数,默认值是 `5`。这个配置在索引创建后不能修改。
number_of_replicas #每个主分片的复制分片个数,默认是 `1`。这个配置可以随时在活跃的索引上修改。
例如创建一个只有一个主分片,没有复制分片的索引:
PUT /my_temp_index
{
"settings": {
"number_of_shards" : 1,
"number_of_replicas" : 0
}
}
或者:
curl -H "Content-Type: application/json" -XPUT 192.168.20.60:9200/my_index?pretty -d ' { "settings": { "number_of_shards": 1, "number_of_replicas": 0 } }'
然后,利用update-index-settings API 动态修改复制分片个数
PUT /my_index/_settings
{
"number_of_replicas" : 1
}
探索集群 The REST API
Elasticsearch提供了一个非常全面和强大的REST API,可以使用它来与群集进行交互。 可以用API完成的几件事情如下:
- 检查您的集群,节点和索引运行状况,状态和统计信息
- 管理您的集群,节点和索引数据和元数据
- 对索引执行CRUD(创建,读取,更新和删除)和搜索操作
- 执行高级搜索操作,如分页,排序,过滤,脚本,聚合等等
健康检查
GET /_cat/health?v
# curl -XGET 192.168.20.60:9200/_cat/health?v
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1524706519 09:35:19 mycluster green 1 1 2 2 0 0 0 0 - 100.0%
由此可以看到集群名称为”mycluster”,集群健康为绿色。
绿色 – 健康状态,指所有主副分片都正常分配
黄色 – 指所有主分派都正常分配,但是有副本分片为正常分配
红色 – 有主分片未分配
注意:当一个群集为红色时,它将继续提供来自可用碎片的搜索请求,但是您可能需要尽快修复它,因为有未分配的碎片
查看集群中的节点列表
GET /_cat/nodes?v
# curl -XGET 192.168.20.60:9200/_cat/nodes?v
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.20.60 65 22 0 0.11 0.10 0.13 mdi * node1
查看索引列表
GET /_cat/indices?v
# curl -XGET 192.168.20.60:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .monitoring-es-6-2018.04.26 ofVrC0TpTZGf2vsZ2tBQaA 1 0 557 4 411.2kb 411.2kb
green open .monitoring-kibana-6-2018.04.26 S5csJnW3TyKhoMst64O-tw 1 0 93 0 70.7kb 70.7kb
可以看到两条索引,x-pack监控索引
创建一个索引
PUT /customer?pretty
# curl -XPUT 192.168.20.60:9200/customer?pretty #创建一个名为customer的索引
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "customer"
}
# curl -XGET 192.168.20.60:9200/_cat/indices?v #查看索引列表
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open customer 0Y6TnERhSuO27j9Vlxzk0A 5 1 0 0 1.1kb 1.1kb
green open .monitoring-es-6-2018.04.26 ofVrC0TpTZGf2vsZ2tBQaA 1 0 1392 12 725.1kb 725.1kb
green open .monitoring-kibana-6-2018.04.26 S5csJnW3TyKhoMst64O-tw 1 0 217 0 81.9kb 81.9kb
可以看到新增一个名为customer的索引,它有5个主分片和1个副本(默认值),它包含0个文档,健康状态为黄色。
黄色意味着一些复制品还没有被分配。这个索引发生的原因是因为Elasticsearch默认为这个索引创建了一个副本。由于此刻我们只有一个节点正在运行,因此,在另一个节点加入集群的较晚时间点之前,尚无法分配一个副本(以获得高可用性)。 一旦该副本被分配到第二个节点上,该索引的健康状态将变成绿色。
插入文档
现在让我们把东西放入我们的客户索引。 我们会将一个简单的客户文档编入客户索引,ID为1,如下所示:
# curl -H'Content-Type: application/json' -XPUT 192.168.20.60:9200/customer/doc/1?pretty -d '
{
"name": "node1"
}'
注意:需要指定header头
-H'Content-Type: application/json'
,否则会报406错误
结果:客户索引里面成功创建了一个新的客户文档。 该文件也有一个我们指定的内部ID
{
"_index": "customer",
"_type": "doc",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": { "total": 2, "successful": 1, "failed": 0 },
"_seq_no": 0,
"_primary_term": 1 }
注意:插入文档时如果没有指定的索引,elasticsearch会自动创建客户索引。
当前索引列表中并没有test索引,执行如下插入动作会自动创建test索引:
# curl -H'Content-Type: application/json' -XPUT 192.168.20.60:9200/test/doc/1?pretty -d '
{
"name": "node1"
}'
检索刚才插入的文档
# curl -XGET 192.168.20.60:9200/customer/doc/1?pretty
{
"_index" : "customer",
"_type" : "doc",
"_id" : "1",
"_version" : 3,
"found" : true,
"_source" : {
"name" : "node1"
}
}
删除索引
curl -XDELETE 192.168.20.60:9200/customer?pretty
修改数据
Elasticsearch几乎实时提供数据操作和搜索功能。默认情况下,从索引/更新/删除数据开始,直到搜索结果中显示的时间为止,您可以预期会有一秒的延迟(刷新间隔)。 这是与SQL等其他平台的重要区别,其中数据在交易完成后立即可用。
索引/替换文档
前面提到的我们在test索引中创建了ID为1的文档
# curl -H'Content-Type: application/json' -XPUT 192.168.20.60:9200/test/doc/1?pretty -d '
{
"name": "node1"
}'
当我们再次执行上述命令,elasticsearch会执行更新操作,"result"
的结果由"created"
变成了"updated"
;如果使用不同的ID,elasticsearch会执行新增操作。
索引时,ID部分是可选的。 如果未指定,Elasticsearch将生成一个随机ID,然后用它来索引文档。 Elasticsearch生成的实际ID。
如果不指定ID,需要使用POST
而不是PUT:
# curl -H'Content-Type: application/json' -XPOST 192.168.20.60:9200/test/doc?pretty -d '
{
"name": "node1"}'
{
"_index" : "test",
"_type" : "doc",
"_id" : "oQIGAGMB0q69El2bk2kr",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
更新文档
Elasticsearch实际上并没有在原地进行更新。无论何时我们进行更新Elasticsearch都会删除旧文档,然后索引一个新文档,一次性应用更新。
通过改变名称字段”node1”为”www”来更新之前的文档(ID为1),同时添加一个年龄字段:
# curl -H'Content-Type: application/json' -XPOST 192.168.20.60:9200/test/doc/1/_update?pretty -d '
{
"doc": {
"name": "www","age": 20}
}'
删除文档
curl -XDELETE 192.168.20.60:9200/test/doc/2?pretty #删除ID为2的文档
批处理
除了能够索引,更新和删除单个文档外,Elasticsearch还提供了使用_bulk API批量执行上述任何操作的功能。 这个功能很重要,因为它提供了一个非常有效的机制,尽可能快地完成多个操作,尽可能少的网络往返。
批量API不会因其中一个操作失败而失败。 如果一个动作因任何原因失败,它将继续处理其余的动作。 批量API返回时,它将为每个操作提供一个状态(与发送的顺序相同),以便您可以检查特定操作是否失败。
如果您要提供文本文件输入curl,则必须使用该 –data-binary标志而不是纯文本-d。
探索数据
将示例数据解压到当前目录,然后加载示例数据:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/account/_bulk?pretty&refresh' --data-binary "@accounts.json"
查看索引:
# curl -XGET 192.168.20.60:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
yellow open bank 1dTTREkWRJa7dBnVZ7IEvg 5 1 1000 0 474.7kb 474.7kb
搜索API
有两种运行搜索的基本方法:一种是通过REST请求URI发送搜索参数,另一种是通过REST请求主体发送搜索参数。请求主体方法允许您更具表现力,并以更易读的JSON格式定义您的搜索。
#请求URI,使用GET
curl -XGET '192.168.20.60:9200/bank/_search?q=*&pretty'
#请求主体,使用POST
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": {"match_all": {} } }'
搜索的REST API可从_search端点访问。 本示例返回银行索引中的所有文档:
curl -XGET '192.168.20.60:9200/bank/_search?q=*&pretty'
#q = *参数指示Elasticsearch匹配索引中的所有文档
列出部分响应结果:
# curl -XGET '192.168.20.60:9200/bank/_search?q=*&pretty'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1000,
"max_score" : 1.0,
"hits" : [
{
"_index" : "bank",
"_type" : "account",
"_id" : "25",
"_score" : 1.0,
"_source" : {
"account_number" : 25,
"balance" : 40540,
"firstname" : "Virginia",
"lastname" : "Ayala",
"age" : 39,
"gender" : "F",
"address" : "171 Putnam Avenue",
"employer" : "Filodyne",
"email" : "virginiaayala@filodyne.com",
"city" : "Nicholson",
"state" : "PA"
}
},
对于这个响应,看到如下结果:
took #Elasticsearch花费了几毫秒的时间来执行搜索,单位毫秒
timed_out #搜索是否超时
_shards #搜索了多少碎片,以及搜索碎片成功/失败的次数
hits #搜索结果
hits.total #符合我们搜索条件的文档总数
hits.hits #实际的搜索结果数组(默认为前10个文档)
hits._score和max_score #现在忽略这些字段
使用请求体方法的等价搜索是:
# curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d '
{
"query": {
"match_all": {} }
}'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 1000,
"max_score" : 1.0,
"hits" : [
{
"_index" : "bank",
"_type" : "account",
"_id" : "25",
"_score" : 1.0,
"_source" : {
"account_number" : 25,
"balance" : 40540,
"firstname" : "Virginia",
"lastname" : "Ayala",
"age" : 39,
"gender" : "F",
"address" : "171 Putnam Avenue",
"employer" : "Filodyne",
"email" : "virginiaayala@filodyne.com",
"city" : "Nicholson",
"state" : "PA"
}
},
....
这里的不同之处在于,并不是向URI中传递q=*,取而代之的是,我们在_search API的请求体中POST
了一个JSON格式请求体。
介绍查询语句
Elasticsearch提供了一种JSON风格的域特定语言,可以用来执行查询。这被称为查询DSL。查询语言非常全面,可以乍一看吓人,但实际学习的最好方法是从几个基本的例子开始。
回到上一个例子,执行了如下查询:
{
"query": { "match_all": {} } }
其中的query
部分告诉我查询的定义,match_all
部分就是我们想要运行的查询的类型。match_all查询,就是简单地查询一个指定索引下的所有的文档。
除了这个query参数之外,我们也可以通过传递其它的参数来影响搜索结果。比如,下面做了一次match_all并只返回第一个文档:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query":{"match_all":{}}, "size":1 #如果没有指定size的值,那么它默认就是10 }'
下面这个例子做一个match_all并返回文档11到20:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query":{"match_all":{}}, "from":10, "size":10 }'
其中的from
参数(0-based)从哪个文档开始,size
参数指明从from参数开始,要返回多少个文档。这个特性对于搜索结果分页来说非常有帮助。注意,如果不指定from的值,它默认就是0。
下面这个例子做了一次match_all并且以账户余额降序排序,最后返前十个文档:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query":{"match_all":{}}, "sort": {"balance": {"order":"desc"}} }'
执行搜索
默认情况下,是返回完整的JSON文档的。这可以通过source来引用(搜索hits中的_sourcei字段)。如果我们不想返回完整的源文档,我们可以指定返回的几个字段。
下面这个例子说明了怎样返回两个字段account_number和balance(_source内):
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": {"match_all":{}}, "size": 1, "_source":["account_number","balance"] }'
返回结果:
{
"took" : 2,
"timed_out" : false,
"_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 },
"hits" : { "total" : 1000, "max_score" : 1.0, "hits" : [ { "_index" : "bank", "_type" : "account", "_id" : "25", "_score" : 1.0, "_source" : { "account_number" : 25, "balance" : 40540 } } ] } }
请注意,上面的例子简单地减少了_source字段。 它仍然只会返回一个名为_source的字段,但在其中只包含字段account_number和balance。
现在我们来看看查询部分。以前,我们已经看过如何使用match_all查询来匹配所有文档。现在我们来介绍一个称为匹配查询的新查询,它可以被看作是一个基本的搜索查询(即针对特定字段或字段集合进行的搜索)。此示例返回编号为20的帐户:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": {"match":{"account_number":20}} }'
此示例返回地址中包含“mill”的所有帐户:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": {"match":{"address": "mill"}} }'
此示例返回地址中包含“mill”或“lane”的所有帐户:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": {"match":{"address": "mill lane"}} }'
这个例子是match的变体(match_phrase),它会去匹配短语“mill lane”:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": {"match_phrase":{"address": "mill lane"}} }'
bool查询允许我们使用布尔逻辑将更小的查询组合成更大的查询。此示例组成两个匹配查询,并返回地址中包含“mill”和“lane”的所有帐户:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": { "bool": { "must": [ {"match": { "address": "mill"}}, {"match": { "address": "lane"}} ] } } }'
bool must
语句指明了,对于一个文档,所有的查询都必须为真,这个文档才能够匹配成功。
相反的,下面的例子组合了两个match查询,它返回的是地址中包含“mill”或者“lane”的所有的账户:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": { "bool": { "should": [ {"match": { "address": "mill"}}, {"match": { "address": "lane"}} ] } } }'
bool should
语句指明,对于一个文档,查询列表中,只要有一个查询匹配,那么这个文档就被看成是匹配的。
现在这个例子组合了两个查询,它返回地址中既不包含“mill”,同时也不包含“lane”的所有的账户信息:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": { "bool": { "must_not": [ {"match": { "address": "mill"}}, {"match": { "address": "lane"}} ] } } }'
bool must_not语句指明,对于一个文档,查询列表中的的所有查询都必须都不为真,这个文档才被认为是匹配的。
可以在一个bool查询里一起使用must
、should
、must_not
。此外,我们可以将bool查询放到这样的bool语句中来模拟复杂的、多等级的布尔逻辑。
下面这个例子返回40岁以上并且不生活在ID(daho)的人的账户:
# curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d '
{
"query": {
"bool": {
"must": [
{ "match": { "age": "40" } }
],
"must_not": [
{ "match": { "state": "ID" } }
]
}
}
}'
执行过滤器
在前一节中,我们跳过了一个小细节,称为文档score(搜索结果中的_score字段)。分数是一个数字值,它是对文档与我们指定的搜索查询匹配程度的相对度量。分数越高,文档越相关,分数越低,文档的相关性越小。
但是查询并不总是需要产生分数,特别是当它们仅用于“过滤”文档集时。弹性搜索可以检测到这些情况,并自动优化查询执行,而不是计算无用的分数。
我们在前一节介绍的bool查询还支持过滤子句,它允许使用查询来限制将被其他子句匹配的文档,而不改变计算得分的方式。 作为一个例子,我们来介绍一下范围查询,它允许我们通过一系列值来过滤文档。 这通常用于数字或日期过滤。
本示例使用bool查询返回余额在20000和30000之间的所有帐户。 换句话说,我们要查找大于或等于20000且小于等于30000的帐户。
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "query": { "bool": { "must":{"match_all":{}}, "filter":{ "range":{ "balance":{ "gte": 20000, "lte": 30000 } } } } } }'
分解上面的例子,被过滤的查询包含一个match_all查询(查询部分)和一个过滤器(filter部分)。我们可以在查询部分中放入其他查询,在filter部分放入其它过滤器。在上面的应用场景中,由于所有的在这个范围之内的文档都是平等的(或者说相关度都是一样的),没有一个文档比另一个文档更相关,所以这个时候使用范围过滤器就非常合适了。
执行聚合
聚合提供了分组并统计数据的能力。理解聚合的最简单的方式是将其粗略地等同为SQL的GROUP BY和SQL聚合函数。在Elasticsearch中,你可以在一个响应中同时返回命中的数据和聚合结果。你可以使用简单的API同时运行查询和多个聚合,并以一次返回,这避免了来回的网络通信,这是非常强大和高效的。
首先,本示例按状态对所有帐户进行分组,然后返回按降序(也是默认值)排序的前10个(默认)状态:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" } } } }'
在SQL中,上面的聚合在概念上类似于:
SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC
部分结果显示:
{
"took" : 1,
"timed_out" : false,
"_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 },
"hits" : { "total" : 1000, "max_score" : 0.0, "hits" : [ ] },
"aggregations" : { "group_by_state" : { "doc_count_error_upper_bound" : 20, "sum_other_doc_count" : 770, "buckets" : [ { "key" : "ID", "doc_count" : 27 }, { "key" : "TX", "doc_count" : 27 }, { "key" : "AL", "doc_count" : 25 }, { "key" : "MD", "doc_count" : 25 }, { "key" : "TN", "doc_count" : 23 },
我们可以看到AL(abama)有25个账户,TX有27个账户,ID(daho)有27个账户
注意我们将size设置成0,这样我们就可以只看到聚合结果了,而不会显示命中的结果
在先前聚合的基础上,现在这个例子计算了每个州的账户的平均余额(还是按照账户数量倒序排序的前10个州):
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword" }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } }'
注意,我们把average_balance聚合嵌套在了group_by_state聚合之中。这是所有聚合的一个常用模式。你可以任意的聚合之中嵌套聚合,这样你就可以从你的数据中抽取出想要的概述。
基于前面的聚合,现在让我们按照平均余额进行排序:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "size": 0, "aggs": { "group_by_state": { "terms": { "field": "state.keyword", "order": { "average_balance": "desc" } }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } }'
下面的例子显示了如何使用年龄段(20-29,30-39,40-49)分组,然后在用性别分组,然后为每一个年龄段的每一个性别计算平均账户余额:
curl -H "Content-Type: application/json" -XPOST '192.168.20.60:9200/bank/_search?pretty' -d ' { "size": 0, "aggs": { "group_by_age": { "range": { "field": "age", "ranges": [ { "from": 20, "to": 30 }, { "from": 30, "to": 40 }, { "from": 40, "to": 50 } ] }, "aggs": { "group_by_gender": { "terms": { "field": "gender.keyword" }, "aggs": { "average_balance": { "avg": { "field": "balance" } } } } } } } }'
参考:
https://www.elastic.co/guide/en/elasticsearch/reference/6.0/index.html
https://www.codercto.com/a/11305.html
http://www.51niux.com/?id=206
http://www.cnblogs.com/hcy-fly/p/7908880.html
今天的文章ELK之elasticsearch分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/25540.html