Elasticsearch基本概念

2017/9/20 posted in  ELK

Node 与 Cluster

Elastic 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。

单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。

Index

Elastic 会索引所有字段,经过处理后写入一个反向索引(Inverted Index)。查找数据的时候,直接查找该索引。

所以,Elastic 数据管理的顶层单位就叫做 Index(索引)。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。

下面的命令可以查看当前节点的所有 Index。


$ curl -X GET 'http://localhost:9200/_cat/indices?v'

Document

Index 里面单条的记录称为 Document(文档)。许多条 Document 构成了一个 Index。

Document 使用 JSON 格式表示,下面是一个例子。


 {
   "user": "张三",
   "title": "工程师",
   "desc": "数据库管理"
 }
 

同一个 Index 里面的 Document,不要求有相同的结构(scheme),但是最好保持相同,这样有利于提高搜索效率。

Type

Document 可以分组,比如weather这个 Index 里面,可以按城市分组(北京和上海),也可以按气候分组(晴天和雨天)。这种分组就叫做 Type,它是虚拟的逻辑分组,用来过滤 Document。

不同的 Type 应该有相似的结构(schema),举例来说,id字段不能在这个组是字符串,在另一个组是数值。这是与关系型数据库的表的一个区别。性质完全不同的数据(比如productslogs)应该存成两个 Index,而不是一个 Index 里面的两个 Type(虽然可以做到)。

下面的命令可以列出每个 Index 所包含的 Type。

 
 $ curl 'localhost:9200/_mapping?pretty=true'
 

根据规划,Elastic 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。

Shards & Replicas

一个index能够存储非常大量的数据,有时可能会超过单个节点硬件的限制。例如。一个index存储一超过1TB的数据,这对于单个节点有可能是负担不起的。为了解决这个问题,es可以讲index分片到不同的shards中。当你创建一个index,你可以定义你想要的shards数量。每一个shard对于自己来说都是一个拥有所有功能并且有独立的index,可以被放到任何node上。
分片有两个重要的优势:

  • 它允许你水平 分割/扩展 你的内容。
  • 它允许你并行处理不同分片上的数据来提高效率。 为了保证高可用性,可以为每个分片节点设置备份节点。

对于如何进行分片以及进行聚合操作时文档是怎样merge的,es都自动管理了,并且对用户是透明的。

在网络环境中,当某个服务失效了,failover机制是非常有效的高可用保障。es也提供了对于index分片的复制。
复制机制有两个重要特点:

  • 它提供了高可用性以防一个shard/node失效。值得注意的是,一个shard复制不要和它本身放在同一个节点。
  • 它通过对所有复制shard的并行搜索来提高你系统的吞吐量。

探索集群

现在我们已经让节点和集群运行起来了,下一步怎么和es进行沟通交流呢?幸运的是,es提供了一个非常好用的restAPI。通过api我们可以做这些事情:

  • 检查集群,节点和index的健康状况,状态和统计数据。
  • 管理集群、节点和index的数据和元数据。
  • 执行CRUD和一些针对index的搜索操作。
  • 执行高级的搜索操作,例如分页,排序,过滤,脚本,聚合以及其他。

集群的健康监测

接下来,我们对集群进行一个基本的简单的健康监测。前文提到了,因为es通过restAPI来进行操作,所以可以使用curl或者postman等。
检测cluster的健康状况,我们可以使用_cat API。

[hadoop@U006 ~]$ curl 'localhost: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
1521000953 12:15:53  test_elasticsearch yellow          1         1     39  39    0    0       39             0                  -                 50.0%

其中status显示了当前的健康状况。
status的定义如下:

  • green : everything is ok。
  • yellow: 所有数据可用,但是一些备份节点的数据尚未被分配。
  • red : 一些数据不可用。

查看节点的状况

[hadoop@U006 ~]$ curl 'localhost:9200/_cat/nodes?v'
host        ip          heap.percent ram.percent load node.role master name
10.10.25.13 10.10.25.13           11          84 2.54 d         *      node1

查询所有的index

[hadoop@U006 ~]$ curl 'localhost:9200/_cat/indices?v'
health status index                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   .marvel-es-1-2017.10.25   1   1      20639          640      7.5mb          7.5mb
yellow open   .marvel-es-1-2017.10.24   1   1     185123          862     66.6mb         66.6mb
yellow open   .marvel-es-1-2017.10.23   1   1     184771          862     66.2mb         66.2mb
yellow open   .marvel-es-1-2017.10.22   1   1     182271          862     65.6mb         65.6mb
yellow open   test_log                  5   1      84539            0     17.2mb         17.2mb
yellow open   website                   5   1          2            0      7.8kb          7.8kb

