Neo4J查询性能不佳

时间:2013-12-25 22:41:52

标签: performance neo4j cypher py2neo

我正在使用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)

3 个答案:

答案 0 :(得分:2)

查询会尝试识别nm之间的每条路径,这可能是一个巨大的数字,具体取决于图表的形状。

在这种情况下尽量避免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 APIgraph 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 BYLIMIT。另外尝试使用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) )