源码分析
PageCacheRecycler的疑问
Elasticsearch • Charele 回复了问题 • 2 人关注 • 1 个回复 • 1728 次浏览 • 2021-04-21 13:13
ElasticSearch 源码 线程池模块 里面居然没有 提交 Callable 任务的接口?
回复Elasticsearch • hapjin 发起了问题 • 1 人关注 • 0 个回复 • 1800 次浏览 • 2019-05-20 18:37
修改logstash源码,按照文件名判断唯一
Logstash • medcl 回复了问题 • 2 人关注 • 1 个回复 • 2924 次浏览 • 2018-05-17 17:36
请问写一个自己的es分词器需要从哪开始
回复Elasticsearch • elasticStack 发起了问题 • 3 人关注 • 0 个回复 • 2542 次浏览 • 2018-05-15 14:49
elasticsearch index、create和update的源码分析
Elasticsearch • rockybean 发表了文章 • 1 个评论 • 6773 次浏览 • 2017-09-20 11:24
执行 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,减少下载时间。
2.安装 gradle,确保版本在 3.3 及以上,然后在源码目录下执行以下命令准备导入 IntelliJ IDEA 需要的文件git clone https://github.com/elastic/elasticsearch.git --depth=1
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 中下面的方法:gradle idea
注意这里的 index 中包含有要写入的 doc, 简单画下该方法的执行流程图,代码这里就不贴了,刚兴趣的自己去看。 请结合上面的流程图来看相应的代码,整个逻辑应该还是很清晰的,接下来我们看 planIndexingAsPrimary 的逻辑。457 public IndexResult index(Index index) throws IOException
这个方法最终返回一个 IndexingStrategy,即一个索引的策略,总共有如下几个策略:558 private IndexingStrategy planIndexingAsPrimary(Index index) throws IOException {
- optimizedAppendOnly
- skipDueToVersionConflict
- processNormally
- overrideExistingAsIfNotThere
- skipAsStale
该方法逻辑比较简单,主要分为2步:389 private VersionValue resolveDocVersion(final Operation op) throws IOException {
- 尝试从 versionMap 中读取待写入文档的 version,也即从内存中读取。versionMap 会暂存还没有 commit 到磁盘的文档版本信息。
- 如果第 1 步中没有读到,则从 index 中读取,也即从文件中读取。
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);
}
代码逻辑很清晰,分两步走:
- 获取待更新文档的数据
- 执行更新文档的操作
这里就接上开篇提到的社区问题中的源码分析了。代码就不展开讲了,感兴趣的自己去看吧。 update 操作需要先获取原始文档的原因也很简单,因为这里是允许用户做部分更新的,而 es 底层每次更新时要求必须是完整的文档(因为 lucene 的更新实际是删除老文档,新增新文档),如果不拿到原始数据的话,就不能组装出更新后的完整文档了。 因此,比较看重效率的业务,最好还是不要用 update 这种操作,直接用上面的 index 会更好一些。 总结 本文通过源码分析的方式解决了开篇提到的问题,答案简单总结在下面。 es 在 index 和 create 操作的时候,如果没有自定义 doc id,那么会使用 append 优化模式,否则会获取待写入文档的版本号,进行版本检查后再决定是否写入lucene。所以这里不会去做一个 get 操作,即获取完整的文档信息。 最后,记住侯捷老师的话: 源码面前,了无秘密! 查看更好的排版350 public GetResult get(Get get, Function<String, Searcher> searcherFactory, LongConsumer onRefresh) throws EngineException {
ElasticSearch 源码 线程池模块 里面居然没有 提交 Callable 任务的接口?
回复Elasticsearch • hapjin 发起了问题 • 1 人关注 • 0 个回复 • 1800 次浏览 • 2019-05-20 18:37
请问写一个自己的es分词器需要从哪开始
回复Elasticsearch • elasticStack 发起了问题 • 3 人关注 • 0 个回复 • 2542 次浏览 • 2018-05-15 14:49
elasticsearch index、create和update的源码分析
Elasticsearch • rockybean 发表了文章 • 1 个评论 • 6773 次浏览 • 2017-09-20 11:24
执行 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,减少下载时间。
2.安装 gradle,确保版本在 3.3 及以上,然后在源码目录下执行以下命令准备导入 IntelliJ IDEA 需要的文件git clone https://github.com/elastic/elasticsearch.git --depth=1
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 中下面的方法:gradle idea
注意这里的 index 中包含有要写入的 doc, 简单画下该方法的执行流程图,代码这里就不贴了,刚兴趣的自己去看。 请结合上面的流程图来看相应的代码,整个逻辑应该还是很清晰的,接下来我们看 planIndexingAsPrimary 的逻辑。457 public IndexResult index(Index index) throws IOException
这个方法最终返回一个 IndexingStrategy,即一个索引的策略,总共有如下几个策略:558 private IndexingStrategy planIndexingAsPrimary(Index index) throws IOException {
- optimizedAppendOnly
- skipDueToVersionConflict
- processNormally
- overrideExistingAsIfNotThere
- skipAsStale
该方法逻辑比较简单,主要分为2步:389 private VersionValue resolveDocVersion(final Operation op) throws IOException {
- 尝试从 versionMap 中读取待写入文档的 version,也即从内存中读取。versionMap 会暂存还没有 commit 到磁盘的文档版本信息。
- 如果第 1 步中没有读到,则从 index 中读取,也即从文件中读取。
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);
}
代码逻辑很清晰,分两步走:
- 获取待更新文档的数据
- 执行更新文档的操作
这里就接上开篇提到的社区问题中的源码分析了。代码就不展开讲了,感兴趣的自己去看吧。 update 操作需要先获取原始文档的原因也很简单,因为这里是允许用户做部分更新的,而 es 底层每次更新时要求必须是完整的文档(因为 lucene 的更新实际是删除老文档,新增新文档),如果不拿到原始数据的话,就不能组装出更新后的完整文档了。 因此,比较看重效率的业务,最好还是不要用 update 这种操作,直接用上面的 index 会更好一些。 总结 本文通过源码分析的方式解决了开篇提到的问题,答案简单总结在下面。 es 在 index 和 create 操作的时候,如果没有自定义 doc id,那么会使用 append 优化模式,否则会获取待写入文档的版本号,进行版本检查后再决定是否写入lucene。所以这里不会去做一个 get 操作,即获取完整的文档信息。 最后,记住侯捷老师的话: 源码面前,了无秘密! 查看更好的排版350 public GetResult get(Get get, Function<String, Searcher> searcherFactory, LongConsumer onRefresh) throws EngineException {