如何使用Cypher压平阵列

时间:2017-03-16 19:54:39

标签: neo4j cypher

我刚刚开始使用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个标准,因此处理更深层次结果的解决方案将非常棒。

3 个答案:

答案 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