查询以获得给定节点集

时间:2017-05-16 19:17:26

标签: neo4j cypher

我有公司指标数据,我想查询

   ----------------------------------------------------
   |Metrics |   Year |   Qtr |   Department  |   Value|
   ----------------------------------------------------
   |Revenue|     2017  |  Q1 |     Dep1 |        2000045|
   |Revenue|     2017  |  Q2 |     Dep1 |        2000046|
   |Revenue|     2017  |  Q2 |     Dep2 |        2000047|
   |Revenue|     2017  |  Q3 |     Dep2 |        2000048|
   |Revenue|     2017  |  Q3 |     Dep3 |        2000049|
   |Sales  |     2017  |  Q1 |     Dep1 |        2000041|
   |Sales  |     2017  |  Q1 |     Dep2 |        2000052|
   |Sales  |     2017  |  Q2 |     Dep1 |        2000053|
   ----------------------------------------------------- 

现在我像这样建模上面的数据

年,Qtr和部门作为节点,如

(d:DIM {name:"2012","type":"year")

这样的节点值

(v:VALUE {value:2000053})

和指标作为关系,如

(d:DIM {name:"2012","type":"year") - [:REVENUE]-> (v:VALUE {value:2000053})

因此,对于每条记录,VALUE节点可能存在三种关系。

现在出现了查询部分:

给定维度,查询应该获取值,如给定年份2017,Qtr q1应该返回与此过滤器对应的值,如果我添加Dep 1,那么它应该进一步过滤结果。

我尝试了一些像

这样的查询
Match (d:DIM)-[:REVENUE]->(v:VALUE)
where d.name in ["2017","q1"]
Return d,v

但是这个查询提供了2017年的UNION和q1而不是我正在寻找的交集。

此外,我可以使用类型属性进行分组。

1 个答案:

答案 0 :(得分:0)

有几种方法可以做到这一点。虽然我个人建议为Year,Qtr和Department使用单独的节点标签(也可能是Metrics),但我会使用您当前的模型。

交集所需的部分是ALL()谓词,它在值列表上运行。在这种情况下,我们将收集所有匹配的:DIM节点。为了使匹配有效,我们希望匹配列表中第一项的v个节点,然后确保v连接到列表中的其余项目(比从所有项目中过滤更快: VALUE节点)。

match (d:DIM)
where d.name in ["2017","q1"]
with collect(d) as dims
with head(dims) as head, tail(dims) as dims
match (head)-[:REVENUE]->(v)
where all(dim in dims where (dim)-[:REVENUE]->(v))
return dims, v

或者,如果您安装了APOC Procedures,则可以使用交叉功能:

match (d:DIM)-[:REVENUE]->(v)
where d.name in ["2017","q1"]
with d, collect(v) as values
with collect(d) as dims, collect(values) as allValues // list of lists
with dims, reduce(inter = head(allValues), values in tail(allValues) | apoc.coll.intersection(inter, values)) as values
return dims, values

修改

我记得另一种可能更快的方法。试试这个:

with ["2017","q1"] as dimInput
with dimInput, size(dimInput) as dimCnt
match (d:DIM)
where d.name in dimInput
match (d)-[:REVENUE]->(v)
with v, dimCnt, count(distinct d) as cnt
where dimCnt = cnt
return v