开始之前先学习
副本
介绍:Elasticsearch的每个索引都被分成shard ,每个shard 可以有多个副本。这些副本称为复制组,在添加或删除文档时必须保持同步。如果我们不这样做,从一个副本阅读将会导致与从另一个副本阅读非常不同的结果。保持碎片副本同步并提供从中读取的过程称为数据复制模型。
Elasticsearch的数据复制模型基于主备份模型。该模型基于复制组中作为主shard 的一个副本。其他的副本称为复制shard 。主索引作为所有索引操作的主要入口点。它负责验证它们并确保它们是正确的。一旦主操作接受了索引操作,主操作还负责将操作复制到其他副本。
本节的目的是对Elasticsearch复制模型作一个高层次的概述,并讨论它对读写操作之间的各种交互的影响。
基本写操作原理
Elasticsearch中的每个索引操作首先使用路由解析为一个复制组,通常基于文档ID。一旦确定了复制组,操作将在内部转发到组的当前主shard 。主shard 负责验证操作并将其转发到其他副本。由于副本可以脱机,主副本不需要复制到所有副本。相反,Elasticsearch维护应该接收操作的shard 副本列表。这个列表称为同步副本,由主节点维护。顾名思义,这些是一组“好的”shard 副本,它们保证已经处理了所有已向用户确认的索引和删除操作。主程序负责维护这个不变量,因此必须将所有操作复制到这个集合中的每个副本。
主碎片遵循这个基本流程:
- 验证传入操作并如果结构无效的话会拒绝它(例如:有一个对象字段,其中有一个数字不是预期的)
- 在本地执行操作,即索引或删除相关文档。这还将验证字段的内容并在需要时拒绝(例如:在Lucene中索引关键字值太长)。
- 将操作转发到当前同步副本集中的每个副本。如果有多个副本,则并行执行。
- 一旦所有副本都成功地执行了操作并响应了主副本,主副本就会确认对客户机的请求已经成功完成。
故障处理
在索引过程中,很多事情都可能出错——磁盘可能损坏,节点可能彼此断开连接,或者一些配置错误可能会导致副本上的操作失败,尽管主服务器上的操作是成功的。这种情况并不常见,但主shard必须对其作出反应。
在主节点本身失败的情况下,主节点所在的节点将向主节点发送关于主节点的消息。索引操作将等待(默认情况下最多1分钟),以便主服务器将一个副本提升为一个新的主副本。然后,操作将被转发到新的主服务器进行处理。注意,主节点还监视节点的健康状况,并可能决定提前降级主节点。这通常发生在持有主节点的节点由于网络问题与集群隔离时。
在主服务器上成功执行操作之后,主服务器必须在副本碎片上执行操作时处理潜在的故障。这可能是由于副本上的实际故障,或由于网络问题阻止操作到达副本(或阻止副本响应)造成的。所有这些都具有相同的最终结果:同步复制集中的一个副本丢失了将要被确认的操作。为了避免违反不变量,主服务器向主服务器发送一条消息,请求从同步复制集中删除有问题的碎片。主服务器只有在删除了碎片后才会确认操作。注意,主节点还将指示另一个节点开始构建一个新的碎片副本,以便将系统恢复到健康状态。
在将操作转发到副本时,主服务器将使用副本来验证它仍然是活动的主服务器。如果主服务器由于网络分区(或长时间GC)而被隔离,在这之前它可能会继续处理传入的索引操作,直到意识到它已经降级了。来自过期主程序的操作将被副本拒绝。当主服务器收到来自副本的拒绝请求的响应,因为它不再是主服务器时,它会联系主服务器,并知道它已经被替换了。然后将操作路由到新的主服务器。
基本读操作原理
在Elasticsearch中读取可以是非常轻量的查找,也可以是繁重的搜索请求,而复杂的聚合会占用大量的CPU资源。主备份模型的优点之一是,它保持所有碎片副本相同(飞行操作除外)。因此,一个同步副本就足以服务于读请求。
当节点接收到读请求时,该节点负责将其转发到持有相关碎片的节点、整理响应和响应客户机。我们将该节点称为该请求的协调节点。基本流程如下:
- 将读取请求解析到相关的碎片。注意,由于大多数搜索将被发送到一个或多个索引,它们通常需要从多个碎片中读取,每个碎片代表数据的不同子集。
- 从碎片复制组中选择每个相关碎片的活动副本。这可以是主副本,也可以是副本。默认情况下,Elasticsearch只会在碎片副本之间进行。
- 将碎片级别的读取请求发送到选中的副本。
- 将结果进行合并。注意,在get by ID查找的情况下,只有一个切分是相关的,可以跳过这一步。
故障处理:
当碎片无法响应读请求时,协调节点将从同一复制组中选择另一个副本,并将碎片级搜索请求发送到该副本。重复的失败会导致碎片副本不可用。在某些情况下,比如_search, Elasticsearch将更喜欢快速响应,尽管会得到部分结果,而不是等待问题得到解决(响应的_shards头中显示了部分结果)。
简单介绍了副本,接下来就学习API了。
Index API
首先是先介绍 mapping type, Mapping types will be completely removed in Elasticsearch 7.0.0.这是官网原话。我也不知道为啥要介绍mapping type,我是按照官网讲的来的。
1)什么是 mapping type:
自从首次发布Elasticsearch以来,每个文档都存储在一个索引中,并分配一个映射类型。映射类型用于表示被索引的文档或实体的类型,例如twitter索引可能有user类型和tweet类型。
每个映射类型都可以有自己的字段,因此用户类型可能有full_name字段、user_name字段和email字段,而tweet类型可以有content字段、tweeted_at字段和用户类型类似的user_name字段。
每个文档都有一个包含类型名的_type元字段,通过在URL中指定类型名,搜索可以被限制为一个或多个类型:
GET twitter/user,tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}
_type字段与文档的_id合并生成_uid字段,因此具有相同_id的不同类型的文档可以存在于单个索引中。
2)为什么要移除mapping type?
最初,我们讨论了类似于SQL数据库中的“数据库”的“索引”,以及等效于“表”的“类型”。
这是一个糟糕的类比,导致了错误的假设。在SQL数据库中,表是相互独立的。一个表中的列与另一个表中的同名列没有关系。对于映射类型中的字段,情况并非如此。换句话说,使用上面的示例,用户类型中的user_name字段存储在与tweet类型中的user_name字段完全相同的字段中,并且两个user_name字段在两种类型中都必须具有相同的映射(定义)。
例如,当您想要删除一个类型中的日期字段和相同索引中的另一个类型中的布尔字段时,这可能会导致挫败。最重要的是,存储在同一索引中具有很少或没有共同字段的不同实体会导致数据稀疏,并妨碍Lucene高效压缩文档的能力。基于这些原因,我们决定从Elasticsearch中删除映射类型的概念。
3)mapping type的替代品
①给每个文档建立一个索引。
②自定义type字段:
当然,集群中可以存在多少个主碎片是有限制的,因此您可能不希望浪费整个碎片来收集几千个文档。在本例中,您可以实现自己的自定义类型字段,该字段的工作方式与旧_type类似。
让我们以上面的user/tweet示例为例。最初,工作流应该是这样的:
PUT twitter
{
"mappings": {
"user": {
"properties": {
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" }
}
},
"tweet": {
"properties": {
"content": { "type": "text" },
"user_name": { "type": "keyword" },
"tweeted_at": { "type": "date" }
}
}
}
}
PUT twitter/user/kimchy
{
"name": "Shay Banon",
"user_name": "kimchy",
"email": "[email protected]"
}
PUT twitter/tweet/1
{
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}
您可以通过添加一个自定义类型字段来实现相同的功能,如下所示:
PUT twitter
{
"mappings": {
"_doc": {
"properties": {
"type": { "type": "keyword" },
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" },
"content": { "type": "text" },
"tweeted_at": { "type": "date" }
}
}
}
}
PUT twitter/_doc/user-kimchy
{
"type": "user",
"name": "Shay Banon",
"user_name": "kimchy",
"email": "[email protected]"
}
PUT twitter/_doc/tweet-1
{
"type": "tweet",
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/_search
{
"query": {
"bool": {
"must": {
"match": {
"user_name": "kimchy"
}
},
"filter": {
"match": {
"type": "tweet"
}
}
}
}
}
显式类型字段取代了隐式_type字段。
ok 前面说了一堆乱起八糟的东西。现在进入正题。
1)添加索引:
索引API在特定索引中添加或更新类型化JSON文档,使其可搜索。下面的示例将JSON文档插入到“twitter”索引中,其类型名为“_doc”,id为1:
curl -X PUT "localhost:9200/twitter/_doc/1" -d'
{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
'
2)自动索引:
索引操作自动创建索引,如果没有之前创建,并自动创建一个动态类型映射为特定类型如果尚未创建。映射本身非常灵活,并且没有模式。新的字段和对象将自动添加到指定类型的映射定义中。
Automatic index creation can be disabled by setting action.auto_create_index
to false
in the config file of all nodes. Automatic mapping creation can be disabled by settingindex.mapper.dynamic
to false
per-index as an index setting.
Automatic index creation can include a pattern based white/black list, for example, set action.auto_create_index
to +aaa*,-bbb*,+ccc*,-*
(+ meaning allowed, and - meaning disallowed)。官方原话.如何设置自动索引。
3)版本:
没看懂。
4)Opration Type:
索引操作还接受op_type,可用于强制创建操作,允许“如果没有”的行为。使用create时,如果该id文档已经存在于索引中,则索引操作将失败。
下面是一个使用op_type参数的例子:
curl -X PUT "localhost:9200/twitter/_doc/1?op_type=create" -d'
{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
'
指定create的另一个选项是使用以下uri:
curl -X PUT "localhost:9200/twitter/_doc/1/_create" -d'
{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
'
自动生成id:
可以在不指定id的情况下执行索引操作。在这种情况下,将自动生成id。此外,op_type将被自动设置为create。下面是一个例子(注意使用的是POST而不是PUT):
curl -X POST "localhost:9200/twitter/_doc/" -d'
{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
'
以上操作的结果为:
{
"_shards" : {
"total" : 2,
"failed" : 0,
"successful" : 2
},
"_index" : "twitter",
"_type" : "_doc",
"_id" : "W0tpsmIBdwcYyG50zbta",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"result": "created"
}
路由:
默认情况下,碎片放置(或路由)是通过使用文档id值的散列来控制的。为了实现更明确的控制,可以使用路由参数直接在每个操作的基础上指定路由器使用的散列函数的值。例如:
curl -X POST "localhost:9200/twitter/_doc?routing=kimchy" -d'
{
"user" : "kimchy",
"post_date" : "2009-11-15T14:12:12",
"message" : "trying out Elasticsearch"
}
'
在上面的示例中,“_doc”文档根据提供的路由参数“kimchy”被路由到一个碎片。
在设置显式映射时,可以选择使用_routing字段指导索引操作,从文档本身提取路由值。这确实需要额外的文档解析传递的成本(非常低)。如果定义了_routing映射并设置为必需的,如果没有提供或提取路由值,索引操作将失败。
副本的分发:
索引操作根据其路由(请参阅上面的路由部分)定向到主碎片,并在包含此碎片的实际节点上执行。主碎片完成操作后,如果需要,更新将分发给适用的副本。
等待活跃的副本:
为了提高对系统的写操作的弹性,可以将索引操作配置为在继续操作之前等待一定数量的活动碎片副本。如果必需的碎片副本数量不可用,那么写操作必须等待并重试,直到必要的碎片副本启动或超时。默认情况下,写操作只等待主碎片处于活动状态后再继续(即wait_for_active_shards=1)。通过设置index.write.wait_for_active_shards,可以在索引设置中动态覆盖此默认值。要更改每个操作的这种行为,可以使用wait_for_active_shards请求参数。
有效值是所有或任何正整数,直到索引中每个碎片的配置副本总数(即number_of_replicas+1)。指定一个负数或一个大于碎片副本数量的数字会抛出错误。
例如,假设我们有一个由三个节点组成的集群,a、B和C,我们创建了一个索引索引,将副本的数量设置为3(结果是4个碎片副本,比节点多一个副本)。如果我们尝试索引操作,默认情况下,操作只会在继续之前确保每个碎片的主副本可用。这意味着,即使B和C宕机,并且A托管主碎片副本,索引操作仍然只处理数据的一个副本。如果将wait_for_active_shards设置为3(所有3个节点都已启动),那么在继续之前,索引操作将需要3个活动碎片副本,这一要求应该得到满足,因为集群中有3个活动节点,每个节点都持有碎片的副本。但是,如果我们将wait_for_active_shards设置为all(或4,这是相同的),索引操作将不会继续,因为索引中没有每个碎片的所有4个副本。除非集群中出现一个新节点来承载碎片的第四个副本,否则操作将超时。
需要注意的是,这个设置大大减少了写入操作不写入到所需碎片副本数量的机会,但它并没有完全排除这种可能性,因为这种检查发生在写入操作开始之前。一旦写操作开始,复制仍然可能在任何数量的碎片副本上失败,但在主副本上仍然成功。写操作响应的_shards部分显示复制成功/失败的碎片副本的数量。
{
"_shards" : {
"total" : 2,
"failed" : 0,
"successful" : 2
}
}
控件何时该请求所做的更改对搜索可见。 See refresh.
GET API
get API可以根据id从索引中获取JSON类型的文档,下面的示例从名为twitter的索引中获取JSON文档,该索引的类型为_doc, id值为0:
curl -X GET "localhost:9200/twitter/_doc/0"
上述get操作的结果为:
{
"_index" : "twitter",
"_type" : "_doc",
"_id" : "0",
"_version" : 1,
"found": true,
"_source" : {
"user" : "kimchy",
"date" : "2009-11-15T14:12:12",
"likes": 0,
"message" : "trying out Elasticsearch"
}
}
上面的结果包括我们希望检索的文档的_index、_type、_id和_version,包括文档的实际内容_source(如响应中的found字段所示)。
get的实时问题:
默认情况下,get API是实时的,不受索引的刷新率的影响(当数据对搜索可见时)。如果文档已经更新但尚未刷新,则get API将发出一个就地刷新调用,以使文档可见。这还将使自上次刷新以来更改的其他文档可见。为了禁用realtime GET,可以将realtime参数设置为false。
Source 过滤:
默认情况下,get操作返回_source字段的内容,除非使用了stored_fields参数或禁用了_source字段。您可以使用_source参数关闭_source检索:
curl -X GET "localhost:9200/twitter/_doc/0?_source=false"
如果只需要完整的_source中的一个或两个字段,则可以使用_source_include & _source_exclude参数来包含或过滤掉需要的部分。这对大型文档特别有用,局部检索可以节省网络开销。两个参数都使用逗号分隔的字段列表或通配符表达式。例子:
curl -X GET "localhost:9200/twitter/_doc/0?_source_include=*.id&_source_exclude=entities"
如果您只想指定include,则可以使用更短的符号:
curl -X GET "localhost:9200/twitter/_doc/0?_source=*.id,retweeted"
Stored Fields:
get操作允许指定一组存储字段,这些字段将通过传递stored_fields参数返回。如果请求的字段没有设置为stored,它们将被忽略。例如,考虑以下映射:
curl -X PUT "localhost:9200/twitter" -d'
{
"mappings": {
"_doc": {
"properties": {
"counter": {
"type": "integer",
"store": false
},
"tags": {
"type": "keyword",
"store": true
}
}
}
}
}
'
现在我们添加一篇文档:
curl -X PUT "localhost:9200/twitter/_doc/1" -d'
{
"counter" : 1,
"tags" : ["red"]
}
'
get它:
curl -X GET "localhost:9200/twitter/_doc/1?stored_fields=tags,counter"
返回结果为:
{
"_index": "twitter",
"_type": "_doc",
"_id": "1",
"_version": 1,
"found": true,
"fields": {
"tags": [
"red"
]
}
}
从文档本身获取的字段值总是作为数组返回。由于counter字段不stored,所以get请求在尝试获取stored_fields时只会忽略它。
直接获取_source:
通过如下方式:
curl -X GET "localhost:9200/twitter/_doc/1/_source"
您还可以使用相同的source过滤参数来控制_source的哪些部分将被返回:
curl -X GET "localhost:9200/twitter/_doc/1/_source?_source_include=*.id&_source_exclude=entities'"
副本偏爱:
可以控制用于在哪个碎片副本上执行get请求的首选项。默认情况下,操作在碎片副本之间随机进行。
首选项可以设置为:
_primary
操作将只在主碎片上执行。
_local
如果可能的话,该操作更愿意在本地分配的碎片上执行。
Custom(字符串)值
将使用自定义值来确保相同的碎片将用于相同的自定义值。当在不同的刷新状态下敲击不同的碎片时,这有助于“跳转值”。示例值可以类似于web会话id或用户名。
refresh:
可以将refresh参数设置为true,以便在get操作之前刷新相关的碎片并使其可搜索。在仔细考虑和验证之后,应该将其设置为true,以确保不会对系统造成沉重的负载(并减慢索引速度)。
Delete API
跳过。
Delete By Query API
_delete_by_query的最简单用法是对匹配查询的每个文档执行删除操作。以下是API:
curl -X POST "localhost:9200/twitter/_delete_by_query" -d'
{
"query": {
"match": {
"message": "some message"
}
}
}
'
_delete_by_query在索引启动时获取一个快照,并使用内部版本控制删除它找到的内容。这意味着,如果文档在快照获取时间和删除请求处理时间之间发生更改,就会出现版本冲突。当版本匹配时,文档将被删除。
注意:由于内部版本控制不支持将值0作为有效的版本号,所以版本为0的文档不能使用_delete_by_query删除,请求将失败。
在_delete_by_query执行期间,将依次执行多个搜索请求,以查找要删除的所有匹配文档。每次发现一批文档时,都会执行相应的批量请求来删除所有这些文档。如果搜索请求或批量请求被拒绝,_delete_by_query依赖默认策略重试被拒绝的请求(最多10次,以指数级后退)。达到最大重试限制会导致_delete_by_query中止,并在响应失败时返回所有失败。已经执行的删除操作仍然有效。换句话说,进程不会回滚,只会中止。当第一个失败导致中止时,失败的批量请求返回的所有失败都在failure元素中返回;因此,可能会有很多失败的实体。
如果您希望统计版本冲突而不是导致它们中止,那么在url上设置conflicts=proceed或请求体中的“conflicts”:“proceed”。
回到API格式,这将从twitter索引中删除tweets:
curl -X POST "localhost:9200/twitter/_doc/_delete_by_query?conflicts=proceed" -d'
{
"query": {
"match_all": {}
}
}
'
也可以同时删除多个索引和多个类型的文档,就像搜索API:
curl -X POST "localhost:9200/twitter,blog/_docs,post/_delete_by_query" -H 'Content-Type: application/json' -d'
{
"query": {
"match_all": {}
}
}
'
切片:
按查询删除支持切片滚动,以并行化删除过程。这种并行化可以提高效率,并提供一种将请求分解为更小的部分的方便方法。
通过为每个请求提供片id和片的总数,手工地对每个查询进行删除:
curl -X POST "localhost:9200/twitter/_delete_by_query" -H 'Content-Type: application/json' -d'
{
"slice": {
"id": 0,
"max": 2
},
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
'
curl -X POST "localhost:9200/twitter/_delete_by_query" -H 'Content-Type: application/json' -d'
{
"slice": {
"id": 1,
"max": 2
},
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
'
验证:
curl -X GET "localhost:9200/_refresh"
curl -X POST "localhost:9200/twitter/_search?size=0&filter_path=hits.total" -H 'Content-Type: application/json' -d'
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
'
结果:
{
"hits": {
"total": 0
}
}
自动切片:
您还可以使用切片滚动在_uid上切片,让逐个查询的删除自动并行化。使用切片来指定要使用的切片数量:
curl -X POST "localhost:9200/twitter/_delete_by_query?refresh&slices=5" -H 'Content-Type: application/json' -d'
{
"query": {
"range": {
"likes": {
"lt": 10
}
}
}
}
'
Update API
update API允许基于提供的脚本更新文档。该操作从索引中获取文档(与碎片合并),运行脚本(使用可选的脚本语言和参数),并对结果进行索引(也允许删除或忽略操作)。它使用版本控制来确保在“get”和“reindex”期间没有发生更新。
注意,这个操作仍然意味着文档的完全重新索引,它只是删除了一些网络往返,减少了get和索引之间版本冲突的机会。需要启用_source字段才能使该特性工作。
例如,让我们索引一个简单的文档:
curl -X PUT "localhost:9200/test/_doc/1" -H 'Content-Type: application/json' -d'
{
"counter" : 1,
"tags" : ["red"]
}
'
脚本更新:
现在,我们可以执行一个脚本来增加counter:
curl -X POST "localhost:9200/test/_doc/1/_update" -d'
{
"script" : {
"source": "ctx._source.counter += params.count",
"lang": "painless",
"params" : {
"count" : 4
}
}
}
'
我们可以添加一个标签到标签列表(注意,如果标签存在,它仍然会添加它,因为它是一个列表):
curl -X POST "localhost:9200/test/_doc/1/_update" -d'
{
"script" : {
"source": "ctx._source.tags.add(params.tag)",
"lang": "painless",
"params" : {
"tag" : "blue"
}
}
}
'
除了_source,通过ctx映射还可以使用以下变量:_index、_type、_id、_version、_routing和_now(当前时间戳)。
我们还可以在文档中添加一个新字段:
curl -X POST "localhost:9200/test/_doc/1/_update" -d'
{
"script" : "ctx._source.new_field = \u0027value_of_new_field\u0027"
}
'
或者移除一个字段:
curl -X POST "localhost:9200/test/_doc/1/_update" -H 'Content-Type: application/json' -d'
{
"script" : "ctx._source.remove(\u0027new_field\u0027)"
}
'
我们甚至可以改变执行的操作。如果标签字段包含绿色,这个例子将删除文档,否则什么也不做:
curl -X POST "localhost:9200/test/_doc/1/_update" -d'
{
"script" : {
"source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = \u0027delete\u0027 } else { ctx.op = \u0027none\u0027 }",
"lang": "painless",
"params" : {
"tag" : "green"
}
}
}
'
文档部分更新:
更新API还支持传更新文档的一部分,这些文档将合并到现有文档中(简单的递归合并、对象的内部合并、替换核心“键/值”和数组)。要完全替换现有文档,应该使用索引API。以下部分更新为现有文档添加了一个新字段:
curl -X POST "localhost:9200/test/_doc/1/_update" -d'
{
"doc" : {
"name" : "new_name"
}
}
'
通过Query API更新
_update_by_query的最简单用法是对索引中的每个文档执行更新,而不更改源。这对于获取新属性或其他在线映射更改非常有用。以下是API:
curl -X POST "localhost:9200/twitter/_update_by_query?conflicts=proceed"
结果:
{
"took" : 147,
"timed_out": false,
"updated": 120,
"deleted": 0,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1.0,
"throttled_until_millis": 0,
"total": 120,
"failures" : [ ]
}
更新和前面查找一样。也存在冲突问题。
_update_by_query支持脚本来更新文档:
curl -X POST "localhost:9200/twitter/_update_by_query" -d'
{
"script": {
"source": "ctx._source.likes++",
"lang": "painless"
},
"query": {
"term": {
"user": "kimchy"
}
}
}
'
正如在更新API中可以设置ctx一样。op更改执行的操作:
无操作
ctx设置。如果您的脚本决定不需要做任何更改,op = "noop"。这会导致_update_by_query从其更新中忽略该文档。在响应体的noop计数器中不会报告此操作。
删除
ctx设置。如果脚本决定必须删除文档,op =“delete”。删除操作将在响应体中已删除的计数器中报告。
设置ctx。操作到其他任何地方都是错误的。在ctx中设置任何其他字段都是一个错误。
注意,我们不再指定conflicts=proceed。在这种情况下,我们希望版本冲突中止进程,以便能够处理失败。
这个API不允许您移动它所触及的文档,只需修改它们的源代码。这是故意的!我们没有规定要把文件从原来的位置移走。
Multi Get API
想要查询的数据写在doc数组中,数据的结构跟GET API的一样。
curl -X GET "localhost:9200/_mget" -d'
{
"docs" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1"
},
{
"_index" : "test",
"_type" : "_doc",
"_id" : "2"
}
]
}
'
mget端点还可以用于索引(在这种情况下,主体中不需要索引):
curl -X GET "localhost:9200/test/_mget" -d'
{
"docs" : [
{
"_type" : "_doc",
"_id" : "1"
},
{
"_type" : "_doc",
"_id" : "2"
}
]
}
'
and type:
GET /test/type/_mget
{
"docs" : [
{
"_id" : "1"
},
{
"_id" : "2"
}
]
}
在这种情况下,ids元素可以直接用于简化请求:
curl -X GET "localhost:9200/test/type/_mget" -d'
{
"ids" : ["1", "2"]
}
'
Source Filter:
具体用法跟 GetAPI类似:
curl -X GET "localhost:9200/_mget" -d'
{
"docs" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_source" : false
},
{
"_index" : "test",
"_type" : "_doc",
"_id" : "2",
"_source" : ["field3", "field4"]
},
{
"_index" : "test",
"_type" : "_doc",
"_id" : "3",
"_source" : {
"include": ["user"],
"exclude": ["user.location"]
}
}
]
}
'
获取字段:
curl -X GET "localhost:9200/_mget" -d'
{
"docs" : [
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"stored_fields" : ["field1", "field2"]
},
{
"_index" : "test",
"_type" : "_doc",
"_id" : "2",
"stored_fields" : ["field3", "field4"]
}
]
}
'
BULK API
如果要提供文本文件输入来进行curl,则必须使用——data-binary标志,而不是普通的-d。后者不保留换行符。例子:
$ cat requests
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
$ curl -s -H "Content-Type: application/x-ndjson" -XPOST localhost:9200/_bulk --data-binary "@requests"; echo
{"took":7, "errors": false, "items":[{"index":{"_index":"test","_type":"_doc","_id":"1","_version":1,"result":"created","forced_refresh":false}}]}
下面是一个正确的批量命令序列示例:
curl -X POST "localhost:9200/_bulk" -d'
{ "index" : { "_index" : "test", "_type" : "_doc", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "_doc", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "_doc", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "_doc", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }
'
结果:
{
"took": 30,
"errors": false,
"items": [
{
"index": {
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201,
"_seq_no" : 0,
"_primary_term": 1
}
},
{
"delete": {
"_index": "test",
"_type": "_doc",
"_id": "2",
"_version": 1,
"result": "not_found",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 404,
"_seq_no" : 1,
"_primary_term" : 2
}
},
{
"create": {
"_index": "test",
"_type": "_doc",
"_id": "3",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 201,
"_seq_no" : 2,
"_primary_term" : 3
}
},
{
"update": {
"_index": "test",
"_type": "_doc",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"status": 200,
"_seq_no" : 3,
"_primary_term" : 4
}
}
]
}
Reindex API
重要:Reindex不会尝试设置目标索引。它不复制源索引的设置。您应该在运行_reindex操作之前设置目标索引,包括设置映射、碎片计数、副本等。
_reindex的最基本形式只是将文档从一个索引复制到另一个索引。这将从twitter索引中复制文档到new_twitter索引中:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
'
返回结果:
{
"took" : 147,
"timed_out": false,
"created": 120,
"updated": 0,
"deleted": 0,
"batches": 1,
"version_conflicts": 0,
"noops": 0,
"retries": {
"bulk": 0,
"search": 0
},
"throttled_millis": 0,
"requests_per_second": -1.0,
"throttled_until_millis": 0,
"total": 120,
"failures" : [ ]
}
就像_update_by_query一样,_reindex获取源索引的快照,但是它的目标必须是不同的索引,因此不太可能发生版本冲突。dest元素可以配置为索引API来控制乐观并发控制。仅仅省略version_type(如上所述)或将其设置为internal将导致Elasticsearch盲目地将文档转储到目标中,覆盖碰巧具有相同类型和id的任何文档:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"version_type": "internal"
}
}
'
将version_type设置为external将导致Elasticsearch从源中保存版本,创建丢失的文档,并更新目标索引中比源索引中版本更老的文档:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"version_type": "external"
}
}
'
设置要创建的op_type将导致_reindex只在目标索引中创建丢失的文档。所有现有文档都会导致版本冲突:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"op_type": "create"
}
}
'
默认情况下,冲突会中止_reindex进程,但是您可以通过在请求体中设置“conflicts”:“proceed”来计算它们:
curl -X POST "localhost:9200/_reindex" -d'
{
"conflicts": "proceed",
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"op_type": "create"
}
}
'
可以通过向source中添加type或添加query来限制文档。这只会把kimchy的tweets复制到new_twitter:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": "twitter",
"type": "_doc",
"query": {
"term": {
"user": "kimchy"
}
}
},
"dest": {
"index": "new_twitter"
}
}
'
索引和输入源都可以是列表,允许您在一个请求中复制许多源。这个例子将会从twitter和blog索引中的_doc和post类型中复制文档。对于更具体的参数,可以使用query。
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": ["twitter", "blog"],
"type": ["_doc", "post"]
},
"dest": {
"index": "all_together"
}
}
'
还可以通过设置大小来限制已处理文档的数量。这将只从twitter复制一个文档到new_twitter:
curl -X POST "localhost:9200/_reindex" -d'
{
"size": 1,
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
}
}
'
如果您想从twitter索引中获得一组特定的文档,您需要使用sort。排序使滚动效率降低,但在某些情况下,它是值得的。如果可能的话,选择更有选择性的查询而不是大小和排序。这将从twitter复制10000个文档到new_twitter:
curl -X POST "localhost:9200/_reindex" -d'
{
"size": 10000,
"source": {
"index": "twitter",
"sort": { "date": "desc" }
},
"dest": {
"index": "new_twitter"
}
}
'
source部分支持搜索请求中支持的所有元素。例如,只有原始文档中字段的一个子集可以使用source过滤进行索引,如下所示:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": "twitter",
"_source": ["user", "_doc"]
},
"dest": {
"index": "new_twitter"
}
}
'
与_update_by_query类似,_reindex支持修改文档的脚本。与_update_by_query不同,脚本可以修改文档的元数据。这个例子中提到了源文档的版本:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter",
"version_type": "external"
},
"script": {
"source": "if (ctx._source.foo == \u0027bar\u0027) {ctx._version++; ctx._source.remove(\u0027foo\u0027)}",
"lang": "painless"
}
}
'
就像在_update_by_query中一样,您可以设置ctx。op更改目标索引上执行的操作:
noop
ctx设置。如果脚本决定不需要在目标索引中对文档进行索引,则op = "noop"。在响应体的noop计数器中不会报告此操作。
delete
ctx设置。如果脚本决定必须从目标索引中删除文档,op =“delete”。删除操作将在响应体中已删除的计数器中报告。
设置ctx。对任何其他字段的op都将返回一个错误,就像在ctx中设置任何其他字段一样。
想想这些可能性吧!只是小心些而已。你可以改变:
- _id
- _type
- _index
- _version
- _routing
远程reindex:
curl -X POST "localhost:9200/_reindex" -d'
{
"source": {
"remote": {
"host": "http://otherhost:9200",
"username": "user",
"password": "pass"
},
"index": "source",
"query": {
"match": {
"test": "data"
}
}
},
"dest": {
"index": "dest"
}
}
'
Trem Vectors
返回关于特定文档字段中的术语的信息和统计信息。文档可以存储在索引中,也可以由用户人工提供。Term vectors默认情况下是实时的,而不是接近实时的。这可以通过将realtime参数设置为false来更改。
curl -X GET "localhost:9200/twitter/_doc/1/_termvectors"
可以选择,您可以使用url中的参数指定检索信息的字段:
curl -X GET "localhost:9200/twitter/_doc/1/_termvectors?fields=message"
未完待续.......