上一篇主要学习了ES及其插件的安装,这一篇主要学习ES集群及其节点管理
一、ES集群概述
1、ES集群简介
ES就是为高可用和可扩展而生的,服务器的扩展可以通过购置性能更强的服务器(垂直扩展或者向上扩展,Vertical Scale/Scaling Up),亦或是通过购置更多的服务器(水平扩展或者向外扩展,Horizontal Scale/Scaling Out)来完成。尽管ES能够利用更强劲的硬件,垂直扩展毕竟还是有它的极限。真正的可扩展性来自于水平扩展 - 通过向集群中添加更多的节点来分布负载,增加可靠性。
在大多数数据库中,水平扩展通常都需要你对应用进行一次大的重构来利用更多的节点。
相反,ES天生就是分布式的:它知道如何管理多个节点来完成扩展和实现高可用性。这也意味着你的应用不需要在乎这一点。
2、ES集群的主节点
集群中的一个节点会被选为主节点(Master Node),它负责管理整个集群的变化,如创建或者删除一个索引(Index),向集群中添加或者删除节点。主节点并不需要参与到文档级别的变化或者搜索中,这意味着虽然只有一个主节点,但它并不会随着流量的增加而成为瓶颈。任何节点都可以成为主节点。在我们的例子中只有一个节点,所以它就承担了主节点的功能。
对于用户,可以和集群中的任意节点进行通信,包括主节点。每个节点都知道每份文档的存放位置,并且能够将请求转发到持有所需数据的节点。用户通信的节点会负责将需要的数据从各个节点收集起来,然后返回给用户。以上整个过程都会由ES透明地进行管理。
3、ES集群的特性
elasticsearch集群一旦建立起来以后,会选举出一个master,其他都为slave节点。
但是具体操作的时候,每个节点都提供写和读的操作。就是说,你不论往哪个节点中做写操作,这个数据也会分配到集群上的所有节点中。
这里有某个节点挂掉的情况,如果是slave节点挂掉了,那么首先关心,数据会不会丢呢?不会。如果你开启了replicate,那么这个数据一定在别的机器上是有备份的。
别的节点上的备份分片会自动升格为这份分片数据的主分片。这里要注意的是这里会有一小段时间的yellow状态时间。
如果是主节点挂掉怎么办呢?当从节点们发现和主节点连接不上了,那么他们会自己决定再选举出一个节点为主节点。
但是这里有个脑裂的问题,假设有5台机器,3台在一个机房,2台在另一个机房,当两个机房之间的联系断了之后,每个机房的节点会自己聚会,推举出一个主节点。
这个时候就有两个主节点存在了,当机房之间的联系恢复了之后,这个时候就会出现数据冲突了。
解决的办法就是设置参数:
discovery.zen.minimum_master_nodes
为3(超过一半的节点数),那么当两个机房的连接断了之后,就会以大于等于3的机房的master为主,另外一个机房的节点就停止服务了。
对于自发现动能这里不难看出,如果把节点直接暴露在外面,不管怎么切换master,必然会有单节点问题。所以一般我们会在可提供服务的节点前面加一个负载均衡。
4、ES集群的自动发现功能
elasticsearch的集群是内嵌自动发现功能的。
意思就是说,你只需要在每个节点配置好了集群名称,节点名称,互相通信的节点会根据es自定义的服务发现协议去按照多播的方式来寻找网络上配置在同样集群内的节点。
和其他的服务发现功能一样,es是支持多播和单播的。多播和单播的配置分别根据这几个参数:
discovery.zen.ping.multicast.enabled: false
# 这个设置把组播的自动发现给关闭了,为了防止其他机器上的节点自动连入。
discovery.zen.fd.ping_timeout: 100
sdiscovery.zen.ping.timeout: 100
# 设置了节点与节点之间的连接ping时长
sdiscovery.zen.minimum_master_nodes: 2
# 这个设置为了避免脑裂。比如3个节点的集群,如果设置为2,那么当一台节点脱离后,不会自动成为master
discovery.zen.ping.unicast.hosts: ["12.12.12.12:10801"]
# 这个设置了自动发现的节点
多播是需要看服务器是否支持的,由于其安全性,其实现在基本的云服务(比如阿里云)是不支持多播的,所以即使你开启了多播模式,你也仅仅只能找到本机上的节点。
单播模式安全,也高效,但是缺点就是如果增加了一个新的机器的话,就需要每个节点上进行配置才生效了。
二、ES集群的管理
ES集群提供了Restful风格的访问接口API
ES访问接口:9200/tcp 基于http协议工作
1、Restful风格API
四类API:
检查集群、节点、索引等是否健康以及获取其相应状态
管理集群,节点、索引及元数据
执行CRUD操作
执行高级操作,例如paging,filtering等
语法格式:
curl -X <VERB> '<protocol>://HOST:PORT/<PATH>?<QUERY_STRING>' -d '<body>'
VERB:
GET,PUT,DELETE等 (GET方法可以省略)
PROTOCOL:
http,https
QUERY_STRING:
查询参数、例如:?pretty表示使用易读的JSON格式输出
BODY:
请求的主体
查看ES节点是否工作正常:
[root@Node2 ~]# curl localhost:9200
{ # JSON格式
"name" : "node2",
"cluster_name" : "RK",
"cluster_uuid" : "pwffDjOKQT6Ss2CRQLXt0g",
"version" : {
"number" : "5.3.0",
"build_hash" : "3adb13b",
"build_date" : "2017-03-23T03:31:50.652Z",
"build_snapshot" : false,
"lucene_version" : "6.4.1"
},
"tagline" : "You Know, for Search" # 正常
}
Elasticsearch通过使用JSON来作为沟通的数据格式,这对于开发者来说很友好,因为很多程序都支持JSON格式。比如js就不说了,Java也有fastjson,ruby什么的都自带json。
1)_cat API
Elasticsearch中信息很多,如果单凭肉眼来寻找复杂数据之间的关系,是很困难的。因此cat命令应运而生,它帮助开发者快速查询Elasticsearch的相关信息。
查看_cat api的所有操作:
[root@Node2 ~]# curl 192.168.10.7:9200/_cat
=^.^=
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/tasks
/_cat/indices
/_cat/indices/{index}
/_cat/segments
/_cat/segments/{index}
/_cat/count
/_cat/count/{index}
/_cat/recovery
/_cat/recovery/{index}
/_cat/health
/_cat/pending_tasks
/_cat/aliases
/_cat/aliases/{alias}
/_cat/thread_pool
/_cat/thread_pool/{thread_pools}
/_cat/plugins
/_cat/fielddata
/_cat/fielddata/{fields}
/_cat/nodeattrs
/_cat/repositories
/_cat/snapshots/{repository}
/_cat/templates
verbose
每个命令都支持使用?v参数,来显示详细的信息:
help
每个命令都支持使用help参数,来输出可以显示的列:
$ curl localhost:9200/_cat/master?help
id | | node id
host | h | host name
ip | | ip address
node | n | node name
headers
通过h参数,可以指定输出的字段:
$ curl localhost:9200/_cat/master?v
id host ip node
QG6QrX32QSi8C3-xQmrSoA 127.0.0.1 127.0.0.1 Manslaughter
$ curl localhost:9200/_cat/master?h=host,ip,node
127.0.0.1 127.0.0.1 Manslaughter
[root@Node2 ~]# curl 192.168.10.2:9200/_cat/master?v
id host ip node
bMAYDjb2Rsyfpn92Lnax3w 192.168.2.116 192.168.2.116 node7
[root@Node2 ~]# curl 192.168.10.2:9200/_cat/master?help
id | | node id
host | h | host name
ip | | ip address
node | n | node name
[root@Node2 ~]# curl 192.168.10.2:9200/_cat/master?h=host,id,host
192.168.2.116 bMAYDjb2Rsyfpn92Lnax3w
数字类型的格式化
很多的命令都支持返回可读性的大小数字,比如使用mb或者kb来表示。
$ curl localhost:9200/_cat/indices?v
health status index pri rep docs.count docs.deleted store.size pri.store.sizeyellow open test 5 1 3 0 9.kb 9.kb
例子:
查看ES集群的切片信息:
[root@Node2 ~]# curl 192.168.10.7:9200/_cat/allocation
9 38.8mb 4.7gb 13gb 17.7gb 26 192.168.2.116 192.168.2.116 node7
9 38.8mb 9.1gb 8.6gb 17.7gb 51 192.168.2.114 192.168.2.114 node2
[root@Node2 ~]# curl 192.168.10.7:9200/_cat/allocation?v # ?v表示显示详细信息(字段名)
shards disk.indices disk.used disk.avail disk.total disk.percent host ip node
9 38.8mb 9.1gb 8.6gb 17.7gb 51 192.168.2.114 192.168.2.114 node2
9 38.8mb 4.7gb 13gb 17.7gb 26 192.168.2.116 192.168.2.116 node7
查看ES集群节点信息:
[root@Node2 ~]# curl 192.168.10.7:9200/_cat/nodes?v
ip heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.2.114 10 96 1 0.00 0.01 0.00 mdi - node2
192.168.2.116 3 100 0 0.00 0.00 0.00 mdi * node7
heap.percent:堆内存占的内存百分比
cpu:表示使用的cpu核心
node.role:表示节点能充当的角色主、数据 节点
master:表示当前是否为主节点,*表示当前为主
2)_Cluster API
集群相关的api接口
[root@Node2 ~]# curl localhost:9200/_cluster/health
{"cluster_name":"RK","status":"green","timed_out":false,"number_of_nodes":2,"number_of_data_nodes":2,"active_primary_shards":9,"active_shards":18,"relocating_shards":0,"initializing_shards":0,"unassigned_shards":0,"delayed_unassigned_shards":0,"number_of_pending_tasks":0,"number_of_in_flight_fetch":0,"task_max_waiting_in_queue_millis":0,"active_shards_percent_as_number":100.0}
[root@Node2 ~]# curl localhost:9200/_cluster/health?pretty # ?pretty JSON格式显示,易读
{
"cluster_name" : "RK",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"active_primary_shards" : 9,
"active_shards" : 18,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
状态信息
输出里最重要的就是 status 这行。很多开源的 ES 监控脚本,其实就是拿这行数据做报警判断。status 有三个可能的值:
green 绿灯,所有分片都正确运行,集群非常健康。
yellow 黄灯,所有主分片都正确运行,但是有副本分片缺失。这种情况意味着 ES 当前还是正常运行的,但是有一定风险。注意,在 Kibana4 的 server 端启动逻辑中,即使是黄灯状态,Kibana 4 也会拒绝启动,死循环等待集群状态变成绿灯后才能继续运行。
red 红灯,有主分片缺失。这部分数据完全不可用。而考虑到 ES 在写入端是简单的取余算法,轮到这个分片上的数据也会持续写入报错。
对 Nagios 熟悉的读者,可以直接将这个红黄绿灯对应上 Nagios 体系中的 Critical,Warning,OK 。
其他数据解释
number_of_nodes 集群内的总节点数。
number_of_data_nodes 集群内的总数据节点数。
active_primary_shards 集群内所有索引的主分片总数。
active_shards 集群内所有索引的分片总数。
relocating_shards 正在迁移中的分片数。
initializing_shards 正在初始化的分片数。
unassigned_shards 未分配到具体节点上的分片数。
delayed_unassigned_shards 延时待分配到具体节点上的分片数。
显然,后面 4 项在正常情况下,一般都应该是 0。但是如果真的出来了长期非 0 的情况,怎么才能知道这些长期 unassign 或者 initialize 的分片影响的是哪个索引呢?本书随后还有有更多接口获取相关信息。不过在集群健康这层,本身就可以得到更详细一点的内容了。
level 请求参数
接口请求的时候,可以附加一个 level 参数,指定输出信息以 indices 还是 shards 级别显示。当然,有三个级别:cluster,indices,shards (如果写错了就默认输出cluster级别)
一般来说,indices 级别就够了。
health:健康信息
curl 'localhost:9200/_cluster/health?pretty'
[root@Node2 ~]# curl localhost:9200/_cluster/health?level=nodes
{"cluster_name":"RK","status":"green","timed_out":false,"number_of_nodes":2,"number_of_data_nodes":2,"active_primary_shards":9,"active_shards":18,"relocating_shards":0,"initializing_shards":0,"unassigned_shards":0,"delayed_unassigned_shards":0,"number_of_pending_tasks":0,"number_of_in_flight_fetch":0,"task_max_waiting_in_queue_millis":0,"active_shards_percent_as_number":100.0}[root@Node2 ~]#
[root@Node2 ~]# curl 'localhost:9200/_cluster/health?level=cluster&pretty'
# 还需要使用JSON格式输出需要加&pretty并使用引用
{
"cluster_name" : "RK",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"active_primary_shards" : 9,
"active_shards" : 18,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0
}
[root@Node2 ~]# curl 'localhost:9200/_cluster/health?level=indices&pretty'
{
"cluster_name" : "RK",
"status" : "green",
"timed_out" : false,
"number_of_nodes" : 2,
"number_of_data_nodes" : 2,
"active_primary_shards" : 9,
"active_shards" : 18,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0,
"delayed_unassigned_shards" : 0,
"number_of_pending_tasks" : 0,
"number_of_in_flight_fetch" : 0,
"task_max_waiting_in_queue_millis" : 0,
"active_shards_percent_as_number" : 100.0,
"indices" : {
".monitoring-es-2-2017.04.20" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".kibana" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".monitoring-data-2" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".monitoring-es-2-2017.04.17" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".monitoring-kibana-2-2017.04.20" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".monitoring-es-2-2017.04.19" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".monitoring-es-2-2017.04.18" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".monitoring-kibana-2-2017.04.18" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
},
".monitoring-kibana-2-2017.04.19" : {
"status" : "green",
"number_of_shards" : 1,
"number_of_replicas" : 1,
"active_primary_shards" : 1,
"active_shards" : 2,
"relocating_shards" : 0,
"initializing_shards" : 0,
"unassigned_shards" : 0
}
}
}
stats:集群统计信息
curl 'localhost:9200/_cluster/stats'
集群节点的统计信息:
curl 'localhost:9200/_nodes/stats'
[root@Node2 ~]# curl 'localhost:9200/_cluster/stats?pretty'
{
"_nodes" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"cluster_name" : "RK",
"timestamp" : 1492754076865,
"status" : "green",
"indices" : {
"count" : 9,
"shards" : {
"total" : 18,
"primaries" : 9,
"replication" : 1.0,
"index" : {
"shards" : {
"min" : 2,
"max" : 2,
"avg" : 2.0
},
"primaries" : {
"min" : 1,
"max" : 1,
"avg" : 1.0
},
"replication" : {
"min" : 1.0,
"max" : 1.0,
"avg" : 1.0
}
}
},
"docs" : {
"count" : 93528,
"deleted" : 286
},
"store" : {
"size_in_bytes" : 81565430,
"throttle_time_in_millis" : 0
},
"fielddata" : {
"memory_size_in_bytes" : 6608,
"evictions" : 0
},
"query_cache" : {
"memory_size_in_bytes" : 0,
"total_count" : 16,
"hit_count" : 0,
"miss_count" : 16,
"cache_size" : 0,
"cache_count" : 0,
"evictions" : 0
},
"completion" : {
"size_in_bytes" : 0
},
"segments" : {
"count" : 96,
"memory_in_bytes" : 902530,
"terms_memory_in_bytes" : 557988,
"stored_fields_memory_in_bytes" : 38640,
"term_vectors_memory_in_bytes" : 0,
"norms_memory_in_bytes" : 3712,
"points_memory_in_bytes" : 52750,
"doc_values_memory_in_bytes" : 249440,
"index_writer_memory_in_bytes" : 0,
"version_map_memory_in_bytes" : 0,
"fixed_bit_set_memory_in_bytes" : 0,
"max_unsafe_auto_id_timestamp" : -1,
"file_sizes" : { }
}
},
"nodes" : {
"count" : {
"total" : 2,
"data" : 2,
"coordinating_only" : 0,
"master" : 2,
"ingest" : 2
},
"versions" : [
"5.3.0"
],
"os" : {
"available_processors" : 3,
"allocated_processors" : 3,
"names" : [
{
"name" : "Linux",
"count" : 2
}
],
"mem" : {
"total_in_bytes" : 4227088384,
"free_in_bytes" : 94605312,
"used_in_bytes" : 4132483072,
"free_percent" : 2,
"used_percent" : 98
}
},
"process" : {
"cpu" : {
"percent" : 0
},
"open_file_descriptors" : {
"min" : 162,
"max" : 214,
"avg" : 188
}
},
"jvm" : {
"max_uptime_in_millis" : 30736656,
"versions" : [
{
"version" : "1.8.0_121",
"vm_name" : "OpenJDK 64-Bit Server VM",
"vm_version" : "25.121-b13",
"vm_vendor" : "Oracle Corporation",
"count" : 2
}
],
"mem" : {
"heap_used_in_bytes" : 224113584,
"heap_max_in_bytes" : 4268818432
},
"threads" : 73
},
"fs" : {
"total_in_bytes" : 38102884352,
"free_in_bytes" : 25168912384,
"available_in_bytes" : 23233347584,
"spins" : "true"
},
"plugins" : [
{
"name" : "x-pack",
"version" : "5.3.0",
"description" : "Elasticsearch Expanded Pack Plugin",
"classname" : "org.elasticsearch.xpack.XPackPlugin"
}
],
"network_types" : {
"transport_types" : {
"netty4" : 2
},
"http_types" : {
"netty4" : 2
}
}
}
}
集群状态信息:
curl 'localhost:9200/_cluster/state/<metrics>?pretty'
metrics:
version
master_node
nodes
routing_table
metadata
blocks
[root@Node2 ~]# curl 'localhost:9200/_cluster/state?pretty'
[root@Node2 ~]# curl 'localhost:9200/_cluster/state/version?pretty'
{
"cluster_name" : "RK",
"version" : 19,
"state_uuid" : "tXW8CtBXS1a3Sn1wCBci2g"
}
[root@Node2 ~]# curl 'localhost:9200/_cluster/state/master_node?pretty'
{
"cluster_name" : "RK",
"master_node" : "bMAYDjb2Rsyfpn92Lnax3w"
}
[root@Node2 ~]# curl 'localhost:9200/_cat/master'
bMAYDjb2Rsyfpn92Lnax3w 192.168.2.116 192.168.2.116 node7
[root@Node2 ~]# curl 'localhost:9200/_cat/nodes'
192.168.2.114 7 96 0 0.00 0.00 0.00 mdi - node2
192.168.2.116 5 100 0 0.00 0.00 0.00 mdi * node7
三、ES的术语详解
在Elasticsearch中存储数据的行为就叫做索引(indexing),不过在索引之前,我们需要明确数据应该存储在哪里。
在Elasticsearch中,文档归属于一种类型(type),而这些类型存在于索引(index)中,我们可以画一些简单的对比图来类比传统关系型数据库:
Relational DB -> Databases -> Tables -> Rows -> Columns
Elasticsearch -> Indices -> Types -> Documents -> Fields
Elasticsearch集群可以包含多个索引(indices)(数据库),每一个索引可以包含多个类型(types)(表),每一个类型包含多个文档(documents)(行),然后每个文档包含多个字段(Fields)(列)。
「索引」含义的区分
你可能已经注意到索引(index)这个词在Elasticsearch中有着不同的含义,所以有必要在此做一下区分:
索引(名词) 如上文所述,一个索引(index)就像是传统关系数据库中的数据库,它是相关文档存储的地方,index的复数是indices 或indexes。
索引(动词) 「索引一个文档」表示把一个文档存储到索引(名词)里,以便它可以被检索或者查询。这很像SQL中的
INSERT
关键字,差别是,如果文档已经存在,新的文档将覆盖旧的文档。倒排索引 传统数据库为特定列增加一个索引,例如B-Tree索引来加速检索。Elasticsearch和Lucene使用一种叫做倒排索引(inverted index)的数据结构来达到相同目的。
四、CRUD操作相关的API
创建:
[root@Node2 ~]# curl -X PUT localhost:9200/students/class1/1?pretty -d '
{
"first_name":"Jing",
"last_name":"Guo",
"gender":"Male",
"courses":"Xianglong Shiba Zhang"
}'
{
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"created" : true
}
[root@Node2 ~]# curl localhost:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .monitoring-es-2-2017.04.19 EMZBcpI7RV6V9aZZ46KSWw 1 1 39720 84 34.1mb 17mb
green open .monitoring-kibana-2-2017.04.20 JqpaERNnQwOhTpVu0F-yCA 1 1 169 0 285.9kb 142.9kb
green open .monitoring-es-2-2017.04.20 nLnAKVKKSOavBc7dc2mOgA 1 1 5536 126 5.5mb 2.7mb
green open .kibana FX7h92rvRwuxxPAYSeORTw 1 1 1 0 6.3kb 3.1kb
green open .monitoring-es-2-2017.04.18 FuWnLKlRRoWlMKznkAle2w 1 1 38676 50 31.8mb 15.9mb
green open .monitoring-kibana-2-2017.04.19 5DNI-F44TJmaErmQ2qRHPQ 1 1 2121 0 969.3kb 484.6kb
green open .monitoring-es-2-2017.04.17 nyfdDSpsQKuyn4ZTAdm6aw 1 1 3874 24 3.2mb 1.6mb
green open students 104QJMEGQjCtxMVI9rWvhQ 5 1 1 0 10.8kb 5.4kb
green open .monitoring-data-2 pIeAPjAQTuihoJenwmlTGA 1 1 3 2 16.6kb 8.3kb
green open .monitoring-kibana-2-2017.04.18 aV6CvYltR2aNl3URpPVDig 1 1 3428 0 1.6mb
我们看到path:/students/class1/1包含三部分信息:
名字 | 说明 |
---|---|
students | 索引名 |
class1 | 类型名 |
1 | 这个员工的ID(如果该ID已存在则替换) |
请求实体(JSON文档),包含了这个员工的所有信息。他的名字叫“Guo Jing”,Male,学习Xianglong Shiba Zhang
很简单吧!它不需要你做额外的管理操作,比如创建索引或者定义每个字段的数据类型。我们能够直接索引文档,Elasticsearch已经内置所有的缺省设置,所有管理操作都是透明的。
和mongodb数据库的GRUD很像,索引和类别不用事先创建
接下来,让我们在目录中加入更多学员信息:
[root@Node2 ~]# curl -X PUT "localhost:9200/students/class1/2?pretty" -d '
{
"first_name":"Rong",
"last_name":"Huang",
"gender":"Female",
"age":23,
"courses":"Luoying Shenjian"
}'
{
"_index" : "students",
"_type" : "class1",
"_id" : "2",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
},
"created" : true
}
列出类型中的文档:GET方法
[root@Node2 ~]# curl localhost:9200/students/class1/1?pretty
{
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"first_name" : "Jing",
"last_name" : "Guo",
"gender" : "Male",
"courses" : "Xianglong Shiba Zhang"
}
}
[root@Node2 ~]# curl localhost:9200/students/?pretty # 列出索引的有有类型结构
{
"students" : {
"aliases" : { },
"mappings" : {
"class1" : {
"properties" : {
"age" : {
"type" : "long"
},
"courses" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"first_name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"gender" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"last_name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
},
"settings" : {
"index" : {
"creation_date" : "1492762539451",
"number_of_shards" : "5",
"number_of_replicas" : "1",
"uuid" : "104QJMEGQjCtxMVI9rWvhQ",
"version" : {
"created" : "5030099"
},
"provided_name" : "students"
}
}
}
}
更新文档:
PUT方法会覆盖原有文档
使用相同的ID替换掉原文档
POST方法,使用_update API,可以只更新部分内容,得
[root@Node2 ~]# curl -X POST 'localhost:9200/students/class1/2/_update?pretty' -d '
> {
> "doc": {"age":22}
> }'
{
"_index" : "students",
"_type" : "class1",
"_id" : "2",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
}
}
[root@Node2 ~]# curl localhost:9200/students/class1/2?pretty
{
"_index" : "students",
"_type" : "class1",
"_id" : "2",
"_version" : 2,
"found" : true,
"_source" : {
"first_name" : "Rong",
"last_name" : "Huang",
"gender" : "Female",
"age" : 22,
"courses" : "Luoying Shenjian"
}
}
删除文档:DELETE 方法
[root@Node2 ~]# curl -X DELETE localhost:9200/students/class1/1?pretty
{
"found" : true,
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"_version" : 2,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 2,
"failed" : 0
}
}
[root@Node2 ~]# curl localhost:9200/students/class1/1?pretty
{
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"found" : false
}
删除索引:
[root@Node2 ~]# curl localhost:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .monitoring-es-2-2017.04.19 EMZBcpI7RV6V9aZZ46KSWw 1 1 39720 84 34.1mb 17mb
green open .monitoring-kibana-2-2017.04.20 JqpaERNnQwOhTpVu0F-yCA 1 1 169 0 285.9kb 142.9kb
green open .monitoring-es-2-2017.04.20 nLnAKVKKSOavBc7dc2mOgA 1 1 5536 126 5.5mb 2.7mb
green open .kibana FX7h92rvRwuxxPAYSeORTw 1 1 1 0 6.3kb 3.1kb
green open .monitoring-es-2-2017.04.18 FuWnLKlRRoWlMKznkAle2w 1 1 38676 50 31.8mb 15.9mb
green open .monitoring-kibana-2-2017.04.19 5DNI-F44TJmaErmQ2qRHPQ 1 1 2121 0 969.3kb 484.6kb
green open .monitoring-es-2-2017.04.17 nyfdDSpsQKuyn4ZTAdm6aw 1 1 3874 24 3.2mb 1.6mb
green open .monitoring-data-2 pIeAPjAQTuihoJenwmlTGA 1 1 3 2 16.6kb 8.3kb
green open .monitoring-kibana-2-2017.04.18 aV6CvYltR2aNl3URpPVDig 1 1 3428 0 1.6mb 850.9kb
green open students 104QJMEGQjCtxMVI9rWvhQ 5 1 0 0 21.6kb 10.8kb
[root@Node2 ~]# curl -X DELETE localhost:9200/students?pretty
{
"acknowledged" : true
}
[root@Node2 ~]# curl localhost:9200/_cat/indices?v
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .monitoring-es-2-2017.04.19 EMZBcpI7RV6V9aZZ46KSWw 1 1 39720 84 34.1mb 17mb
green open .monitoring-kibana-2-2017.04.20 JqpaERNnQwOhTpVu0F-yCA 1 1 169 0 285.9kb 142.9kb
green open .monitoring-es-2-2017.04.20 nLnAKVKKSOavBc7dc2mOgA 1 1 5536 126 5.5mb 2.7mb
green open .kibana FX7h92rvRwuxxPAYSeORTw 1 1 1 0 6.3kb 3.1kb
green open .monitoring-es-2-2017.04.18 FuWnLKlRRoWlMKznkAle2w 1 1 38676 50 31.8mb 15.9mb
green open .monitoring-kibana-2-2017.04.19 5DNI-F44TJmaErmQ2qRHPQ 1 1 2121 0 969.3kb 484.6kb
green open .monitoring-es-2-2017.04.17 nyfdDSpsQKuyn4ZTAdm6aw 1 1 3874 24 3.2mb 1.6mb
green open .monitoring-kibana-2-2017.04.18 aV6CvYltR2aNl3URpPVDig 1 1 3428 0 1.6mb 850.9kb
green open .monitoring-data-2 pIeAPjAQTuihoJenwmlTGA 1 1 3
这里没有对类型的操作?
五、搜索(查询)数据
查询数据需要使用ES的_search API
Query DSL:域类型(格式)查询语言 ,基于JSON,用于实现诸多类型的查询操作,
比如:简单查询,模糊插叙,范围查询,布尔查询等
ES查询操作的执行分为两个阶段:
分散阶段:
合并阶段:
ES中搜索的数据广义上可被理解为两类:
types:exact 在指定类型上做精确值搜索 ,在搜索时做精确搜索
精确值:指未经加工的原始值,如:Notebook,notebook就不是精确值
full-text:全文搜索
用于引用文本中数据,判断文档在多大程度上匹配查询请求;即评估文档与用户请求查询的相关度;为了完成full-text搜索,ES必须首先分析文本,并创建倒排索引。倒排索引中的数据还需要进行“正规化”为标准格式。
查询方式:
向ES发起查询请求的方式有两种:
1、通过Restful request API查询,也称为query string
2、通过发送REST request body进行
列出索引的所有文档:
[root@Node2 ~]# curl localhost:9200/students/_search?pretty # Restful request API
"took" : 5, # 执行时长,ms
"timed_out" : false, # 查询是否超时
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "students",
"_type" : "class1",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"first_name" : "Rong",
"last_name" : "Huang",
"gender" : "Female",
"age" : 23,
"courses" : "Luoying Shenjian"
}
},
{
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"first_name" : "Jing",
"last_name" : "Guo",
"gender" : "Male",
"courses" : "Xianglong Shiba Zhang"
}
}
]
}
}
[root@Node2 ~]# curl localhost:9200/students/_search?pretty -d ' # REST request body
> {
> "query":{"match_all":{}}
> }'
{
"took" : 93,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 3,
"max_score" : 1.0,
"hits" : [
{
"_index" : "students",
"_type" : "class1",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"first_name" : "Rong",
"last_name" : "Huang",
"gender" : "Female",
"age" : 23,
"courses" : "Luoying Shenjian"
}
},
{
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"first_name" : "Jing",
"last_name" : "Guo",
"gender" : "Male",
"courses" : "Xianglong Shiba Zhang"
}
},
{
"_index" : "students",
"_type" : "s1",
"_id" : "yw",
"_score" : 1.0,
"_source" : {
"first_name" : "xiejun",
"age" : 27
}
}
]
}
}
多索引,多类型查询:
/_search:所有索引
/INDEX_NAME/_search:单索引
/INDEX1_NAME1,INDEX2_NAME/_search:多索引
/s*,t*/_search:
/students/class1/_search:单类型搜索
/students/class1,class1/_search:多类型搜索
Mapping和Analysis:映射和分析
ES对每一个文档,会取得其所有域的所有值,生成一个名为“_all”的域;执行查询时,如果在query_string未指定查询的域,则在_all域上执行操作
例子:
GET /_search?q="Xianglog" # 没有指定域则在_all域中查询
GET /_search?q='Xianglong%20Shiba%20Zhang' # 指定域中查询,空格需要使用%20代替
GET /_search?q=courses:'Xianglong'
GET /_search?q=courses:'Xianglong%20Shiba%20Zhang'
数据类型:
string,numbers,boolean,dates
查看文档中域的数据类型:
[root@Node2 ~]# curl "localhost:9200/students/class1/_mapping?pretty"
{
"students" : {
"mappings" : {
"class1" : {
"properties" : {
"age" : {
"type" : "long"
},
"courses" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"first_name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"gender" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
},
"last_name" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
创建倒排索引的过程:
分词 -- 正规化;这个过程即是分析,分析需要分析器(analyzer)来进行
分析器由三个组件构成:
字符过滤器,分词器,分词过滤器
ES内置的分析器:
Standard analyzer:标准分析器,ES的默认分析器,适用于多种语言,基于unicode分析
Simple analyzer:简单分析器,根据所有的非字母分词(把非字母当作单词边界)
Whitespace analyzer:只把空白符当作单词边界
Language analyzer:适用于多种语言的专用语言分析器
分析器不仅在创建索引时用到,在构建查询时也会用到
request body:
又分成2类:
query dsl:执行full-text查询时,基于相关度来评判其匹配结果
查询执行过程复杂,且不会被缓存
filter dsl:执行exact查询时,基于其结果为"yes"或"no"进行评判
速度快,且结果缓存
filter dsl:
term filter:精确匹配包含指定term的文档
如:{
"query":{
"term":{
"name":"Guo"
}
}
}
[root@Node2 ~]# curl "localhost:9200/students/_search?pretty" -d '
{
"query":{
"term":{
"name":"Guo"
}
}
}'
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 0,
"max_score" : null,
"hits" : [ ]
}
}
terms filter:用于多值精确匹配
如:{
"query":{
"terms":{
“name”:["Guo","Rong"]
}
}
}
range filters:用于在指定范围内查询数值或时间
如:{
"query":{
“range”:{
"age":{
"gte":15,
"lte":25
}
}
}
}
[root@Node2 ~]# curl "localhost:9200/students/_search?pretty" -d '
{
"query":{
"range":{
"age":{
"gte":15,
"lte":27
}
}
}
> }'
{
"took" : 24,
"timed_out" : false,
"_shards" : {
"total" : 5,
"successful" : 5,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "students",
"_type" : "class1",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"first_name" : "Rong",
"last_name" : "Huang",
"gender" : "Female",
"age" : 23,
"courses" : "Luoying Shenjian"
}
},
{
"_index" : "students",
"_type" : "s1",
"_id" : "yw",
"_score" : 1.0,
"_source" : {
"first_name" : "xiejun",
"age" : 27
}
}
]
}
}
exists and missing filters:
{
"query":{
"exists":{
"age":23
}
}
}
boolean filter:基于boolean的逻辑来合并多个filter子句
must:其内部所有的子句条件必须同时匹配,即and
例:
must:{
"term":{"age":25},
"term":{"gender":"Female"}
}
must_not:其所有子句必须不匹配,即not
must_not:{
"term":{"age":25}
}
should:至少有一个子句匹配,即or
should:{
"term":{"age":25},
"term":{"gender":"Female"}
}
QUERY DSL:
match_all Query:用于匹配所有文档,没有指定任何query,默认即为match_all query
{"match_all":{}}
match Query:在几乎任何域上执行full-text或exact-value查询
如果执行full-text查询需要先做分析
{"match":{"students":"Guo}}
如果执行exact-value查询则搜索精确值,此时,建议使用过滤而非查询
{"match":{"name":"Guo"}}
multi_match Query:用于在多个域上执行相同的查询
{
“multi_match”:{
“ query”:{
"students":"Guo"
}
"field":{
"name",
"description"
}
}
}
bool query:基于boolean逻辑合并多个查询语句,与bool filter不同的是,查询子句不是返回“yes”或"no",而是其计算出的匹配度分值,因此boolean query会为各子句合并其score:
must:
must_not:
should:
也可以合并filter和query语句:
{
"filterd":{
query:{"match":{"gender":"Female"}
filter:{"term":{"age":25}}
}
}
查询语句语法检查:
GET /INDEX/_validate/query?explain&pretty -d '
{
...
}'
显示详细信息:
GET /INDEX/_valudate/query?explain&pretty -d '
{
...
}'
[root@Node2 ~]# curl "localhost:9200/students/_validate/query?pretty" -d '
{
"query":{
"range":{
"age":{
"gte":15,
"lte":27
}
}
}
}'
{
"valid" : true,
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
}
}
[root@Node2 ~]# curl "localhost:9200/students/_validate/query?explain&pretty" -d '
{
"query":{
"range":{
"age":{
"gte":15,
"lte":27
}
}
}
}'
{
"valid" : true,
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"explanations" : [
{
"index" : "students",
"valid" : true,
"explanation" : "age:[15 TO 27]"
}
]
}