【问题标题】:Neo4j - don't know how to improve cypher queryNeo4j - 不知道如何改进密码查询
【发布时间】:2015-05-12 02:14:05
【问题描述】:

我有这个查询返回非常快,0.5 秒并返回所有预期的 303 条记录。注意:“Woka”在这里的意思是“书”。

MATCH (p:Publisher)-[r:PUBLISHED]->(w:Woka)<-[s:AUTHORED]-(a:Author),
(l:Language)-[t:USED]->(w:Woka)-[u:INCLUDED]->(b:Bisac) 
WHERE (a.author_name = 'Camus, Albert') 
RETURN w.woka_id as woka_id, p.publisher_name as publisher_name, w.woka_title as woka_title, a.author_name as author_name, l.language_name as language_name, b.bisac_code as bisac_code, b.bisac_value as bisac_value 
ORDER BY woka_id;

我想添加更多信息,例如描述。我创建了描述节点,并且在语言和描述以及描述和书籍(Woka)之间创建了关系。 下面的查询将所有描述返回为空,但仅针对 60 条记录而不是 303 条。这是因为并非所有书籍都有描述。执行时间还可以,0.3秒。

MATCH (p:Publisher)-[r:PUBLISHED]->(w:Woka)<-[s:AUTHORED]-(a:Author), 
(l:Language)-[t:USED]->(w:Woka), (b:Bisac)<-[u:INCLUDED]-(w:Woka),
(d:Description)-[v:HAS_DESCRIPTION]-(w) 
WHERE (a.author_name = 'Camus, Albert') 
RETURN w.woka_id as woka_id, p.publisher_name as publisher_name, w.woka_title as woka_title, a.author_name as author_name, l.language_name as language_name, b.bisac_code as bisac_code, b.bisac_value as bisac_value, d.description as description 
ORDER BY woka_id;

但是我知道结果集中遗漏了一些记录,50 和 303 的区别确实有描述。我使用 OPTIONAL 构建了另一个查询,但是这个(如下所示)永远不会返回,永远运行。

MATCH (p:Publisher)-[r:PUBLISHED]->(w:Woka)<-[s:AUTHORED]-(a:Author),
 (l:Language)-[t:USED]->(w:Woka)-[u:INCLUDED]->(b:Bisac) 
OPTIONAL MATCH (d:Description)-[v:HAS_DESCRIPTION]-(w:Woka)-[:AUTHORED]-(a:Author)  
WHERE (a.author_name = 'Camus, Albert') 
RETURN w.woka_id as woka_id, p.publisher_name as publisher_name, w.woka_title as woka_title, a.author_name as author_name, l.language_name as language_name, b.bisac_code as bisac_code, b.bisac_value as bisac_value, d.description as description 
ORDER BY woka_id;

对于 303 条记录的原始结果集,不知道如何改进查询以获取存在的可选描述和不存在的空值?

【问题讨论】:

  • 你用的是什么版本?

标签: neo4j cypher


【解决方案1】:

我想我们之前已经进行过这样的对话了。

你必须降低你的中间基数

在你的人际关系中使用方向

不要重复你已经解决的模式,比如

OPTIONAL MATCH (d:Description)-[v:HAS_DESCRIPTION]-(w:Woka)-[:AUTHORED]-(a:Author)

应该是

OPTIONAL MATCH (d:Description)-[v:HAS_DESCRIPTION]-(w)

如果您匹配长路径,则您会在其间创建很多潜在匹配,对于这些行中的每一,执行下一个匹配,如果它们创建多行,每行乘以rows1*rows2*rows3

因此,您必须使用DISTINCT 或两者之间的聚合来尽可能降低基数。

只是为您的第一个示例演示它,一次使用DISTINCT,一次使用collect。这里可能没有必要,但只是为了演示,因为示例足够小。

MATCH (p:Publisher)-[r:PUBLISHED]->(w:Woka)<-[s:AUTHORED]-(a:Author)
WHERE (a.author_name = 'Camus, Albert') 
WITH DISTINCT w,a,p

MATCH (l:Language)-[t:USED]->(w)
WITH w,a,p, collect(l) as languages

MATCH (w)-[u:INCLUDED]->(b:Bisac) 
RETURN w.woka_id as woka_id, w.woka_title as woka_title, 
       p.publisher_name as publisher_name, 
       a.author_name as author_name, 
       [l in languages | l.language_name] as language_names, 
       b.bisac_code as bisac_code, b.bisac_value as bisac_value 
ORDER BY woka_id;

您正确地使用了OPTIONAL MATCH,但您必须再次考虑到潜在的额外行数会相乘。

OPTIONAL MATCH 的另一种选择是使用路径表达式和解构,例如描述:

RETURN w.woka_id as woka_id, w.woka_title as woka_title, 
       [p in ()<-[:HAS_DESCRIPTION]-(w) | head(nodes(p)).description] as descriptions

【讨论】:

  • 好像这个比其他返回快,记录数和结果集都对。
【解决方案2】:

除了@pablosaraiva 的回复,请确保您有一个索引:作者和财产author_name

create index on :Author(author_name)

如果这和 pablo 的回复没有帮助,请发布您的查询的查询计划。为此使用explain &lt;myquery&gt;(假设您使用>=2.2)

【讨论】:

  • 已编入索引。 ON :Author(author_name) ONLINE(用于唯一性约束)
【解决方案3】:

你能试试这个吗?

MATCH (p:Publisher)-[r:PUBLISHED]->(w:Woka)<-[s:AUTHORED]-(a:Author), (l:Language)-[t:USED]->(w)-[u:INCLUDED]->(b:Bisac) 
WHERE (a.author_name = 'Camus, Albert') 
WITH p,r,w,s,a,l,t,u,b
OPTIONAL MATCH (d:Description)-[v:HAS_DESCRIPTION]-(w)
RETURN w.woka_id as woka_id, p.publisher_name as publisher_name, w.woka_title as woka_title, a.author_name as author_name, l.language_name as language_name, b.bisac_code as bisac_code, b.bisac_value as bisac_value, d.description as description 
ORDER BY woka_id;

【讨论】:

  • 我会把WHERE放在WITH之前。
  • 编辑后的版本有效,在 0.5 秒内返回 303 行。上一个再也没有回来。但是,这 303 行之一的描述不应为空,但结果行的描述为空。这发生在 woka_id = '97818691945290000000' 显示对此的描述不为空的小查询是: MATCH (d:Description)-[:HAS_DESCRIPTION]-(w:Woka)-[:AUTHORED]-(a:Author ), (l:Language)-[:USED]-(w)-[:PUBLISHED]-(p:Publisher), (b:Bisac)-[:INCLUDED]-(w) 其中 (d.woka_id = '97818691945290000000 ') 返回 d, w, a, l, p, b;
  • 您能否发布您的数据子集,其中存在这些关系并且有该作者的描述?
  • 对不起,不需要发布一些数据,我发现错误,查询应该返回 d.description_text 而不是 d.description。 d.description 不作为属性存在,这就是返回 null 的原因。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-29
  • 1970-01-01
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多