# 索引文档 API

索引**API**在特定索引中**add**( 添加 ) 或**update** ( 更新 )**a typed JSON document**( 类型化的 **JSON** 文档 )，使其可搜索。以下示例将**JSON**文档插入&#x5230;**“twitter”**&#x7D22;引中，**ID**为**1**：

```
curl -XPUT 'localhost:9200/twitter/tweet/1?pretty' -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'
```

上边的索引操作结果为：

```
{
    "_shards" : {
        "total" : 2,
        "failed" : 0,
        "successful" : 2
    },
    "_index" : "twitter",
    "_type" : "tweet",
    "_id" : "1",
    "_version" : 1,
    "created" : true,
    "result" : created
}
```

**\_shards header**提供有关索引操作的复制过程的信息。

* **total** - 指示应对多少**shard copies** ( 分片副本 )（**primary**( 主 )分片和**replica**( 副本 ) 分片）执行索引操作。
* **successful** - 表示索引操作成功的分片副本的数量。
* **failed** - 在索引操作在副本碎片上失败的情况下包含与复制相关的错误的数组。

在**successful**至少为**1**的情况下索引操作成功。

> 注意
>
> 当索引操作**successful**返回时，可能不会全部启动副本碎片（默认情况下，只需要主索引，但可以更改此行为）。在这种情况下，**total**将等于基于**number\_of\_replicas**设置的总分片，并且**successful**将等于已启动的分片数（主副本和副本）。如果没有失败，**failed**将是 0 。

### automatic index creation ( 自动创建索引 )

如果索引操作尚未创建，则索引操作自动创建索引（**check out**用于手动创建索引的 [**create index API**](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-index.html)），并且如果尚未创建，则自动为特定类型创建**dynamic type mapping** ( 动态类型映射 )（**check out** [**put mapping**](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-put-mapping.html) **API**用于手动创建类型映射）。

**mapping**( 映射 ) 本身非常灵活，并且是**schema-free** ( 无模式的 )。**New fields**( 新字段 ) 和**objects** ( 对象 )将自动添加到指定类型的映射定义。查看[映射部分](https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html)以获取有关映射定义的更多信息。

可以通过在所有节点的配置文件中将 **action.auto\_create\_index**设置为**false**来禁用 自动创建索引。可以通过将 **index.mapper.dynamic**设置为**false**为每个索引作为索引设置来禁用自动映射创建。

自动索引创建可以包括 **a pattern based white/black list**( 基于模式的 白/黑 列表 )，例如，设置

**action.auto\_create\_index to +aaa\*,-bbb\*,+ccc\*,-\*** （**+**&#x8868;示 允许，**-**&#x8868;示不允许）。

### Versioning ( 版本控制 )

每个索引文档都有一个版本号。相关的版本号作为对索引**API**请求的响应的一部分返回。索引**API**可选地允许在指定**version**参数时进行**optimistic concurrency control** ( 乐观并发控制 )。这将控制要对其执行操作的文档的版本。一个用于版本控制的用例的好例子是**performing atransactional read-then-update**( 执行事务读取然后更新 ) 。从初始读取的文档指定版本可以确保在此期间没有发生更改（当为了更新而读取时，建议将**preference**( 偏好 ) 设置&#x4E3A;**\_primary**）。例如：

```
curl -XPUT 'localhost:9200/twitter/tweet/1?version=2&pretty' -H 'Content-Type: application/json' -d'
{
    "message" : "elasticsearch now has versioning support, double cool!"
}
'
```

注意：

> 版本控制是完全实时的，并且不受搜索操作的**near real time** ( 近实时 ) 方面的影响。如果没有提供版本，则在没有任何版本检查的情况下执行操作。
>
> 默认情况下，使用从**1**开始的内部版本控制，每个**update**( 更新 )，包括**deletes**( 删除 )。可选地，版本号可以用外部值（例如，如果在数据库中维护）来补充。要启用此功能， **version\_type**应该设置为 **external**。提供的值必须是大于或者等于**0**且小于大约**9.2e+18**的数字长值。当使用**external version type**( 外部版本类型 ) 时，系统检查传递给索引请求的版本号是否大于当前存储的文档的版本，而不是检查匹配的版本号。如果为**true**，则文档将被索引并使用新的版本号。如果提供的值小于或等于存储的文档的版本号，则会出现版本冲突，并且索引操作将失败。
>
> 警告
>
> 外部版本支持 值**0**作为有效的版本号。这允许版本与外部版本系统同步，其中版本号从零开始而不是从**1**开始。它的副作用是，版本号等于**0**的文档既不能使用[**Update-By-Query API**](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update-by-query.html) 更新，也不能使用[**Delete By Query API**](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-delete-by-query.html)删除，只要他们的版本号等于 0 。

