1

我想这可以轻松实现,但无法弄清楚。是否有可能在一次遍历(Neo4j 1.9RC2)中实现以下目标:从一个节点开始,包括它的所有第一个邻居(深度 1)并包括它的邻居之间的所有链接(如果有的话)。方向无关紧要。

这是一个测试场景:

  +-+     +-+                 +-+
  |7+----->5|                 |4+------+
  +++     +-+-----------------+-+      |
   |        |                 |        |
   |        |      +--+       |        |
   |        +------|1 |-------+        |
  ++>              +-++               +-+     +-+
  |8|                |                |2+-----|6|
  +-+                +----------------+++     +-+
                                       |
                                       |
                                      +-+
                                      |3|
                                      +-+

从节点 1 开始,我想包括节点 2,4 和 5 以及关系 2-4 和 4-5,但不包括 2-6 或 5-7。和测试夹具:

Node[] nodes = new Node[10];
Transaction tx = graphDb.beginTx();
try {
    for (int i = 1; i < 10; i++) {
        Node node = graphDb.createNode();
        node.setProperty("id", i);
        otuIdIndex.add(node, "id", i);
        nodes[i] = node;//nodes[0] is empty!
    }
    nodes[1].createRelationshipTo(nodes[2], RelTypes.CONNECTED_TO);
    nodes[1].createRelationshipTo(nodes[4], RelTypes.CONNECTED_TO);
    nodes[1].createRelationshipTo(nodes[5], RelTypes.CONNECTED_TO);
    nodes[2].createRelationshipTo(nodes[4], RelTypes.CONNECTED_TO);
    nodes[2].createRelationshipTo(nodes[6], RelTypes.CONNECTED_TO);
    nodes[3].createRelationshipTo(nodes[2], RelTypes.CONNECTED_TO);
    nodes[5].createRelationshipTo(nodes[4], RelTypes.CONNECTED_TO);
    nodes[7].createRelationshipTo(nodes[5], RelTypes.CONNECTED_TO);
    nodes[7].createRelationshipTo(nodes[8], RelTypes.CONNECTED_TO);
    tx.success();
} finally {
    tx.finish();
}

final TraversalDescription traversalDescription = Traversal.description().breadthFirst()
        .relationships(RelTypes.CONNECTED_TO, Direction.BOTH)
        .uniqueness(Uniqueness.RELATIONSHIP_GLOBAL)
        .evaluator(Evaluators.toDepth(2))
        .evaluator(Evaluators.excludeStartPosition());
for (Path path : traversalDescription.traverse(nodes[1])) {
    System.out.println(path);
}

输出是:

(1)--[CONNECTED_TO,0]-->(2)
(1)--[CONNECTED_TO,1]-->(4)
(1)--[CONNECTED_TO,2]-->(5)
(1)--[CONNECTED_TO,0]-->(2)--[CONNECTED_TO,3]-->(4)
(1)--[CONNECTED_TO,0]-->(2)--[CONNECTED_TO,4]-->(6)
(1)--[CONNECTED_TO,0]-->(2)<--[CONNECTED_TO,5]--(3)
(1)--[CONNECTED_TO,1]-->(4)<--[CONNECTED_TO,6]--(5)
(1)--[CONNECTED_TO,2]-->(5)<--[CONNECTED_TO,7]--(7)

我想要做的是排除这三个:

(1)--[CONNECTED_TO,0]-->(2)<--[CONNECTED_TO,5]--(3)
(1)--[CONNECTED_TO,0]-->(2)--[CONNECTED_TO,4]-->(6)
(1)--[CONNECTED_TO,2]-->(5)<--[CONNECTED_TO,6]--(7)

Lasse建议使用以下密码查询http://console.neo4j.org/?id=3ihr7l

start one=node:node_auto_index(name='One') 
match one-[r:R*1]->m, m-[s]-l--one 
return distinct s

哪种可以满足我的需要,但我想知道这是否可行Traversal

4

1 回答 1

1

好的,找到了一种方法,但是太慢了,在 200K 节点/700K 关系数据库中,加载一个网络需要一秒钟,而 fromDepth(1).toDepth(1) 评估器需要 0.006 秒(150 倍因子):

final TraversalDescription traversalDescription = Traversal.description().breadthFirst()                                    
        .relationships(RelTypes.CONNECTED_TO, Direction.BOTH)                                                               
        .uniqueness(Uniqueness.RELATIONSHIP_GLOBAL)                                                                         
        .evaluator(Evaluators.includeIfAcceptedByAny(new PathEvaluator() {                                                  
            private final Set<Long> firstNeighbors = new HashSet<Long>();                                                   
            @Override                                                                                                       
            public Evaluation evaluate(Path path, BranchState state) {                                                      
                if (path.length() == 0) {                                                                                    
                    return Evaluation.EXCLUDE_AND_CONTINUE;                                                                 
                } else if (path.length() == 1) {                                                                             
                    firstNeighbors.add(path.endNode().getId());                                                             
                    return Evaluation.INCLUDE_AND_CONTINUE;                                                                 
                } else if (path.length() == 2) {                                                                            
                    final Iterator<Node> iterator = path.nodes().iterator();                                                
                    iterator.next();//start node, just skip                                                                 
                    Node firstNeighbor = iterator.next();                                                                   
                    if (firstNeighbors.contains(path.endNode().getId()) && firstNeighbors.contains(firstNeighbor.getId())) {
                        return Evaluation.INCLUDE_AND_CONTINUE;                                                             
                    } else {                                                                                                
                        return Evaluation.EXCLUDE_AND_CONTINUE;                                                             
                    }                                                                                                       
                } else {                                                                                                    
                    return Evaluation.EXCLUDE_AND_PRUNE;                                                                    
                }                                                                                                           
            }                                                                                                               

            @Override                                                                                                       
            public Evaluation evaluate(Path path) {                                                                         
                return evaluate(path, null);                                                                                
            }                                                                                                               
        }));     

更新tstorms建议更快的查询

public class NeoTraversal {

public static void main(final String[] args) {
    final GraphDatabaseService db = new GraphDatabaseFactory()
            .newEmbeddedDatabaseBuilder("/neo4j")
            .loadPropertiesFromURL(NeoTraversal.class.getClassLoader().getResource("neo4j.properties"))
            .newGraphDatabase();
    final Set<Long> uniquePartnerRels = new HashSet<Long>();
    long startTime = System.currentTimeMillis();
    final Node start = db.getNodeById(36);
    for (final Path path : Traversal.description()
            .breadthFirst()
            .relationships(Rel.COOCCURS_WITH, Direction.BOTH)
            .uniqueness(Uniqueness.NODE_GLOBAL)
            .evaluator(Evaluators.atDepth(1))
            .traverse(start)) {
        Node partner = start.equals(path.startNode()) ? path.endNode() : path.startNode();
        for (final Path partnerPath : Traversal.description()
                .depthFirst()
                .relationships(Rel.COOCCURS_WITH, Direction.BOTH)
                .uniqueness(Uniqueness.RELATIONSHIP_PATH)
                .evaluator(Evaluators.atDepth(2))
                .evaluator(Evaluators.includeWhereEndNodeIs(start))
                .traverse(partner)) {
            uniquePartnerRels.add(partnerPath.relationships().iterator().next().getId());
        }
    }
    System.out.println("Execution time: " + (System.currentTimeMillis() - startTime));
    System.out.println(uniquePartnerRels.size());
}

static enum Rel implements RelationshipType {
    COOCCURS_WITH
}

}
于 2013-04-29T16:48:12.917 回答