直接邻居关系密码查询性能

这个问题类似于这两个: 16283441,15456345 。

更新 :这是一个数据库转储 。

在190K节点和727K关系的数据库(以及128MB的数据库磁盘使用)中,我想运行以下查询 :

START start_node=node() MATCH (start_node)-[r:COOCCURS_WITH]-(partner), (partner)-[s:COOCCURS_WITH]-(another_partner)-[:COOCCURS_WITH]-(start_node) RETURN COUNT(DISTINCT s) as num_partner_partner_links; 

在这个db中,90%的节点有0个关系,剩下的10%有1到670个,所以这个查询可以返回的最大网络不可能有超过220K的链接(670 * 670)/ 2)。

在partner_partner_links小于10K的节点上,查询需要2-4秒,当被查出时。 对于更多连接的节点(20-45K链路),它需要大约40-50秒(不知道连接最多的节点需要多少)。

指定关系方向有点但不多(但是查询不会返回我需要它返回的内容)。

在一个最大的节点上分析查询说:

 ==> ColumnFilter(symKeys=[" INTERNAL_AGGREGATE48d9beec-0006-4dae-937b-9875f0370ea6"], returnItemNames=["num_partner_links"], _rows=1, _db_hits=0) ==> EagerAggregation(keys=[], aggregates=["( INTERNAL_AGGREGATE48d9beec-0006-4dae-937b-9875f0370ea6,Distinct)"], _rows=1, _db_hits=0) ==> PatternMatch(g="(partner)-['r']-(start_node)", _rows=97746, _db_hits=34370048) ==> TraversalMatcher(trail="(start_node)-[ UNNAMED3:COOCCURS_WITH WHERE true AND true]-(another_partner)-[s:COOCCURS_WITH WHERE true AND true]-(partner)", _rows=116341, _db_hits=117176) ==> ParameterPipe(_rows=1, _db_hits=0) neo4j-sh (0)$ 

我不明白为什么这么慢,大多数东西都应该在RAM中。 有可能在100毫秒以内或者neo4j不能达到这个目的吗? 如果有帮助的话,我可以将整个数据库放在某处。

最大的困惑是,当重写以使用不同的节点符号时,相同的查询运行速度较慢:)

 START n=node(36) MATCH (n)-[r:COOCCURS_WITH]-(m), (m)-[s:COOCCURS_WITH]-(p)-[:COOCCURS_WITH]-(n) RETURN COUNT(DISTINCT s) AS num_partner_partner_links; START start_node=node(36) MATCH (start_node)-[r:COOCCURS_WITH]-(partner), (partner)-[s:COOCCURS_WITH]-(another_partner)-[:COOCCURS_WITH]-(start_node) RETURN COUNT(DISTINCT s) AS num_partner_partner_links; 

前者总是在+4.2秒内运行,后者在3.8以下运行,无论我运行多少次(交错)!?

SW / HW详细信息:(高级)Neo4j v1.9.RC2,JDK 1.7.0.10,带有SSD磁盘的macbook pro,8GBRAM,2核i7,具有以下neo4j配置:

 neostore.nodestore.db.mapped_memory=550M neostore.relationshipstore.db.mapped_memory=540M neostore.propertystore.db.mapped_memory=690M neostore.propertystore.db.strings.mapped_memory=430M neostore.propertystore.db.arrays.mapped_memory=230M neostore.propertystore.db.index.keys.mapped_memory=150M neostore.propertystore.db.index.mapped_memory=140M wrapper.java.initmemory=4092 wrapper.java.maxmemory=4092 

将您的查询更改为以下一个。 在我的笔记本电脑上,规格明显低于你的笔记本电脑,执行时间缩短了一半。

 START start_node=node(36) MATCH (start_node)-[r:COOCCURS_WITH]-(partner) WITH start_node, partner MATCH (partner)-[s:COOCCURS_WITH]-(another_partner)-[:COOCCURS_WITH]-(start_node) RETURN COUNT(DISTINCT s) AS num_partner_partner_links; 

此外,与默认设置相比,使用您的设置不会影响性能。 我担心你无法获得你想要的性能,但这个问题是朝着正确方向迈出的一步。

通常,遍历API将比Cypher更快,因为您明确控制遍历。 我模仿了查询如下:

 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 uniquePartnerRels = new HashSet(); 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 } } 

这明显优于cypher查询,因此这对您来说可能是一个不错的选择。 优化很可能仍然存在。

似乎除了深度/广度首次遍历之外的任何事情,neo4j并不是“快速快速”。 我通过预先计算所有网络并将它们存储到MongoDB中解决了这个问题。 描述网络的节点文档如下所示:

 { node_id : long, partners : long[], partner_partner_links : long[] } 

合作伙伴和partner_partner_links是描述egdes的文档ID。 获取整个网络需要2个查询:一个用于此文档,另一个用于边缘属性(也包含节点属性):

 db.edge.find({"_id" : {"$in" : network.partner_partner_links}});