Datetime Hive中高效的数据案例逻辑

Datetime Hive中高效的数据案例逻辑,datetime,hive,hiveql,Datetime,Hive,Hiveql,我在Hive中有一个65M~record表,其中包含患者、设施、服务开始和服务结束日期。下表与MWE类似: 创建表。示例 accountId字符串, 提供程序字符串, 起始日期时间戳, 结束日期时间戳; 插入到表中。示例值 “123A”、“史密斯”、“2019-03-01 00:00:00”、“2019-03-04 00:00:00”, “456B”、“罗杰斯”、“2019-03-02 00:00:00”、“2019-03-03 00:00:00”, “123A”、“史密斯”、“2019-03-

我在Hive中有一个65M~record表,其中包含患者、设施、服务开始和服务结束日期。下表与MWE类似:

创建表。示例 accountId字符串, 提供程序字符串, 起始日期时间戳, 结束日期时间戳; 插入到表中。示例值 “123A”、“史密斯”、“2019-03-01 00:00:00”、“2019-03-04 00:00:00”, “456B”、“罗杰斯”、“2019-03-02 00:00:00”、“2019-03-03 00:00:00”, “123A”、“史密斯”、“2019-03-03 00:00:00”、“2019-03-06 00:00:00”, “123A”、“史密斯”、“2019-03-07 00:00:00”、“2019-03-08 00:00:00”, “456B”、“丹尼尔斯”、“2019-03-04 00:00:00”、“2019-03-05 00:00:00”, “456B”、“丹尼尔斯”、“2019-03-06 00:00:00”、“2019-03-09 00:00:00”, “123A”、“史密斯”、“2019-03-10 00:00:00”、“2019-03-12 00:00:00”; 选择*FROM.example; example.accountid example.provider example.startdate example.enddate 123A史密斯2019-03-01 00:00:00.0 2019-03-04 00:00:00.0 2456B罗杰斯2019-03-02 00:00:00.0 2019-03-03 00:00:00.0 123A史密斯2019-03-03 00:00:00.0 2019-03-06 00:00:00.0 4123A史密斯2019-03-07 00:00:00.0 2019-03-08 00:00:00.0 5456B丹尼尔2019-03-04 00:00:00.0 2019-03-05 00:00:00.0 6456B丹尼尔2019-03-06 00:00:00.0 2019-03-09 00:00:00.0 7 123A史密斯2019-03-10 00:00:00.0 2019-03-12 00:00:00.0 我想为accountId和provider组合定义连续的startdate和enddate,其中一条记录的enddate和下一条记录的startdate之间的间隔不超过1天,然后计算称为los的连续数据块中停留时间的天数。这种分组称为案例。下面是案例输出需要的样子:

results.accountid results.provider results.los results.startdate results.enddate 123A史密斯7 2019-03-01 00:00:00.0 2019-03-08 00:00:00.0 2456B罗杰斯2019-03-02 00:00:00.0 2019-03-03 00:00:00.0 3 456B丹尼尔5 2019-03-04 00:00:00.0 2019-03-09 00:00:00.0 4 123A史密斯2 2019-03-10 00:00:00.0 2019-03-12 00:00:00.0 我们目前使用的是公认的答案,但对于我们实际的65M记录表来说,这是一个非常昂贵的操作。我认为一个更有效的解决方案是首先合并并定义每个案例的startdate和enddate,然后运行datediff计算,而不是分解每个日期范围,但我不确定如何在HiveQL中实现这一点


提前谢谢

翻阅我们公司的回购协议,我发现下面的创造性解决方案符合我们的要求。尚未测试其相对于当前“爆炸式”解决方案的性能改进。它符合我在原始问题中提出的要求,但有点复杂,尽管评论很好

/* 步骤1:输入 */ 删除表(如果存在)。tmp_completedatepairs; 将表创建为.tmp_completedatepairs作为 选择CONCATisnullaccountid、-isnullprovider作为标记 ,起始日期 ,结束日期 来自。例如 其中startdate不为NULL 并且enddate不为空; /* 步骤2:创建新的开始和结束日期对 在整个停留期间有更好的时间跨度 */ 删除表格(如果存在)。tmp_响应_输入; 创建TABLE.tmp_respaned_输入为 选择SD.tag ,SD.startdate ,ED.enddate 从选择* ,按标签顺序划分的分区上的行号,按起始日期ASC作为rnsd FROM.tmp_completedatepairs作为SD 左连接 挑选* ,分区上的行号,按标记顺序,按结束日期ASC,如图所示 FROM.tmp_completedatepairs AS ED ON SD.tag=ED.tag 和SD.rnsd=ED.rned; /* 第3步:查找>1天的间隙,并在其周围定义停留时间 这包括几个子步骤: a隔离具有相同标记的前一个开始日期后超过1天的所有开始日期,或是标记的最早日期。按顺序给它们编号。 b用同一标签隔离所有比下一个结束日期早1天以上的结束日期,或是标签的最后日期。按顺序给它们编号。 c仅选择终止案例的日期,而不是案例边界内发生的日期后,匹配相应的开始和结束日期 */ 删除表格(如果存在)。结果; 创建表。结果为 -c仅选择终止案例的日期,而不是案例边界内发生的日期后,匹配相应的开始和结束日期 选择SPLITtag“-”[0]作为accountid ,将“-”[1]拆分为提供程序 ,日期不同,起始日期为服务水平 ,起始日期 ,结束日期 从…起 -a隔离具有相同标记的前一个结束日期后超过1天的所有开始日期,或是标记的最早日期。按顺序给它们编号。 选择标签 , 起始日期 ,CONCATtag,CASTROW_编号,按标签顺序划分,按startdate ASC作为字符串作为rnlink 从中选择L.tag ,L.起始日期作为起始日期 ,DateDiff.startdate,R.enddate为d 从选择* ,CONCATtag,CASTROW_编号,按标签顺序划分,按startdate ASC作为字符串作为rnstart FROM.tmp_respaned_输入L 左连接 挑选* 、CONCATtag、CASTROW_编号按标记顺序按结束日期ASC+1作为字符串作为开始 FROM.tmp_respaned_input R 在L.rnstart=R.rnstart X上 其中d>1或d为空 左连接 -b用同一标签隔离所有比下一个开始日期早1天以上的结束日期,或者是标签的最后日期。按顺序给它们编号。 选择结束日期 ,CONCATtag,CASTrow_编号按标记顺序按结束日期ASC按字符串按rnlink划分 从中选择L.tag ,L.enddate作为enddate ,DateDiff.startdate,L.enddate为d 从选择* ,CONCATtag,CASTrow_编号按标记顺序按结束日期ASC按字符串按rnend划分 FROM.tmp_respaned_输入L 左连接 挑选* ,CONCATtag,CASTrow_编号,按标签顺序划分,按起始日期ASC-1作为字符串作为rnend FROM.tmp_respaned_input R 在L.rnend=R.rnend X上 其中d>1或d为空E 在S.rnlink上=E.rnlink; -打印结果 挑选* 来自。结果 由起始日期ASC订购; results.accountid results.provider results.los results.startdate results.enddate 123A史密斯7 2019-03-01 00:00:00.0 2019-03-08 00:00:00.0 2456B罗杰斯2019-03-02 00:00:00.0 2019-03-03 00:00:00.0 3 456B丹尼尔5 2019-03-04 00:00:00.0 2019-03-09 00:00:00.0 4 123A史密斯2 2019-03-10 00:00:00.0 2019-03-12 00:00:00.0
这是我的解决方案,请参见代码中的注释:

--configuration
set hive.cli.print.header=true;
set hive.execution.engine=tez;
set hive.mapred.reduce.tasks.speculative.execution=false;
set mapred.reduce.tasks.speculative.execution=false;
set hive.exec.parallel=true;
set hive.exec.parallel.thread.number=36;
set hive.vectorized.execution.enabled=true;
set hive.vectorized.execution.reduce.enabled=true;
set hive.vectorized.execution.reduce.groupby.enabled=true;
set hive.map.aggr=true;

