1.什么是拉链表

拉链表是针对数据仓库设计中表存储数据的方式而定义的,顾名思义,所谓拉链,就是记录历史。记录一个事物从开始,一直到当前状态的所有变化的信息。

我们先看一个示例,这就是一张拉链表,存储的是汇率以及每条记录的生命周期。我们可以使用这张表拿到最新的当天的最新数据以及之前的历史数据。
我们首先介绍一下我们公司用到的汇率分区拉链表

每个公司的拉链表设计可能并不相同但是拉链表以记录生命周期的设计目的是不会改变的。

2.汇率拉链表转日连续流水表

进行对间断的时间序列补全,然后对null补全(这里的规则是取同类上一条数据的非空值)

3.汇率拉链表转日连续流水表

代码实现思路是

step1.使用utf生成连续的时间序列 left join exchangeRate拉链表

step2.使用开窗函数解决补空值问题

为了简单我们用下面这个表代替

1.udtf函数

public class GenDay extends GenericUDTF {
private PrimitiveObjectInspector poi1;
private PrimitiveObjectInspector poi2;
@Override
public StructObjectInspector initialize(StructObjectInspector argOIs) throws UDFArgumentException {
if (argOIs.getAllStructFieldRefs().size() != 2) {
throw new UDFArgumentException("参数个数只能为2");
}
//如果输入字段类型非String,则抛异常
ObjectInspector oi1 = argOIs.getAllStructFieldRefs().get(0).getFieldObjectInspector();
if (oi1.getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentException("参数非基本类型,需要基本类型");
}
//如果输入字段类型非String,则抛异常
ObjectInspector oi2 = argOIs.getAllStructFieldRefs().get(1).getFieldObjectInspector();
if (oi2.getCategory() != ObjectInspector.Category.PRIMITIVE) {
throw new UDFArgumentException("参数非基本类型,需要基本类型");
}
//强转为基本类型对象检查器
poi1 = (PrimitiveObjectInspector) oi1;
if (poi1.getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {
throw new UDFArgumentException("参数1非string,需要基本类型string");
}
poi2 = (PrimitiveObjectInspector) oi2;
if (poi2.getPrimitiveCategory() != PrimitiveObjectInspector.PrimitiveCategory.STRING) {
throw new UDFArgumentException("参数1非string,需要基本类型string");
} //构造字段名,word
List<String> fieldNames = new ArrayList<String>();
fieldNames.add("everyday"); //构造字段类型,string
List<ObjectInspector> fieldOIs = new ArrayList<ObjectInspector>();
//通过基本数据类型工厂获取java基本类型oi
fieldOIs.add(PrimitiveObjectInspectorFactory.javaStringObjectInspector); //构造对象检查器
return ObjectInspectorFactory.getStandardStructObjectInspector(fieldNames,
fieldOIs); } @Override
public void process(Object[] args) throws HiveException {
Date dBegin=null;
Date dEnd=null; //得到一行数据
String start = (String) poi1.getPrimitiveJavaObject(args[0]);
String end = (String) poi2.getPrimitiveJavaObject(args[1]);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
dBegin = sdf.parse(start);
dEnd = sdf.parse(end);
} catch (ParseException e) {
e.printStackTrace();
} assert dEnd != null;
List<String> lDate=getDatesBetweenTwoDate(dBegin,dEnd);
StringBuilder stringBuffer = new StringBuilder();
for (int i=0;i<lDate.size(); i += 1) {
if (i!=0){
stringBuffer.append(" ").append(lDate.get(i));
}else {
stringBuffer.append(lDate.get(i)); } }
String s = stringBuffer.toString();
Object[] objs = new Object[1];
objs[0]= s;
forward(objs); } @Override
public void close() throws HiveException { } public List<String> getDatesBetweenTwoDate(Date beginDate, Date endDate) {
List<String> lDate = new ArrayList<String>();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); lDate.add(sdf.format(beginDate));
Calendar cal = Calendar.getInstance();
// 使用给定的 Date 设置此 Calendar 的时间
cal.setTime(beginDate);
while (true) {
// 根据日历的规则,为给定的日历字段添加或减去指定的时间量
cal.add(Calendar.DAY_OF_MONTH, 1);
// 测试此日期是否在指定日期之后
if (endDate.after(cal.getTime())) {
lDate.add(sdf.format(cal.getTime()));
} else {
break;
}
}
lDate.add(sdf.format(endDate));// 把结束时间加入集合
return lDate;
} }

