我有以下密码查询:
MATCH (country:Country { name: 'norway' }) <- [:LIVES_IN] - (person:Person)
WITH person
MATCH (skill:Skill { name: 'java' }) <- [:HAS_SKILL] - (person)
WITH person
OPTIONAL MATCH (skill:Skill { name: 'javascript' }) <- [rel:HAS_SKILL] - (person)
WITH person, CASE WHEN skill IS NOT NULL THEN 1 ELSE 0 END as matches
ORDER BY matches DESC
LIMIT 50
RETURN COLLECT(ID(person)) as personIDs
Run Code Online (Sandbox Code Playgroud)
添加更多节点时似乎表现更差.现在只有5000个Person节点(Person节点可以与Skill节点有多个HAS_SKILL关系).现在,执行查询大约需要180毫秒,但添加另外1000个具有关系的Person节点会为查询添加30-40毫秒.我们计划拥有数百万个Person节点,因此每1000人添加40毫秒是不行的.
我在查询中使用参数而不是上面查询中的'norway','java','javascript'.我已经创建了索引:国家(名称)和:技能(名称).
我的查询目标是匹配生活在指定国家(挪威)的每个人,这些人也具有'java'技能.如果此人也具有技能'javascript',则应在结果中命令更高.
如何重构查询以提高性能?
如果我转出,那么:Country节点似乎也存在问题
MATCH (country:Country { name: 'norway' }) <- [:LIVES_IN] - (person:Person)
Run Code Online (Sandbox Code Playgroud)
同
MATCH (city:City { name: 'vancouver' }) <- [:LIVES_IN] - (person:Person)
Run Code Online (Sandbox Code Playgroud)
查询时间会下降到大约15-50毫秒,具体取决于我查询的城市.添加更多节点时,查询时间仍然明显增加.
当第一个匹配子句中有很多行时,我似乎查询时间增加了很多.因此,如果我首先切换查询以匹配技能节点,则查询时间会大幅减少.该查询是API的一部分,它是动态创建的,我不知道哪个匹配子句将返回最小的行数.当数据库增长时,每个匹配子句中可能还会有更多行.
我已经从答案中做了一些测试,现在我有以下查询:
MATCH (country:Country { name: 'norway'})
WITH country
MATCH (country) <- [:LIVES_IN] - (person:Person)
WITH person
MATCH (person) - [:HAS_SKILL] -> (skill:Skill) WHERE skill.name = 'java'
MATCH (person) - [:MEMBER_OF_GROUP] -> (group:Group) WHERE group.name = 'some_group_name'
RETURN DISTINCT ID(person) as id
LIMIT 50
Run Code Online (Sandbox Code Playgroud)
这仍然存在性能问题,首先匹配所有技能等可能更好,比如Country节点?查询也可以变得更大,我可能必须添加匹配多个技能,组,项目等.
我略微修改了查询,看起来这样做了.我现在首先匹配所有需要的技能,公司,团体,国家等.然后在查询中使用它们.在分析器中,这将数据库命中数从700k减少到188或其他.它与我的原始查询(不同的标记节点等)略有不同,但它解决了同样的问题.我想这可以通过首先匹配具有最少关系等的节点来进一步改进,以减少节点数量开始.我稍后会做一些测试!
MATCH (company:Company { name: 'relinkgroup' })
WITH company
MATCH (skill:Skill { name: 'java' })
WITH company, skill
MATCH (skill2:Skill { name: 'ajax' })
WITH company, skill, skill2
MATCH (country:Country { name: 'canada' })
WITH company, skill, skill2, country
MATCH (company) <- [:WORKED_AT] - (person:Person)
, (person) - [:HAS_SKILL] -> (skill)
, (person) - [:HAS_SKILL] -> (skill2)
, (person) - [:LIVES_IN] -> (country)
RETURN DISTINCT ID(person) as id
LIMIT 50
Run Code Online (Sandbox Code Playgroud)
对于查询的第一行,执行必须查找国家/地区之间的所有可能路径.限制您的初始匹配(从而为遍历定义更准确的起点)您将赢得一些表现.
而不是
MATCH (country:Country { name: 'norway' }) <- [:LIVES_IN] - (person:Person)
Run Code Online (Sandbox Code Playgroud)
尝试分两步:
MATCH (country:Country { name: 'norway' })
WITH country
MATCH (country)<-[:LIVES_IN]-(person:Person)
WITH person
Run Code Online (Sandbox Code Playgroud)
举个例子,我将在neo4j控制台中使用简单的电影应用程序:http://console.neo4j.org/
查找与您相同的查询以查找知道密码的人:
MATCH (n:Crew)-[r:KNOWS]-m WHERE n.name='Cypher' RETURN n, m
Run Code Online (Sandbox Code Playgroud)
执行计划将是:
Execution Plan
ColumnFilter
|
+Filter
|
+TraversalMatcher
+------------------+------+--------+-------------+----------------------------------------+
| Operator | Rows | DbHits | Identifiers | Other |
+------------------+------+--------+-------------+----------------------------------------+
| ColumnFilter | 2 | 0 | | keep columns n, m |
| Filter | 2 | 14 | | Property(n,name(0)) == { AUTOSTRING0} |
| TraversalMatcher | 7 | 16 | | m, r, m |
+------------------+------+--------+-------------+----------------------------------------+
Total database accesses: 30
Run Code Online (Sandbox Code Playgroud)
并通过定义一个准确的起点:
MATCH (n:Crew) WHERE n.name='Cypher' WITH n MATCH (n)-[:KNOWS]-(m) RETURN n,m
Run Code Online (Sandbox Code Playgroud)
导致以下执行计划:
Execution Plan
ColumnFilter
|
+SimplePatternMatcher
|
+Filter
|
+NodeByLabel
+----------------------+------+--------+-------------------+----------------------------------------+
| Operator | Rows | DbHits | Identifiers | Other |
+----------------------+------+--------+-------------------+----------------------------------------+
| ColumnFilter | 2 | 0 | | keep columns n, m |
| SimplePatternMatcher | 2 | 0 | m, n, UNNAMED53 | |
| Filter | 1 | 8 | | Property(n,name(0)) == { AUTOSTRING0} |
| NodeByLabel | 4 | 5 | n, n | :Crew |
+----------------------+------+--------+-------------------+----------------------------------------+
Total database accesses: 13
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,第一种方法使用遍历模式,这对于节点数量来说是非常昂贵的,并且您在图上进行了全局匹配.
第二个使用标签索引使用显式起点.
编辑
对于技能部分,我会做这样的事情,如果你有一些测试数据提供它可能对测试更有帮助:
MATCH (country:Country { name: 'norway' })
WITH country
MATCH (country)<-[:LIVES_IN]-(person:Person)-[:HAS_SKILL]->(skill:Skill)
WHERE skill.name = 'java'
WITH person
OPTIONAL MATCH (person)-[:HAS_SKILL]->(skillb:Skill) WHERE skillb.name = 'javascript'
WITH person, skillb
Run Code Online (Sandbox Code Playgroud)
不需要全局查找,因为他已经找到了人,他只是遵循"HAS_SKILL"关系并过滤skill.name值
编辑2:
关于你的上一次编辑,可能是查询的最后一部分:
MATCH (company) <- [:WORKED_AT] - (person:Person)
, (person) - [:HAS_SKILL] -> (skill)
, (person) - [:HAS_SKILL] -> (skill2)
, (person) - [:LIVES_IN] -> (country)
Run Code Online (Sandbox Code Playgroud)
可以写得更好:
MATCH (person:Person)-[:WORKED_AT]->(company)
WHERE (person)-[:HAS_SKILL]->(skill)
AND (person)-[:HAS_SKILL]->(skill2)
AND (person)-[:LIVES_IN]->(country)
Run Code Online (Sandbox Code Playgroud)