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

标签 python database neo4j cypher object-relational-model

我正在寻找一些关于如何重写应用程序代码以使其变得非天真的一般性建议,或者是否放弃 Neo4j 以使用另一种数据存储模型。这不仅仅是“主观”,因为它与 Python 中 Neo4j 驱动程序的具体、正确使用以及它为何以我的代码的方式执行有很大关系。

背景:

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

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

...等等,创建一些相当复杂且冗长的层次结构。

对于原型(prototype)设计,我们使用 RDFLib 将这些数据存储为语法三元组序列(主语 -> 动词/谓语 -> 宾语),并使用 RDFLib 的图形生成器来构建图形。

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

为了永久存储这些对象,并希望加速这些数据的写入和读取(查询/过滤),我们构建了自定义对象映射代码,该代码利用官方 neo4j python 驱动程序来写入和读取这些 Python 对象,递归地,往返于 Neo4j 数据库。

问题:

对于大型且复杂的数据集(例如 15k+ 节点和 15k+ 关系),我们代码的对象关系映射 (ORM) 部分太慢,并且扩展性很差。但我和我的同事都不是数据库或 Neo4j 方面的专家。我认为我们对于如何完成这个 ORM 的想法太天真了。我们开始怀疑使用 Neo4j 是否有意义,而更传统的 ORM(例如 SQL Alchemy)可能是更好的选择。

例如,我们现在的ORM提交算法是一个递归函数,它提交一个像这样的对象(伪代码):

def commit(object):
    for childstr in object:             # For each child object
        child = getattr(object, childstr)   # Get the actual object

        if attribute is <our object base type): # Open transaction, make nodes and relationship
            with session.begin_transaction() as tx:
                <construct Cypher query with:
                MERGE object            (make object node)
                MERGE child             (make its child node)
                MERGE object-[]->child  (create relation)
                >
                tx.run(<All 3 merges>)

            commit(child)                   # Recursively write the child and its children to neo4j

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

我们真的必须实现每种方法和性能基准吗?似乎必须有一些最佳实践(除了使用 batch IMPORT ,它不适合我们的用例)。我们已经阅读了类似链接的文章,并看到了有关编写更好的查询的各种技巧,但在尝试逐行优化代码之前,最好退一步并更广泛地检查案例。虽然很明显我们可以在某种程度上改进 ORM 算法。

使用这样的递归策略在 Neo4j 中写入和读取大型、深层层次结构对象是否有意义? Cypher 或 neo4j 驱动程序中是否有我们缺少的东西?或者使用 Py2neo 的 OGM 之类的东西更好?最好完全放弃 neo4j 吗? neo4j 和 Cypher 的好处很难被忽视,而且我们的数据确实似乎很适合图表。谢谢。

最佳答案

如果不查看所有代码并了解类层次结构,就很难知道,但目前我大胆猜测您的代码在 OGM 位中很慢,因为每个关系都是在其自己的事务中创建的。因此,您正在为更大的图表进行大量交易,这会减慢速度。

我建议在初始导入时创建每个类/对象,而不是仅仅添加一个新类/对象或编辑一个类的关系,而是使用类检查器简单地创建该类/对象的图形表示数据,然后使用 Cypher 在 Neo4J 中以更少的事务来构建它。使用一些基本的拓扑图理论,您还可以通过减少需要执行的查找次数来优化它。

您可以创建 NetworkX MultiDiGraph在你的Python代码中对你的类的结构进行建模。从那时起,有一些不同的策略可以将数据放入 Neo4J - 我也刚刚发现 this但不知道它是否有效或效率如何。

查询导入图的最有效方法将取决于图的拓扑以及它是否是循环的。下面是一些选项。

<强>1。在两组查询中创建图表

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

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

如果您有许多不同的边缘标签和节点标签,这可能需要编写大量结合 UNWINDFOREACH (CASE r.label = 'SomeLabel' THEN [1 ] ELSE [] | CREATE (n:SomeLabel {node_unique_id: x})->,但是如果图形非常分层,您也可以使用 python 来跟踪哪些节点已经创建了所有较低的节点和关系然后使用这些知识来限制查询中发送到 Neo4J 的路径的大小。

<强>3。使用APOC导入整个图

另一个选项(可能适合也可能不适合您的用例,也可能会或可能不会更高效)是使用 NetworkX 将图形导出到 GraphML,然后 use the APOC GraphML import tool .

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

关于python - 我为 Neo4j 做的 Python 对象映射是否太天真了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50916340/

相关文章:

python - 我如何使用 __getitem__ 和 __iter__ 并从字典返回值?

php - 如何使用 php 和 fpdf 创建发票 pdf?

database - 在 Slick 中实现触发器

database - 为什么此查询增加的计数超过预期? (密码/neo4j)?

json - 无法在 Neo4j 3.2.6 上调用 apoc.load.json

python - 使用 header 和特定文件名将 spark 数据帧导出到 .csv

iterator - 使用 python 连接上一句和下一句

python - Python什么时候做自动类型转换?

mysql - 如何找到所有mysql表之间的所有关系?

delphi - 在 delphi 中使用 Neo4j