2.先用笛卡尔积找到所有的uid和连续完全的时间序列的组合,然后left join得到 时间连续但有空值的 序列。

select c.uid,c.everyday,d.event
from
(select a.uid,b.everyday from
(select uid from group by big12.test) a
join (select expode(split(everyday,' ')) as everyday select everyday from GenDay('2018-01-01','2018-12-31'))b
--笛卡尔积
on 1=1) c
left join test d
on c.uid=d.uid and c.everyday=d.time;

像是这样:

3.1用上一条数据补充字段空值(我自己想的)

不过必须单节点 对于汇率来说,一般我的口径里只用到3-5个汇率,这样最多1500条。数据量不大。有风险(自己玩吧别去生产)

package udf;

import org.apache.hadoop.hive.ql.exec.UDF;

public class GetNotNull extends UDF {

    private static String lrkey = null;
private static String lrvalue = null; public String evaluate(String key, String value) {
if (key.equals(lrkey)) {
if (value.isEmpty()) {
value = lrvalue;
}else{
lrvalue=value;
}
} else {
lrkey = key;
lrvalue = value;
}
return value;
}
}

使用静态类保存上一条非空值。

3.2用上一条数据补充字段空值

drop table if exists big12.test;
create table big12.test(
uid int,
time string,
event string
)comment ''
row format delimited
fields terminated by '\031'
stored as textfile
; insert into big12.test values(1,'2018-12-02 11:00:29','');
insert into big12.test values(1,'2018-12-02 11:00:30','');
insert into big12.test values(1,'2018-12-02 11:00:31','');
insert into big12.test values(1,'2018-12-02 11:00:32','');
insert into big12.test values(1,'2018-12-02 11:00:33','');
insert into big12.test values(2,'2018-12-02 11:00:40','');
insert into big12.test values(2,'2018-12-02 11:00:41','');
insert into big12.test values(2,'2018-12-02 11:00:42','');
insert into big12.test values(2,'2018-12-02 11:00:44',''); use big12;
select
t1.uid,
t1.time,
t2.event
from
(
select
uid,
time,
event,
row,
all_row
from
(
select
uid,
time,
event,
row_number()over(partition by case when event is not null and trim(event)<>'' then 1 else 0 end order by time asc) as row,
row_number()over( order by time asc) as all_row
from test
)t
where event is null or trim(event)=''
)t1
left join
(
select
uid,
time,
event,
row,
all_row
from
(
select
uid,
time,
event,
row_number()over(partition by case when event is not null and trim(event)<>'' then 1 else 0 end order by time asc) as row,
row_number()over( order by time asc) as all_row
from test
)t
where event is not null and trim(event)<>''
)t2
on t1.all_row-t1.row=t2.row
union all
select
uid,
time,
event
from test
where event is not null and trim(event)<>'';

