我在Neo4j中有以下cypher查询:
MATCH (n0:Company)
WHERE n0.name = 'Google'
WITH n0
MATCH (n0) <- [r0:WORKED_AT] - (person:Person)
WITH DISTINCT ID(person) as id,
((CASE WHEN r0.count IS NOT NULL THEN toFloat(r0.count) ELSE 1.00 END) *
(CASE WHEN r0.source = 'someSource' THEN
CASE TYPE(r0)
WHEN 'WORKED_AT' THEN 0.7
WHEN 'HAS_SKILL' THEN 0.3
WHEN 'HAS_INTEREST' THEN 0.6
WHEN 'LIVED_IN_COUNTRY' THEN 0.8
ELSE 0.5 END
ELSE 0.5 END)) as score
WITH id, score
ORDER BY score DESC
LIMIT 20
RETURN COLLECT({id: id, score: score}) as result
我试图根据关系的类型和关系上的.source属性对结果进行排序。此查询是基于用户输入构建的,因此在查询的第一部分中,它可以是基于用户输入的任何类型的节点或关系。标签公司可以使用技能切换,WORKED_AT可以使用HAS_SKILL等切换出来
我希望能够根据relationship.source和type(relationship)控制relationship.count值乘以的因子。
这很好用,我担心的是当结果变大时,这可能是一个非常慢的查询,因为它需要对每一行进行计算,并且在完成所有计算之后,根据计算对结果进行排序。有什么方法可以优化这个查询,这样它可以用于任何大小的结果吗?
我对查询的最终目标是找到符合条件的所有人,根据我在cypher查询中的计算对结果进行排序,然后限制结果以获得给定用户查询的前20个结果。
MATCH (n0:Company)
WHERE n0.name = 'Google'
WITH n0
MATCH (n1:Skill)
WHERE n1.name = 'java'
WITH n1, n0
MATCH (n0) <- [r0:WORKED_AT] - (person:Person)
, (person) - [r1:HAS_SKILL] -> (n1)
WITH DISTINCT ID(person) as id,
((CASE WHEN r0.count IS NOT NULL THEN toFloat(r0.count) ELSE 1.00 END) *
(CASE WHEN r0.source = 'unreliable' THEN CASE TYPE(r0)
WHEN 'WORKED_AT' THEN 0.2
WHEN 'HAS_SKILL' THEN 0.3
WHEN 'HAS_INTEREST' THEN 0.1
WHEN 'LIVED_IN_COUNTRY' THEN 0.3
WHEN 'STUDIED_AT' THEN 0.2
ELSE 0.3 END
ELSE 0.3 END))
+
((CASE WHEN r1.count IS NOT NULL THEN toFloat(r1.count) ELSE 1.00 END) *
(CASE WHEN r1.source = 'reliable' THEN CASE TYPE(r1)
WHEN 'WORKED_AT' THEN 0.8
WHEN 'HAS_SKILL' THEN 0.7
WHEN 'HAS_INTEREST' THEN 0.6
WHEN 'LIVED_IN_COUNTRY' THEN 0.5
WHEN 'STUDIED_AT' THEN 0.8
ELSE 0.7 END
ELSE 0.7 END)) as score
ORDER BY score DESC
LIMIT 20
RETURN COLLECT({id: id, score: score}) as result
我删除了额外的WITH语句。我还用更复杂的一个更新了我的查询,我试图在原始问题中保持简单,但我想我可能遗漏了一些关于查询的重要信息。
在这个查询中,我可以有多个我需要匹配的节点,因此可以有多个关系(r0,r1 ... rn)等,最多可达到合理数量的c。添加更多要匹配的节点将缩小返回的人数,这很好。但它也增加了更多CASE WHEN语句。我的修饰符目前设置如下:
var modifiers = {
reliable: {
HAS_SKILL: 0.8,
WORKED_AT: 0.7,
HAS_INTEREST: 0.7,
LIVED_IN_COUNTRY: 0.6,
default: 0.8
},
unreliable: {
HAS_SKILL: 0.2,
WORKED_AT: 0.4,
HAS_INTEREST: 0.1,
LIVED_IN_COUNTRY: 0.3,
default: 0.3
},
...
default: 0.5
};
我尝试将它们作为参数传递,但我不认为Neo4j支持&#34;嵌套&#34;像这样的参数。如果源是可靠的,我需要有不同的修饰符。因此,来自可靠来源的技能将获得比不可靠来源等更高的修饰符。如果我以某种方式可以删除CASE语句,那将是非常好的。 JohnMark13关于hyperEdges的建议听起来很有意思,会调查一下。
答案 0 :(得分:1)
tl; dr 最后,h 数据集中可能有多大?我不认为有任何理由认为即使数据集增长超出适度大小,这也应该很慢查询总是在受约束的子图中运行,没有复杂的遍历,并且聚合不复杂或本身是迭代的。你可以把一些数字放在&#34;任何尺寸&#34;。
据我所知,您试图以类似于Lucene索引的方式获得/提升搜索结果。
坚持你已经给出的例子,并假设如果一个人多次在Google工作,那么关系上将有一个count属性而不是多个关系(如果你使用当前查询有多个关系,我认为同一个人将在结果集合中两次)。
首先MATCH看起来很好,但是(取决于版本)你不需要WHERE或WITH(我不相信速度不利/优势):
MATCH (n0:Company{name:'Google})<-[r0:WORKED_AT]-(person:Person)
我认为你现在有一个重复的WITH语句,它再次赢得了任何速度惩罚,但第二个WITH id, score
没有添加任何我能看到的内容。
你说&#34;已经退出&#34;所以你知道你要查询的关系类型,然后你可以跳过所有的case语句并将权重作为参数传递吗?即在示例查询中,您知道关系类型是WORKED_AT,因此case语句浪费了处理能力。只有在匹配多种关系类型(例如(c)<-[:WORKED_AT|LIVED_AT]-(p)
)时,case语句才有意义。这会将您的查询更改为:
(CASE WHEN r0.count IS NOT NULL THEN toFloat(r0.count) ELSE 1.00 END) *
(CASE WHEN r0.source = {sourceParam} THEN {scoreParam} ELSE 0.5 END) as score
这就是说我认为不将这些乘数编码到您的查询中,而是将它们存储到新的Source
节点中会更加图形化。在这个新节点中,您可以将信任值(或权重所代表的任何值)分配给该源。这会为您的图形引入一个新的(in)方向,并且需要您将WORKED_AT
关系分解为一个节点,该节点将Person链接到公司并添加一个源(源)。 (这称为HyperEdge。)您现在已经获得了能够通过Source遍历图形并且能够通过修改每个源提供的权重来调整查询结果而无需永远摆弄查询的优势。 / p>
如果你不想这样做,我仍会引入一个源节点,但你可以通过源属性(r0.source)查找它作为一个单独的匹配。这似乎更接近于关系方法,并且几乎肯定不那么快,但它会将查询逻辑从查询和数据中分解出来:
MATCH (n0:Company{name:'Google})<-[r0:WORKED_AT]-(person:Person)
OPTIONAL MATCH (s:Source{name:r0.source})
关于尺寸的说明
我相信您的图表可以增长到数亿人,但如果您始终使用上面的公司匹配声明(然后是修订版中的后续SKill匹配)开始查询,那么您的操作集不是数百已经有数百万了。无论该集合有多大(这假定在Company.name和Skill.name上都有一个索引),图表应该能够非常快速地找到为谷歌工作的人使用Java。
有关汇总的说明
如果您希望在单个查询中实时地在数百万个节点上执行聚合,那么您可能会遇到麻烦(内存密集型)。在处理聚合时,限制响应不会增加任何好处,因为仍需要计算所有聚合以确定如何订购以及返回哪些结果。 (限制 - 与分页有关 - 在Neo4J中可能不会做你认为他们做的事情,因为他们在整个数据集上工作受限制然后返回一个狭窄的窗口。)
运行一个程序来生成公共分数并将它们存储回图表,或使用其他值来限制数据集没有任何问题(我在15年前编写了Assembler编程器,我喜欢招聘数据库忘记了事实上,但他们一直在呼唤)。然后你的常见查询在看到你自己的迷你索引时看起来都非常高效......
如果这是一个真实的用例,你想要为你的所有人,他们的所有工作和他们所有的技能得分,那么你需要使用比Cypher更多的实现它并且它不是实时的 - 我想知道这是否是过早优化的情况还是真正的要求?