我为neo4j做的Python对象映射是否太天真了?

2024-05-19 18:19:39 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在寻找一些关于如何重写应用程序代码的一般性建议,或者是放弃neo4j而使用另一种数据存储模型。这不仅仅是“主观的”,因为它与Python中neo4j驱动程序的特定、正确用法以及它为什么会以我的代码执行的方式来执行,有着重大的关系。在

背景:

我和我的团队一直在使用neo4j存储图形友好型数据,这些数据最初存储在Python对象中。最初,本地/内部专家建议我们使用neo4j,因为它似乎适合我们的数据存储和操作/查询需求。数据总是一组精心构建的本体的具体实例。例如(伪数据):

Superclass1 -contains-> SubclassA
Superclass1 -implements->SubclassB
Superclass1 -isAssociatedWith-> Superclass2
SubclassB -hasColor-> Color1
Color1 -hasLabel-> string::"Red"

…等等,以创建一些相当复杂和冗长的层次结构。在

对于原型,我们使用RDFLib将这些数据存储为语法三元组(subject->;verb/predicate->;object)的序列,并使用RDFLib的图形生成器来构造一个图。在

现在,由于这些信息只是一个复杂的层次结构,我们只需将其存储在一些定制的Python对象中。我们这样做也是为了向其他需要与我们核心服务接口的开发人员提供一个简单的API。我们给他们一个Python库,这个库是我们的对象模型,让他们用数据填充它,或者,我们填充它并把它交给他们以便于阅读,他们用它做他们想做的事情。在

为了永久地存储这些对象,并希望能够加速这些数据的写入和读取(查询/过滤),我们构建了定制的对象映射代码,该代码利用官方的neo4jpython驱动程序将这些python对象递归地写入和读取到neo4j数据库中。在

问题是:

对于大型和复杂的数据集(例如15k+节点和15k+关系),我们代码中的对象关系映射(ORM)部分太慢,并且伸缩性较差。但我和我的同事都不是数据库或neo4j方面的专家,我认为我们对于如何完成这个ORM是幼稚的。我们开始怀疑使用neo4j是否有意义,因为更传统的ORMs(例如SQL炼金术)可能是更好的选择。在

例如,我们现在拥有的ORM commit算法是一个递归函数,它可以提交如下对象(伪代码):

^{pr2}$

这样做太天真了吗?像Py2neo's OGM这样的OGM库会更好吗,尽管我们的库是定制的?我见过this和类似的问题,它们推荐这种或那种OGM方法,但在this文章中,它说根本不要使用OGM。在

我们真的必须实现每个方法和性能基准吗?似乎必须有一些最佳实践(除了使用batch IMPORT,这不适合我们的用例)。我们已经通读了类似链接的文章,并看到了编写更好查询的各种技巧,但是在尝试逐行优化代码之前,最好退一步,更全面地研究一下这种情况。虽然我们可以在一定程度上改进ORM算法。在

使用这样的递归策略在neo4j中写入和读取大型、深层层次的对象是否有意义?Cypher或neo4j驱动程序中有什么东西我们遗漏了吗?还是使用Py2neo的OGM更好?完全放弃neo4j是不是最好?neo4j和Cypher的优点很难忽视,我们的数据似乎很适合图表。谢谢。在


Tags: 数据对象代码模型图形层次结构关系驱动程序
2条回答

这里有很多事情要做,所以我将试着用较小的问题来解决这个问题

Would an OGM library like Py2neo's OGM be better

对于任何ORM/OGM库,实际情况是,通过绕过它们并深入研究野兽的腹部,您总能获得更好的性能。不过,这并不是ORMs的全部工作。ORM的目的是使相对高效的数据库更容易使用,从而节省您的时间和精力。在

因此,这取决于,如果你想要最好的性能,跳过ORM,把你的时间投入到尽可能低的级别上(*需要对你正在工作的beast有高级的低级知识,而且需要大量的时间)。否则,ORM库通常是最好的选择。在

Our code is too slow, and scales poorly

数据库很复杂。如果可能的话,我建议你找个人来做公司范围内的数据库管理员/专家。(当你还没有一个新员工真正了解他们在谈论什么时,这就更难了)

