我刚刚开始使用Neo4j - 首先,我意识到可以有更好的工具来获得我正在描述的这些结果,但我正在使用Neo4j来学习Cypher。我写了一个查询,返回符合三个MATCH标准的数字国家代码,返回与这三个匹配的国家/地区列表。每个标准都有一个根节点和2-10个与该类型的特定标准节点的关系,例如:
[ERROR] : TiExceptionHandler: (main) [1605,1605] ----- Titanium Javascript Runtime Error -----
[ERROR] : TiExceptionHandler: (main) [0,1605] - In /alloy/controllers/index.js:359,27
[ERROR] : TiExceptionHandler: (main) [1,1606] - Message: Uncaught TypeError: Cannot read property 'hide' of undefined
[ERROR] : TiExceptionHandler: (main) [0,1606] - Source: win.activity.actionBar.hide();
[ERROR] : V8Exception: Exception occurred at /alloy/controllers/index.js:359: Uncaught TypeError: Cannot read property 'hide' of undefined
(另外两个条件的数值范围从1-10开始。)图中的每个非根节点都有一个'countries'数组属性,其中包含适用于条件的国家/地区ID,如下所示:
CREATE (root:Age {name: "root"}),
(A1:Age {name: "Younger"}),
(A2:Age {name: "Older"}),
(root)-[:AGE]->(A1),
(root)-[:AGE]->(A2)
下面的查询找到每个条件的匹配项,然后使用APOC交集函数仅返回符合所有三个条件的国家/地区代码:
MATCH (a:Age {name: 'Younger'})
SET a.countries = [1,2,3,4,5,6]
RETURN a
MATCH (a:Age {name: 'Older'})
SET a.countries = [7,8,9,10,11,12]
RETURN a
查询运行正常,返回正确的结果。但是,我得到的结果类似于以下多级数组,并且希望得到一个简单的国家代码数组。目前我得到这个:[[9],[8],[10],[7],[12],[11]],我想改为:[9,8,10,7,12, 11]
请注意
MATCH (a:Age) WHERE a.name = 'Older'
MATCH (h:Health) WHERE h.rank > 0
MATCH (w:Wealth) WHERE w.rank < 11
RETURN filter(x IN collect(apoc.coll.intersection(apoc.coll.intersection(a.countries,h.countries),w.countries))
WHERE x <> [])
在RETURN语句中的是为了摆脱否则会显示的空国家/地区阵列。
最后,我将增加3-5个标准,因此处理更深层次结果的解决方案将非常棒。
答案 0 :(得分:0)
您可以尝试收集节点的国家/地区集合,然后使用apoc.coll.intersection()运行REDUCE()
MATCH (a:Age) WHERE a.name = 'Older'
WITH COLLECT(a.countries) as allCountries
MATCH (h:Health) WHERE h.rank > 0
WITH allCountries + collect(h.countries) as allCountries
MATCH (w:Wealth) WHERE w.rank < 11
WITH allCountries + collect(w.countries) as allCountries
RETURN REDUCE(intersection = HEAD(allCountries), countries in TAIL(allCountries)
| apoc.coll.intersection(intersection, countries)) as intersection
除了避免在比赛中使用笛卡尔积之外,这一优势还在于,无论您计划在查询中添加多少额外MATCH ... WITH
,RETURN都可以保持完全相同。
编辑
仅当您还希望交集在每个匹配节点类型中的国家/地区上执行时,上述查询才有效。例如,:财富匹配可能匹配多个:财富节点,每个节点都有自己的国家/地区集合。问题是,在匹配中的每个节点类型中,他们的国家是要联合还是相交?
上面的查询假定它们是相互交叉的,但似乎你想要国家的联合,然后在不同的节点类型之间交叉这些国家。这需要不同类型的查询。
MATCH (a:Age) WHERE a.name = 'Older'
WITH a.countries as intersection
MATCH (h:Health) WHERE h.rank > 0
WITH apoc.coll.intersection(intersection,
REDUCE(union = [], countries in collect(h.countries) |
union + countries)) as intersection
MATCH (w:Wealth) WHERE w.rank < 11
WITH apoc.coll.intersection(intersection,
REDUCE(union = [], countries in collect(w.countries) |
union + countries)) as intersection
RETURN intersection
答案 1 :(得分:0)
你不需要APOC:
MATCH (a:Age) WHERE a.name = 'Older'
WITH [collect(a.countries)] as prev
MATCH (h:Health) WHERE h.rank > 0
WITH prev + [collect(h.countries)] as prev
MATCH (w:Wealth) WHERE w.rank < 11
WITH prev + [collect(w.countries)] as contSets
RETURN FILTER(c in contSets[0] WHERE ALL(contSet in contSets WHERE c in contSet))
答案 2 :(得分:0)
此查询应该有效:
MATCH (h:Health) WHERE h.rank > 0
UNWIND h.countries AS hc
WITH COLLECT(DISTINCT hc) AS hcs
MATCH (w:Wealth) WHERE w.rank < 11
UNWIND w.countries AS wc
WITH COLLECT(DISTINCT wc) AS wcs, hcs
MATCH (a:Age) WHERE a.name = 'Older'
RETURN apoc.coll.intersection(a.countries, apoc.coll.intersection(hcs, wcs)) AS res
它在一个单独的平面集合中收集所有不同的匹配Health
个国家/地区;它对匹配Wealth
个国家/地区也是如此。然后它获得匹配的Age
节点,并在其国家和其他集合之间进行3向交叉。由此产生的集合是扁平的,因为所有3个相交的集合都是扁平的。
此查询也比您的查询更高效,因为它避免了Cartesian Products。