一个好的作用是，不需要维护作为对源数据库的改变的结果执行的异步索引操作的严格排序，只要使用来自源数据库的版本号。即使使用外部版本控制也可以简化使用数据库中的数据更新弹性搜索索引的简单情况，因为如果索引操作因为某种原因而出现故障，将只使用最新版本。

### Version types ( 版本类型 ) <a href="#indexapiversiontypes-ban-ben-lei-xing" id="indexapiversiontypes-ban-ben-lei-xing"></a>

在上边解释的**internal** ( 内部 ) 和**external**( 外部 ) 版本类型旁边，**Elasticsearch**还支持特定用例的其他类型。这里是不同版本类型及其语义的概述。

**internal**

仅在给定版本与存储的文档的版本相同时索引文档。

**external 或 external\_gt**

如果给定版本严格高于存储的文档的版本或如果没有现有文档，则仅索引文档。给定版本将用作新版本，并与新文档一起存储。提供的版本必须是**non-negative long number**( 非负长数字 ) 。

**external\_gte**&#x20;

如果给定版本 等于 或者 高于 存储的文档的版本，则仅索引文档。如果没有现有文档，操作也将成功。给定版本将用作新版本，并与新文档一起存储。提供的版本必须是**non-negative long number**( 非负长数字 )。

注意：

&#x20;**external\_gte**版本类型适用于特殊用例，应谨慎使用。如果使用不正确，可能会导致数据丢失。还有一个选项，**force**，它也被弃用，因为它可能导致主分片和副本分片。

### Operation type ( 操作类型 )

索引操作还接受可用于强制创建操作的**op\_type**，允&#x8BB8;**"put-if-absent"**&#x884C;为。使用**create**时，如果索引中已存在该标识的文档，索引操作将失败。

下面是使用**op\_type**参数的示例：

```
curl -XPUT 'localhost:9200/twitter/tweet/1?op_type=create&pretty' -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'
```

指定**create**的另一个选项是使用以下**uri**：

```
curl -XPUT 'localhost:9200/twitter/tweet/1/_create?pretty' -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'
```

### automatic ID generation ( 自动 ID 生成 )

可以在不指定**ID**的情况下执行索引操作。在这种情况下，将自动生成**id**。此外，**op\_type**将自动设置为**create**。这里是一个例子（注意**POST**使用，而不是**PUT**）：

```
curl -XPOST 'localhost:9200/twitter/tweet/?pretty' -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'
```

上述索引操作的结果是：

```
{
    "_shards" : {
        "total" : 2,
        "failed" : 0,
        "successful" : 2
    },
    "_index" : "twitter",
    "_type" : "tweet",
    "_id" : "6a8ca01c-7896-48e9-81cc-9f70661fcb32",
    "_version" : 1,
    "created" : true,
    "result": "created"
}
```

### Routing ( 路由信息 )

默认情况下，分片**placement** ( 展示位置 )——或**routing**( 路由 ) ——通过使用文档的**id**值的哈希值来控制。对于更明确的控制，馈送到由路由使用的散列函数的值可以使用路由参数基于每个操作直接指定。例如：

```
curl -XPOST 'localhost:9200/twitter/tweet?routing=kimchy&pretty' -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'
```

在上面的示例中，**"tweet"**&#x6587;档根据提供的**routing parameter**( 路由参数 ) 发送到**shard ( 分片 ) ："kimchy"**。

设置**up explicit mapping** ( 显式映射 ) 时，可以选择使&#x7528;**\_routing**字段来指示索引操作从文档本身提取路由值。这是在额外的文档解析通过的（非常小）成本。如果定&#x4E49;**\_routing**映射并将其设置为必需，则如果未提供或提取路由值，则索引操作将失败。

### Parnets & Children

通过在索引时指定其父级，可以索引子文档。例如：

