【问题标题】:Optimizing Cypher Query优化密码查询
【发布时间】:2017-03-07 19:43:09
【问题描述】:

我目前开始使用 Neo4J 和它的查询语言密码。 我有多个遵循相同模式的查询。

我正在对 SQL 数据库和 Neo4J 进行一些比较。

在我的 Neo4J 数据库中,我拥有一种标签(人)和一种关系(朋友)。该人具有personID、姓名、电子邮件、电话等属性。 现在我想拥有朋友的第n个学位。我也想过滤掉那些也是朋友程度较低的人。 例如,如果我想搜索 3 度的朋友,我想过滤掉那些也是第一和/或第二度朋友的朋友。

这里是我的查询类型:

MATCH (me:person {personID:'1'})-[:FRIENDSHIP*3]-(friends:person)
WHERE NOT (me:person)-[:FRIENDSHIP]-(friends:person)
AND NOT (me:person)-[:FRIENDSHIP*2]-(friends:person)
RETURN COUNT(DISTINCT friends);

我在某处发现了类似的东西。

此查询有效。

我的问题是,如果我搜索更高程度的友谊和/或如果人数变得更多,这种查询模式会很慢。

如果有人可以帮助我优化它,我将不胜感激。

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

    如果您只想处理 3 的深度,这应该返回 3 度以外但也不小于 3 度的不同节点:

    MATCH (me:person {personID:'1'})-[:FRIENDSHIP]-(f1:person)-[:FRIENDSHIP]-(f2:person)-[:FRIENDSHIP]-(f3:person)
    RETURN apoc.coll.subtract(COLLECT(f3), COLLECT(f1) + COLLECT(f2) + me) AS result;
    

    上述查询使用 APOC 函数 apoc.coll.subtract 从结果中删除不需要的节点。该函数还确保集合包含不同的元素。

    以下查询更通用,并且应该适用于任何给定的深度(只需替换 * 之后的数字)。例如,此查询将使用 4 的深度:

    MATCH p=(me:person {personID:'1'})-[:FRIENDSHIP*4]-(:person)
    WITH NODES(p)[0..-1] AS priors, LAST(NODES(p)) AS candidate
    UNWIND priors AS prior
    RETURN apoc.coll.subtract(COLLECT(DISTINCT candidate), COLLECT(DISTINCT prior)) AS result;
    

    【讨论】:

      【解决方案2】:

      Cypher 的可变长度关系匹配的问题在于它正在寻找到达该深度的所有可能路径。当您只关心特定深度的节点而不是它们的路径时,这可能会导致不必要的性能问题。

      APOC's path expander 使用 'NODE_GLOBAL' uniqueness 是匹配包含深度的节点的更有效方法。

      当使用“NODE_GLOBAL”唯一性时,节点在遍历期间只会被访问一次。因此,当我们将路径扩展器的minLevelmaxLevel 设置为相同时,结果是该级别的节点在任何较低级别都不存在,这正是您想要获得的结果。

      安装 APOC 后试试这个查询:

      MATCH (me:person {personID:'1'})
      CALL apoc.path.expandConfig(me, {uniqueness:'NODE_GLOBAL', minLevel:4, maxLevel:4}) YIELD path
      // a single path for each node at depth 4 but not at any lower depth
      RETURN COUNT(path)
      

      当然,当您有机会时,您会希望参数化您的输入(personID、级别)。

      【讨论】: