【问题标题】:Neo4j Traversal API vs. CypherNeo4j 遍历 API 与 Cypher
【发布时间】:2015-02-22 11:16:00
【问题描述】:

什么时候应该选择 Neo4j 的遍历框架而不是 Cypher?

例如,对于朋友的朋友查询,我会编写如下 Cypher 查询:

MATCH (p:Person {pid:'56'})-[:FRIEND*2..2]->(fof) 
WHERE NOT (p)-[:FRIEND]->(fof) 
RETURN fof.pid

相应的 Traversal 实现将需要对 friends_at_depth_1friends_at_depth_2 进行两次遍历(或核心 API 调用以获取关系),并在遍历描述之外使用纯 java 构造找到这两组的差异。如果我在这里错了,请纠正我。

有什么想法吗?

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

    关于 Cypher 与遍历 API 的关键是要记住,遍历 API 是访问图的命令式方法,而 Cypher 是访问图的声明式方法。 You can read more about that difference here 但简短的版本是,在命令式访问中,您准确地告诉数据库如何 去获取图表。 (例如,我想做深度优先搜索,修剪这些分支,当我碰到某些节点时停止,等等)。在声明性图形查询中,您是在指定您想要什么,并且您将如何获得它的所有方面都委托给 Cypher 实现。

    在您的查询中,我会稍微修改一下:

    MATCH (p:Person {pid:'56'})-[:FRIEND*2..2]->(fof) 
    WHERE NOT (p)-[:FRIEND]->(fof) AND
          p <> fof
    RETURN fof.pid
    

    (我添加了确保p&lt;&gt;fof,因为朋友链接可能会回到原来的人)

    要在遍历器中执行此操作,您不需要两个遍历器,只需一个。您将只遍历 FRIEND 关系,在深度 2 处停止,并累积一组结果。

    现在,我将尝试证明您应该几乎总是使用 Cypher,除非您有非常特殊的情况,否则永远不要使用遍历 API。以下是我的理由:

    1. 声明式查询非常强大,因为它使您无需考虑如何操作。你只需要知道你想要什么。这意味着您可以将更多时间花在代码应该做的事情上,而花更少的时间在实现细节上。
    2. cypher 查询执行器一直在变得更好(2.2 版将有一个基于成本的计划器),当然他们付出了很多努力来确保 cypher 能够利用所有可用的索引。对于许多查询,我认为 cypher 在查找数据方面可能比您的遍历做得更好,除非您在对遍历进行编码时非常小心。
    3. Cypher 的代码比编写您自己的遍历要少得多,后者通常需要您实现某些类来执行专门的停止条件等。
    4. 目前,cypher 可以在嵌入式数据库中运行,也可以在服务器上运行。如果要运行遍历,则不能将其远程发送到要执行的服务器;也许充其量你可以编写一个执行遍历的服务器扩展。所以我认为目前 cypher 更灵活。

    好的,那么什么时候应该使用遍历?我知道的两个关键案例(其他人可能会建议其他人)

    1. 有时您需要对遍历的所有内容执行复杂的自定义 java 代码操作。在这种情况下,您将遍历器用作某种“访问者函数”,有时遍历器比密码更方便使用,具体取决于您在节点上运行的 Java 的性质。
    2. 有时您的性能要求非常高,您需要手动遍历图,因为您可以在遍历器中利用图结构的某些方面来使其运行速度更快,而 Cypher 无法利用。确实会发生这种情况,但首先这样做通常不是一个好主意。

    【讨论】:

    • PROFILE'ing Cypher 还有助于确定查询是否会导致底层的一些浪费操作。
    • 您的链接已损坏。我以反对票将你的一些分数作为人质。赎金是修复链接而不是删除链接。
    • 我更新了链接。这是一个重要的讨论点,人们可以从中学到很多东西,因此似乎值得更新这个 2015 年的答案,而不是那些虚构的互联网点。 :)
    【解决方案2】:

    本书摘录

    核心 API、遍历框架还是 Cypher?

    Core API 允许开发人员微调他们的查询,以便他们表现出高 与底层图的亲和力。编写良好的 Core API 查询通常比 任何其他方法。缺点是这样的查询可能很冗长,需要相当多的 开发人员的努力。此外,它们与底层图的高度相似性 使它们与其结构紧密耦合。当图结构发生变化时,它们 可以经常打破。 Cypher 可以更容忍结构变化——比如 可变长度路径有助于减少变化和变化。

    遍历框架都比核心 API 更松散耦合(因为它 允许开发人员声明信息性目标),并且不那么冗长,因此 使用 Traversal Framework 编写的查询通常需要较少的开发人员工作量 比使用 Core API 编写的等价物。因为它是通用的 然而,遍历框架往往表现得不太好 而不是编写良好的 Core API 查询。

    如果我们发现自己处于使用 Core API 或 Traversal 编码的不寻常情况 框架(因此避开了 Cypher 及其提供的功能),这是因为我们是 处理一个边缘案例,我们需要精心设计一个无法实现的算法 使用 Cypher 的模式匹配有效地表达。在核心之间进行选择 API 和 Traversal Framework 是决定更高抽象/ Traversal Framework 的低耦合度就足够了,或者是否接近 实际上,核心 API 的金属/更高耦合对于实现一个 算法正确并符合我们的性能要求。

    参考:Graph Databases, New Opportunities for Connected Data, p161

    什么是密码?

    开发者文档中的定义如下:cypher 是一种声明性的、受 SQL 启发的语言,用于使用 ascii-art 语法直观地描述图形中的模式。

    您可以在here找到更多相关信息。

    什么是核心 API?

    我发现this page 有以下句子:

    除了图形数据库的面向对象 API(与 NodeRelationshipPath 对象一起使用外,它还提供高度可定制的高速遍历和图形算法实现。

    所以实际上,核心 API 处理基本对象,例如属于 org.neo4j.graphdb 包的 NodeRelationship

    您可以在its developer guide 找到更多信息。

    什么是遍历API?

    Traversal API 为核心 API 添加了更多接口,帮助我们方便地进行遍历,而不是从头开始编写整个遍历逻辑。这些接口包含在org.neo4j.graphdb.traversal 包中。

    您可以在its developer guide 找到更多信息。

    三者之间的关系

    根据this answer

    Traversal API 建立在 Core API 之上,Cypher 建立在 Traversal API 之上;所以你可以在 Cypher 中做的任何事情都可以用其他 2 来完成。

    三个都做同样的例子

    This 2012 年的教程展示了所有三个执行相同任务的操作,其中核心 API 是最快的。其中包括 Andres Taylor 的一句话:

    Cypher 才刚满一岁。由于我们对开发人员的限制非常有限,因此我们必须对我们的工作非常挑剔,第一阶段的重点是探索语言,了解我们的用户如何使用查询语言,并扩展功能集达到一个合理的水平。
    我相信 Cypher 是我们未来的 API。我知道您可以通过手写查询轻松超越 Cypher。就像曾经创造的每一种语言一样,一开始你总是可以通过手工编写比编译器做得更好,但最终,编译器会赶上来

    文章结论:

    到目前为止,我只使用与 neo4j 配合使用的 Java Core API,我将继续这样做。
    如果您处于高速场景(我相信每个 Web 应用程序都是一个),您应该真正考虑切换到 neo4j Java 核心 API 来编写查询。它可能不如 Cypher 或 traverser 框架那么好看,但速度的提升是值得的。
    我个人也喜欢你自己遍历核心时所拥有的控制量。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多