欢迎来到 临沂市某某旅行用品制造厂
全国咨询热线:020-123456789
联系我们

地址:联系地址联系地址联系地址

电话:020-123456789

传真:020-123456789

邮箱:admin@aa.com

新闻中心
ES 源码分析之数据类型转换
  来源:临沂市某某旅行用品制造厂  更新时间:2024-05-03 21:38:47

ES 源码分析之数据类型转换

公司有的源码小伙伴问我  ,为什么不推荐我们使用 nested 结构呢,分析还说性能低 。据类那么 ,型转ES 针对 nested 之类的源码结构 。因为ES 源码我也基本看完了。分析索性 ,据类直接写成笔记。型转比直接在代码里面写注释来的源码更舒心点 。

1问题描述

  • ES 是分析 lucene 不仅仅是集群版的概念,还有涉及到支持丰富的据类数据类型。如 nested 、型转object 等等结构 。源码它是分析怎么支持的呢?
  • ES 还支持 _id、_version 等等字段 。据类这种是怎么存储的呢?
  • 听说 ES 的 parent doc 和 nested doc 是分开来存储的,那么获取的时候,他们是通过哪种关系关联的呢?

2类型转换

2.1初步代码入口

代码具体入口 org.elasticsearch.index.shard.IndexShard#prepareIndex

