【问题标题】:Neo4j bad performance with OR operatorNeo4j 使用 OR 运算符时性能不佳
【发布时间】:2019-05-28 11:56:49
【问题描述】:

我正在使用 neo4j-3.5 社区版本。并且使用 neo4j 构建了一个巨大的图表,其中包含约 2000 万个电影数据节点。我还插入了流派和关键字并构建了图表。 以下查询需要 > 5 秒

MATCH 
    (p:`Program`),  
    (p:Program)-[genre:of_genre]->(g:Genre), 
    (p:Program)-[key_rel:associated_keyword]->(k:Keyword)
  WHERE   
    ((g.id IN [1010]) OR (k.id IN ['keyword_121'])) AND 
    ((p.show_type IN ['movie'])) AND 
    (p.imdb_score > 0)
  RETURN distinct p.id, p.imdb_score
  ORDER BY p.imdb_score desc
  LIMIT 50

而如果我将 OR 替换为 AND,则需要

MATCH 
    (p:`Program`),  
    (p:Program)-[genre:of_genre]->(g:Genre), 
    (p:Program)-[key_rel:associated_keyword]->(k:Keyword)
  WHERE   
    ((g.id IN [1010]) AND (k.id IN ['keyword_121'])) AND 
    ((p.show_type IN ['movie'])) AND 
    (p.imdb_score > 0)
  RETURN distinct p.id, p.imdb_score
  ORDER BY p.imdb_score desc
  LIMIT 50

类型 ID 和关键字 ID 上有索引。

'OR' 的 PROFILE 响应:

“AND”的 PROFILE 响应:

用 OR 运算符编写查询有更好的方法吗?

【问题讨论】:

  • 您能否在开始时使用PROFILE 运行查询并在此处分享扩展计划?
  • @Raj:我已经用 PROFILE 输出更新了问题。
  • 很难说计划的哪一部分与查询的哪一部分相对应。请先展开计划的所有元素(查看查询计划时查询结果窗格右下角的双向下箭头),然后将其添加到您的问题中,替换您提供的折叠计划。
  • @InverseFalcon:我已经更新了查询计划。

标签: neo4j cypher graph-databases query-performance boolean-expression


【解决方案1】:

您的查询在 3 个不连贯的模式之间构建了一个笛卡尔积。

尝试以下查询:

  MATCH 
    (k:Keyword)<-[key_rel:associated_keyword]-(p:Program)-[genre:of_genre]->(g:Genre)
  WHERE   
    ((g.id IN [1010]) OR (k.id IN ['keyword_121'])) AND 
    ((p.show_type IN ['movie'])) AND (p.imdb_score > 0)
  RETURN distinct p.id, p.imdb_score
  ORDER BY p.imdb_score desc
  LIMIT 50

【讨论】:

  • 这仍然需要与以前相似的时间。
  • @Raj 我认为IN 不需要我们可以使用等于运算符
  • 在需要匹配多个 id 时使用 IN。
  • @sravan 你可以在没有 IN 的情况下检查一次吗?
  • @Govind Singh:我必须使用 IN 运算符。
【解决方案2】:

可能更适合你:

OPTIONAL MATCH (g:Genre) WHERE g.id IN [1010]
OPTIONAL MATCH (k:Keyword) WHERE k.id IN ['keyword_121']
WITH g, k
MATCH (p:`Program`)
WHERE
  p.show_type IN ['movie'] AND
  p.imdb_score > 0 AND
  ((p)-[:of_genre]->(g) OR (p)-[:associated_keyword]->(k))
RETURN distinct p.id, p.imdb_score
ORDER BY p.imdb_score desc
LIMIT 50

此查询可能会使用您的两个索引(或者至少您可以提供hints 以使用它们)。此外,如果电影在您的数据库中不是很常见,您可能希望在 :Program(show_type) 上创建索引。

WHERE 子句也只是测试是否存在单个所需的 :of_genre:associated_keyword 关系——它不会尝试实际扫描并保存所有这些关系。

【讨论】:

  • 此更改不会将性能提高到预期的水平。 ~4 秒变为 ~1.5 秒。但“AND”查询在 100 毫秒内执行。
  • 您不应该期望性能会提高到那个水平。了解简单地将 OR 更改为 AND 并不简单。它改变了查询必须做什么才能正确的逻辑。它不能只依赖于从k 遍历,它必须完成从g 遍历的工作,否则如果使用AND 则不需要。必须做更多的工作,因为没有其他选择可以使其在逻辑上正确。
  • 你应该对cybersam的查询进行PROFILE。如果它在 kg 上使用索引查找,那么它可能是你能得到的最好的。
猜你喜欢
  • 2017-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-08
  • 2012-05-15
  • 2021-08-17
  • 2015-07-08
相关资源
最近更新 更多