使用Gremlin将数据加载到Neptune中,使用db.r5.4xlarge(16个虚拟CPU)的Neptune基础设施。
通过AWS Glue job和5个worker线程使用pyspark将数据加载到Neptune中。
通过执行插入操作,对去重后的数据集进行分批处理(每批50条记录),作为单个查询一起发送到Neptune中。
顶点:在去重之后计算要加载到图中的所有顶点(没有重复节点)。
使用的查询:
g.V().has(T.id, record.id).fold().coalesce(__.unfold(),__.addV(record.source).property(T.id, record.id)
.V().has(T.id, record.id).fold().coalesce(__.unfold(),__.addV(record.source).property(T.id, record.id)
(Do 48 items).next()
对于 245 万个唯一的顶点执行所需的时间为5分钟
边缘:计算所有要加载到图中的边缘,去重后(没有重复边缘)
使用的查询语句:
g.V(edgeData.id1).bothE().where(__.otherV().hasId(edgeData.id2)).fold().coalesce(__.unfold(),__.addE('coincided_with').from_(__.V(edgeData.id1)).to(__.V(edgeData.id2))).property(Cardinality.single, timestamp, edgeData.timestamp).property(Cardinality.single, count, edgeData.count)
.V(edgeData.id1).bothE().where(__.otherV().hasId(edgeData.id2)).fold().coalesce(__.unfold(),__.addE('coincided_with').from_(__.V(edgeData.id1)).to(__.V(edgeData.id2))).property(Cardinality.single, timestamp, edgeData.timestamp).property(Cardinality.single, count, edgeData.count)
(Do 48 items).next()
对于具有属性的1.88M个唯一边执行所需的时间为21分钟
如果我们仅仅执行边的创建而没有任何属性,
使用的查询语句:
g.V(edgeData.id1).bothE().where(__.otherV().hasId(edgeData.id2)).fold().coalesce(__.unfold(),__.addE('coincided_with').from_(__.V(edgeData.id1)).to(__.V(edgeData.id2)))
.V(edgeData.id1).bothE().where(__.otherV().hasId(edgeData.id2)).fold().coalesce(__.unfold(),__.addE('coincided_with').from_(__.V(edgeData.id1)).to(__.V(edgeData.id2)))
(Do 48 items).next()
在没有属性的情况下执行 1.88M 个唯一边缘所需的时间为 4 分钟
性能问题:
- 理想情况下,在插入顶点时,我们不应该看到任何 ConcurrentModification 异常,但是即使在 Neptune 的新实例(db.r5.4xlarge)中创建顶点时,我们也经常会遇到此异常。我们通过对它们进行重试逻辑来缓解这种情况。在进行从顶点 (A -> B) 的边插入时,有些情况即使重试了10次,并且间隔为300毫秒,仍然无法插入它们。总体问题是,我们需要更多的时间来插入我们的数据,是否有一种方法可以避免并发异常,即使我们避免并发情况。
- 在批量插入期间添加边属性时,所需的时间比不带属性的边要长得多 例如:向边添加2个属性 具有属性的1.8M条边需要近21分钟才能插入我们的数据 不带属性的1.8M条边需要接近4分钟才能插入我们的数据。 带属性的边的创建速度要慢得多,是否有一种方式可以加快带属性的边的加载速度(我们有40M条边,因此插入时间更长)
- 添加更多的并行工作线程,我们会变得更慢,并发错误更多(CPU负载约为50%,而不是最大值)。
任何改进性能的建议都将非常有帮助