
社区日报 第62期 (2017-09-29)
http://t.cn/RInoI4c
2、ElasticSearch的实时日志系统架构与总结。
http://t.cn/RaX2lMm
3、你早该知道的Elasticsearch性能指标!
http://t.cn/R0Nn3KK
4、P2P领域ES实战经验分享!
http://t.cn/R0NmyhU
编辑:laoyang360
归档:https://www.elasticsearch.cn/article/302
订阅:https://tinyletter.com/elastic-daily
http://t.cn/RInoI4c
2、ElasticSearch的实时日志系统架构与总结。
http://t.cn/RaX2lMm
3、你早该知道的Elasticsearch性能指标!
http://t.cn/R0Nn3KK
4、P2P领域ES实战经验分享!
http://t.cn/R0NmyhU
编辑:laoyang360
归档:https://www.elasticsearch.cn/article/302
订阅:https://tinyletter.com/elastic-daily
收起阅读 »



社区日报 第61期 (2017-09-28)
2.详解Elasticsearch的nested类型aggregations? http://t.cn/R0Nk3EA
3.社区热议:elasticsearch的中文打分到底是怎样的呢? https://elasticsearch.cn/question/2275
编辑:金桥
归档:https://elasticsearch.cn/article/299
订阅:https://tinyletter.com/elastic-daily
2.详解Elasticsearch的nested类型aggregations? http://t.cn/R0Nk3EA
3.社区热议:elasticsearch的中文打分到底是怎样的呢? https://elasticsearch.cn/question/2275
编辑:金桥
归档:https://elasticsearch.cn/article/299
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

社区日报 第60期 (2017-09-27)
http://t.cn/R0SZfFx
2. 利用Elasticsearch、Beats、Logstash、Grafana完成API实时监控(需要翻墙)
http://t.cn/R0SZo52
3. 小众SKD Elasticsearch的Lua客户端(Github)
http://t.cn/RLZkGbS
滴滴招聘:
https://elasticsearch.cn/article/296
编辑:江水
归档:https://elasticsearch.cn/article/298
订阅:https://tinyletter.com/elastic-daily
http://t.cn/R0SZfFx
2. 利用Elasticsearch、Beats、Logstash、Grafana完成API实时监控(需要翻墙)
http://t.cn/R0SZo52
3. 小众SKD Elasticsearch的Lua客户端(Github)
http://t.cn/RLZkGbS
滴滴招聘:
https://elasticsearch.cn/article/296
编辑:江水
归档:https://elasticsearch.cn/article/298
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

【滴滴招聘】ES技术专家
薪资待遇:25k ~ 50k
工作挑战:
PB级数据的检索平台,峰值千万条数据的实时写入,1000+ES节点,数百个线上应用场景的支撑。
工作职责:
1. 独立完成中大型项目的系统分析、设计,并能够完成核心代码的编写,确保技术方案能够按计划要求,高质量的完成;
2. 具有一定的技术架构思维,确保设计的技术方案、开发的代码有较高性能、质量保障、扩展性,前瞻性;
3. 对技术有较强的钻研及学习精神,能够深入了解开源技术、现有系统技术等相关技术原理,出现问题时能够通过较强的技术手段较好的解决问题;
岗位要求:
1. JAVA基础扎实,理解io、多线程、集合等基础框架,对JVM原理有一定的了解;
2. 3年及以上使用JAVA开发的经验,对于用过的开源框架,能了解到它的原理和机制;
3. 对spring,mybatis,kafka,spark,elasticsearch等开源框架熟悉者优先;
4. 熟悉分布式系统的设计和应用,能对分布式常用技术进行合理应用,解决问题;
5. 掌握多线程及高性能的设计与编码及性能调优;有高并发应用开发经验优先;
6. 学习能力强,适应能力好;具备耐心/细心的品质;
7. 我们希望你喜欢去看及尝试最新的技术,追求编写优雅的代码,从技术趋势和思路上能影响技术团队
简历投递:weizijun@didichuxing.com
薪资待遇:25k ~ 50k
工作挑战:
PB级数据的检索平台,峰值千万条数据的实时写入,1000+ES节点,数百个线上应用场景的支撑。
工作职责:
1. 独立完成中大型项目的系统分析、设计,并能够完成核心代码的编写,确保技术方案能够按计划要求,高质量的完成;
2. 具有一定的技术架构思维,确保设计的技术方案、开发的代码有较高性能、质量保障、扩展性,前瞻性;
3. 对技术有较强的钻研及学习精神,能够深入了解开源技术、现有系统技术等相关技术原理,出现问题时能够通过较强的技术手段较好的解决问题;
岗位要求:
1. JAVA基础扎实,理解io、多线程、集合等基础框架,对JVM原理有一定的了解;
2. 3年及以上使用JAVA开发的经验,对于用过的开源框架,能了解到它的原理和机制;
3. 对spring,mybatis,kafka,spark,elasticsearch等开源框架熟悉者优先;
4. 熟悉分布式系统的设计和应用,能对分布式常用技术进行合理应用,解决问题;
5. 掌握多线程及高性能的设计与编码及性能调优;有高并发应用开发经验优先;
6. 学习能力强,适应能力好;具备耐心/细心的品质;
7. 我们希望你喜欢去看及尝试最新的技术,追求编写优雅的代码,从技术趋势和思路上能影响技术团队
简历投递:weizijun@didichuxing.com
收起阅读 »