假设这不是一个选项,这里有一些事情要考虑。在

  • IO很贵。尤其是通过网络。最小化必须向任一方向发送的数据。(这就是页面返回结果的原因。只返回您需要的数据,因为您实际上需要它)
    • 需要注意的是,创建请求连接是非常昂贵的。最小化对数据库的调用。(注意:ORMs通常内置机制,只提交更改的内容)
  • 快速获取所需数据。在数据库中创建索引以大大提高获取速度。id越是唯一和一致,就越好。
    • 注意,索引中的值发生更改时,必须对其进行更新。因此,索引降低了写入速度并消耗了更多内存以获得读取速度。最小化索引。在
  • 事务是一种内存操作。提交事务是一个磁盘IO操作。这就是为什么批处理作业的效率要高得多。
    • 警告,记忆不是无限的。保持你的工作规模合理。在

正如您可能知道的那样,将数据库操作扩展到生产级别并不有趣。在任何轴上过度优化都太容易了,这只是表面上的过度简化。在

For prototyping, we were storing these data as sequences of grammatical triples

少了一个问题,多了一个陈述,但不同类型的数据库有不同的优势和劣势。无模式数据库更专门用于缓存存储;图形数据库专门用于基于关系(边缘)的查询;关系数据库专门用于获取/更新记录(表);而三元组数据库更专门用于三元组(RDF)(等等)。有更多类型)

我之所以提到这一点,是因为听起来你的数据可能大多是“一次写入,多次读取”。在这种情况下,您可能实际上应该使用三层存储。您可以使用任何数据库类型来进行任何操作,但是选择最好的数据库需要您知道如何使用数据,以及这种使用是如何演变的。在

Must we really just implement every method and benchmark for performance?

好吧,这就是为什么存储过程如此重要的部分原因。拥有一个抽象领域的专家会有帮助的。它可能只是你在突破一台机器的极限。也许你只需要升级到一个集群;或者你有可怕的代码效率低下,在没有(或1)值改变的情况下,你在一次保存操作中接触到一个节点10k次。但老实说,除非你知道自己在找什么,否则替补并没有多大作用。例如,通常5小时和0.5秒之间的差异可以很简单地创建1个索引。在

(公平地说,虽然购买更大更好的数据库服务器/集群可能是效率低下的解决方案,但与1名数据库管理员的工资相比,有时这是最具成本效益的解决方案。所以,再一次,取决于你的优先级。我相信你的老板可能会把你想要的东西放在不同的优先级上)


TL;DR

你应该聘请一个领域专家来帮助你。在

如果that不是一个选择,去书店(或谷歌)拿起数据库4个傻瓜(动手学习数据库在线教程班),并成为领域专家自己。(你可以用它来提升你对公司的价值)

如果你没有时间,也许你唯一能节省的恩典就是升级你的硬件,用暴力来解决问题。(*只要增长不是指数增长)

如果不查看所有的代码和了解类的层次结构,很难知道,但目前我可能会冒险猜测,您的代码在OGM中运行得很慢,因为每个关系都是在自己的事务中创建的。所以你要为一个更大的图做大量的事务处理,这会减慢速度。在

我建议在初始导入中创建每个类/对象,而不是只添加一个新的类或编辑一个类的关系,而是使用类检查器简单地创建数据的图形表示,然后使用Cypher在Neo4J中用更少的事务来构造它图论你可以通过减少你需要做的查找来优化它。在

您可以在python代码中创建一个NetworkX MultiDiGraph来建模类的结构。从那以后,有几种不同的策略将数据放入Neo4J中-我也刚刚发现了this,但不知道它是否有效或效率如何。在

查询导入图的最有效方法取决于图的拓扑结构,以及它是否是周期性的。下面是一些选项。在

1。在两组查询中创建图形

对每个节点标签运行一个查询以创建每个节点,然后运行另一个查询以在每个节点标签组合之间创建每条边(此操作的效率取决于使用的不同节点标签的数量)。在

2。从图中的拓扑最高点或最低点开始,将图形创建为一系列路径

如果有很多不同的边缘标签和节点标签,这可能需要编写大量的密码逻辑组合UNWIND和{},但是,如果图是非常分层的,您也可以使用python来跟踪哪些节点已经创建了所有较低的节点和关系,然后使用这些知识来限制查询中发送到Neo4J的路径的大小。在

3。使用APOC导入整个图形

另一个选项,可能适合也可能不适合您的用例,性能可能更好也可能不太好,那就是使用NetworkX将图形导出到GraphML,然后使用use the APOC GraphML import tool。在

同样,在没有看到所有数据的情况下很难提供一个精确的解决方案,但我希望这对正确的方向有一定的帮助!很乐意根据更多数据帮助/回答任何其他问题。在

相关问题 更多 >