【问题标题】:Cypher MATCH query speedCypher MATCH 查询速度
【发布时间】:2015-04-08 17:28:19
【问题描述】:

我在一台有 12 个处理器和 64GB 内存的 Windows 机器上安装了 Neo4j。我没有更改 Neo4j 允许的任何内存设置。

我的数据库有 380 万个节点,其中 210,000 个被标记为地理标记,总共有 650,000 个关系。我正在尝试运行以下查询,我想知道这是否是一个非常密集的查询,可能需要很长时间。

Messages.csv 是我的关系文件。已经创建了关系,但是由于我不知道如何将关系创建与下面的距离生成相结合,我正在加载并运行两次关系文件。

USING PERIODIC COMMIT 15000
LOAD CSV WITH HEADERS FROM "file:d:/messages.csv" AS line
MATCH (a:Geotagged { username: line.sender }) - [r:MSGED] -> (b:Geotagged { username: line.recipient })
SET r.Distance = (2 * 6371 * asin(sqrt(haversin(radians(toFloat(b.statusLat) - toFloat(a.statusLat))) + cos(radians(toFloat(b.statusLat))) * cos(radians(toFloat(a.statusLat))) * haversin(radians(toFloat(b.statusLon) - toFloat(a.statusLon))))));

初始关系生成大约需要 3-5 分钟。我让上面的运行了一个多小时,它仍然没有完成。我在同一个初始数据库上运行了一个类似的算法(尽管它有更多的触发调用),让它运行了 18 多个小时,但仍未完成。

我的问题:这是一个非常密集的查询吗?我没有给它足够的时间吗?更重要的是,有什么方法可以优化它吗?

我尝试添加“WHERE NOT HAS(r.Distance)”以排除算法已经设置了距离的节点对,但我不确定 MATCH 是一次性匹配还是每个匹配CSV 文件中的行?

对此的任何想法将不胜感激。

【问题讨论】:

    标签: neo4j cypher


    【解决方案1】:

    我开始调试的一种方法是使用WITH 对其进行限制:

    USING PERIODIC COMMIT 15000
    LOAD CSV WITH HEADERS FROM "file:d:/messages.csv" AS line
    WITH line LIMIT 100
    MATCH (a:Geotagged { username: line.sender }) - [r:MSGED] -> (b:Geotagged { username: line.recipient })
    SET r.Distance = (2 * 6371 * asin(sqrt(haversin(radians(toFloat(b.statusLat) - toFloat(a.statusLat))) + cos(radians(toFloat(b.statusLat))) * cos(radians(toFloat(a.statusLat))) * haversin(radians(toFloat(b.statusLon) - toFloat(a.statusLon))))));
    

    这样,您可以更改LIMIT 数字,以查看性能如何随着限制的增加而下降。

    另外,Geotagged 标签的username 属性索引?如果不是,那肯定应该是这样的:

    CREATE INDEX ON :Geotagged(username)
    

    如果它是唯一的并且您希望数据库强制执行:

    CREATE CONSTRAINT ON (g:Geotagged) ASSERT g.username IS UNIQUE
    

    【讨论】:

    • 对不起,是的,我已经将用户名限制为唯一,尽管我的印象是 CONSTRAINT 会自动创建索引....?
    【解决方案2】:

    这是对 Brian 回复的补充:

    您的语句的查询计划显示EAGER,以验证运行

    EXPLAIN explain LOAD CSV WITH HEADERS FROM "file:d:/messages.csv" AS line
    WITH line LIMIT 100
    MATCH (a:Geotagged { username: line.sender }) - [r:MSGED] -> (b:Geotagged { username: line.recipient })
    SET r.Distance = (2 * 6371 *asin(sqrt(haversin(radians(toFloat(b.statusLat) - toFloat(a.statusLat))) + cos(radians(toFloat(b.statusLat))) * cos(radians(toFloat(a.statusLat))) * haversin(radians(toFloat(b.statusLon) - toFloat(a.statusLon))))));
    

    LOAD CSV 的热情非常糟糕,请参阅这些博客文章为什么:

    按照 Mark 的建议,将 MATCH/SET 替换为 MERGE ON MATCH SET,我们可以将其重构为:

    explain LOAD CSV WITH HEADERS FROM "file:d:/messages.csv" AS line
    WITH line LIMIT 100
    MATCH (a:Geotagged { username: line.sender }), (b:Geotagged { username: line.recipient })
    MERGE (a)-[r:MSGED]->(b)
    ON MATCH SET r.Distance = (2 * 6371 * asin(sqrt(haversin(radians(toFloat(b.statusLat) - toFloat(a.statusLat))) + cos(radians(toFloat(b.statusLat))) * cos(radians(toFloat(a.statusLat))) * haversin(radians(toFloat(b.statusLon) - toFloat(a.statusLon))))));
    

    eager 已经消失了。

    【讨论】:

    • Stefan,谢谢,我不知道 PROFILE 功能,甚至不知道 Eager 的问题。此后,我按照您的建议更改了查询,并以 10 和 100 的限制运行。两者都进行了 0 次修改(即,这些行不代表从一个地理标记用户发送到另一个地理标记用户的消息)。 10 行耗时 11.5 秒,100 行耗时 71 秒。该文件有 3,712,112 行,因此根据 71 秒/100 行推断,大约需要 30 天。这是令人惊讶的还是正常的?仅供参考,我的原始查询在 36 秒内运行了 100 行(是修改后语法的一半)。
    • 这太慢了。我想你可以通过切换到 Linux 获得很多。
    • 嗨 Stefan,windows 实现真的那么不可靠吗?我也更改了页面缓存,没有任何变化。我还发布了另一个问题,但是当我运行'index --indexes'时,由唯一约束创建的索引没有显示在shell中,这正常吗?
    • 到目前为止,我所知道的大多数生产安装都在 Linux 上运行。在 Neo4j
    • 你还有 NodeByLabel 扫描 stefan :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多