社区日报 第59期 (2017-09-26)
http://t.cn/R0fAJwK
2.ELK实战 - 利用Nginx日志分析API耗时。
http://t.cn/R6sgQfU
3.Kibana中的地区分布图和仪表盘工具,强大而又实用。
http://t.cn/Rpry9fv
编辑:叮咚光军
归档:https://elasticsearch.cn/article/295
订阅:https://tinyletter.com/elastic-daily
http://t.cn/R0fAJwK
2.ELK实战 - 利用Nginx日志分析API耗时。
http://t.cn/R6sgQfU
3.Kibana中的地区分布图和仪表盘工具,强大而又实用。
http://t.cn/Rpry9fv
编辑:叮咚光军
归档:https://elasticsearch.cn/article/295
订阅:https://tinyletter.com/elastic-daily
收起阅读 »

社区日报 第58期 (2017-09-25)
http://t.cn/R0cFOIz
2.(自备梯子)如何完成360亿数据的reindex。
http://t.cn/R0VPRLa
3.使用Beats?elastic发布了一个关于Beats的问卷,填写它来帮助Beats更好的发展。
http://t.cn/R0VZZAL
编辑:cyberdak
归档:https://elasticsearch.cn/article/294
订阅:https://tinyletter.com/elastic-daily
http://t.cn/R0cFOIz
2.(自备梯子)如何完成360亿数据的reindex。
http://t.cn/R0VPRLa
3.使用Beats?elastic发布了一个关于Beats的问卷,填写它来帮助Beats更好的发展。
http://t.cn/R0VZZAL
编辑:cyberdak
归档:https://elasticsearch.cn/article/294
订阅:https://tinyletter.com/elastic-daily
收起阅读 »

社区日报 第57期 (2017-09-24)
http://t.cn/R0GmjQC
2.(自备梯子)不仅仅是一篇Elasticsearch入门级文章!看看别人的团队是怎么选的吧。
http://t.cn/R0GmTgf
3.Elasticsearch最佳实践,看看大牛在日常工作中都是怎么做的。
http://t.cn/R0Gm8bE
编辑:至尊宝
归档:https://elasticsearch.cn/article/293
订阅:https://tinyletter.com/elastic-daily
http://t.cn/R0GmjQC
2.(自备梯子)不仅仅是一篇Elasticsearch入门级文章!看看别人的团队是怎么选的吧。
http://t.cn/R0GmTgf
3.Elasticsearch最佳实践,看看大牛在日常工作中都是怎么做的。
http://t.cn/R0Gm8bE
编辑:至尊宝
归档:https://elasticsearch.cn/article/293
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

社区日报 第56期 (2017-09-23)
http://t.cn/RCTbs2d
2. es6.0节省了更多的存储空间,你知道原因吗?
http://t.cn/R0LvDlt
3. 一个用elasticsearch追踪网站点击的案例
http://t.cn/R9kMs8G
编辑:bsll
归档:https://www.elasticsearch.cn/article/292
订阅:https://tinyletter.com/elastic-daily
http://t.cn/RCTbs2d
2. es6.0节省了更多的存储空间,你知道原因吗?
http://t.cn/R0LvDlt
3. 一个用elasticsearch追踪网站点击的案例
http://t.cn/R9kMs8G
编辑:bsll
归档:https://www.elasticsearch.cn/article/292
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

