一、问题描述
在定义atlasEntityType(可类比为java的类)的时候,发现relationship关系定义(可认为是atlasEntityType与atlasEntityType之间的关系),调用详情接口时实体relationship属性对应的array数据是无序的。
由于业务原因,要求必须有序,所以只能着手解决问题了。
二、解决思路
1、定义entityType时,添加array<T>属性,将关联关系放在array属性中(不采纳)
该属性确实是有序的,并且如果T根据类型不同有不同的展示效果:
(1)是基本类型,如string,则多次操作属性为覆盖。(这是曲线救国的办法,但是不如从根本解决问题,给自己一个锻炼提升的机会)
(2)是atlas实体类型,即对象类型,则多次操作属性为"追加"
但是方案不通过,原因是array<entityType>会返回所有数据,包含DELETED状态,并且调用API返回数据时没有status字段让你判断数据状态。这也是为什么上述中的"追加"有引号的原因(当时debug半天,最后发现这个情况的时候差点吐血)
2、修改relationship关联关系定义相关的源码,达到多值有序的目的(采纳)
至于为什么不修改array<entityType>源码返回status,考虑的点是因为Apache Atlas既然有relationship系统,那么关联关系放在relationship里比较合理。
三、解决方案
3.1 版本描述
Apache Atlas源码版本:2.2.0-rc1,这个版本是官方git上最新的Tag版本。
3.2 源码跟踪问题
3.2.1 保存逻辑
先查看保存期间是否有哪一步操作,导致集合乱序。
3.2.1.1 创建or更新API入口:
package:org.apache.atlas.repository.store.graph.v2
class:AtlasEntityStoreV2
method:createOrUpdate
3.2.1.2 创建or更新逻辑入口:
1、遍历所有create或者update数据,进行操作
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphMapper
method:mapAttributesAndClassifications
3.2.1.3 核心处理逻辑之前的小步骤
1、遍历所有relationship的key,然后进行关联处理:
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphMapper
method:mapAttributesAndClassifications
2、将当前entity的relationship里的数据,通过生成图库中的"顶点+边"进行关联:
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphMapper
method:mapAttribute
3、根据值类型进行对应relationship关联逻辑处理:由于关联数据是多个,所以匹配到ARRAY
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphMapper
method:mapToVertexByTypeCategory
3.2.1.4 多数据关联的核心处理逻辑
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphMapper
method:mapArrayValue
1、获取当前对象当前属性已有的数据,分为两种类型,红框为atlasEntity类型,即对象类型;蓝框为基本类型。
2、创建新数据,如果基本类型则为edge,即图库的“边”(图库中的关系由两点一边表示)。
3、创建新数据后续处理:
(1)、红框为对象类型的处理,将当前已有元素和新疆的元素进行合并,注意这个unionCurrentAndNewElements方法
(2)、蓝框是基本元素的处理逻辑,这也是为什么在二-1-(1)提到的array<基本类型>多次操作是覆盖的原因。
(3)、isAppendOnPartialUpdate是属性一个配置,默认为false,先不管。
4、万恶之源出现:
unionCurrentAndNewElements方法导致list元素乱序!
(1)、unionCurrentAndNewElements方法内部:
(2)、CollectionUtils.union方法:
根本原因找到了:union的时候,使用了无序的HashSet集合进行遍历操作
5、创建新数据最终处理:
(1)、红框的逻辑是为“边”元素添加下标属性,这点很重要
(2)、蓝框由于setArrayElementsProperty方法的判断,对对象类型是不会生效的
3.2.1.4 万恶之源修改
自己创建一个工具类,使用有序集合操作,让代码调用新的工具类即可。
3.2.2 查询逻辑
由于在3.3.1发现了是保存的时候导致乱序,那么使用新的union方法保存后查询应该有序了。(然而还是太年轻了,不了解janusgraph图库,吃了没文化的亏。)
3.2.2.1 核心逻辑之前的流程
1、查询详情API入口:
package:org.apache.atlas.repository.store.graph.v2
class:AtlasEntityStoreV2
method:getById
2、省略无关紧要的步骤,到达处理relationship属性的入口:
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphRetriever
method:mapVertexToAtlasEntity
3、遍历处理relationship属性:
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphRetriever
method:mapRelationshipAttributes
4、处理relationship核心逻辑入口:
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphRetriever
method:mapVertexToRelationshipAttribute
3.2.2.2 查询核心逻辑
package:org.apache.atlas.repository.store.graph.v2
class:EntityGraphRetriever
method:mapRelationshipArrayAttribute
1、绿框为查询relationship所有边数据,返回值是个Iterator迭代器,debug到源码发现底层调用janusgraph图库返回的数据就是无序的迭代器了。
2、红框遍历所有“边”,将“边”转化为关联实体
3、蓝框为将“边”转为关联实体的方法
3.2.2.2 查询核心逻辑修改
还记得 三-3.2-3.2.1.4-5 说的最终处理“边”元素设置的下标吗?我们可以先讲边集合根据下标属性排序后在进行转为关联实体,最终代码:
蓝框是atlas封装好的获取下标属性的方法:
edge边元素的属性:
3.3 修改源码后的最终效果:
四、小结
1)本文更侧重于源码的大致跟踪,debug过程没有加上数据讲解;
2)遇到困难不要慌,静下心来一步一步完成就好了。另外就是要学会有目的性的查找资料,比如到官方的jira搜搜资料等;
3)实际的debug过程,其实是先判断了查询无序(janusgraph查询边是无序),然后修改完代码发现还有无序的情况,于是认真debug发现了CollectionUtils.union的“问题”(即乱序导致和入参顺序不一致,那查询时再根据index属性排序也没用了),修改union方法后最终才调试成功。
4)郑重声明:这个问题算不算是atlas的bug,那就仁者见仁智者见智了。重点是我需要修改为符合公司业务的功能,并且又成长了一些!