文章目录

  • 1.什么是partial update
    • 1.1 全量修改文档的原理
    • 1.2 修改指定field的思路
    • 1.3 partial update的优势
    • 1.4 partial update的使用
  • 2 通过脚本进行partial update操作
    • 2.1 内置painless脚本修改文档
    • 2.2 外置Groovy脚本修改文档
    • 2.3 内置painless脚本upsert文档
    • 2.4 外置Groovy脚本delete文档
  • 3 partial update的并发控制策略
    • 3.1 控制方式
    • 3.2 retry原理


转载: ES 26 - Elasticsearch如何部分更新文档 (partial update的使用)

1.什么是partial update

1.1 全量修改文档的原理

全量修改文档的语法: PUT index/type/1, 如果id=1的文档不存在, 则创建, 如果存在, 将发生替换原有文档的操作.

全量替换文档的性能比较低, 为了避免替换操作的发生, 引入partial update: 只修改指定的field, 不用全量修改数据.

1.2 修改指定field的思路

(1) 根据用户请求, 获得要修改的文档;

(2) 在内存中封装用户提交的新文档, 发送PUT请求到ES内部;

(3) 将要替换的旧文档标记为deleted;

(4) 最后将封装好的新文档存入索引中.

1.3 partial update的优势

(1) 所有的查询、修改和写回操作, 都在同一个shard中进行, 避免了网络传输的开销.

不需要: 从特定shard查询文档 -> 返回到内存 -> 内存中修改 -> 将修改的文档发送到原来的shard -> 写索引 —— 这个复杂的操作, 显著提升了性能.

(2) 减少了查询和修改的时间间隔, 可以有效减少并发冲突.

1.4 partial update的使用

使用方法: 通过_update关键字实现增量更新:

// 添加测试数据:
PUT employee/developer/1
{"name": "shou feng", "sex": "male","age": 20
}// partial update修改指定field:
POST employee/developer/1/_update
{"doc": {"age": 21}
}// 响应结果:
{"_index": "employee","_type": "developer","_id": "1","_version": 2,"result": "updated","_shards": {"total": 2,"successful": 1,"failed": 0}
}// 查看文档, 发现age已经从20变为21了.
GET employee/developer/1

如果不使用_update, 则会直接覆盖掉源文档, 导致原文档丢失部分数据:

// 不使用_update:
POST employee/developer/1
{"doc": {"age": 22}
}// 再次查看, 发现id=1的该文档就只剩一个age字段了:
GET employee/developer/1

2 通过脚本进行partial update操作

ES提供了脚本支持 —— 可以通过Groovy外置脚本(已过时)、内置painless脚本实现各种复杂操作.

2.1 内置painless脚本修改文档

插入文档:

PUT employee/developer/1
{"name": "shou feng", "age": 20,"salary": 10000
}

执行脚本: —— 这里使用的是更轻快简短的painless脚本, 就是直接由字符串表示的脚本:

POST employee/developer/1/_update    // 发送POST请求, 执行partial update
{"script": "ctx._source.salary+=500"    // 为salary自增500
}

查看修改结果:

GET employee/developer/1// 结果如下:
{"_index": "employee","_type": "developer","_id": "1","_version": 5,"found": true,"_source": {"name": "shou feng","age": 20,"salary": 10500           // 自增500成功}
}

2.2 外置Groovy脚本修改文档

说明: 在ES 6.x版本之后, groovy脚本不再支持, 这里演示所用的是ES 5.6.10版本, 如果在6.x版本中使用, 将会抛出如下异常:

"type": "illegal_argument_exception",
"reason": "script_lang not supported [groovy]"

将脚本文件存放在${ES_HOME}/config/scripts下, 文件名为xxx.groovy, 内容为:

ctx._source.salary+=bonus —— 增加值为将近bonus的值, 脚本信息示例如下:

[root@localhost scripts]# pwd
/data/elk-5.6.10/es-node/config/scripts
[root@localhost scripts]# cat change_salary.groovy
ctx._source.salary+=bonus
[root@localhost scripts]#

修改文档:

POST employee/developer/1/_update
{"script": {"lang": "groovy", "file": "change_salary","params": {"bonus": 500}}
}// 响应结果为:
#! Deprecation: [groovy] scripts are deprecated, use [painless] scripts instead
{"_index": "employee","_type": "developer","_id": "1","_version": 6,"result": "updated","_shards": {"total": 2,"successful": 1,"failed": 0}
}

查看修改结果:

GET employee/developer/1
// 结果如下:
{"_index": "employee","_type": "developer","_id": "1","_version": 6,"found": true,"_source": {"name": "shou feng","age": 20,"salary": 9000}
}

说明:
在执行外置Groovy脚本时, ES提示Groovy脚本已经过时, 建议我们使用painless —— 更轻快的表达方式, 即类似于ctx._source.salary+=bonus的简短表达方式.
Elasticsearch 5.6开始, 默认脚本使用的方式就已经是painless了. 关于脚本的详细使用, 请查看博文: ES 27 - Elasticsearch的painless脚本使用实践.

2.3 内置painless脚本upsert文档

(先删除id=1的文档: DELETE employee/developer/1) 假设我们并不知道id=1的文档已经被删除了, 现在为其添加"level": 1的内容:

POST employee/developer/1/_update
{"doc": {"level": 1}
}

抛出 [404 - 文档丢失] 的错误:

{"error": {"root_cause": [{"type": "document_missing_exception","reason": "[developer][1]: document missing","index_uuid": "rT6tChP2QISaVd2OzdCEMA","shard": "3","index": "employee"}],"type": "document_missing_exception","reason": "[developer][1]: document missing","index_uuid": "rT6tChP2QISaVd2OzdCEMA","shard": "3","index": "employee"},"status": 404
}

修改upsert策略: 如果指定的文档不存在, 就执行upsert中的初始化操作; 如果存在, 就执行doc或script中的partial update操作:

POST employee/developer/1/_update
{"script": "ctx.source.level+=1","upsert": {"name": "heal","age": 20}
}

此时发现"result" : “created” —— 新建了文档.

2.4 外置Groovy脚本delete文档

说明: 这里演示所用的是ES 5.6.10版本.
脚本路径: ${ES_HOME}/config/scripts/delete_doc.groovy
脚本内容: ctx.op = ctx._source.age == age ? 'delete': 'none' ctx.op = ctx._source.age == param ? 'delete' : 'none'

使用示例:

POST employee/developer/1/_update
{"script": {"lang": "groovy", "file": "delete_doc","params": {"age": 20   // 如果年龄是20, 则删除之}}
}

响应结果:

#! Deprecation: [groovy] scripts are deprecated, use [painless] scripts instead
{"_index": "employee","_type": "developer","_id": "1","_version": 13,"result": "deleted","_shards": {"total": 2,"successful": 1,"failed": 0}
}

查看文档是否被删除:

GET employee/developer/1
// 响应结果 - 成功删除:
{"_index": "employee","_type": "developer","_id": "1","found": false
}

3 partial update的并发控制策略

partial update内部也是通过乐观锁进行并发控制的.
关于并发控制, 请参见博文: Elasticsearch的并发控制策略.

3.1 控制方式

POST index/type/id/_update?retry_on_conflict=5
POST index/type/id/_update?retry_on_conflict=5&version=5

3.2 retry原理

retry_on_conflict: 发生冲突后的重试次数.

(1) 客户端A、B几乎同时获取同一个文档, 一并获得_version版本信息, 假设此时_version=1;

(2) 客户端A修改文档中的部分内容, 将修改写入索引;

(3) Elasticsearch在写入索引时, 检查客户端A提交的文档的版本信息(这里仍然是1) 和 现存的文档的版本信息(这里也是1), 发现相同后, 执行写入操作, 并修改版本号_version=2;

(4) 客户端B也修改文档中的部分内容, 其操作写回索引的速度稍慢. 此时同样执行过程(3): ES发现客户端B提交的文档的版本为1, 而现存文档的版本为2 ===> 发生冲突, 此次partial update将失败;

(5) partial update操作失败后, 将重复(1) - (3) 过程, 重复的次数, 就是retry_on_conflict参数的值.

【elasticsearch】如何部分更新文档 (partial update的使用)相关推荐

  1. Elasticsearch如何创建索引,添加,删除,更新文档

    文章目录 准备工作 检查 es 及 Kibana 是否运行正常 创建索引及文档 创建文档相关知识点 mulit-field 字段 关于两个type的解释 关于两个keyword的解释 mulit-fi ...

  2. 开始使用Elasticsearch (1): 如何创建index,添加、删除、更新文档

    本文内容来自 https://blog.csdn.net/UbuntuTouch/article/details/99481016 ,有删减和文字修正. 在开始使用ES之前, 请安装好ES & ...

  3. php elasticsearch更新文档

    部分更新 如果你要部分更新文档(如更改现存字段,或添加新字段),你可以在 body 参数中指定一个 doc 参数.这样 doc 参数内的字段会与现存字段进行合并. $params = ['index' ...

  4. Elasticsearch 为什么会产生文档版本冲突?如何避免?

    1.Elasticsearch 版本冲突复现 先让大家直观的看到 Elasticsearch 文档版本冲突. 1.1 场景1:create 场景 DELETE my-index-000001 # 执行 ...

  5. Elastic Search创建文档和更新文档

    Elastic Search创建文档和更新文档(Put && Update) 在平时的es中需要对文档创建或者更新,通常情况下有2种api实现,举例如下: 第1种:PUT /testi ...

  6. php solr 更新数据类型,Solr更新文档数据

    使用XML更新文档 以下是用于更新现有文档中的字段的XML文件.将下面的内容保存在名称为update.xml的文件中. 001 Raj Malhotra 9000000000 Delhi 正如上面看到 ...

  7. ElasticSearch修改和删除文档

    ElasticSearch修改和删除文档 修改文档方式一:使用prepareUpdate,prepareIndex两者选其一皆可 client.prepareUpdate("blog2&qu ...

  8. Facebook 游戏开发更新文档 API 参考文档 v6.0

    Facebook 游戏开发更新文档 API 参考文档 v6.0 更新日志 1.排行榜 此版本全新推出排行榜 API!提供一套强大的 API, 使得游戏可获取排行榜.查询得分 情况和设置新分数(支持分数 ...

  9. 如何在Mongoose中更新/更新文档?

    本文翻译自:How do I update/upsert a document in Mongoose? Perhaps it's the time, perhaps it's me drowning ...

最新文章

  1. 详细讲解np.cumsum()
  2. Windows下安装Zabbix agent
  3. angular2.0学习日记1
  4. maven设置jdk版本
  5. 解决高版本SpringBoot整合swagger时启动报错:Failed to start bean ‘documentationPluginsBootstrapper‘ 问题
  6. JavaScript浮点运算0.2+0.1 !== 0.3
  7. mysql 导入日期 0000_解决Excel导入MySQL日期为0000-00-00
  8. layui 加载第三方插件
  9. RabbitMQ(六) Routing路由模式
  10. 数据科学 IPython 笔记本 9.5 NumPy 数组上的计算:通用函数
  11. AppServ 介绍
  12. AAtitit 项目管理 提升开发效率的项目流程方法模型 哑铃型  橄榄型 直板型titi
  13. ① 数据库介绍 及 关系型数据库的关系代数表达式
  14. codevs 1044 拦截导弹
  15. elk笔记25--快速体验APM
  16. RPG游戏制作-03-人物行走及A*寻路算法
  17. java 创建用户界面_建立图形用户界面 JAVA实验
  18. 周测作业五(apache的安装与配置)
  19. VB编程:UBound获取数组上限;LBound获取数组下限-25_彭世瑜_新浪博客
  20. ATmega16智能遥控小车

热门文章

  1. 荣耀50 Pro+配置参数曝光:AMOLED高刷屏+骁龙888旗舰芯片
  2. 一波三折,这些离国出走的品牌又回来了!
  3. 最狠的钉子户手机!最后一款已战斗5年,还能继续...
  4. 滴滴上线特快和特惠:极端天气绝不动态加价
  5. 交钱赎“人”!B站500万粉UP主被黑客勒索,腾讯都表示无解
  6. 美团联合创始人王慧文卸任摩拜高管职位
  7. 一加7T Pro渲染图曝光:后置相机出乎意料
  8. 魅族16s Pro跑分曝光:高通骁龙855 Plus+UFS 3.0闪存
  9. 拳王虚拟项目公社:闲鱼知乎引流售卖虚拟资源的虚拟兼职副业项目实操
  10. MiniGUI编程--列表框