新建和删除 Index

新建 Index

新建 Index,可以直接向 Elastic 服务器发出 PUT 请求。下面的例子是新建一个名叫weather的 Index。

 
 $ curl -X PUT 'localhost:9200/weather'
 

服务器返回一个 JSON 对象,里面的acknowledged字段表示操作成功。

 
 {
   "acknowledged":true,
   "shards_acknowledged":true
 }
 

删除 Index

然后,我们发出 DELETE 请求,删除这个 Index。

 
 $ curl -X DELETE 'localhost:9200/weather'
 

数据操作

新增记录

向指定的 /Index/Type 发送 PUT 请求,就可以在 Index 里面新增一条记录。比如,向/accounts/person发送请求,就可以新增一条人员记录。

 
 $ curl -X PUT 'localhost:9200/accounts/person/1' -d '
 {
   "user": "张三",
   "title": "工程师",
   "desc": "数据库管理"
 }' 
 

服务器返回的 JSON 对象,会给出 Index、Type、Id、Version 等信息。

 
 {
   "_index":"accounts",
   "_type":"person",
   "_id":"1",
   "_version":1,
   "result":"created",
   "_shards":{"total":2,"successful":1,"failed":0},
   "created":true
 }
 

如果你仔细看,会发现请求路径是/accounts/person/1,最后的1是该条记录的 Id。它不一定是数字,任意字符串(比如abc)都可以。

新增记录的时候,也可以不指定 Id,这时要改成 POST 请求。

 
 $ curl -X POST 'localhost:9200/accounts/person' -d '
 {
   "user": "李四",
   "title": "工程师",
   "desc": "系统管理"
 }'
 

上面代码中,向/accounts/person发出一个 POST 请求,添加一个记录。这时,服务器返回的 JSON 对象里面,_id字段就是一个随机字符串。

 
 {
   "_index":"accounts",
   "_type":"person",
   "_id":"AV3qGfrC6jMbsbXb6k1p",
   "_version":1,
   "result":"created",
   "_shards":{"total":2,"successful":1,"failed":0},
   "created":true
 }
 

注意,如果没有先创建 Index(这个例子是accounts),直接执行上面的命令,Elastic 也不会报错,而是直接生成指定的 Index。所以,打字的时候要小心,不要写错 Index 的名称。

查看记录

/Index/Type/Id发出 GET 请求,就可以查看这条记录。

 
 $ curl 'localhost:9200/accounts/person/1?pretty=true'
 

上面代码请求查看/accounts/person/1这条记录,URL 的参数pretty=true表示以易读的格式返回。

返回的数据中,found字段表示查询成功,_source字段返回原始记录。

 
 {
   "_index" : "accounts",
   "_type" : "person",
   "_id" : "1",
   "_version" : 1,
   "found" : true,
   "_source" : {
     "user" : "张三",
     "title" : "工程师",
     "desc" : "数据库管理"
   }
 }
 

如果 Id 不正确,就查不到数据,found字段就是false

 
 $ curl 'localhost:9200/weather/beijing/abc?pretty=true'
 
 {
   "_index" : "accounts",
   "_type" : "person",
   "_id" : "abc",
   "found" : false
 }
 

删除记录

删除记录就是发出 DELETE 请求。

 
 $ curl -X DELETE 'localhost:9200/accounts/person/1'
 

这里先不要删除这条记录,后面还要用到。

更新记录

更新记录就是使用 PUT 请求,重新发送一次数据。

 
 $ curl -X PUT 'localhost:9200/accounts/person/1' -d '
 {
     "user" : "张三",
     "title" : "工程师",
     "desc" : "数据库管理,软件开发"
 }' 
 
 {
   "_index":"accounts",
   "_type":"person",
   "_id":"1",
   "_version":2,
   "result":"updated",
   "_shards":{"total":2,"successful":1,"failed":0},
   "created":false
 }
 

上面代码中,我们将原始数据从"数据库管理"改成"数据库管理,软件开发"。 返回结果里面,有几个字段发生了变化。

 
 "_version" : 2,
 "result" : "updated",
 "created" : false
 

