从Java中的Cypher查询中检索结果缓慢 - Neo4j 2.0

时间:2014-01-15 13:29:14

标签: java neo4j cypher

当我从Java中获得Cypher查询执行结果时,我遇到ResourceIterator<Node>的结果检索速度非常慢。 next()命令平均需要156毫秒,标准差为385! 这种行为是期待的,还是我做错了什么?任何人都可以提出一种更有效的方法来实现同样的目标吗?


图形结构

我有以下图形布局,其中Point节点与其他点具有LinksTo关系:

节点:点
属性:
- idPoint (此属性上的新样式架构唯一约束)
- x (此属性上的新样式架构索引)
- y (此属性上的新样式架构索引)

关联:LinksTo
属性:
- idLink
- 长度
(...关系甚至在我的问题中都没有发挥作用......)

图表统计信息:
- 节点数:890,000
- 关系数:910,000


旧代码

(在Ubuntu上使用Neo4j 2.0.0与Oracle Java 7稳定)
(基本上,此代码在给定点周围的60x60方格中搜索节点(点)。)

GraphDatabaseService graphDB = new GraphDatabaseFactory ( ).newEmbeddedDatabase ("points_db");

ExecutionEngine engine = new ExecutionEngine (graphDB);

for (Coordinate c : coords) // coords holds 500 different coordinates
{
    int size = 30;
    int xMin = c.x - size;
    int xMax = c.x + size;
    int yMin = c.y - size;
    int yMax = c.y + size;

    String query = "MATCH (n:POINT) " +
                     "  WHERE n.x > " + xMin +
                     "    AND n.x < " + xMax +
                     "    AND n.y > " + yMin +
                     "    AND n.y < " + yMax +
                     "RETURN n AS neighbour";

    ExecutionResult result = engine.execute (query); // command1

    ResourceIterator<Node> ri = result.columnAs ("neighbour"); // command2

    while (ri.hasNext ( ))
    {
        Node n = ri.next ( ); // command3
        // ... some code ...
    }
}

测量

command1平均执行时间:7.5毫秒
command2平均执行时间:&lt; 1 ms
command3平均执行时间:156毫秒(标准差为358)

(在每次迭代中找到500次迭代(不同坐标)和平均6个点的测量。测量是可重复的。)


编辑1(如Luanne和Michael所建议的)

带参数化的新的更快的代码

(在Ubuntu上使用Neo4j 2.0.0与Oracle Java 7稳定)
(基本上,此代码在给定点周围的60x60方格中搜索节点(点)。)

GraphDatabaseService graphDB = new GraphDatabaseFactory ( ).newEmbeddedDatabase ("points_db");

ExecutionEngine engine = new ExecutionEngine (graphDB);
Map<String, Object> params = new HashMap<> ( );

int size = 30;
String query = "MATCH (n:POINT) " +
               "  WHERE n.x > {xMin}" +
               "    AND n.x < {xMax}" +
               "    AND n.y > {yMin}" +
               "    AND n.y < {yMax}" +
               "  RETURN n AS neighbour";

for (Coordinate c : coords) // coords holds 500 different coordinates
{
    params.put ("xMin", (int) c.x - size);
    params.put ("xMax", (int) c.x + size);
    params.put ("yMin", (int) c.y - size);
    params.put ("yMax", (int) c.y + size);

    ExecutionResult result = engine.execute (query, params); // command1

    ResourceIterator<Node> ri = result.columnAs ("neighbour"); // command2

    while (ri.hasNext ( ))
    {
        Node n = ri.next ( ); // command3
        // ... some code ...
    }
}

测量

command1平均执行时间:1.7 ms
command2平均执行时间:&lt; 1 ms
command3平均执行时间:112 ms(标准差为270)
(在每次迭代中找到500次迭代(不同坐标)和平均6个点的测量。测量是可重复的。)

1 个答案:

答案 0 :(得分:1)

您所做的不是图表查询,而是对整个数据库进行范围扫描。

所以它必须拉入所有节点,并为每个节点进行比较。

您通常通过将节点放入树(r-tree)中来解决此问题,该树将几何图形编码为二维树结构,然后您可以仅log(levels)复杂度访问所需的任何形状。 / p>

查看有关此主题的Neo4j空间的演示文稿:

http://neo4j.org/develop/spatial

您还强制Neo4j为每个节点重新解析并重新构建查询(500次)。 我同意Luanne的参数化,所以你的查询应该是这样的。 您也应该在for-loop

之前提取此信息
String query = "MATCH (n:POINT) " +
                 "  WHERE n.x > {xMin}" +
                 "    AND n.x < {xMax}" +
                 "    AND n.y > {yMin}" +
                 "    AND n.y < {yMax}" +
                 "  RETURN n AS neighbour";

ExecutionResult result = engine.execute (query,
          map("xMin",xmMin,"xMax",xMax,"yMin",yMin,"yMax",yMax)); // query + params

...