如何在符合条件的情况下返回符合特定条件的任何节点列表以及可用值?

时间:2016-11-21 20:59:04

标签: neo4j cypher

我想从我的数据集中获取国家/地区列表。假设组织我正在为#34;操作"在各个国家。但是,操作的定义可以通过几种方式构建。

首先,如果有一个人为在该国家的公司工作。

第二,如果该国家/地区支持任何获奖企业(如果该奖项中的任务附属于该国家/地区,该奖项已知在该国家/地区)

第三,如果该组织获得特别许可在那里开展业务。例如,该公司可能已获得许可,但实际上并未在那里进行任何工作。

所以,我希望从另一端获得一些json,我可以用它来支持与svg国家地图的互动。这意味着我要么需要满足这些标准的国家的json列表,以及有关每个国家/地区遇到的标准(e.g.: {Country:"The United State", Code:"USA", hasPeople:true, hasActiveAward: false, isLicensed:true})的一些信息,或者我需要三个单独的列表(每个标准一个)和一个子集其中的国家。

我尝试了各种各样的事情,包括下面的这一部分,这一部分失败最为惊人,同时也是最简单的阅读理解。

// get all types of country
match (c1)<-[:SITS_IN|GEO_IN*]-(p:Person)
match (c2)<-[:TASK_IN_COUNTRY]-(:Task)-[:PART_OF*2]->(a:Award {awardStatus:"ACTIVE"})
match (c3)<-[:LICENSED_IN]-(d:Department)

return {
    peopleCountries:[{country:c1.name, code:c1.code, people:count(p)}],
    awardCountries:[{country:c2.name, code:c2.code, awards:count(a)}],
    licensedCountries:[{country:c3.name, code:c3.code, department:d.name}]
    }

这是我试过的另一个实际上工作正常,但仍然需要大约14秒才能运行:

match (c:Country)
where exists((c)<-[:SITS_IN|GEO_IN*]-(:Person)) or
exists((c)<-[:TASK_IN_COUNTRY]-(:Task)-[:PART_OF*2]->(:Award {awardStatus:"ACTIVE"}))
or exists((c)<-[:LICENSED_IN]-(:Department))
with c
optional match (c)<-[:SITS_IN|GEO_IN*]-(p:Person)
optional match (c)<-[:TASK_IN_COUNTRY]-(:Task)-[:PART_OF*2]->(a:Award {awardStatus:"ACTIVE"})
optional match (c)<-[:LICENSED_IN]-(d:Department)
with c, count(p) as people, count(a) as awards, d.name as department
return {
    country:c.name,
    people:people,
    awards:awards,
    department:department
}

任何帮助非常感谢。我认为我应该将这些请求分成三个完全独立的请求,或者使用路径变量,但我还是刚刚开始使用Cypher,所以我愿意学习更好的方法来考虑这个问题。 。

谢谢!

1 个答案:

答案 0 :(得分:2)

要注意的一件事是连续多个匹配或可选匹配,您的意图是稍后汇总结果。请记住,Neo4j将结果构建为行,并处理这些行上的操作(匹配和可选匹配),即使它是多余的。

例如,参加前两个可选比赛:

with c
optional match (c)<-[:SITS_IN|GEO_IN*]-(p:Person)
optional match (c)<-[:TASK_IN_COUNTRY]-(:Task)-[:PART_OF*2]->(a:Award {awardStatus:"ACTIVE"})

让我们说一个国家,比如说法国,由于第一场可选比赛,有50人。仅在法国,我们现在有50排:法国与每个匹配的人配对。现在我们运行第二个可选匹配,即使你打算每个国家只执行一次,它每行执行一次,所以它对法国的每一行在法国执行50次与第一场比赛的人。

等等。如果在法国找到3个奖项,那么现在法国有150排,法国的每个组合排成一排,匹配的人之一,以及匹配的奖项之一。现在,最后一个可选匹配必须在这150行上运行。当您正在处理多个国家时,这对于一个国家来说只是理论上的。

为避免这一切,最好立即处理每个可选匹配的聚合,在它们之间使用WITH,因此在每个WITH之后,每个国家/地区的行数保持不变。这适合您的可选匹配,因为它们都来自一个国家/地区,您的目的是让它们每个国家/地区运行一次,而不是多次运行。改进后的查询可能如下所示:

match (c:Country)
where exists((c)<-[:LICENSED_IN]-(:Department))
or exists((c)<-[:SITS_IN|GEO_IN*]-(:Person)) 
or exists((c)<-[:TASK_IN_COUNTRY]-(:Task)-[:PART_OF*2]->(:Award {awardStatus:"ACTIVE"}))
with c
optional match (c)<-[:SITS_IN|GEO_IN*]-(p:Person)
with c, count(distinct p) as people
optional match (c)<-[:TASK_IN_COUNTRY]-(:Task)-[:PART_OF*2]->(a:Award {awardStatus:"ACTIVE"})
with c, people, count(distinct a) as awards
optional match (c)<-[:LICENSED_IN]-(d:Department)
with c, people, awards, collect(d.name) as departments
return {
    country:c.name,
    people:people,
    awards:awards,
    departments:departments
}

我重新排序了你的第一个匹配谓词,这样就可以更容易,更快速地进行比较,这样可以避免不必要地执行更复杂的谓词。

我还收集了在该国获得许可的部门(我假设多个部门可以获得许可,而不仅仅是一个部门)。

每个国家/地区的输出应该是一行。