集群(cluster)
一个集群就是由一个或多个节点组织在一起, 它们共同持有你全部的数据, 并一起提供索引和搜索功能。 一个集群由一个唯一的名字标识, 这个名字默认就是“elasticsearch”。 这个名字很重要, 因为一个节点只能通过指定某个集群的名字,来加入这个集群。在生产环境中显式地设定这个名字是一个好习惯,但是使用默认值来进行测试/开发也是不错的。
注意,一个集群中只包含一个节点是合法的。另外,你也可以拥有多个集群,集群以名字区分。
节点(node)
一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。 和集群类似, 一个节点也是由一个名字来标识的, 默认情况下, 这个名字是一个随机的Marvel角色的名字,这个名字会在节点启动时分配给它。这个名字对于管理工作来说很重要,因为在这个管理过程中,你会去确定网络中的哪些 服务器对应于Elasticsearch集群中的哪些节点。
一个节点可以通过配置集群名称的方式来加入一个指定的集群。 默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点, 并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch” 的集群中。
在一个集群里可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的单节点集群。
索引(index)
一个索引就是一个拥有相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来 标识(必须全部是小写字母的),并且当我们要对这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。在一个集群中,你能够创建任意多个索引。
文档(document)
一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档、某一个产品的一个文档、某个订单的一个文档。文档以JSON格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个index/type里面,你可以存储任意多的文档。注意,一个文档物理上存在于一个索引之中,但文档必须被索引/赋予一个索引的type。
分片和复制(shards and replicas)
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点可能没有这样大的磁盘空间来存储或者单个节点处理搜索请求,响应会太慢。
为了解决这个问题,Elasticsearch提供了将索引划分成多片的能力,这些片叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引” 可以被放置到集群中的任何节点上。
分片之所以重要,主要有两方面的原因:
允许你水平分割/扩展你的内容容量允许你在分片(位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
在一个网络/云的环境里,失败随时都可能发生。在某个分片/节点因为某些原因处于离线状态或者消失的情况下,故障转移机制是非常有用且强烈推荐的。为此, Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
复制之所以重要,有两个主要原因:
在分片/节点失败的情况下,复制提供了高可用性。复制分片不与原/主要分片置于同一节点上是非常重要的。因为搜索可以在所有的复制上并行运行,复制可以扩展你的搜索量/吞吐量
总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(即没有复制) 或多次。一旦复制了,每个索引就有了主分片(作为复制源的分片)和复制分片(主分片的拷贝)。 分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制的数量,但是你不能再改变分片的数量。
默认情况下,Elasticsearch中的每个索引分配5个主分片和1个复制。这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样每个索引总共就有10个分片。
rest 接口
现在我们已经有一个正常运行的节点(和集群),下一步就是要去理解怎样与其通信。幸运的是,Elasticsearch提供了非常全面和强大的REST API,利用这个REST API你可以同你的集群交互。下面是利用这个API,可以做的几件事情:
查你的集群、节点和索引的健康状态和各种统计信息管理你的集群、节点、索引数据和元数据对你的索引进行 CRUD(创建、读取、更新和删除)和搜索操作执行高级的查询操作, 像是分页、排序、过滤、脚本编写(scripting)、小平面刻画(faceting)、聚合(aggregations)和许多其它操作集群操作
检查集群健康,我们将使用_cat API。需要事先记住的是,我们的节点HTTP的端口是9200:
curl 'localhost:9200/_cat/health?v'
相应的响应是:
epoch timestamp cluster status node.total node.data shards pri relo init unassign1394735289 14:28:09 elasticsearch green 1 1 0 0 0 0 0
可以看到,我们集群的名字是“elasticsearch”,正常运行,并且状态是绿色。
当我们查看集群状态的时候,我们可能得到绿色、黄色或红色三种状态。绿色代表一切正常(集群功能齐全);黄色意味着所有的数据都是可用的,但是某些复制没有被分配(集群功能齐全); 红色则代表因为某些原因,某些数据不可用。注意,即使是集群状态是红色的,集群仍然是部分可用的(它仍然会利用可用的分片来响应搜索请求),但是可能你需要尽快修复它,因为你有丢失的数据。
获得节集群中的节点列表:
curl 'localhost:9200/_cat/nodes?v'
对应的响应是:
curl 'localhost:9200/_cat/nodes?v'host ip heap.percent ram.percent load node.role master namemwubuntu1 127.0.1.1 8 4 0.00 d * New Goblin
这儿, 我们可以看到叫“New Goblin”的节点,这个节点是我们集群中的唯一节点。
列出所有的索引让我们看一下我们的索引:
curl 'localhost:9200/_cat/indices?v'
对应的响应是:
curl 'localhost:9200/_cat/indices?v'health index pri rep docs.count docs.deleted store.size pri.store.size
这个结果意味着,在我们的集群中没有任何索引。
创建一个索引现在让我们创建一个叫做“customer” 的索引,然后再列出所有的索引:
curl -XPUT 'localhost:9200/customer?pretty'curl 'localhost:9200/_cat/indices?v'
第一个命令使用PUT创建了一个叫做“customer” 的索引。我们简单地将pretty附加到调用的尾部,使其以美观的形式打印出JSON响应
响应如下:
curl -XPUT 'localhost:9200/customer?pretty'{ "acknowledged" : true}curl 'localhost:9200/_cat/indices?v'health index pri rep docs.count docs.deleted store.size pri.store.sizeyellow customer 5 1 0 0 495b 495b
第二个命令的结果告知我们,我们现在有一个叫做 customer 的索引,并且它有5个主分片和1份复制(都是默认值),其中包含0个文档。
你可能也注意到了这个customer索引有一个黄色健康标签。回顾我们之前的讨论,黄色意味着某些复制没有(或者还未)被分配。这个索引之所以这样,是因为 Elasticsearch默认 为这个索引创建一份复制。 由于现在我们只有一个节点在运行,那一份复制就分配不了了(为了高可用),直到当另外一个节点加入到这个集群后,才能分配。一旦那份复制在第二个节点上被复制,这个节点的健康状态就会变成绿色。
索引并查询一个文档现在让我们放一些东西到customer索引中。首先要知道的是,为了索引一个文档,我们必须告诉Elasticsearch这个文档要到这个索引的哪个类型(type)下。
让我们将一个简单的客户文档索引到customer 索引 、“external” 类型中,这个文档的ID是1,操作如下:
curl -XPUT 'localhost:9200/customer/external/1?pretty' -d ' /索引名/类型/id{ "name": "John Doe"}'
响应如下:
curl -XPUT 'localhost:9200/customer/external/1?pretty' -d '{ "name": "John Doe"}'{ "_index" : "customer", "_type" : "external", "_id" : "1", "_version" : 1, "created" : true}
从上面的响应中,我们可以看到,一个新的客户文档在customer索引和external类型中被成功创建。文档也有一个内部id 1, 这个id是我们在索引的时候指定的。
需要注意的是,当你想将文档索引到某个索引的时候,Elasticsearch并不强制要求这个索引被显式地创建。在前面这个例子中,如果customer索引不存在,Elasticsearch将会自动地创建这个索引。
现在,让我们把刚刚索引的文档取出来:
curl -XGET 'localhost:9200/customer/external/1?pretty'
响应如下:
curl -XGET 'localhost:9200/customer/external/1?pretty'{ "_index" : "customer", "_type" : "external", "_id" : "1", "_version" : 1, "found" : true, "_source" : { "name": "John Doe" }}
除了found字段-(指明我们找到了一个ID为1的文档)和_source字段(返回我们前一步中索引的完整JSON文档)之外,没有什么特别之处。
删除一个文档现在让我们删除我们刚刚创建的索引,并再次列出所有的索引:
curl -XDELETE 'localhost:9200/customer?pretty'curl 'localhost:9200/_cat/indices?v'
响应如下:
curl -XDELETE 'localhost:9200/customer?pretty'{ "acknowledged" : true}curl 'localhost:9200/_cat/indices?v'health index pri rep docs.count docs.deleted store.size pri.store.size
这表明我们成功地删除了这个索引,现在我们回到了集群中空无所有的状态。
我们细看一下我们学过的API命令:
curl -XPUT 'localhost:9200/customer'curl -XPUT 'localhost:9200/customer/external/1' -d '{ "name": "John Doe"}'curl 'localhost:9200/customer/external/1'curl -XDELETE 'localhost:9200/customer'
仔细研究以上的命令,我们可以发现访问Elasticsearch中数据的一个模式。这个模式可以被总结为:
curl -X
这个REST访问模式普遍适用于所有的API命令,如果你能记住它,你就会为掌握Elasticsearch 开一个好头。
高级查询DSL uri搜索$ curl -XGET 'http://localhost:9200/twitter/tweet/_search?q=user:kimchy'
请求体搜索$ curl -XGET 'http://localhost:9200/twitter/tweet/_search' -d '{ "query" : { "term" : { "user" : "kimchy" } }}'
索引名中的日期数学支持
几乎所有具有 index(索引)参数的 API,都支持 index(索引)参数值中的日期数学。
日期数学索引名字采用以下形式:
其中:
注意 date_format(日期格式)中使用的大小写字母。例如,mm 表示分钟,MM表示月份。类似的,hh 表示 1-12 范围内的小时,与 AM/PM 组合使用,而 HH 表示 0-23 24小时范围内的小时。
日期数学表达式与区域无关。因此,不以使用格列高利历之外的日历。
必须将日期数学索引名字表达式包在尖括号内,并且所有特殊字符都应进行 URI 编码。例如:
为了在索引名字模板的静态部分中使用字符 { 和 },请使用反斜杠 转义,例如:
# PUT / 以下例子展示了一个搜索请求,该请求搜索过去三天的 Logstash 索引,假设索引使用默认的 Logstash 索引名字格式 logstash-yyyy.MM.dd。 # GET / 所有的 REST API 都接受 filter_path 参数,它可以用于减少 Elasticsearch 返回的响应。此参数采用逗号分隔的过滤器列表,过滤器用点符号表示: GET /_search?q=kimchy&filter_path=took,hits.hits._id,hits.hits._score 别名存在 API HEAD _alias/my-alias HEAD _alias/HEAD 如果 Elasticsearch 安全特性启用,你必须对索引有 view_index_metadata 或 manage 索引权限。如果你指定一个目标,你必须对目标也有 view_index_metadata 或 manage 索引权限。 (可选,字符串)以逗号分隔的待检查的别名列表。支持通配符(*)。 (可选,字符串)用于限制请求的,逗号分隔的数据流或索引。 expand_wildcards (可选,字符串)通配符表达式可以匹配的索引类型。如果请求可以数据流为目标,则此参数确定通配符表达式是否匹配隐藏的数据流。支持逗号分隔的值,如 open,hidden。有效的值有: 默认为 all。 ignore_unavailable (可选,布尔值)如果为 true,丢失的或关闭的索引不包含在响应中。默认为 false。 local (可选,布尔值)如果为 true,请求只从本地节点获取信息。默认为 false,意味着信息从主节点获取。 200 所有指定的别名都存在。 404 一个或多个指定的别名不存在。 注意: 索引别名可以指向一个或多个索引,并且可以在任何需要索引名称的API中使用。 别名为我们提供了极大的灵活性。它们允许我们执行以下操作,类似与mysql中的视图的作用。 使用场景,当同时对多个索引操作时,可以直接使用对应的索引别名 以下请求为索引 test1 添加别名 alias1。 POST /_aliases{ "actions" : [ { "add" : { "index" : "test1", "alias" : "alias1" } } ]} 索引别名支持日期数学。 POST /_aliases{ "actions" : [ { "add" : { "index" : "logs", "alias" : " 以下请求移除别名 alias1。 POST /_aliases{ "actions" : [ { "remove" : { "index" : "test1", "alias" : "alias1" } } ]} 重命名一个别名,简单地在同一个 API 中执行操作 remove(移除)又 add(添加)。这个操作是原子的,不用担心别名会短时间的不指向索引。 POST /_aliases{ "actions" : [ { "remove" : { "index" : "test1", "alias" : "alias1" } }, { "add" : { "index" : "test1", "alias" : "alias2" } } ]} 通过简单的几个操作 add(添加),就能将别名关联到多个索引。 POST /_aliases{ "actions" : [ { "add" : { "index" : "test1", "alias" : "alias1" } }, { "add" : { "index" : "test2", "alias" : "alias1" } } ]} 多个索引也可以通过一个操作中的 indices 数组的语法指定: POST /_aliases{ "actions" : [ { "add" : { "indices" : ["test1", "test2"], "alias" : "alias1" } } ]} 为了在一个操作中指定多个别名,相应的 aliases 数组语法也可以使用。 如上示例,匹配模式也可以用于关联一个别名给共享同一个名字的多个索引: POST /_aliases{ "actions" : [ { "add" : { "index" : "test*", "alias" : "all_test_indices" } } ]} 在这种情况下,别名是一个即时别名,它将对所有当前匹配的索引进行分组,与此模式匹配的新索引将被添加或移除时,它不会自动更新。 索引指向多个索引的别名是错误的。 也可以在一个原子操作中用别名交换索引。这意味着在集群状态下,不会有别名指向无索引的时间点。然而,由于索引和搜索涉及多个步骤,因此正在运行或排队的请求可能会由于临时不存在索引而失败。 PUT testPUT test_2POST /_aliases{ "actions" : [ { "add": { "index": "test_2", "alias": "test" } }, { "remove_index": { "index": "test" } } //remove_index是移除索引本身 //remove 是将对应的索引移除对应的别名 ]} 带过滤器的别名提供了一种简单的方法来创建同一索引的不同“视图”。可以通过查询 DSL 定义过滤器,可应用于使用别名的所有搜索、按查询删除和其他类似操作。 为了创建带过滤器的别名,首先我们需要确认字段已经在映射中存在: PUT /my-index-000001{ "mappings": { "properties": { "@timestamp": { "type": "date" }, "user": { "properties": { "id": { "type": "keyword" } } } } }} 现在我们可以在 @timestamp 和 user.id 上创建一个带过滤器的别名: POST /_aliases{ "actions": [ { "add": { "index": "my-index-000001", "alias": "alias2", "filter": { "bool": { "filter": [ { "range": { "@timestamp": { "gte": "now-1d/d", "lt": "now/d" } } }, { "term": { "user.id": "kimchy" } } ] } } } } ]} 别名可以关联路由值。此功能可以与筛选别名一起使用,以避免不必要的分片操作。 以下命名创建一个指向索引 test 的新别名 alias1。在 alias1 被创建后,通过此别名的操作都会自动修改为使用值 1 来路由: POST /_aliases{ "actions": [ { "add": { "index": "test", "alias": "alias1", "routing": "1" } } ]} 也可以为搜索和索引操作指定不同的路由值: POST /_aliases{ "actions": [ { "add": { "index": "test", "alias": "alias2", "search_routing": "1,2", "index_routing": "2" } } ]} 如上例所示,搜索路由可以包含几个由逗号分隔的值。索引路由可以只包含一个值。 如果使用路由别名的搜索操作也具有路由参数,则使用该参数中指定的搜索别名路由和路由的交集。例如以下的命令中会使用 2 作为路由值: GET /alias2/_search?q=user.id:kimchy&routing=2,3 在ElaticSearch里面,路由功能算是一个高级用法,大多数时候我们用的都是系统默认的路由功能,我们知道一个es索引可以分多个shard和每个shard又可以有多个replia,那么现在思考一个问题,我们添加进去的数据,是如何分布在各个shard上面的,而查询时候它是又怎么找到特定的数据呢。 默认情况下,索引数据的分片规则,是下面的公式: shard_num = hash(_routing) % num_primary_shards 可以将别名指向的索引关联为写索引。当指定时,指向多个索引的别名的所有索引和更新请求都将尝试解析为一个索引,即写入索引。每个别名一次只能分配一个索引作为写索引。如果未指定写索引,并且别名引用了多个索引,则不允许写。 可以使用别名 API 和索引创建 API 将与别名关联的一个索引指定为写索引。将索引设置为具有别名的写索引也会影响在翻转期间如何操作别名(参阅带写索引的翻转)。 POST /_aliases{ "actions": [ { "add": { "index": "test", "alias": "alias1", "is_write_index": true } }, { "add": { "index": "test2", "alias": "alias1" } } ]} 在这个例子中,我们将别名 alias1 关联到 test 和 test2,而 test 选择作为写索引。 PUT /alias1/_doc/1{ "foo": "bar"} 索引到 /alias1/_doc/1 的新文档正如它是 /test/_doc/1。 GET /test/_doc/1 要交换别名的哪个索引来作为写索引,可用别名 API 来原子交换。 POST /_aliases{ "actions": [ { "add": { "index": "test", "alias": "alias1", "is_write_index": false } }, { "add": { "index": "test2", "alias": "alias1", "is_write_index": true } } ]} 响应过滤
检查一个别名是否存在。请求
前置条件
路径参数
查询参数
响应码
添加一个别名
移除一个别名
重命名一个别名
多个索引使用同一个别名
过滤的别名
路由
_routing字段的取值,默认是_id字段或者是_parent字段,这样的取值在hash之后再与有多少个shard的数量取模,最终得到这条数据应该在被分配在那个一个shard上,也就是说默认是基于hash的分片,保证在每个shard上数据量都近似平均,这样就不会出现负载不均衡的情况,然后在检索的时候,es默认会搜索所有shard上的数据,最后在master节点上汇聚在处理后,返回最终数据。
写索引