如何在Neo4j中映射树结构?

Son*_*ata 7 tree neo4j cypher

我正在努力描述Neo4j中的树结构数据集.在我当前的模型中,一个节点可以有n个链接到其他节点,使其成为这些节点的子节点:

root
 |
 \-- A
     |
     \-- 1
     |
     \-- 2
Run Code Online (Sandbox Code Playgroud)
  • 指向root的链接
  • 1和2链接到A.
  • root是A的父级
  • 1和2是A的孩子

因为我使用的是nodejs(带有node-neo4j),所以读取数据库仅限于使用Cypher.要读取节点,我使用以下查询:

START n=node(1)
    -- this is the root node

MATCH (n)<-[linkedby:links*]-x, x-[linksto?:links*1]->()
    -- get all nodes that link to the root node and all nodes linking to those nodes, etc, etc and retrieve all nodes those found nodes link to

RETURN n, x, linkedby, LAST(linkedby) AS parent, COLLECT(DISTINCT linksto) AS links      
    -- the last in the path of linkedby is the direct parent

ORDER BY length(linkedby), parent.rank?
    -- ordering so that parents are fetched before their children from the result set
Run Code Online (Sandbox Code Playgroud)

我的问题:随着节点数和关系数的增加,这个查询变得非常慢(> 1 s).

是否有更好的方法来建模节点和关系?父节点和子节点之间是否需要不同的关系?或者我应该以任何方式更改查询?

感谢您的任何指示!


1)现实问题:一种业务流程工具,其中服务与流程,组织,团队等相关联,以提供何时以及由谁提供服务的信息,以及提供将提供此服务或负责的信息.

例如:

服务S用于过程P1和P2:

P1  P2
|   |
\---+-- S
Run Code Online (Sandbox Code Playgroud)

服务S由Team T管理:

T
|
\-- S
Run Code Online (Sandbox Code Playgroud)

T队是组织O的一部分:

O
|
\-- T
Run Code Online (Sandbox Code Playgroud)

树:

root
 |
 |
 +-- Processes
 |   |
 |   +-- P1
 |   |   |
 |   |   \-- S
 |   |
 |   \-- P2
 |   |   |
 |   |   \-- S
 |
 +-- Organisations
 |   |
 |   +-- O
 |       |
 |       \-- T
 |           |
 |           \-- S
Run Code Online (Sandbox Code Playgroud)

2)我在console.neo4j.org中的数据:

CREATE 
  (r {name:'root'}), 
  (ps {name: 'Processes'})-[:links]->r, 
    (p1 {name: 'P1'})-[:links]->ps,
    (p2 {name: 'P2'})-[:links]->ps,
      (s {name: 'Service'})-[:links]->p1,
      s-[:links]->p2,
  (org {name: 'Organisations' })-[:links]->r,
    (t {name: 'Team'})-[:links]->org,
      s-[:links]->t
Run Code Online (Sandbox Code Playgroud)

Son*_*ata 2

因此,有一天我与Michael Hunger进行了交谈,他承认 Cypher(尚)不擅长处理递归查询。这应该在 2.1 中改变,但在那之前他建议我编写一个非托管扩展,然后我可以从 nodejs 调用它。

这完全解决了我的问题:使用纯 Java 检索树比使用 Cypher 快大约 10 倍。

简化代码:

public class EntitiesStream {
    public Entity load(long nodeId) {
        Node n = database.getNodeById(nodeId);
        Entity entity = Entity.from(n);
        loadChildren(n, entity);
        return entity;
    }

    private void loadChildren(Node n, Entity e) {
        for (Relationship linksFrom: n.getRelationships(Direction.INCOMING, Relationships.links)) {
            Node startNode = linksFrom.getStartNode();
            Entity childEntity = Entity.from(startNode);
            e.addChild(((Number) linksFrom.getProperty("rank")).longValue, childEntity);
            this.loadChildren(startNode, childEntity);
        }
    }
}

public class Entity {
    private final TreeMap<Long, Entity> sortedChildren;

    Entity(long dbId) {
        this.sortedChildren = new TreeMap<>();
        // ...
    }

    public static Entity from(Node node) {
        Entity e = new Entity(node.getId());
        // ...

        return e;
    }

    public void addChild(Long rank, Entity childEntity) {
        sortedChildren.put(rank, childEntity);
    }
}
Run Code Online (Sandbox Code Playgroud)