我试图在一次传递中执行以下查询,但我得出结论认为这是不可能的,并且还会导致某种形式的“嵌套”结构,这在性能方面绝不是好消息。
但是我可能会在这里遗漏一些东西,所以我想我可能会问。
底层数据结构是两个实体A<---0:*--->B
最终目标是获取在特定时间间隔内分配给实体B
的对象的实体A
的对象的次数占总分配的百分比。
正是这个问题的后半部分引起了头痛。
实体A
包含item_date
字段
实体B
包含item_category
字段。
结果的显示可以扩展到一个表,其列是不同的item_date
,行是不同的item_category
规范化计数。我只是为了清楚起见提到这一点,查询不必以确切的形式返回结果。
我的尝试:
with 12*30*24*3600 as window_length, "1980-1-1" as start_date,
"1985-12-31" as end_date
unwind range(apoc.date.parse(start_date,"s","yyyy-MM-dd"),apoc.date.parse(end_date,"s","yyyy-MM-dd"),window_length) as date_step
match (a:A)<-[r:RELATOB]-(b:B)
where apoc.date.parse(a.item_date,"s","yyyy-MM-dd")>=date_step and apoc.date.parse(a.item_date,"s","yyyy-MM-dd")<(date_step+window_length)
with window_length, date_step, count(r) as total_count unwind ["code_A", "code_B", "code_C"] as the_code [MATCH THE PATTERN AGAIN TO COUNT SPECIFIC `item_code` this time.
我发现很难在一次传递中表达这一点,因为在图形模式的定义之后它需要相当于两个独立的GROUP BY
- 类子句。你不能并行表达这两个,所以你必须解开它们。我担心的是,这导致两个评估:一个用于总计数,一个用于部分计数。我试图优化的位是重写查询的某种方式,这样它就不必计算它之前已“捕获”的节点,但这对于将集合函数应用于集合的隐含方式来说非常困难。
基本上,任何不是聚合函数的属性都会成为分层变量。我必须在这里说一个简单的简单双重分层(“抓住一切,按item_date
产生一个等级的计数,产生item_code
的另一个计数水平”对我来说不起作用,因为没有办法控制window_length
的宽度。这意味着我无法在item_code
s的不同分配率的两个时间段之间进行比较,因为时间段不相等:(
请注意,检索item_code
的计数然后在一段时间内(在cypher外部)对那些特定代码的总和进行标准化将不会导致准确的百分比,因为规范化将针对 item_code
的特定子集而不是总数。
是否可以在一段时间内同时执行r
计数,然后(以某种方式)重新使用已匹配的a
,b
节点子集,以便现在评估b
的具体(b:{item_code:the_code})-[r2:RELATOB]-(a) where a.item_date...
的部分计数?
如果没有,那么我将转向下一个最快的事情,即执行两个独立的查询(一个用于总计数,一个用于部分)然后在外部进行除法:/。
答案 0 :(得分:0)
Tomaz Bratanic在评论中提出的解决方案是(我认为)沿着这些方向:
with 1*30*24*3600 as window_length,
"1980-01-01" as start_date,
"1985-12-31" as end_date
unwind range(apoc.date.parse(start_date,"s","yyyy-MM-dd"),apoc.date.parse(end_date,"s","yyyy-MM-dd"),window_length) as date_step
unwind ["code_A","code_B","code_c"] as the_code
match (a:A)<-[r:RELATOB]-(b:B)
where apoc.date.parse(a.item_date,"s","yyyy-MM-dd")>=date_step and apoc.date.parse(a.item_category,"s","yyyy-MM-dd")<(date_step+window_length)
return the_code, date_step, tofloat(sum(case when b.item_category=code then 1 else 0 end)/count(r)) as perc_count order by date_step asc
此:
ELSE 0
即使没有计数数据也会强制为零。但在现实条件下,它比我正在使用的重新匹配至少慢30秒(不是,请参见编辑)。 (不,这不是因为填充缺失数据时现在返回的额外数据,这是原始查询时间。)
我认为可能值得在此附加查询计划:
这是应用相同模式两次但快速方式的计划:
这是一次性执行计数但是这样做的计划:
我可能会看到时间尺度如何与输入中的数据进行比较,也许这两个是以不同的速率缩放,但此时,&#34;一次通过&#34;似乎已经慢了&#34;双通&#34;坦率地说,我看不出它如何能够通过更多数据获得更快的速度。这已经是在18个项目(约)中分配的3个类别的12个月的简单计数。
希望这也可以帮助其他人。
修改强>
虽然我最初做过这个,但还有另一个修改,我没有包括第二次放松 AFTER 匹配的地方。这会将时间缩短20秒 &#34;双重匹配&#34;因为展开会影响返回,而不是现在变为同一查询的多次执行:
with 1*30*24*3600 as window_length,
"1980-01-01" as start_date,
"1985-12-31" as end_date
unwind range(apoc.date.parse(start_date,"s","yyyy-MM-dd"),apoc.date.parse(end_date,"s","yyyy-MM-dd"),window_length) as date_step
match (a:A)<-[r:RELATOB]-(b:B)
where apoc.date.parse(a.item_date,"s","yyyy-MM-dd")>=date_step and apoc.date.parse(a.item_category,"s","yyyy-MM-dd")<(date_step+window_length)
unwind ["code_A","code_B","code_c"] as the_code
return the_code, date_step, tofloat(sum(case when b.item_category=code then 1 else 0 end)/count(r)) as perc_count order by date_step asc
这也是它的执行计划:
原创双人赛大约55790ms,一次性完成(两场比赛前都展开) 82306ms ,一次性完成(第二次放松 匹配后)<强> 23461ms 强>