我正在运行此查询(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
答案 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的解决方案:
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
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;