Neo4j - 算得很慢

时间:2015-07-27 18:48:41

标签: neo4j cypher

我正在运行此查询(bisac_code是唯一索引的)。 执行时间超过2.5分钟。 从总共近4000个中选择了52个主要代码。 wokas的总数非常大,有1900万个节点。

有没有可能让它跑得更快?

neo4j-sh (?)$ MATCH (b:Bisac)-[r:INCLUDED_IN]-(w:Woka)
> WHERE (b.bisac_code =~ '.*000000') 
> RETURN b.bisac_code as bisac_code, count(w) as wokas_count
> ORDER BY b.bisac_code
> ;

+---------------------------+
| bisac_code  | wokas_count |
+---------------------------+
| "ANT000000" | 13865       |
| "ARC000000" | 32905       |
| "ART000000" | 79600       |
| "BIB000000" | 2043        |
| "BIO000000" | 256082      |
| "BUS000000" | 226173      |
| "CGN000000" | 16424       |
| "CKB000000" | 26410       |
| "COM000000" | 44922       |
| "CRA000000" | 18720       |
| "DES000000" | 2713        |
| "DRA000000" | 62610       |
| "EDU000000" | 228182      |
| "FAM000000" | 42951       |
| "FIC000000" | 474004      |
| "FOR000000" | 41999       |
| "GAM000000" | 8803        |
| "GAR000000" | 37844       |
| "HEA000000" | 36939       |
| "HIS000000" | 3908869     |
| "HOM000000" | 5123        |
| "HUM000000" | 29270       |
| "JNF000000" | 40396       |
| "JUV000000" | 200144      |
| "LAN000000" | 89059       |
| "LAW000000" | 153138      |
| "LCO000000" | 1528237     |
| "LIT000000" | 89611       |
| "MAT000000" | 58134       |
| "MED000000" | 80268       |
| "MUS000000" | 75997       |
| "NAT000000" | 35991       |
| "NON000000" | 107513      |
| "OCC000000" | 42134       |
| "PER000000" | 26989       |
| "PET000000" | 4980        |
| "PHI000000" | 72069       |
| "PHO000000" | 8546        |
| "POE000000" | 104609      |
| "POL000000" | 309153      |
| "PSY000000" | 55710       |
| "REF000000" | 96477       |
| "REL000000" | 133619      |
| "SCI000000" | 86017       |
| "SEL000000" | 40901       |
| "SOC000000" | 292713      |
| "SPO000000" | 172284      |
| "STU000000" | 10508       |
| "TEC000000" | 77459       |
| "TRA000000" | 9093        |
| "TRU000000" | 12041       |
| "TRV000000" | 27706       |
+---------------------------+
52 rows
198310 ms

响应时间不一致。 过了一会儿,不到一分钟就到了。

52 rows
31207 ms

2 个答案:

答案 0 :(得分:1)

速度慢是由正则表达式模式匹配(=~)引起的。尽管您的bisac_code已编入索引,但正则表达式匹配会导致索引无效。索引仅在匹配完整bisac_code值时才有效。

Cypher确实包含了一些字符串操作工具,可以让你在不使用正则表达式=~的情况下顺利完成,但我怀疑它会有什么不同,因为索引仍然没用。

我可能会建议您考虑是否可以进一步对bisac_code进行分类,以便您不需要进行模式匹配。也许是一个额外的索引属性,它以某种方式表示那些以000000结尾的代码?

如果您不想添加属性,可以先尝试仅匹配Bisac,然后再添加Woka。像这样:

MATCH (b:Bisac) WHERE (b.bisac_code =~ '.*000000')
WITH b
MATCH (b)-[r:INCLUDED_IN]-(w:Woka)
RETURN b.bisac_code as bisac_code, count(w) as wokas_count
ORDER BY b.bisac_code

这可能有助于Cypher在进行模式匹配时坚持4000个Bisac节点,然后再参与所有1900万个Woka节点,但我不确定这是否会产生重大影响。即使通过4000个节点(实际上没有索引),也是一个缓慢的过程。

数据库索引中的哈希表

您的索引对正则表达式模式匹配无效的原因是Neo4j可能使用哈希表来索引属性。这在许多数据库中很常见。 Wikipedia has an article here

但基本原则是索引不存储您要搜索的所有属性。它存储表示要搜索的属性的值,表示仅对整个属性有效。如果只搜索属性值的一部分,则索引中存储的哈希值是无用的,数据库必须以旧式方式逐个搜索属性。

修改:您的修改

多次运行此查询后响应时间的改善肯定是由于缓存。 Neo4j记住你经常访问Bisac节点和bisac_code属性,并将它们保存在内存中。这使得将来的查询更快,因为不需要从磁盘读取值。

但是,最终,这些节点的属性很可能会从缓存中删除,因为Neo4j会发现您正在操作不同的节点,而它将缓存它们。在耗尽内存之前,Neo4j只能缓存很多节点,因此它会选择最新和/或经常使用的数据。

答案 1 :(得分:1)

在Neo4j 2.3中,会有前缀LIKE搜索的索引支持,但可能不支持后缀。

有两种方法可以更快地制作@ user2194039的解决方案:

使用路径表达式计算每个Bisac的Woka:

MATCH (b:Bisac) WHERE (b.bisac_code =~ '.*000000')
WITH b, size((b)-[:INCLUDED_IN]->()) as wokas_count
RETURN b.bisac_code as bisac_code, wokas_count
ORDER BY b.bisac_code

使用标签

标记Bisac的图案
MATCH (b:Bisac) WHERE (b.bisac_code =~ '.*000000') SET b:Main;

MATCH (b:Main:Bisac)
WITH b, size((b)-[:INCLUDED_IN]->()) as wokas_count
RETURN b.bisac_code as bisac_code, wokas_count
ORDER BY b.bisac_code;