ElasticStack系列之十六 ElasticSearch5.x index/create 和 update 源码分析
开篇
在ElasticSearch 系列十四中提到的问题即 ElasticStack系列之十四 & ElasticSearch5.x bulk update 中重复 id 性能骤降,继续这个问题再继续查看更加多的源代码,看看底层在执行 index、create 和 update 操作到底有什么不同,有什么可以使得我们使用性能更加好的。
准备
使用 Intellij IDEA 来阅读 ElasticSearch 源码,操作相对来说比较简单。具体操作步骤如下:
1. 下载 ElasticSearch 源码
git clone https://github.com/elastic/elasticsearch.git
2. 下载安装 gradle,确保版本在 3.3 及以上,我电脑是 macOS,自动下载最新版本为:4.2.1
brew update && brew install gradle
在 mac 上按照上面的命令执行完毕之后它会自动安装到 /usr/local/bin/gradle , 源文件目录我到现在都没有找到,最后一怒之下直接下载对应最新版本的 zip 包,放到指定目录自己执行安装
首先,先download最新版本的gradle,网址:http://www.gradle.org/get-started
然后将下载下来的zip包放在你要安装的路径上,我安装在 /usr/myname/
然后打开电脑上的.bash_profile文件,输入以下命令:
export GRADLE_HOME=/Users/myname/gradle-4.2.1export PATH=$PATH:$GRADLE_HOME/bin
然后执行命令:source ~/.bash_profile 使刚才配置生效。
3. 进入到 ElasticSearch 源码目录,在该目录下执行以下命令准备导入 IntelliJ IDEA 需要的文件
gradle idea
以上命令执行完毕之后,打开 IntelliJ IDEA 工具它会自己进行编译,需要你配置对应的 gradle home 目录,即上面指定的 /Usrs/myname/gradle-4.2.1 ,配置完毕之后项目就算导入成功了。
注意:
1. 运行这个命令需要下载很多东西,有时候可能因为某一个包卡住,不要紧张,退出重新运行该命令,多尝试几次就好了。
2. 各个版本代码上有一定的差别,但是核心代码整体是不会有大改动的,我查看的源码版本为当前最新版本:5.6.3
Index/Create 源码分析
es index 和 create 最终都会调用 org/elasticsearch/index/engine/InternalEngine.java 中下面的方法:
public IndexResult index(Index index) throws IOException
注意这里的 index 中包含有要写入的 doc, 简单画下该方法的执行流程图,代码这里就不贴了
请结合上面的流程图来看相应的代码,整个逻辑应该还是很清晰的,接下来我们看 planIndexingAsPrimary 的逻辑。
private IndexingStrategy planIndexingAsPrimary(Index index) throws IOException
这个方法最终返回一个 IndexingStrategy,即一个索引的策略,总共有如下几个策略:
- optimizedAppendOnly
- skipDueToVersionConflict
- processNormally
- overrideExistingAsIfNotThere
- skipAsStale
不同的策略对应了不同的处理逻辑,前面3个是常用的,我们来看下流程图。
这里的第一步判断:是否是自定义 doc id? 这一步就是 es 对于日志类非自定义 doc id 的优化,感兴趣的可以自己去看下代码,简单讲就是在非自定义 id 的情况下,直接将文档 add ,否则需要 update,而 update 比 add 成本高很多。
而第二个判断:检查版本号是否冲突? 涉及到是如何根据 文档版本号(doc version) 来确认文档可写入,代码都在 index.versionType().isVersionConflictForWrites 方法里,逻辑也比较简单,不展开讲了,感兴趣的自己去看吧。
上面的流程图也比较清晰地列出了策略选择的逻辑,除去 optimizedAppendOnly 策略,其他都需要根据待写入文档的版本号来做出决策。接下来我们就看下获取文档版本号的方法。
private VersionValue resolveDocVersion(final Operation op) throws IOException
该方法逻辑比较简单,主要分为2步:
- 尝试从 versionMap 中读取待写入文档的 version,也即从内存中读取。versionMap 会暂存还没有 commit 到磁盘的文档版本信息。
- 如果第 1 步中没有读到,则从 index 中读取,也即从文件中读取。
看到这里,开篇问题便有了答案。es 在 index 或者 create 的时候并不会 get 整个文档,而是只会获取文档的版本号做对比,而这个开销不会很大。
Update 源码分析
es update 的核心代码在 org/elasticsearch/action/update/UpdateHelper.java 中,具体方法如下:
public Result prepare(UpdateRequest request, IndexShard indexShard, LongSupplier nowInMillis) {final GetResult getResult = indexShard.getService().get(request.type(), request.id(),new String[]{RoutingFieldMapper.NAME, ParentFieldMapper.NAME},true, request.version(), request.versionType(), FetchSourceContext.FETCH_SOURCE);return prepare(indexShard.shardId(), request, getResult, nowInMillis); }
代码逻辑很清晰,分两步走:
- 获取待更新文档的数据
- 执行更新文档的操作
第 1 步最终会调用 InternalEngine 中的 get 方法,如下:
public GetResult get(Get get, Function<String, Searcher> searcherFactory, LongConsumer onRefresh) throws EngineExceptio
update 操作需要先获取原始文档的原因也很简单,因为这里是允许用户做部分更新的,而 es 底层每次更新时要求必须是完整的文档(因为 lucene 的更新实际是删除老文档,新增新文档),如果不拿到原始数据的话,就不能组装出更新后的完整文档了。
因此,比较看重效率的业务,最好还是不要用 update 这种操作,直接用上面的 index 会更好一些。
总结
本文通过源码分析的方式解决了开篇提到的问题,答案简单总结在下面。
es 在 index 和 create 操作的时候,如果没有自定义 doc id,那么会使用 append 优化模式,否则会获取待写入文档的版本号(doc version),进行版本检查后再决定是否写入 lucene。所以这里不会去做一个 get 操作,即获取完整的文档信息。
转载于:https://www.cnblogs.com/liang1101/p/7661810.html
ElasticStack系列之十六 ElasticSearch5.x index/create 和 update 源码分析相关推荐
- 【vue-router源码】十二、useRoute、useRouter、useLink源码分析
[vue-rouer源码]系列文章 [vue-router源码]一.router.install解析 [vue-router源码]二.createWebHistory.createWebHashHis ...
- Java Collection系列之HashMap、ConcurrentHashMap、LinkedHashMap的使用及源码分析
文章目录 HashMap HashMap的存储结构 初始化 put & get put元素 get元素 扩容 遍历Map jdk1.8中的优化 ConcurrentHashMap jdk1.7 ...
- 深入理解Spark 2.1 Core (十二):TimSort 的原理与源码分析
在博文<深入理解Spark 2.1 Core (十):Shuffle Map 端的原理与源码分析 >中我们提到了: 使用Sort等对数据进行排序,其中用到了TimSort 这篇博文我们就来 ...
- 并发编程(十六)——java7 深入并发包 ConcurrentHashMap 源码解析
以前写过介绍HashMap的文章,文中提到过HashMap在put的时候,插入的元素超过了容量(由负载因子决定)的范围就会触发扩容操作,就是rehash,这个会重新将原数组的内容重新hash到新的扩容 ...
- 人为什么活着系列之十六:具体的人具体的环境具体分析
非常感谢阿懒-上海-PM分享! 今天下午抽空粗略地读完了十五贴 人为什么活着?依坛上前十五贴中的一贴有分两个问题来回答,以下是个人观点: 一是:人为什么活着? 为什么? 我的回答是:没有为什么.人的出 ...
- spring boot实战(第六篇)加载application资源文件源码分析
前言 在上一篇中了解了spring配置资源的加载过程,本篇在此基础上学习spring boot如何默认加载application.xml等文件信息的. ConfigFileApplicationLis ...
- Spring 源码分析衍生篇十 :Last-Modified 缓存机制
文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...
- Java源码详解六:ConcurrentHashMap源码分析--openjdk java 11源码
文章目录 注释 类的继承与实现 数据的存储 构造函数 哈希 put get 扩容 本系列是Java详解,专栏地址:Java源码分析 ConcurrentHashMap 官方文档:ConcurrentH ...
- jQuery源码分析系列
声明:本文为原创文章,如需转载,请注明来源并保留原文链接Aaron,谢谢! 版本截止到2013.8.24 jQuery官方发布最新的的2.0.3为准 附上每一章的源码注释分析 :https://git ...
最新文章
- 小程序网络最大并发限制解决思路
- linux无法联网使用yum提示cannot find a valid baseurl for repobase7x86_64
- 数据库更新记录,但程序查不到新记录问题
- python打包安卓的方法_30个你想打包带走的Python技巧(下)
- 前端学习(221):字体属性
- Luogu P3975 [TJOI2015]弦论
- LeetCode 2206. 将数组划分成相等数对
- LeetCode OJ:Pascal's Triangle(帕斯卡三角)
- 华为商城抢手机软件_华为p40配置详细参数
- 远程登录工具 —— filezilla(FTP vs. SFTP)、xshell、secureCRT
- Shp数据批量导入Postgresql工具的原理和设计
- ElementUI:el-container实现高度占满
- 快易准粤语拼音输入法 绿色
- iOS证书(p12)获取解密公私钥
- oracle重建inventory,Oracle中Inventory目录作用以及如何重建此目录-Oracle
- Giving an effective oral presentation at university(The Hong Kong Polytechnic University 香港理工大学)
- Oracle项目管理系统之设计任务下达及成果交付
- H3C服务器带外默认账号和密码,H3C产品的默认密码是多少?
- 广告坑死人,这年头如何辨别互联网金融的可靠性?
- 使用WASAPI捕获声卡音频