社区日报 第55期 (2017-09-22)
http://t.cn/R0297wW
2、这一招,解决了mysql与elasticsearch删除同步的难题!
http://t.cn/R029ld9
3、ElasticPress | 基于Elasticsearch构建你的wordpress博客检索助手!
http://t.cn/R07kUUQ
编辑:laoyang360
归档:https://www.elasticsearch.cn/article/290
订阅:https://tinyletter.com/elastic-daily
http://t.cn/R0297wW
2、这一招,解决了mysql与elasticsearch删除同步的难题!
http://t.cn/R029ld9
3、ElasticPress | 基于Elasticsearch构建你的wordpress博客检索助手!
http://t.cn/R07kUUQ
编辑:laoyang360
归档:https://www.elasticsearch.cn/article/290
订阅:https://tinyletter.com/elastic-daily
收起阅读 »

【摩拜招聘】ES高级工程师
工作职责:
开发、维护ES,支持各种场景需求
开发、维护fluentd/flume/kafka等大数据产品
业务推动,解决大数据、高并发下的产品需求
跟进研究业界前沿技术,推动产品技术升级
职位要求:
1. 编程能力扎实,熟悉Java/C++/go中的一种,具有良好的数据结构、算法、操作系统等计算机基本知识;
2. 熟悉ElasticSearch/Lucene开源系统,有实际开发经验者优先;
3. 具有敏捷开发、完整产品生命周期开发者优先;
4. 学习能力强,善于独立思考,思维活跃,对技术有强烈激情;
欢迎投递简历:zhengchangshuai@mobike.com
薪资20K~50K
公司属于高速成长的独角兽,非常国际化的一家公司,具体感兴趣的请发简历到邮箱
工作职责:
开发、维护ES,支持各种场景需求
开发、维护fluentd/flume/kafka等大数据产品
业务推动,解决大数据、高并发下的产品需求
跟进研究业界前沿技术,推动产品技术升级
职位要求:
1. 编程能力扎实,熟悉Java/C++/go中的一种,具有良好的数据结构、算法、操作系统等计算机基本知识;
2. 熟悉ElasticSearch/Lucene开源系统,有实际开发经验者优先;
3. 具有敏捷开发、完整产品生命周期开发者优先;
4. 学习能力强,善于独立思考,思维活跃,对技术有强烈激情;
欢迎投递简历:zhengchangshuai@mobike.com
薪资20K~50K
公司属于高速成长的独角兽,非常国际化的一家公司,具体感兴趣的请发简历到邮箱 收起阅读 »

社区日报 第54期 (2017-09-21)
2.还在为设置es的分片数量纠结?一篇文章教你全部 http://t.cn/R0vFh2G
3.基于elasticsearch nested object的关联分析 http://t.cn/R0vFMG9
编辑:金桥
归档:https://elasticsearch.cn/article/287
订阅:https://tinyletter.com/elastic-daily
2.还在为设置es的分片数量纠结?一篇文章教你全部 http://t.cn/R0vFh2G
3.基于elasticsearch nested object的关联分析 http://t.cn/R0vFMG9
编辑:金桥
归档:https://elasticsearch.cn/article/287
订阅:https://tinyletter.com/elastic-daily 收起阅读 »