public static Engine.Index prepareIndex(DocumentMapperForType docMapper, SourceToParse source, long seqNo,n long primaryTerm, long version, VersionType versionType, Engine.Operation.Origin origin,n long autoGeneratedIdTimestamp, boolean isRetry,n long ifSeqNo, long ifPrimaryTerm) { n long startTime = System.nanoTime();nn // 涉及到 nested 等等结构的转换 ,直接看【2.2 类型具体转换代码】n ParsedDocument doc = docMapper.getDocumentMapper().parse(source);nn // Mapping 是否要处理n if (docMapper.getMapping() != null) { n doc.addDynamicMappingsUpdate(docMapper.getMapping());n }nn // _id 转 uid。这里是为了数据能保持整齐,方便压缩。可以参考 【哈夫曼编码】 。n Term uid = new Term(IdFieldMapper.NAME, Uid.encodeId(doc.id()));nn return new Engine.Index(uid, doc, seqNo, primaryTerm, version, versionType, origin, startTime, autoGeneratedIdTimestamp, isRetry,n ifSeqNo, ifPrimaryTerm);n }n

2.2类型具体转换代码

/**n * 内部转换文档,如果有 nested 结构,需要再次转换一下n * @param mappingn * @param contextn * @param parsern * @throws IOExceptionn */n private static void internalParseDocument(Mapping mapping, MetadataFieldMapper[] metadataFieldsMappers,n ParseContext context, XContentParser parser) throws IOException { n final boolean emptyDoc = isEmptyDoc(mapping, parser);nn /**n * 预处理,为 root document 拆开,添加如下 :比如  ,_id、_version 也是一个 document,具体看下面的 【2.3 支持 _id 之类的字段】n */n for (MetadataFieldMapper metadataMapper : metadataFieldsMappers) { n metadataMapper.preParse(context);n }nn if (mapping.root.isEnabled() == false) { n // entire type is disabledn parser.skipChildren();n } else if (emptyDoc == false) { n // 转换对象或者 nested 结构 ,这个方法会反复递归调用 。主要是 object 结构或者 nested 结构n parseObjectOrNested(context, mapping.root);n }nn // 为各个非 root document 添加 _version 等等字段n for (MetadataFieldMapper metadataMapper : metadataFieldsMappers) { n metadataMapper.postParse(context);n }n }n

2.3前置处理之支持_id之类的字段

代码位置  :org.elasticsearch.index.mapper.MetadataFieldMapper#preParse
下面只贴出 _id 的处理

/**n * _id 也是一个 docn * @param contextn */n @Overriden public void preParse(ParseContext context) { n BytesRef id = Uid.encodeId(context.sourceToParse().id());n context.doc().add(new Field(NAME, id, Defaults.FIELD_TYPE));n }n

这里只是了其中的一个例子:_id ,其他的比如 _version、_seqno、_source 等等处理也类似 。

2.4转换复杂的结构 ,比如nested结构

ES 在转换 nested 结构的时候,比较有意思。

2.4.1类型转换整体入口

/**n * 转换 object 或者 nested 结构的,这里会出现递归调用 ,主要是为了解决 object 、nested 结构n * @param contextn * @param mappern * @throws IOExceptionn */n static void parseObjectOrNested(ParseContext context, ObjectMapper mapper) throws IOException { n if (mapper.isEnabled() == false) { n context.parser().skipChildren();n return;n }n XContentParser parser = context.parser();n XContentParser.Token token = parser.currentToken();n if (token == XContentParser.Token.VALUE_NULL) { n // the object is null ("obj1" : null), simply bailn return;n }nn String currentFieldName = parser.currentName();n if (token.isValue()) { n throw new MapperParsingException("object mapping for [" + mapper.name() + "] tried to parse field [" + currentFieldNamen + "] as object, but found a concrete value");n }nn ObjectMapper.Nested nested = mapper.nested();n // 如果是 nested 结构 ,每次都会new 一个空白的 document ,而且,这个方法 #{ innerParseObject},是递归实现,把 object 或者 document 变成多个 documentn if (nested.isNested()) { n // 进入下方的:【2.4.2 nested 转换初步入口】n context = nestedContext(context, mapper);n }nn // if we are at the end of the previous object, advancen if (token == XContentParser.Token.END_OBJECT) { n token = parser.nextToken();n }n if (token == XContentParser.Token.START_OBJECT) { n // if we are just starting an OBJECT, advance, this is the object we are parsing, we need the name firstn token = parser.nextToken();n }nn // 转换对象n innerParseObject(context, mapper, parser, currentFieldName, token);nn // restore the enable path flagn if (nested.isNested()) { n nested(context, nested);n }n }n

2.4.2nested转换初步入口

/**n * 内部转换 nested 结构 ,生成一个空白的 nested 结构n * TODO nested 文档的 _id 既然跟父文档的一样 ,lucene 写入每个 doc ,都是拼接。那么,在get 的时候,自然会获取到相同的 _id 多个文档,包含了 nested 结构 。然后 ,再内部转换为我们 最想要的结果 。n * @param contextn * @param mappern * @returnn */n private static ParseContext nestedContext(ParseContext context, ObjectMapper mapper) { nn // 创建 nested 上下文 ,并且,new 一个空白的 document 。为后面的 nested 的字段或者对象之类的,全部加上n context = context.createNestedContext(mapper.fullPath());nn ParseContext.Document nestedDoc = context.doc();n ParseContext.Document parentDoc = nestedDoc.getParent();nn // We need to add the uid or id to this nested Lucene document too,n // If we do not do this then when a document gets deleted only the root Lucene document gets deleted andn // not the nested Lucene documents! Besides the fact that we would have zombie Lucene documents, the ordering ofn // documents inside the Lucene index (document blocks) will be incorrect, as nested documents of different rootn // documents are then aligned with other root documents. This will lead tothe nested query, sorting, aggregationsn // and inner hits to fail or yield incorrect results.n IndexableField idField = parentDoc.getField(IdFieldMapper.NAME);n if (idField != null) { n // We just need to store the id as indexed field, so that IndexWriter#deleteDocuments(term) can thenn // delete it when the root document is deleted too.n nestedDoc.add(new Field(IdFieldMapper.NAME, idField.binaryValue(), IdFieldMapper.Defaults.NESTED_FIELD_TYPE));n } else { n throw new IllegalStateException("The root document of a nested document should have an _id field");n }nn // the type of the nested doc starts with __, so we can identify that its a nested one in filtersn // note, we don't prefix it with the type of the doc since it allows us to execute a nested queryn // across types (for example, with similar nested objects)n nestedDoc.add(new Field(TypeFieldMapper.NAME, mapper.nestedTypePathAsString(), TypeFieldMapper.Defaults.NESTED_FIELD_TYPE));n return context;n }n

仔细看看里面的英文  。主要的一点是:nested 结构的 _id 和 parent 的 _id 保持一致  。那么,通过 GET docId 这种操作 ,就可以拿到所有的文档了。而且 ,删除的时候  ,特别的方便。算是 ES 这种的一个方案吧。

2.4.3数据处理

每个字段的填充入口在  :org.elasticsearch.index.mapper.DocumentParser#innerParseObject
这里是一个递归调用的操作。比较绕。

2.5后置处理之设置_version等等

下面贴出来 _version 的处理
代码的入口 :org.elasticsearch.index.mapper.VersionFieldMapper#postParse ,可以看看具体的实现。

@Overriden public void postParse(ParseContext context) { n // In the case of nested docs, let's fill nested docs with version=1 so that Lucene doesn't write a Bitset for documentsn // that don't have the field. This is consistent with the default value for efficiency.n Field version = context.version();n assert version != null;n for (Document doc : context.nonRootDocuments()) { n // 为此 doc 添加一个 _version 字段n doc.add(version);n }n }n

这里支持举了 _version 举个例子 ,其他类似。

3总结

  • ES 是 lucene 不仅仅是集群版的概念 ,还有涉及到支持丰富的数据类型。如 nested 、object 等等结构。它是怎么支持的呢 ?
    答:ES 针对 nested  、object 直接拍平处理
  • ES 还支持 _id 、_version 等等字段。这种是怎么存储的呢?
    答 :ES 针对 _id 、_version 是保存为独立的文档的 。
  • 听说 ES 的 parent doc 和 nested doc 是分开来存储的 ,那么获取的时候 ,他们是通过那种关系关联的呢 ?
    答:通过 root Doc 的 ID 来做关联的 。

4其他

后续请关注 ES 写入流程  。让我们看看 ES 是如何处理分布式请求及保证高可用的。


友情链接世界最贵的珠宝品牌有哪些?盘点世界上最贵的十大皇室珠宝三国杀每天银两上限是多少?三国杀如何快速获得大量银币?梦幻西游:鼠标点一下就不见了4w,神兜兜换特殊兽决让人上头!净天之命隐藏英雄,吞食天地 荆州之战0990有7个隐藏英雄英雄联盟惩戒之箭出装《英雄联盟》S13赛季星界驱驰妖姬出装推荐dnf110级阿修罗刷图加点攻略《格斗10》新版官网上线 同步发放激活码三国美人计山海经新证DNF武神加点换装与刷图技巧详细解说历数NBA2K系列各个版本中评分最高的球员---詹皇表示我要刷屏《LOL》Xiaobai鳄鱼S10攻略 天赋出装介绍5个拼音小游戏,让孩子在快乐中学习!三国杀每天银两上限是多少?三国杀如何快速获得大量银币?棘轮效应 | 开通的“花呗”咋就这么难关闭?哈利波特魔法觉醒雪中的诞生卡组怎么获得(雪花奇遇金色线索雪中的诞生)「2023推荐」很多网友玩dnf却不知道在哪儿可以免费获取黑钻,有部分玩家还在做着每个月充几十块大洋买黑钻的事儿!殊不知仅需要每天动动发财的小手,你就能拥有这辈子都不会过期的黑钻了,赶快用你发财的小手点起来吧。8块9的情怀究竟有多香?—影时光魔兽iPhone6手机壳小晒可下载的游戏大全手机游戏前十名2021 十款可下载的游戏排行有什么魔兽世界TBC怀旧服制皮图纸来源一览 70新增制皮图纸介绍光遇边陲荒漠冥想在哪里介绍仙剑奇侠传5中文语音包2024年《王者荣耀》关羽顶级六神装推荐一生只玩一个游戏公司的作品,你选择哪个DHF剑豪 技能加点推荐各种方法尝试云顶之弈11.17复生游侠阵容怎么搭配-11.17复生游侠阵容搭配推荐仙剑奇侠传4配音版激活码获得方法和免费安装教程S7EZ出装加点 LOL伊泽瑞尔2017赛季玩法攻略DNF:12.2强化增幅概率曝光!机器提示成功数值,药剂称号均加算访问被拦截!名刃现世!《阴阳师》日本国宝级刀匠锻刀访谈[萌新速成]勾玉蓝票获取DNF国服起源版本什么时候更新 DNF国服起源版本更新内容预告亚历山大变石猫眼价格(亚历山大变石猫眼有收藏价值吗)dnf退出公会后多久可以重新加入,dnf退出工会后多久可以重新加入DNF:阿拉德谋略战怪物卡片梯队排行,神级仅有三位王者荣耀:S22赛季版本最强黑马,核弹流苏烈教学!《心灵杀手2》私人小屋保险箱密码分享可下载的游戏大全手机游戏前十名2021 十款可下载的游戏排行有什么
联系我们

地址:联系地址联系地址联系地址

电话:020-123456789

传真:020-123456789

邮箱:admin@aa.com

0.173

Copyright © 2024 Powered by 临沂市某某旅行用品制造厂   sitemap