乐观并发控制

编辑

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

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

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

resp = client.index(
    index="products",
    id="1567",
    document={
        "product": "r2d2",
        "details": "A resourceful astromech droid"
    },
)
print(resp)
response = client.index(
  index: 'products',
  id: 1567,
  body: {
    product: 'r2d2',
    details: 'A resourceful astromech droid'
  }
)
puts response
const response = await client.index({
  index: "products",
  id: 1567,
  document: {
    product: "r2d2",
    details: "A resourceful astromech droid",
  },
});
console.log(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 字段中返回

resp = client.get(
    index="products",
    id="1567",
)
print(resp)
response = client.get(
  index: 'products',
  id: 1567
)
puts response
const response = await client.get({
  index: "products",
  id: 1567,
});
console.log(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"
  }
}

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

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

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

resp = client.index(
    index="products",
    id="1567",
    if_seq_no="362",
    if_primary_term="2",
    document={
        "product": "r2d2",
        "details": "A resourceful astromech droid",
        "tags": [
            "droid"
        ]
    },
)
print(resp)
const response = await client.index({
  index: "products",
  id: 1567,
  if_seq_no: 362,
  if_primary_term: 2,
  document: {
    product: "r2d2",
    details: "A resourceful astromech droid",
    tags: ["droid"],
  },
});
console.log(response);
PUT products/_doc/1567?if_seq_no=362&if_primary_term=2
{
  "product": "r2d2",
  "details": "A resourceful astromech droid",
  "tags": [ "droid" ]
}