ELK之elasticsearch

ELK之elasticsearchElasticsearch学习整理基本概念:集群(Cluster)节点(Node)索引(Index)文档(Document)分片和复制(Sshards&Replicas)探索集群TheRESTAPI:检查集群,节点和索引运行状况,状态和统计信息GET/_cat/health?v#查看集群健康状态检查GET/_cat/no…

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查询里一起使用mustshouldmust_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

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注