用hive/pig填充不存在的数据

ykejflvf  于 2021-06-24  发布在  Pig
关注(0)|答案(2)|浏览(529)

我有一个具有以下结构的配置单元表:

id1, id2, year, value 
1, 1, 2000, 20
1, 1, 2002, 23
1, 1, 2003, 24
1, 2, 1999, 34
1, 2, 2000, 35
1, 2, 2001, 37
2, 3, 2005, 50
2, 3, 2006, 56
2, 3, 2008, 60

我有两个标识“用户”的id,对于每个用户和年份我都有一个值,但是有些年份没有值,这些值不会出现在表中。我想为每个id[id1,id2]和年份(考虑最小年份和最大年份之间的所有年份)添加一个值,如果年份不存在,则使用上一年的值。所以这个表应该变成:

id1, id2, year, value 
1, 1, 2000, 20
1, 1, 2001, 20
1, 1, 2002, 23
1, 1, 2003, 24
1, 2, 1999, 34
1, 2, 2000, 35
1, 2, 2001, 37
2, 3, 2005, 50
2, 3, 2006, 56
2, 3, 2007, 56
2, 3, 2008, 60

我需要在Hive或Pig里做,或者在最坏的情况下我可以用spark
谢谢,

osh3o9ms

osh3o9ms1#

如果可以将年份存储为一个表,则最好实现这一点。

create table dbname.years 
location 'hdfs_location' as
select 2000 as yr union all select 2001 as yr --include as many years as possible

1) 有了这个表,可以交叉连接id以生成所有年份的组合,然后 left join 重新整理原来的table。
2) 然后将行分组,这样 null 上一步中的值(id的原始表中缺少年份)被指定为与上一个非空值相同的组。这是用一个连续的总和来完成的。运行子查询以查看如何分配组。
3) 然后,选择 max 对于每个id1、id2、组组合。

select id1,id2,yr,max(val) over(partition by id1,id2,grp) as val
from (select i.id1,i.id2,y.yr,t.val
      ,sum(case when t.val is null then 0 else 1 end) 
       over(partition by i.id1,i.id2 order by y.yr) as grp
      from (select distinct id1,id2 from tbl) i
      cross join (select yr from years) y
      left join tbl t on i.id1=t.id1 and i.id2=t.id2 and y.yr=t.yr
     ) t
dsekswqp

dsekswqp2#

我会用临时table做这个。每个id1和id2的年份各不相同,因此我将根据id1和id2创建一系列年份,而不是为所有人创建一系列年份。1) 根据id1和id2获取最小年份和最大年份。调用这个series\u dtes表2)左连接到手头的表(我称之为calu date)3)用series\u dtes表和calu date表的组合创建一个temp表。这将填补每id1,id2说,2001年和2007年失踪的年份。4) 使用滞后函数填写2001和2007的缺失值。

create table tmp as 
with  series_dtes as (
select id1, id2, (t.min_dt+pe.idx) as series_year
from (select id1, id2, min(year) as min_dt, max(year) as max_dt from cal_date group by id1, id2) t
lateral view posexplode(split(space(t.max_dt-t.min_dt),' ')) pe as idx, dte)
select dte.id1, dte.id2, dte.series_year, t.value
from series_dtes dte
left join cal_date  t
on dte.series_year=t.year and t.id1=dte.id1 and t.id2=dte.id2
order by dte.id1, dte.id2, dte.series_year;

select id1, id2, series_year as year, 
(case when value is null then (lag(value) over (partition by id1,id2 order by series_year)) else value end) as value
from tmp;

Result:
id1     id2     year    value
1       1       2000    20
1       1       2001    20
1       1       2002    23
1       1       2003    24
1       2       1999    34
1       2       2000    35
1       2       2001    37
2       3       2005    50
2       3       2006    56
2       3       2007    56
2       3       2008    60

相关问题