with example as (--this is your data example
select stack (9, '123A', 'smith', '2019-03-01 00:00:00', '2019-03-04 00:00:00',
'456B', 'rogers', '2019-03-02 00:00:00', '2019-03-03 00:00:00',
'123A', 'smith', '2019-03-03 00:00:00', '2019-03-06 00:00:00',
'123A', 'smith', '2019-03-07 00:00:00', '2019-03-08 00:00:00',
'456B', 'daniels', '2019-03-04 00:00:00', '2019-03-05 00:00:00',
'456B', 'daniels', '2019-03-06 00:00:00', '2019-03-09 00:00:00',
'123A', 'smith', '2019-03-10 00:00:00', '2019-03-12 00:00:00',
--I added one more case
'123A', 'smith', '2019-03-14 00:00:00', '2019-03-17 00:00:00',
'123A', 'smith', '2019-03-18 00:00:00', '2019-03-19 00:00:00'
) as (accountId, provider, startdate, enddate )
)

select --aggregate start and end dates for the whole case, count LOS 
       accountId, provider, datediff(max(enddate),min(startdate)) as los, min(startdate) startdate , max(enddate) enddate
from
(
select --distribute case_id across all records in the same case
       accountId, provider, startdate, enddate,
       last_value(case_id, true) over(partition by accountid, same_case_flag order by startdate ) as case_id --Bingo!!! we have case_id     
from
(
select --generate UUID as case_id if previous same_case_flag != current one or previous was NULL. 
       --One UUID will be generated for each new case
       accountId, provider, startdate, enddate, same_case_flag, 
       case when lag(same_case_flag) over(partition by accountid order by startdate) = same_case_flag 
              then NULL else java_method("java.util.UUID", "randomUUID") 
        end case_id      
from
(
select --calculate same case flag
       accountId, provider, startdate, enddate,
        case when  datediff(startdate,lag(enddate) over(partition by accountId order by startdate)) <=1    --startdate - prev_enddate                          
                   OR  
                   datediff(lead(startdate) over(partition by accountId order by startdate), enddate) <=1  --next_startdate-enddate
                then true else false 
         end as same_case_flag                  
  from example s
)s)s)s
group by accountId, provider, case_id
order by startdate;  --remove order by if not necessary to sppeed-up processing !!! I added it to get the same ordering as in your example
取下订单以除去最后一个减速器

根据您的日期,可能为了分配案例id,您可以使用concataccountid、rand或concat always startdate,或者类似的东西,而不是randomUUID,如果后面有具有相同accountid的单独案例,但randomUUID更安全,因为它总是唯一的


此方法根本不使用联接。

我尝试解决此问题,但由于表中第三行的开始日期小于同一组的上一个结束日期,此问题变得棘手。表中第三行的数据正确,因为同一accountid在两个不同的日期都处于活动状态3 123A smith 2019-03-03 00:00:00.0 2019-03-06 00:00:00.0 . 我是说他们有不同的开始日期?只是问一下,请核对我的答案
--------------------------------------------------------------------------------
        VERTICES      STATUS  TOTAL  COMPLETED  RUNNING  PENDING  FAILED  KILLED
--------------------------------------------------------------------------------
Map 1 ..........   SUCCEEDED      1          1        0        0       0       0
Reducer 2 ......   SUCCEEDED      1          1        0        0       0       0
Reducer 3 ......   SUCCEEDED      1          1        0        0       0       0
Reducer 4 ......   SUCCEEDED      1          1        0        0       0       0
Reducer 5 ......   SUCCEEDED      1          1        0        0       0       0
Reducer 6 ......   SUCCEEDED      1          1        0        0       0       0
--------------------------------------------------------------------------------
VERTICES: 06/06  [==========================>>] 100%  ELAPSED TIME: 10.79 s
--------------------------------------------------------------------------------
OK
accountid       provider        los     startdate       enddate
123A    smith   7       2019-03-01 00:00:00     2019-03-08 00:00:00
456B    rogers  1       2019-03-02 00:00:00     2019-03-03 00:00:00
456B    daniels 5       2019-03-04 00:00:00     2019-03-09 00:00:00
123A    smith   2       2019-03-10 00:00:00     2019-03-12 00:00:00
123A    smith   5       2019-03-14 00:00:00     2019-03-19 00:00:00
Time taken: 29.049 seconds, Fetched: 5 row(s)