被用来确保并发更新时变更不会丢失:
悲观并发控制
悲观并发控制一般锁住当前被操作的资源。
乐观并发控制
Elasticsearch 中使用的这种方法假定冲突是不可能发生的,并且不会阻塞正在尝试的操作。 然而,如果源数据在读写当中被修改,更新将会失败。应用程序接下来将决定该如何解决冲突。 例如,可以重试更新、使用新的数据、或者将相关情况报告给用户。Elasticsearch 是分布式的,当创建和更新文档的时候,如果你是多个node,并且还有replication备份数据,这中间就会有时间差存在,并且还会存在检索-修改-重建索引间隔。或者说并发更新发生的时候,所获取并在处理中的数据,可能已经被其他请求更新掉,这就导致数据的过期,结果就是覆盖更新,过期数据覆盖新数据。在ES中 我们解决此问题的方式就是利用更新中指定_version版本号来确保相互冲突的更新不会丢失。所有文档的更新或删除 API,都可以接受 version 参数,比如:
PUT /website/blog/1?version=1
过指定了version,如果请求到达ES后,该条数据version已经不是1了,这时就会更新失败并返回409 Conflict响应码。之后应该怎么处理,就取决于你的场景了,正如上面所说的可以重试更新、使用新的数据、或者将相关情况报告给用户。另外一种方式是使用外部版本号,而非ES内置自增的版本号。外部的版本号源于你自己的系统控制,比如更新一条ES文档,指定使用外部版本号为5:
PUT /website/blog/2?version=5&version_type=external
为了并发控制,下一次你的请求给到了version为10,如果你的请求version小于等于上面的5则会更新失败,像前面提到的409一样,只有新version大于ES文档已有version,更新才会成功。
PUT /website/blog/2?version=10&version_type=external
ES文档是不可变的,即使是在部分更新情况下。比如:
POST /website/blog/1/_update { "doc" : { "tags" : [ "testing" ], "views": 0 } } //其将会覆盖现有字段,增加新字段。被称为Update API
部分更新的时候,如果被更新的文档还不存在,这时应该使用upsert参数
POST /website/pageviews/1/_update { "script" : "ctx._source.views+=1", "upsert": { "views": 1 } }
如果你某个场景中经常会出现所更新文档不存在的情况下,那么使用它是明智之选,该方式会在文档存在的时候,直接执行更新脚本将值应用,不存在的时候,则执行upsert.
ES update API还提供了retry_on_conflict参数,指示了返回失败之前,要重试多少次。
POST /website/pageviews/1/_update?retry_on_conflict=5
update API和前面index API所提到的乐观并发控制一样,也支持制定version参数来控制冲突。
ES提供了mget API (multi-get),可以减少网络传输时间等,比如:
GET /_mget { "docs" : [ { "_index" : "website", "_type" : "blog", "_id" : 2 }, { "_index" : "website", "_type" : "pageviews", "_id" : 1, "_source": "views" } ] }
可以看到这段代码中index和type 实在docs数组的item项中。所得到的响应数组中,每个item和使用单个get拿到的结果是一样的。
如果想检索的数据都在相同的 _index 中(甚至相同的 _type 中),则可以在 URL 中指定默认的 /_index或者默认的 /_index/_type 。
你仍然可以通过单独请求覆盖这些值:
GET /website/blog/_mget { "docs" : [ { "_id" : 2 }, { "_type" : "pageviews", "_id" : 1 } ] }
事实上,如果所有文档的 _index 和 _type 都是相同的,你可以只传一个 ids 数组,而不是整个 docs 数组:
GET /website/blog/_mget { "ids" : [ "2", "1" ] }
如果数组中某个寻找目标未找到结果,则响应数组中,其他值正常,未找到的found字段则为false "found" : false,并不妨碍其他文档。所以在应用中,应该检查的不是200还是404,而是found字段标记。
既然提供了mget, 同时bulk API也提供了单个步骤进行多次create index, update和delete请求。
POST /_bulk {
"delete": { "_index": "website", "_type": "blog", "_id": "123" }}
{ "create": { "_index": "website", "_type": "blog", "_id": "123" }} { "title": "My first blog post" }
{ "index": { "_index": "website", "_type": "blog" }} { "title": "My second blog post" }
{ "update": { "_index": "website", "_type": "blog", "_id&quo