我正在使用NEO4J数据库进行“压力测试”。这不是什么大问题,但部分结果让我想知道这项技术是否适合在线应用(或者我只是不会得到Cypher)。
第一个测试是按节点添加节点,如
(1° node) -[:NEXT_FRAME]-> () -[:NEXT_FRAME]-> () -[:NEXT_FRAME]-> () -[:NEXT_FRAME]-> ... -[:NEXT_FRAME]-> (last node)
然后使用此查询检索整个路径
START n=node:Frame(node_id="0"), m=node:Frame(node_id="9000")
MATCH p=(n)-[:FRAME_NEXT*]->(m)
RETURN p
ORDER BY m.node_id DESC
LIMIT 1
注意,当m.node_id == 2
时,查询大约需要100毫秒。现在有~9000个节点,最多可能需要30秒。我不是专家,但是时间太长了!我不认为9K节点会产生这么大的差异。
那么,我错过了什么?
干杯(和圣诞快乐)
编辑:
我正在使用py2neo并以这种方式对查询进行计时:
q_str = """
START n=node:Frame(node_id="0"), m=node:Frame(node_id="%d")
MATCH p=(n)-[:FRAME_NEXT*]->(m)
RETURN p
ORDER BY m.node_id DESC
LIMIT 1
""" % (i,)
print q_str
before = datetime.datetime.now()
query = neo4j.CypherQuery(graph_db, q_str)
record, = query.execute().data
after = datetime.datetime.now()
diff = after - before
diff_ms = diff.total_seconds() *1000
print 'Query took %.2f ms' % (diff_ms)
答案 0 :(得分:2)
查询会尝试识别n
和m
之间的每条路径,这可能是一个巨大的数字,具体取决于图表的形状。
在这种情况下尽量避免ORDER BY
。以下内容可能更快,因为只需要识别一条路径:
START n=node:Frame(node_id="0"), m=node:Frame(node_id="9000")
MATCH p=(n)-[:FRAME_NEXT*]->(m)
RETURN p
LIMIT 1
如果您正在寻找纯粹的表现,最好直接使用traversal API或graph algorithms。这需要一些Java编码。
答案 1 :(得分:2)
这是Cypher的一个缺点,它现在不能很好地处理长的可变长度路径。
你能试试MATCH p=shortestPath((n)-[:FRAME_NEXT*]->(m))
吗?
另外,如果可以,您可以尝试使用Neo4j 2.0而不是使用旧版索引,使用标签和新索引。根据查询计划,应该使用更快的双向遍历匹配器。
MATCH (n: Frame {node_id:"0"})-[:FRAME_NEXT*]->(m:Frame {node_id:"9000"})
RETURN p
使用REST遍历器可能会更好: http://docs.neo4j.org/chunked/milestone/rest-api-traverse.html
或REST-graph-algo: http://docs.neo4j.org/chunked/milestone/rest-api-graph-algos.html
答案 2 :(得分:1)
如果只有一个路径,则可以删除ODER BY
和LIMIT
。另外尝试使用shortestPath
函数,即使图中只有一个匹配路径(即使所有路径都是最短的),它也会快得多。最后,如果您知道变量深度关系有多深,请在您的模式中声明,如果您只知道大致有多深,则指定范围。尝试将这些组合用于比较,您可以在neo4j-shell中对它们进行分析,然后查看执行计划。
MATCH p=(n)-[:FRAME_NEXT*9000]->(m)
MATCH p=(n)-[:FRAME_NEXT*8900..9100]->(m)
MATCH p=shortestPath( (n)-[:FRAME_NEXT*]->(m) )
MATCH p=shortestPath( (n)-[:FRAME_NEXT*8900..9100]->(m) )