nginx和kibana/es集成
1、记录kibana的每个请求日志
2、kibana通过nginx连到es,可以实现负载均衡的请求es。
集成方法比较简单,在任意一台机器上安装nginx,nginx里配置es相关信息,kibana配置文件中的elasticsearch.url改成nginx相应的ip和监听端口即可。
nginx配置文件的主要内容如下:
upstream elasticsearch {
server 10.10.10.1:9200;
server 10.10.10.2:9200;
server 10.10.10.3:9200;
keepalive 10;
}
server {
listen 8888;
server_name hostname;
location / {
proxy_pass http://elasticsearch;
access_log_bypass_if ($request = 'HEAD / HTTP/1.1');
access_log_bypass_if ($request = 'GET /_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip HTTP/1.1');
access_log_bypass_if ($request = 'GET /_nodes/_local?filter_path=nodes.*.settings.tribe HTTP/1.1');
access_log_bypass_if ($request_body = '{\"docs\":[{\"_index\":\".kibana\",\"_type\":\"config\",\"_id\":\"5.5.1\"}]}');
access_log_bypass_if ($request = 'GET /_cluster/health/.kibana?timeout=5s HTTP/1.1');
access_log_bypass_if ($request = 'POST /.kibana/config/_search HTTP/1.1');
access_log_bypass_if ($request = 'GET /_cluster/settings?include_defaults=true&filter_path=**.script.engine.*.inline HTTP/1.1');
access_log_bypass_if ($request = 'GET /_aliases HTTP/1.1');
access_log_bypass_if ($request = 'GET /_mapping HTTP/1.1');
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
upstream定义了es有哪些节点。另外,nginx加了日志过滤模块ngx_log_if,用来过滤kibana和es之间的心跳请求日志,这个模块可以在github上下载
1、记录kibana的每个请求日志
2、kibana通过nginx连到es,可以实现负载均衡的请求es。
集成方法比较简单,在任意一台机器上安装nginx,nginx里配置es相关信息,kibana配置文件中的elasticsearch.url改成nginx相应的ip和监听端口即可。
nginx配置文件的主要内容如下:
upstream elasticsearch {
server 10.10.10.1:9200;
server 10.10.10.2:9200;
server 10.10.10.3:9200;
keepalive 10;
}
server {
listen 8888;
server_name hostname;
location / {
proxy_pass http://elasticsearch;
access_log_bypass_if ($request = 'HEAD / HTTP/1.1');
access_log_bypass_if ($request = 'GET /_nodes?filter_path=nodes.*.version%2Cnodes.*.http.publish_address%2Cnodes.*.ip HTTP/1.1');
access_log_bypass_if ($request = 'GET /_nodes/_local?filter_path=nodes.*.settings.tribe HTTP/1.1');
access_log_bypass_if ($request_body = '{\"docs\":[{\"_index\":\".kibana\",\"_type\":\"config\",\"_id\":\"5.5.1\"}]}');
access_log_bypass_if ($request = 'GET /_cluster/health/.kibana?timeout=5s HTTP/1.1');
access_log_bypass_if ($request = 'POST /.kibana/config/_search HTTP/1.1');
access_log_bypass_if ($request = 'GET /_cluster/settings?include_defaults=true&filter_path=**.script.engine.*.inline HTTP/1.1');
access_log_bypass_if ($request = 'GET /_aliases HTTP/1.1');
access_log_bypass_if ($request = 'GET /_mapping HTTP/1.1');
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
upstream定义了es有哪些节点。另外,nginx加了日志过滤模块ngx_log_if,用来过滤kibana和es之间的心跳请求日志,这个模块可以在github上下载 收起阅读 »

elasticsearch index、create和update的源码分析
社区里面有人问了如下一个问题:
执行 bulk 索引文档的时候,用 index 或者 create 类型并且自定义 doc id 的情况下,是否会像 update 一样每次都要去 get 一遍原始文档? 比如下面的这条命令:
POST _bulk
{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }
{ "field1" : "value1" }
{ "create" : { "_index" : "test", "_type" : "type1", "_id" : "3" } }
{ "field1" : "value3" }
问题出现的原因是他们在 bulk 测试的时候遇到了写性能的问题,而正巧社区里面前几天有这么一个类似的帖子,说的是 es 5.x 版本里面做 update 操作的性能问题。虽然和这个问题不完全一致,但都涉及到 es 索引数据的部分。
侯捷老师说:“源码面前,了无秘密”,那我们就来简单看下 es 这部分的相关代码,以便回答开篇提出的问题。
准备工作
我是用 IntelliJ IDEA 来阅读 elasticsearch 源码的,操作也简单。操作步骤如下:
1.下载 es 源码,由于 es 的commit信息比较多,可以增加 --depth=1 只下载最近的commit,减少下载时间。
git clone https://github.com/elastic/elasticsearch.git --depth=1
2.安装 gradle,确保版本在 3.3 及以上,然后在源码目录下执行以下命令准备导入 IntelliJ IDEA 需要的文件
gradle idea
3.下载安装 IntelliJ IDEA,确保版本为 2017.2 及以上版本。安装完成后,将 elasticsearch 以 gradle 形式导入即可。
大家可以参考 elasticsearch 文档说明 和 elasticsearch 文档说明 这两篇文章,细节我这里就不赘述了。
另外我是分析的 5.5.0 分支,大家记得 checkout,防止行数对应不起来。另外由于 es 代码结构有些复杂,先不在这篇文章里面梳理整个流程了,直接说核心代码。
Index/Create 源码分析
es index 和 create 最终都会调用 org/elasticsearch/index/engine/InternalEngine.java 中下面的方法:
457 public IndexResult index(Index index) throws IOException
注意这里的 index 中包含有要写入的 doc, 简单画下该方法的执行流程图,代码这里就不贴了,刚兴趣的自己去看。
请结合上面的流程图来看相应的代码,整个逻辑应该还是很清晰的,接下来我们看 planIndexingAsPrimary 的逻辑。
558 private IndexingStrategy planIndexingAsPrimary(Index index) throws IOException {
这个方法最终返回一个 IndexingStrategy,即一个索引的策略,总共有如下几个策略:
- optimizedAppendOnly
- skipDueToVersionConflict
- processNormally
- overrideExistingAsIfNotThere
- skipAsStale
不同的策略对应了不同的处理逻辑,前面3个是常用的,我们来看下流程图。
这里的第一步判断 是否是自定义 doc id?这一步就是 es 对于日志类非自定义 doc id的优化,感兴趣的可以自己去看下代码,简单讲就是在非自定义 id 的情况下,直接将文档 add ,否则需要 update,而 update 比 add 成本高很多。
而第二个判断 检查版本号是否冲突? 涉及到是如何根据文档版本号来确认文档可写入,代码都在index.versionType().isVersionConflictForWrites方法里,逻辑也比较简单,不展开讲了,感兴趣的自己去看吧。
上面的流程图也比较清晰地列出了策略选择的逻辑,除去 optimizedAppendOnly 策略,其他都需要根据待写入文档的版本号来做出决策。接下来我们就看下获取文档版本号的方法。
389 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, TTLFieldMapper.NAME, TimestampFieldMapper.NAME},
true, request.version(), request.versionType(), FetchSourceContext.FETCH_SOURCE);
return prepare(indexShard.shardId(), request, getResult, nowInMillis);
}
代码逻辑很清晰,分两步走:
- 获取待更新文档的数据
- 执行更新文档的操作
第 1 步最终会调用 InternalEngine 中的 get 方法,如下:
350 public GetResult get(Get get, Function<String, Searcher> searcherFactory, LongConsumer onRefresh) throws EngineException {
这里就接上开篇提到的社区问题中的源码分析了。代码就不展开讲了,感兴趣的自己去看吧。
update 操作需要先获取原始文档的原因也很简单,因为这里是允许用户做部分更新的,而 es 底层每次更新时要求必须是完整的文档(因为 lucene 的更新实际是删除老文档,新增新文档),如果不拿到原始数据的话,就不能组装出更新后的完整文档了。
因此,比较看重效率的业务,最好还是不要用 update 这种操作,直接用上面的 index 会更好一些。
总结
本文通过源码分析的方式解决了开篇提到的问题,答案简单总结在下面。
es 在 index 和 create 操作的时候,如果没有自定义 doc id,那么会使用 append 优化模式,否则会获取待写入文档的版本号,进行版本检查后再决定是否写入lucene。所以这里不会去做一个 get 操作,即获取完整的文档信息。
最后,记住侯捷老师的话:
源码面前,了无秘密!
查看更好的排版
社区里面有人问了如下一个问题:
执行 bulk 索引文档的时候,用 index 或者 create 类型并且自定义 doc id 的情况下,是否会像 update 一样每次都要去 get 一遍原始文档? 比如下面的这条命令:
POST _bulk
{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }
{ "field1" : "value1" }
{ "create" : { "_index" : "test", "_type" : "type1", "_id" : "3" } }
{ "field1" : "value3" }
问题出现的原因是他们在 bulk 测试的时候遇到了写性能的问题,而正巧社区里面前几天有这么一个类似的帖子,说的是 es 5.x 版本里面做 update 操作的性能问题。虽然和这个问题不完全一致,但都涉及到 es 索引数据的部分。
侯捷老师说:“源码面前,了无秘密”,那我们就来简单看下 es 这部分的相关代码,以便回答开篇提出的问题。
准备工作
我是用 IntelliJ IDEA 来阅读 elasticsearch 源码的,操作也简单。操作步骤如下:
1.下载 es 源码,由于 es 的commit信息比较多,可以增加 --depth=1 只下载最近的commit,减少下载时间。
git clone https://github.com/elastic/elasticsearch.git --depth=1
2.安装 gradle,确保版本在 3.3 及以上,然后在源码目录下执行以下命令准备导入 IntelliJ IDEA 需要的文件
gradle idea
3.下载安装 IntelliJ IDEA,确保版本为 2017.2 及以上版本。安装完成后,将 elasticsearch 以 gradle 形式导入即可。
大家可以参考 elasticsearch 文档说明 和 elasticsearch 文档说明 这两篇文章,细节我这里就不赘述了。
另外我是分析的 5.5.0 分支,大家记得 checkout,防止行数对应不起来。另外由于 es 代码结构有些复杂,先不在这篇文章里面梳理整个流程了,直接说核心代码。
Index/Create 源码分析
es index 和 create 最终都会调用 org/elasticsearch/index/engine/InternalEngine.java 中下面的方法:
457 public IndexResult index(Index index) throws IOException
注意这里的 index 中包含有要写入的 doc, 简单画下该方法的执行流程图,代码这里就不贴了,刚兴趣的自己去看。
请结合上面的流程图来看相应的代码,整个逻辑应该还是很清晰的,接下来我们看 planIndexingAsPrimary 的逻辑。
558 private IndexingStrategy planIndexingAsPrimary(Index index) throws IOException {
这个方法最终返回一个 IndexingStrategy,即一个索引的策略,总共有如下几个策略:
- optimizedAppendOnly
- skipDueToVersionConflict
- processNormally
- overrideExistingAsIfNotThere
- skipAsStale
不同的策略对应了不同的处理逻辑,前面3个是常用的,我们来看下流程图。
这里的第一步判断 是否是自定义 doc id?这一步就是 es 对于日志类非自定义 doc id的优化,感兴趣的可以自己去看下代码,简单讲就是在非自定义 id 的情况下,直接将文档 add ,否则需要 update,而 update 比 add 成本高很多。
而第二个判断 检查版本号是否冲突? 涉及到是如何根据文档版本号来确认文档可写入,代码都在index.versionType().isVersionConflictForWrites方法里,逻辑也比较简单,不展开讲了,感兴趣的自己去看吧。
上面的流程图也比较清晰地列出了策略选择的逻辑,除去 optimizedAppendOnly 策略,其他都需要根据待写入文档的版本号来做出决策。接下来我们就看下获取文档版本号的方法。
389 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, TTLFieldMapper.NAME, TimestampFieldMapper.NAME},
true, request.version(), request.versionType(), FetchSourceContext.FETCH_SOURCE);
return prepare(indexShard.shardId(), request, getResult, nowInMillis);
}
代码逻辑很清晰,分两步走:
- 获取待更新文档的数据
- 执行更新文档的操作
第 1 步最终会调用 InternalEngine 中的 get 方法,如下:
350 public GetResult get(Get get, Function<String, Searcher> searcherFactory, LongConsumer onRefresh) throws EngineException {
这里就接上开篇提到的社区问题中的源码分析了。代码就不展开讲了,感兴趣的自己去看吧。
update 操作需要先获取原始文档的原因也很简单,因为这里是允许用户做部分更新的,而 es 底层每次更新时要求必须是完整的文档(因为 lucene 的更新实际是删除老文档,新增新文档),如果不拿到原始数据的话,就不能组装出更新后的完整文档了。
因此,比较看重效率的业务,最好还是不要用 update 这种操作,直接用上面的 index 会更好一些。
总结
本文通过源码分析的方式解决了开篇提到的问题,答案简单总结在下面。
es 在 index 和 create 操作的时候,如果没有自定义 doc id,那么会使用 append 优化模式,否则会获取待写入文档的版本号,进行版本检查后再决定是否写入lucene。所以这里不会去做一个 get 操作,即获取完整的文档信息。
最后,记住侯捷老师的话:
源码面前,了无秘密!
查看更好的排版
收起阅读 »