乐观并发控制编辑

Elasticsearch 是分布式的。当创建、更新或删除文档时,新版本的文档必须复制到集群中的其他节点。Elasticsearch 也是异步和并发的,这意味着这些复制请求是并行发送的,并且可能以不同的顺序到达目的地。Elasticsearch 需要一种方法来确保旧版本的文档永远不会覆盖新版本。

为了确保旧版本的文档不会覆盖新版本,对文档执行的每个操作都会由协调该更改的主分片分配一个序列号。序列号随着每次操作而增加,因此较新的操作保证具有比较旧操作更高的序列号。然后,Elasticsearch 可以使用操作的序列号来确保较新的文档版本永远不会被分配了较小序列号的更改覆盖。

例如,以下索引命令将创建一个文档并为其分配初始序列号和主项

response = client.index(
  index: 'products',
  id: 1567,
  body: {
    product: 'r2d2',
    details: 'A resourceful astromech droid'
  }
)
puts response
PUT products/_doc/1567
{
  "product" : "r2d2",
  "details" : "A resourceful astromech droid"
}

您可以在响应的 _seq_no_primary_term 字段中看到分配的序列号和主项

{
  "_shards": {
    "total": 2,
    "failed": 0,
    "successful": 1
  },
  "_index": "products",
  "_id": "1567",
  "_version": 1,
  "_seq_no": 362,
  "_primary_term": 2,
  "result": "created"
}

Elasticsearch 会跟踪它存储的每个文档的最后一次更改操作的序列号和主项。序列号和主项在 GET API 响应的 _seq_no_primary_term 字段中返回

response = client.get(
  index: 'products',
  id: 1567
)
puts response
GET products/_doc/1567

返回

{
  "_index": "products",
  "_id": "1567",
  "_version": 1,
  "_seq_no": 362,
  "_primary_term": 2,
  "found": true,
  "_source": {
    "product": "r2d2",
    "details": "A resourceful astromech droid"
  }
}

注意:Search API 可以通过设置 seq_no_primary_term 参数 为每个搜索命中返回 _seq_no_primary_term

序列号和主项唯一地标识更改。通过记下返回的序列号和主项,您可以确保仅在自检索文档以来没有对它进行其他更改时才更改文档。这是通过设置 index APIupdate APIdelete APIif_seq_noif_primary_term 参数来完成的。

例如,以下索引调用将确保在不丢失对描述的任何潜在更改或另一个 API 添加的另一个标签的情况下,将标签添加到文档中

PUT products/_doc/1567?if_seq_no=362&if_primary_term=2
{
  "product": "r2d2",
  "details": "A resourceful astromech droid",
  "tags": [ "droid" ]
}