如何在Neo4j中映射树结构?

时间:2013-09-18 09:42:59

标签: tree neo4j cypher

我正在研究在Neo4j中描述树结构化数据集。在我当前的模型中,节点可以与其他节点建立 n 链接,使其成为这些节点的子节点:

root
 |
 \-- A
     |
     \-- 1
     |
     \-- 2
  • 指向根
  • 的链接
  • 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

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

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

感谢您的任何指示!


1)现实问题: 一种业务流程工具,其中服务链接到流程,组织,团队等,以提供何时和由谁提供服务的信息,并提供将提供此服务或负责的信息。

例如:

服务S用于流程P1和P2:

P1  P2
|   |
\---+-- S

服务S由Team T管理:

T
|
\-- S

T队是组织O的一部分:

O
|
\-- T

树:

root
 |
 |
 +-- Processes
 |   |
 |   +-- P1
 |   |   |
 |   |   \-- S
 |   |
 |   \-- P2
 |   |   |
 |   |   \-- S
 |
 +-- Organisations
 |   |
 |   +-- O
 |       |
 |       \-- T
 |           |
 |           \-- S

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

1 个答案:

答案 0 :(得分:1)

所以,前几天我和Michael Hunger进行了一次谈话,他承认Cypher在处理递归查询方面并不好。这应该在2.1中改变,但在那之前他建议我写一个unmanaged extension,然后我可以从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);
    }
}