hive 汇率拉链表转日连续流水表的更多相关文章

  1. hive 历史拉链表的处理

    1. CREATE TABLE lalian_test(id int,col1 string,col2 string,dt string)--测试表COMMENT 'this is a test2'  ...

  2. hive拉链表

    前言 本文将会谈一谈在数据仓库中拉链表相关的内容,包括它的原理.设计.以及在我们大数据场景下的实现方式. 全文由下面几个部分组成:先分享一下拉链表的用途.什么是拉链表.通过一些小的使用场景来对拉链表做 ...

  3. 漫谈数据仓库之拉链表(原理、设计以及在Hive中的实现)

    本文将会谈一谈在数据仓库中拉链表相关的内容,包括它的原理.设计.以及在我们大数据场景下的实现方式. 全文由下面几个部分组成: 先分享一下拉链表的用途.什么是拉链表. 通过一些小的使用场景来对拉链表做近 ...

  4. hive拉链表取数

    例如,一个借款用户在hive上的拉链表.(end_dt存放逻辑与普通介绍的拉链表不一致) 需要拉去它在2019-05-01日的状态, 取数逻辑是: select * from tb where sta ...

  5. hive拉链表以及退链例子笔记

    拉链表设计: 在企业中,由于有些流水表每日有几千万条记录,数据仓库保存5年数据的话很容易不堪重负,因此可以使用拉链表的算法来节省存储空间.  例子: -- 用户信息表; 采集当日全量数据存储到 (当日 ...

  6. 数仓1.4 |业务数仓搭建| 拉链表| Presto

    电商业务及数据结构 SKU库存量,剩余多少SPU商品聚集的最小单位,,,这类商品的抽象,提取公共的内容 订单表:周期性状态变化(order_info) id 订单编号 total_amount 订单金 ...

  7. DataBase 之 拉链表结构设计

    一.概念 拉链表是针对数据仓库设计中表存储数据的方式而定义的,顾名思义,所谓拉链,就是记录历史.记录一个事物从开始,一直到当前状态的所有变化的信息. 在历史表中对客户的一生的记录可能就这样几条记录,避 ...

  8. merge实现拉链表

    建表如下( 历史拉链表): 新表(每日更新的): 实现语句: MERGE INTO test_target t1 USING ( SELECT nvl(c.id, b.id) AS id ,CASE ...

  9. mysql执行拉链表操作

    拉链表需求: 1.数据量比较大 2.变化的比例和频率比较小,例如客户的住址信息,联系方式等,比如有1千万的用户数据,每天全量存储会存储很多不变的信息,对存储也是浪费,因此可以使用拉链表的算法来节省存储 ...

随机推荐

  1. [SDOI2013]直径 题解

    题面 这道题明显的一定要找到直径的具体路径,所以两遍dfs是比较好的选择: 第一问是一道弱智题吧? 主要难度全部分摊在了第二问: 其实不难,先找到任意一个直径: 对于任意一个在直径上的点: 设nxt[ ...

  2. PAT A1005 Spell It Right (20)

    书中AC代码 #include <cstdio> #include <cstring> #include <iostream> char num[10][10] = ...

  3. 网站如何接入微信公众号JSAPI支付PHP版

    1.首先,我们要有一个微信公众号(分类类型有订阅号,服务号,企业号)我们的微信公众号一定是个服务号只有它才有微信支付接口.. 并且这个微信公众号一定要进行微信认证才能申请微信支付接口. 2.申请JSA ...

  4. Codeforces 1237F. Balanced Domino Placements

    传送门 很妙的题 首先先考虑一个简化的问题,现在有一行格子让你填 你要么填一格 要么填两格 有的格子不让你填 问你填了 $a$ 个一格和填了 $b$ 个两格有多少种方案 那么显然先只考虑放两格的方案, ...

  5. 牛客 40F 珂朵莉的约数 (莫队)

    珂朵莉给你一个长为n的序列,有m次查询 每次查询给两个数l,r 设s为区间[l,r]内所有数的乘积 求s的约数个数mod 1000000007 直接莫队暴力维护复杂度是$O(8m\sqrt{m})$. ...

  6. Hinton等人最新研究:大幅提升模型准确率,标签平滑技术到底怎么用?

    Hinton等人最新研究:大幅提升模型准确率,标签平滑技术到底怎么用? 2019年07月06日 19:30:55 AI科技大本营 阅读数 675   版权声明:本文为博主原创文章,遵循CC 4.0 B ...

  7. 7-Perl 数组

    1.Perl 数组Perl 数组一个是存储标量值的列表变量,变量可以是不同类型.数组变量以 @ 开头.访问数组元素使用 $ + 变量名称 + [索引值] 格式来读取,实例如下:#!/usr/bin/p ...

  8. Python(八) —— 异常(概念、捕获、传递、抛出)

    异常的概念 捕获异常 异常的传递 抛出异常 异常的概念 程序在运行时,如果 Python 解释器 遇到 到一个错误,会停止程序的执行,并且提示一些错误信息,这就是 异常 程序停止执行并且提示错误信息  ...

  9. SQL SERVER中Datetime时间的范围与.net的DateTime对象的区别

    对于编写.net程序中我们一般写默认的时间,我们会自动创建一个new DateTime()对象.但与SQL SERVER连用我们就会出现一个时间范围的问题. 今天我就记录一下该时间问题. 我们创建的n ...

  10. 解决 'mvn' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    'mvn' 不是内部或外部命令,也不是可运行的程序 或批处理文件. 九步完成