【问题标题】:Low performance of neo4jneo4j 性能低下
【发布时间】:2016-02-12 13:01:32
【问题描述】:

我是一家提供约会服务的公司的服务器工程师。 目前我正在为我们的新推荐引擎构建一个 PoC。 我尝试使用neo4j。但是这个数据库的性能并不能满足我们的需要。 我有强烈的感觉,我做错了什么,neo4j 可以做得更好。 那么有人可以给我一个建议如何提高我的 Cypher 查询的性能或如何以正确的方式调整 neo4j? 我正在使用在带有 Amazon Linux 的 c4.4xlarge 实例上运行的 neo4j-enterprise-2.3.1。 在我们的数据集中,每个用户可以与其他用户有 4 种类型的关系 - LIKE、DISLIKE、BLOCK 和 MATCH。 他还有一个属性,比如国家代码、生日和性别。

我使用 neo4j-import 工具将我们所有的用户和关系从 RDBMS 导入到 neo4j。 所以每个用户都是一个有属性的节点,每个引用都是一个关系。

neo4j-import 工具的报告说:

2 558 667 个节点,

1 674 714 539属性和

1 664 532 288 关系

已导入。

所以这是一个巨大的数据库 :-) 在我们的例子中,一些节点可以有多达 30 000 个传出关系..

我在 neo4j 中做了 3 个索引:

Indexes
ON :User(userId)           ONLINE  
ON :User(countryCode)      ONLINE  
ON :User(birthday)         ONLINE  

然后我尝试使用此查询构建在线推荐引擎:

MATCH (me:User {userId: {source_user_id} })-[:LIKE | :MATCH]->()<-[:LIKE |  :MATCH]-(similar:User)
USING INDEX me:User(userId)
USING INDEX similar:User(birthday)
WHERE similar.birthday >= {target_age_gte} AND
      similar.birthday <= {target_age_lte} AND
      similar.countryCode = {target_country_code} AND
      similar.gender = {source_gender}
WITH similar, count(*) as weight ORDER BY weight DESC 
SKIP {skip_similar_person} LIMIT {limit_similar_person}
MATCH (similar)-[:LIKE | :MATCH]-(recommendation:User)
WITH recommendation, count(*) as sheWeight
WHERE recommendation.birthday >= {recommendation_age_gte} AND
      recommendation.birthday <= {recommendation_age_lte} AND
      recommendation.gender= {target_gender}
WITH recommendation, sheWeight ORDER BY sheWeight DESC 
SKIP {skip_person} LIMIT {limit_person}
MATCH (me:User {userId: {source_user_id} })
WHERE NOT ((me)--(recommendation))
RETURN recommendation

这是其中一位用户的执行计划: plan

当我对用户列表执行此查询时,我得到了结果:

count=2391, min=4565.128849, max=36257.170065, mean=13556.750555555178, stddev=2250.149335254768, median=13405.409811, p75=15361.353029999998, p95=17385.136478, p98=18040.900481, p99=18426.811424, p999=19506.149138, mean_rate=0.9957385490980866, m1=1.2148195797996817, m5=1.1418078036067119, m15=0.9928564378521962, rate_unit=events/second, duration_unit=milliseconds

因此,对于实时推荐来说,即使是最快的速度也太慢了..

你能告诉我我做错了什么吗?

谢谢。

编辑 1:使用扩展框进行计划:

【问题讨论】:

  • 你能上传扩展框的计划吗?
  • 上传的扩展方案
  • 嗨,迈克,你能给我发一封电子邮件吗,neo4j.com 的迈克尔,很想访问你的数据库来帮助你进行查询。

标签: neo4j cypher


【解决方案1】:

我构建了一个非托管扩展,看看我是否能比 Cypher 做得更好。你可以在这里抓住它 => https://github.com/maxdemarzi/social_dna

这是第一次尝试,我们可以做一些事情来加快速度。我们可以预先计算/保存相似的用户,在这里和那里缓存东西,以及随机的其他技巧。试一试,告诉我们进展如何。

问候, 最大

【讨论】:

  • 谢谢 Max,这是您的扩展结果:count=67659, min=66.381489, max=2812.473438, mean=1057.0306443213133, stddev=507.4902115282372, median=1021.305496, p75=1424.2454759999998, p95=1919.475549, p98=2159.701725, p99=2322.1246849999998, p999=2812.473438, mean_rate=16.823460426561933, m1=14.954869485935108, m5=14.840333898992547, m15=14.832090331866569, rate_unit=events/second, duration_unit=milliseconds 令人印象深刻!
【解决方案2】:

如果我没看错的话,它会通过userId 为用户查找所有匹配项,并根据您的各种条件分别为用户查找所有匹配项。然后它会找到它们聚集在一起的所有地方。

由于您从左侧开始使用单个节点的情况,我的猜测是我们会更好地遵循路径,然后通过关系遍历过滤它得到的内容。

让我们看看这样的开始对你有何帮助:

MATCH
  (me:User {userId: {source_user_id} })-[:LIKE | :MATCH]->()
  <-[:LIKE |  :MATCH]-(similar:User)
WITH similar
WHERE similar.birthday >= {target_age_gte} AND
      similar.birthday <= {target_age_lte} AND
      similar.countryCode = {target_country_code} AND
      similar.gender = {source_gender}
WITH similar, count(*) as weight ORDER BY weight DESC 
SKIP {skip_similar_person} LIMIT {limit_similar_person}



MATCH (similar)-[:LIKE | :MATCH]-(recommendation:User)
WITH recommendation, count(*) as sheWeight
WHERE recommendation.birthday >= {recommendation_age_gte} AND
      recommendation.birthday <= {recommendation_age_lte} AND
      recommendation.gender= {target_gender}
WITH recommendation, sheWeight ORDER BY sheWeight DESC 
SKIP {skip_person} LIMIT {limit_person}
MATCH (me:User {userId: {source_user_id} })
WHERE NOT ((me)--(recommendation))
RETURN recommendation

【讨论】:

  • 嗨,布赖恩,感谢您的回答。但是对于同一用户,您的方式要慢 15 倍。这是plan
【解决方案3】:

[更新]

查询效率低下的一个可能(非直观)原因是,当您指定 similar:User(birthday) 过滤器时,Cypher 使用带有 :User(birthday) 索引的索引搜索(以及针对 @ 987654324@ 和 gender) 查找similar所有可能 DB 匹配项。让我们将这组similar 节点称为A

只有在找到 A 之后,查询过滤器才会查看其中哪些节点实际连接到 me,正如您的 MATCH 模式所指定的那样。

现在,如果与 A 的大小相比,mesimilar 的路径相对较少(由 MATCH 模式指定,但不考虑其 WHERE 子句)——比如说,小 2 个或更多数量级 - 然后从 similar 中删除 :User 标签可能会更快(因为我认为在您的数据模型中他们可能都将成为用户),并删除 @ 987654339@ 子句。在这种情况下,不使用similar 的索引实际上对您来说可能更快,因为您只会在相对较小的一组节点上使用WHERE 子句。

同样的注意事项也适用于recommendation 节点。

当然,这一切都必须通过对您的实际数据进行测试来验证。

【讨论】:

  • 删除标签以提高速度听起来很违反直觉
  • @cybersam 感谢您的帮助,但此解决方案不起作用。删除:用户标签工作量增加20倍。同一用户的 20 055 758 总 db 点击次数为 1 218 639 ......这是plan
  • 是的,我建议的答案确实取决于您数据的特征。我已经更新了我的答案,希望能更清楚一点。但是,不幸的是,它似乎对您的情况没有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-15
  • 2011-11-03
  • 2019-08-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多