```
curl -XPUT 'localhost:9200/blogs?pretty' -H 'Content-Type: application/json' -d'
{
  "mappings": {
    "tag_parent": {},
    "blog_tag": {
      "_parent": {
        "type": "tag_parent"
      }
    }
  }
}
'
curl -XPUT 'localhost:9200/blogs/blog_tag/1122?parent=1111&pretty' -H 'Content-Type: application/json' -d'
{
    "tag" : "something"
}
'
```

对子文档建立索引时，**routing value**( 路由值 ) 会自动设置为与其父代相同，除非使用路由参数显式指定路由值。

### Distributed ( 分布式 )

索引操作基于其路由定向到**primary shard** ( 主分片 ) （参见上面的路由部分），并在包含此分片的实际节点上执行。在主分片完成操作后，如果需要，将更新分发到适用的副本。

### wait for active shards ( 等待活动分片 )

为了提高写入系统的**resiliency**( 弹性 )，索引操作可以配置为在继续操作之前等待一定数量的活动分片副本。如果所需的活动分片副本数不可用，则写操作必须等待并重试，直到必需的分片副本已启动或发生超时为止。默认情况下，写操作只等待主分片处于活动状态，然后再继续（**wait\_for\_active\_shards=1**）。可以通过设置 **index.write.wait\_for\_active\_shards**来动态地在索引设置中覆盖此默认值。要更改每个操作的此行为，可以使用 **wait\_for\_active\_shards**请求参数。

有效值是所有或任何正整数，直到索引中每个分片的配置副本的总数（即**number\_of\_replicas+1**）。指定负值或者大于分片副本数的数字将抛出错误。

例如，假设我们有一个三个节点A，B和C的集群，我们创建一个索引，索引副本数设置为 3 （导致 4 个**shard**副本，比节点多一个副本）。如果我们尝试索引操作，默认情况下，操作将仅确保每个分片的主副本在继续之前可用。这意味着，即使 B 和 C 下降，并且 A 托管主分片副本，索引操作仍然将继续只有一个数据副本。如果对请求设置 wait\_for\_active\_shards 设置为 3 （并且所有3个节点都已启动），则索引操作将在继续之前需要 3 个活动分片副本，这是应该满足的要求，因为在集群有3个活动节点，每个节点有一个碎片的副本。但是，如果我们将 **wait\_for\_active\_shards**设置为 all （或者 4， 这是相同的），索引操作将不会继续，因为索引中的每个碎片的所有的 4 个副本没有处于活动状态。该操作将超时，除非在集群中启动新节点以托管分片的第四个副本。

重要的是要注意，这个设置极大地减少了写操作不写入所需数量的分片副本的机会，但是它不能完全消除可能性，因为这种检查在写操作开始之前发生。一旦写操作正在进行，复制仍然可能在任意数量的**shard**副本上失败，但在主数据库上仍然成功。写操作响应&#x7684;**\_shard**部分显示复制成功/失败的分片副本的数量。

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

### Refresh ( 刷新 )

控制此请求所做的更改对搜索可见。请参阅[ 刷新](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-refresh.html) 。

### Noop Updates

当使用索引**API**更新文档时，即使文档没有更改，也始终创建新版本的文档。如果这不可接受，请使用将 **detect\_noop**设置为**true**&#x7684;**\_updateAPI**。此选项在索引**API**上不可用，因为索引**apidoesn’t fetch the old source**( 不提取旧源 )，并且无法将其与**new source**( 新源 ) 进行比较。

没有一个强制和快速的规则，当**noop**更新是不能接受的。它是许多因素的组合，例如数据源发送实际上是**noops**的更新的频率，以及每秒多少查询，**elasticsearch**在接收更新时在分片上运行。

## Timeout ( 超时 ) <a href="#indexapitimeout-chao-shi" id="indexapitimeout-chao-shi"></a>

执行索引操作时分配的**primary shard** ( 主分片 ) 可能不可用。这种情况的一些原因可能是主分片当前正在从**gateway** ( 网关 ) 恢复或正在进行重定位。默认情况下，索引操作将在主分片上等待最多**1**分钟，然后失败并响应错误。**timeout**参数可以用于显式指定等待时间。以下是将其设置为**5**分钟的示例：

```
curl -XPUT 'localhost:9200/twitter/tweet/1?timeout=5m&pretty' -H 'Content-Type: application/json' -d'
{
    "user" : "kimchy",
    "post_date" : "2009-11-15T14:12:12",
    "message" : "trying out Elasticsearch"
}
'
```
