【问题标题】:Neo4j Cypher has ultra-restrictive pattern comprehension - or am I using it wrong?Neo4j Cypher 具有超限制性的模式理解——还是我用错了?
【发布时间】:2020-08-10 12:30:03
【问题描述】:

我最近选择了 Neo4j,因为它似乎是存储数据的最佳数据库类型,我目前正在从一些在线讨论论坛中抓取。图的主要结构是社区 -> 论坛 -> 主题 -> 帖子 -> 作者

我正在尝试编写 Cypher 查询来解析 GraphQL 查询,并希望对论坛 -> 线程连接进行分页(例如)。关系是包含一个order 属性,即(f:Forum)-[:CONTAINS]->(t:Thread)

从 neo4j-graphql-js 库中,我了解到他们使用模式理解在子节点上运行“内部查询”。例如:

MATCH (f:Forum { id: $id })
RETURN f { .id, .name, .url, threads: [(f)-[:CONTAINS]->(t:Thread) | t { .id, .title, .url }] }

我真的很想在内部模式理解上使用 ORDER BY、LIMIT 和 SKIP,但不幸的是,这不受支持:https://github.com/opencypher/openCypher/issues/202 - neo4j-graphql-js 库通过使用 apoc.coll.sortMulti 解决了这个问题,但我'已经注意到性能不是很好并且比我在顶级模式等效项上使用 ORDER BY 子句慢很多。

由于我是图形 DBMS 的新手,这让我想知道我是否误解了应该如何使用图形 DB。从“前端”的角度来看,以最低级别的查询语言实现分页的能力似乎是一个关键部分,但同样,也许我没有正确理解事情。方钉、圆孔等等!

这是一个公平的评价吗? Cypher 中是否有另一个选项可以解决这个问题?或者,我应该回去使用 SQL 数据库来处理这个用例吗?

【问题讨论】:

    标签: neo4j graphql cypher


    【解决方案1】:

    [编辑]

    如果您将order 属性移动到Thread 节点中(如果每个Thread 节点仅连接到一个Forum,这应该是有效的),那么您可以创建一个index(或@ 987654322@) 上:Thread(order) 以加快您的查询速度。

    例如,此查询应利用索引更快地向前分页(假设f.id、用于分页目的的order 值和limit 值作为parameters 传递idorderlimit):

    MATCH (f:Forum)-[:CONTAINS]->(t:Thread)
    WHERE f.id = $id AND t.order > $order
    WITH f, t
    ORDER BY t.order
    LIMIT $limit
    RETURN f{.id, .name, .URL,
      firstOrder: MIN(t.order),
      lastOrder: MAX(t.order),
      threads: [x IN COLLECT(t) | x{.id, .title, .URL}]}
    

    这里有一个(稍微复杂,但也很快)向后分页的查询:

    MATCH (f:Forum)-[:CONTAINS]->(t:Thread)
    WHERE f.id = $id AND t.order < $order
    WITH f, t
    ORDER BY t.order DESC
    LIMIT $limit
    WITH f, t
    ORDER BY t.order
    RETURN f{.id, .name, .URL,
      firstOrder: MIN(t.order),
      lastOrder: MAX(t.order),
      threads: [x IN COLLECT(t) | x{.id, .title, .URL}]}
    

    如果用各种$limit 值分析上述查询的PROFILE,您应该看到db-hit 复杂度为O(F*L),其中FForum 节点的数量(即可能相对恒定)和L$limit 值。因此,这些查询应该会明显更快——使用索引——只要:

    F*L << (average number of `Threads` per `Forum`).
    

    【讨论】:

    • Brilliant @cybersam - 您知道 Cypher 规范的哪一部分确保内部 COLLECT 仅在每个论坛收集正确的线程吗?我删除了 WHERE 子句并运行了查询,令我惊讶的是,它没有为每个结果收集相同的线程集,而是按论坛对它们进行了分区。不确定我解释得是否好,但相比之下,如果 collect() 在 "f { ... }" 扩展之外,它会从任何地方收集所有线程,对吗?
    • 另外,很遗憾您不能对关系属性进行索引。我无法移动 order 属性,因为来自其他节点的线程的其他列表视图也需要关系的 order 属性。你知道是否真的没有办法提高关系属性的排序性能,或者管道中可以解决这个问题的任何东西?
    • 不清楚为什么关系上真的需要order 节点。你是说Thread 节点可以有多个CONTAINS 关系,还是类似的?无论如何,wrt COLLECT,阅读 aggregating functions 以及他们如何使用“分组键”——你看到的结果正是调整后的查询应该发生的结果。
    • 我刚刚调整了我的答案以提供向前和向后分页的查询。
    • 您可以查看full-text indexes,它确实支持关系索引,但它们使用 string 属性,也需要您付出更多努力。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多