可以看到,记录的 Id 没变,但是版本(version)从1变成2,操作类型(result)从created变成updatedcreated字段变成false,因为这次不是新建记录。

数据查询

返回所有记录

使用 GET 方法,直接请求/Index/Type/_search,就会返回所有记录。


 $ curl 'localhost:9200/accounts/person/_search'
 
 {
   "took":2,
   "timed_out":false,
   "_shards":{"total":5,"successful":5,"failed":0},
   "hits":{
     "total":2,
     "max_score":1.0,
     "hits":[
       {
         "_index":"accounts",
         "_type":"person",
         "_id":"AV3qGfrC6jMbsbXb6k1p",
         "_score":1.0,
         "_source": {
           "user": "李四",
           "title": "工程师",
           "desc": "系统管理"
         }
       },
       {
         "_index":"accounts",
         "_type":"person",
         "_id":"1",
         "_score":1.0,
         "_source": {
           "user" : "张三",
           "title" : "工程师",
           "desc" : "数据库管理,软件开发"
         }
       }
     ]
   }
 }
 

上面代码中,返回结果的 took字段表示该操作的耗时(单位为毫秒),timed_out字段表示是否超时,hits字段表示命中的记录,里面子字段的含义如下。

  • total:返回记录数,本例是2条。
  • max_score:最高的匹配程度,本例是1.0
  • hits:返回的记录组成的数组。

返回的记录中,每条记录都有一个_score字段,表示匹配的程序,默认是按照这个字段降序排列。

全文搜索

Elastic 的查询非常特别,使用自己的查询语法,要求 GET 请求带有数据体。

 
 $ curl 'localhost:9200/accounts/person/_search'  -d '
 {
   "query" : { "match" : { "desc" : "软件" }}
 }'
 

上面代码使用 Match 查询,指定的匹配条件是desc字段里面包含"软件"这个词。返回结果如下。

 
 {
   "took":3,
   "timed_out":false,
   "_shards":{"total":5,"successful":5,"failed":0},
   "hits":{
     "total":1,
     "max_score":0.28582606,
     "hits":[
       {
         "_index":"accounts",
         "_type":"person",
         "_id":"1",
         "_score":0.28582606,
         "_source": {
           "user" : "张三",
           "title" : "工程师",
           "desc" : "数据库管理,软件开发"
         }
       }
     ]
   }
 }
 

Elastic 默认一次返回10条结果,可以通过size字段改变这个设置。

 
 $ curl 'localhost:9200/accounts/person/_search'  -d '
 {
   "query" : { "match" : { "desc" : "管理" }},
   "size": 1
 }'
 

上面代码指定,每次只返回一条结果。

还可以通过from字段,指定位移。

 
 $ curl 'localhost:9200/accounts/person/_search'  -d '
 {
   "query" : { "match" : { "desc" : "管理" }},
   "from": 1,
   "size": 1
 }'
 

上面代码指定,从位置1开始(默认是从位置0开始),只返回一条结果。

逻辑运算

如果有多个搜索关键字, Elastic 认为它们是or关系。

 
 $ curl 'localhost:9200/accounts/person/_search'  -d '
 {
   "query" : { "match" : { "desc" : "软件 系统" }}
 }'
 

上面代码搜索的是软件 or 系统

如果要执行多个关键词的and搜索,必须使用布尔查询

 
 $ curl 'localhost:9200/accounts/person/_search'  -d '
 {
   "query": {
     "bool": {
       "must": [
         { "match": { "desc": "软件" } },
         { "match": { "desc": "系统" } }
       ]
     }
   }
 }'
 

使用过滤器

之前提到的score是一个数字,它用来评价当前返回的文档和我们需要的文档的匹配程度。分数越高的匹配程度越好。
但是查询并不是总需要产生score,尤其是它们只是用来过滤文档的时候。es能够自动的优化查询并不计算这些无用的score。
上文中的bool query也支持filter语句。filter语句可以在不改变score的情况下使用查询语句来限定文档。

curl -XPOST 'localhost:9200/customer/_search?pretty' -d '
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "age": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}'

执行聚合

聚合可以对数据进行分组并对分组进行数据统计。类似于SQL中的group by。在es中,可以一次性返回查询结果和聚合结果。

curl -XPOST 'localhost:9200/customer/_search?pretty' -d '
{
  "size": 0,
  "aggs": {
    "group_by_name": {
      "terms": {
        "field": "name"
      }
    }
  }
}'

参考链接