标签:style blog class code c java
就像在Updating
a whole
document中所说的一样,更新document的步骤就是检索——修改——插入整个document。然而使用update,就能局部更新,就像在一个请求里增加一个计数器一样。
以前说过document是不可变的——不能被修改,只能被替换,update也必须遵守这个规则。在外部看来是局部更新的,在内部,update依然执行了检索——修改——重新插入这个流程。不同的是这个过程是发生在shard中,因此避免了多次网络请求的开销,通过减少检索和重新插入的时间,降低了来自于其他线程的访问导致的数据冲突的可能性。
最简单的update格式就是请求体中接受部分的document作为“doc"的参数。这个参数的值会和已经存在的document合并,已经存在的field将会被重写,新的field将会被添加,例如,增加一个tags字段和一个views字段到blog中:
POST /website/blog/1/_update
{
"doc":{
"tags":["testing"],
"views":0
}
}
如果成功将会相应如下数据:
{
"_index": "website",
"_id": "1",
"_type": "blog",
"_version":3
}
检索这个document,注意一下_source字段:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 3,
"found": true,
"_source":{
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"tags":["testing"],
"views": 0
}
}
标注1和2表示就是局部更新的内容。
使用script进行局部更新。我们会在 Scripting – when you need more (TODO)更详细的介绍script,但是现在来说我们已经足够了解script在ES中的几个合适的用武之地,已满足某些不被API直接支持的但是用户需要的动作。默认的script语言是MVEL,但是ES也是支持JavaScript,Groovy和Python的。MVEL是简单的,快速的,基于jiava的动态脚本语言,语法类似于JavaScript。你可以在 Elasticsearch scripting docs和MVEL website了解更过关于MVEL的内容。
script能用作update API,用来修改_source的内容,这被称为一个更新的脚本ctx._source。例如,可以使用script增加这个views的数目:
POST /website/blog/1/_update
{
"script":"ctx._source.views+=1"
}
我们也能使用script给tags数组增加一个元素,在这个例子中我们指定新的tag作为参数而不是在scritp中硬编码。这个方式允许ES在以后可以重用这个参数,并且不需要每次从新编译这个script:
POST /website/blog/1/_update
{
"script":"ctx._source.tags+=new_tag",
"params":{
"new_tag":"search"
}
}
最后两个的请求相应如下:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 5,
"found": true,
"_source":{
"title": "My first blog entry",
"text": "Starting to get the hang of this...",
"tags": ["testing","search"],
"views": 1
}
}
标记1表示search这个元素已经追加到tags的数组中。
标记2表示views的数量已经增加了。
通过设置ctx.op为delete,我们甚至能通过script删除一个document。
POST /website/blog/1/_update
{
"script":"ctx.op = ctx._source.views == count ? ‘delete‘ : ‘none‘",
"params":{
"count":1
}
}
注:以上执行在curl下失败,在head中成功。
更新一个或许不存在的document
如果我们需要在ES中存储一个页面访问量的计数器conter,每次用户访问这个页面,我们都对这个页面增加一个数,但是增加这个counter之前要确定这个counter是已经存在的哦。如果要更新一个不存在的document,update将会出错。
可以使用upsert参数来解决这个问题,如果指定的document不存在,就创建一个:
POST /website/pageviews/1/_update
{
"script":"ctx._source.views+=1",
"upsert":{
"views":1
}
}
首次执行这个请求,这个upsert数值做为一个新的document被插入,被初始化为1。接下来的执行将会对views直接增加1。
更新和冲突
在本章节的说明部分,在检索和重新插入的间隔越小,冲突的机会就越小,但并不是完全没有冲突。依然有可能一个线程在另外一个线程执行update之前执行了reindex的动作。
为了防止这个事情的发生,updateAPI在执行检索的时候会检查记录document的_version的数量,并且在执行重新插入之间把_version传递给其他线程的index的请求。如果另外的线程在检索——重新插入之间修改了document,这个_version就不会和update记录的_version匹配导致update失败。
对于很多情况下的局部update来说,update并不关心一个document是否已经被修改,例如,两个线程同时增加页面的访问数量,以什么样的顺序发生update都是无所谓的——即使冲突发生了,唯一要做的事情就是重新执行update就行了。如果你在请求时候设置了retry_on_conflict参数并设定重复执行的次数(默认是0),这个重新执行就会自动进行:
POST /website/pageviews/1/_update?retry_on_conflict=5
{
"script":"ctx._source.views+=1",
"upsert":{
"views":0
}
}
标记1表示在成功更新之前尝试五次update。
这个设置对不强调顺序的多个线程无序的增加也个页面访问数量的值是很有效的,但是有另外的情况,就是更新的次序很重要。像index API,update API就默认采用了”last-write-wins“这个办法,但是也能采用version参数,这个参数允许你使用 optimistic concurrency control 指定你要更新的document的version。
原文:http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/partial-updates.html
局部更新document(partial updates to documents),布布扣,bubuko.com
局部更新document(partial updates to documents)
标签:style blog class code c java
原文地址:http://www.cnblogs.com/blog1350995917/p/3732180.html