Elasticsearch7.2中文教程翻译(十): 详解索引API

@高效码农  July 31, 2019

索引API是在指定索引中添加或更新JSON文档,使其可搜索。下面的示例将JSON文档插入id为1的“twitter”索引:

PUT twitter/_doc/1
{
    "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" : "1",
    "_version" : 1,
    "_seq_no" : 0,
    "_primary_term" : 1,
    "result" : "created"
}

_shards节点提供了索引操作复制过程的信息:

  • total: 表示索引操作应在多少个碎片副本(主碎片和副本碎片)上执行。
  • successful : 表示索引操作成功执行的碎片副本的数目。
  • failed : 索引在复制碎片操作失败时包含与复制相关错误的数组。

如果索引操作返回successful为 1, 则表明索引成功;

注意:当索引操作成功返回时,复制碎片可能不会全部启动(默认情况下,只需要主碎片,但是可以更改此行为)。在这种情况下,total将等于基于number_of_replicas设置的总碎片,并且success将等于启动的碎片数量(主碎片加上副本)。如果没有失败,则failed为0。

自动创建索引

如果索引不存在,索引操作将自动创建索引,并应用已配置的任何索引模板。如果还不存在动态映射,则索引操作还创建动态映射。默认情况下,如果需要,新的字段和对象将自动添加到映射定义中。有关映射定义的更多信息,请参阅mapping部分,有关手动更新映射的信息,请参阅put mapping API

自动索引创建由action.auto_create_index设置控制。这个设置默认为true,这意味着索引总是自动创建的。只允许对匹配某些模式的索引自动创建索引,方法是将此设置的值更改为这些模式的逗号分隔列表。它还可以通过在列表中使用+或-前缀模式显式地允许和禁止。最后,将此设置更改为false可以完全禁用它。

PUT _cluster/settings
{
    "persistent": {
        "action.auto_create_index": "twitter,index10,-index1*,+ind*" # 注1
    }
}

PUT _cluster/settings
{
    "persistent": {
        "action.auto_create_index": "false"  # 注2
    }
}

PUT _cluster/settings
{
    "persistent": {
        "action.auto_create_index": "true" # 注3
    }
}
  • 注1: 只允许自动创建名为twitter、index10的索引,不允许匹配index1和匹配ind的索引自动创建。这些模式是按照它们被给出的顺序匹配的。
  • 注2:完全禁用自动创建索引。
  • 注3:允许使用任何名称自动创建索引。这是默认值。

操作类型

索引操作还接受可用于强制创建操作的op_type,允许“put-if-absent”行为。 使用create时,如果索引中已存在该id的文档,则索引操作将失败。

以下是使用op_type参数的示例:

PUT twitter/_doc/1?op_type=create
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

使用create参数uri:

PUT twitter/_create/1
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

自动生成ID

索引操作可以在不指定id的情况下执行。在这种情况下,id将自动生成。此外,op_type将自动设置为create。下面是一个例子(注意用POST代替PUT):

POST twitter/_doc/
{
    "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"
}

乐观的并发控制

索引操作是有条件的,只有在为文档的最后一次修改分配了if_seq_no和if_primary_term参数指定的序列号和主要术语时才能执行索引操作。 如果检测到不匹配,则操作将导致VersionConflictException和状态代码409.有关详细信息,请参阅乐观并发控制

路由

默认情况下,碎片的位置或路由是通过使用文档id值的散列来控制。对于显式的控制,可以使用routing参数根据每次操作直接指定传入路由器使用的hash函数的值。例如:

POST twitter/_doc?routing=kimchy
{
    "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活性碎片复制之前,应满足的要求,因为有三个活跃集群中的节点,每一个碎片的副本。但是,如果将wait_for_active_shards设置为all(或4,两者是相同的),索引操作将不会继续,因为索引中没有每个shard的所有4个副本都是活动的。除非集群中出现一个新节点来承载碎片的第四个副本,否则操作将超时。

需要注意的是,这个设置极大地降低了写操作未写入到所需碎片副本数量的机会,但它并没有完全消除这种可能性,因为这个检查发生在写操作开始之前。在执行写操作之后,仍然有可能在任意数量的碎片副本上复制失败,但在主副本上仍然成功。写操作的响应的_shards部分显示复制成功/失败的shard副本的数量。

{
    "_shards" : {
        "total" : 2,
        "failed" : 0,
        "successful" : 2
    }
}

刷新

控制何时可以搜索到此请求所做的更改。

Noop更新

使用索引API更新文档时,即使文档未更改,也始终会创建新版本的文档。 如果这是不可接受的,请使用_update API,并将detect_noop设置为true。 此选项在索引API上不可用,因为索引API不会获取旧源,也无法将其与新源进行比较。

关于何时不接受noop更新,没有一条硬性规定。 它是许多因素的组合,例如您的数据源发送实际noops更新的频率以及Elasticsearch在接收更新的分片上运行的每秒查询数。

超时

在执行索引操作时,分配给执行索引操作的主碎片可能不可用。其中的一些原因可能是主碎片目前正在从网关中恢复或正在进行重新定位。默认情况下,索引操作将等待主碎片可用最多1分钟,然后失败并响应错误。可以使用timeout参数显式地指定它等待的时间。下面是一个设置为5分钟的例子:

PUT twitter/_doc/1?timeout=5m
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}

版本控制

每个索引文档都有一个版本号。默认情况下,使用从1开始的内部版本控制,并随着每次更新(包括删除)而递增。可以选择将版本号设置为外部值(例如,如果在数据库中维护版本号)。要启用此功能,应将version_type设置为external。所提供的值必须是一个数值,长值大于或等于0,小于9.2e+18左右。

当使用外部版本类型时,系统检查传递给索引请求的版本号是否大于当前存储文档的版本。如果为真,将索引文档并使用新版本号。如果提供的值小于或等于存储文档的版本号,则会发生版本冲突,索引操作将失败。例如:

PUT twitter/_doc/1?version=2&version_type=external
{
    "message" : "elasticsearch now has versioning support, double cool!"
}

注意:版本控制是完全实时的,不受搜索操作的近实时方面的影响。如果没有提供版本,则在不进行任何版本检查的情况下执行操作。

上述操作将成功,因为所提供的版本2比当前文档版本1高。如果已经更新了文档,并且将其版本设置为2或更高,那么索引命令将失败并导致冲突(409 http状态码)。

使用源数据库的版本号的有点是不需要维护由于更改源数据库而执行的异步索引操作的严格顺序。如果使用外部版本控制,虽然使用来自数据库的数据更新Elasticsearch索引会是情况简化,但如果索引操作由于某种原因出现顺序错误,则只使用最新版本。

版本类型

除了上面解释的外部版本类型之外,Elasticsearch还支持针对特定用例的其他类型。下面是不同版本类型及其语义的概述。

  • internal: 只有当给定的版本与存储的文档版本相同时,才索引文档。
  • external or external_gt: 只有当给定的版本严格高于存储文档的版本,或者没有现有文档时,才对文档进行索引。给定的版本将作为新版本使用,并与新文档一起存储。所提供的版本必须是非负的长数字。
  • external_gte: 只有当给定的版本等于或高于存储文档的版本时,才对文档进行索引。如果没有现有文档,操作也将成功。给定的版本将作为新版本使用,并与新文档一起存储。所提供的版本必须是非负的long类型数字。

注意:external_gte版本类型用于特殊的用例,应该谨慎使用。如果使用不当,可能会导致数据丢失。还有另一个选项force,它是不推荐的,因为它可能导致主碎片和复制碎片出现分歧。



添加新评论