hive离线数仓
- 数据仓库概念:
1. 为企业决策提供数据支撑、存储、计算、分析。 2. 分类:业务数据、用户行为数据、爬虫数据。
- 数据仓库流程:
数据输入:用户行为数据、业务数据、爬虫数据等--------->>>数据分析:对数据进行备份、聚合、统计------------->>>数据输出:报表系统、用户画像(打标签:统计类标签、规则类标签、机器学习标签)、推荐系统(需要构建推荐模型)、机器学习。
- 准备工作:
1. 用户行为数据采集平台 flume(source-chanel->sink)->hive 2. 业务数据采集平台 mysql->dataX->hive 3. 数据仓库维度建模(核心):ods,dwd,dws,dwt,ads 4. 分析需求主题,统计报表指标 5. 采用即席查询工具,随时进行指标分析 6. 对集群性能进行监控,发生异常要报警(电话,短信,邮件,钉钉等) 7. 元数据管理(将所有数据的执行过程和依赖关系在图形化界面上展示出来)hive管理,元数据存储在MySQL中。 8. 数据质量监控(监控数据的异常变化,对于计算错误或异常的数据要监控) 9. 权限管理 项目技术选型、框架版本、服务器选型(物理机或者云主机)、确认集群规模。考虑成本,阿里云贵,但是不用专门运维人员维护,也不需要机房存放服务器。物理机便宜,需要专业运维以及机房存放服务器。
- 数据工具:
1. 用户行为数据,通过flume采集数据存储在hive中。日志文件 为什么用flume不用logstash或者Java程序直接采集? 答:开源免费,大厂使用广泛,有成熟的案例和踩坑经验,传输效率非常高。 2. 业务数据,通过dataX采集到hive。业务数据存储在mysql中,通过dataX采集到hive中。 通过jdbc组件也可以直接连mysql采集数据,也可以通过hadoop的inputformat自定义组件,连接mysql数据库,采集业务数据。 其实sqoop底层就是hadoop,4个map采集。 3. 分层:ods备份-dwd清洗-dws聚合-dwt聚合-ads统计。一般分为四层,还有一层dim维度层。ods存放原始数据,dwd对数据进行清洗,dws和dwt对数据进行join形成大的宽表,这样每次统计不用join太多表,dws可以按照天来join,dwt是个累计的宽表,可以保存很多年的,ads层就是报表,最终统计结果。 4. 代码运行:hive on spark 5. 数据采集:DS调度、flume、kafka(削峰)、sqoop、logstash(ELK数据分析)、dataX。(dataX和sqoop都可以采集) 6. 数据存储:mysql、hdfs、HBASE、Redis、MongoDB。 7. 数据计算:hive、tez、spark、flink 8. 数据查询:presto、kylin、impala、druid、clickhouse、Doris 9. 数据可视化:echarts、superset、quickBI、dataV 10. 任务调度:azkaban、oozie、DS、airflow(Python脚本) 11. 集群监控:zabbix(离线)grafana、prometheus(实时) 12. 元数据管理:Atlas 13. 权限管理:ranger、sentry
- 数据采集:
Sqoop 依赖 JDBC 来操作数据库,常用于离线计算,执行时本质是 MapReduce 任务,数据量小的话不如dataX。如果数据量非常庞大,还是用sqoop来采集,但是只能采集关系型数据库。 flume实时采集,用来采集日志。
- 数据分层:
1. 为什么要分层? 把复杂问题简单化 减少重复开发 隔离原始数据 2. 数据仓库与数据集市区别? 数据集市是一种微型的数据仓库,是部门级别的。数据仓库是企业级的,为整个企业的运行提供决策支持手段。 3. 命名规范 表命名:ods_,dim_,dwd_,dws_,dwt_,ads,tmp_; 脚本命名:数据源_to_目标_db/log.sh 4. 范式概念 函数依赖:完全函数依赖(a完全依赖于b和c),部分函数依赖(a完全依赖于b和c,a部分依赖于b和c和d,因为通过b和c就可以推出a,无需再加d),传递函数依赖(a依赖于b和c,b和c依赖于d,a传递依赖于d)。 第一范式:1nf,符合1NF的关系中的每个属性都不可再分。1nf是所有关系型数据库的最基本要求,如果数据表的设计不符合这个要求,那么操作一定是不成功过的。 第二范式:2nf,不能存在非主键字段部分依赖于主键字段。有主键,非主键字段完全依赖主键; 第三范式:3nf,不能存在传递函数依赖。非主键字段之间不能存在依赖。 5. 建模概念: 关系建模和维度建模是两种数据仓库的建模技术。现在普遍采用维度建模。关系建模主要应用在业务系统的业务数据库中。 数据建模必须遵循一定的规则,在关系建模中,这种规则就是范式。采用范式,可以降低数据的冗余性。 关系建模:将复杂的数据抽象为两个概念--关系和实体,并使用规范化的方式(三范式)表示出来,模型较为松散、零碎,物理表数量较多。且严格遵循三范式,数据冗余低,一致性好,大数据查询效率低。 维度建模:以数据分析作为出发点,不遵循三范式,故数据存在一定的冗余。维度模型面向业务,将业务用维度表和事实表呈现出来。表结构简单,查询效率高。 维度表:一般是对事实的描述信息,每一张维表对应现实世界中的一个对象或者概念。例如:用户、商品、地区、日期等。 维度表特征: 维度表的范围很宽(具有多个属性、列比较多),字段较多。 跟事实表相比,行数相对较少,通常小于10万条。 内容相对固定:编码表。维度表内容变化不会太频繁。 事实表:每行数据通常代表一个业务事件(下单、支付、退款、评价等)。事实这个术语表示的是业务事件的度量值(可统计次数、金额、个数等)。 事实表特征: 非常大 内容相对窄,列数很少。(主要是外键ID和度量值) 经常发生变化,每天会新增加很多。 事务型事实表:以每个事务或者事件为单位,作为事实表中的一行数据。如一笔订单记录等。一旦事务被提交,事务表数据被插入,数据就不再进行更改,其更新方式为增量更新。 周期型快照事实表:不会保留所有数据,只保留固定时间间隔的数据,例如购物车操作,有加减商品随时都可能变化,但是我们更关心每天结束时里面有多少商品,方便我们统计。 累积型快照事实表:通常用于跟踪业务事实的变化。如快递的下单时间,揽货时间,签收时间,收货时间等,每个时间点需要跟踪,时间节点也不断增加。 总结: 一个事实表关联多个维度表。事实表主要包含两类字段,一类是维度表外键,一类是度量值。
- 维度模型分类
在维度建模的基础上又分为三种模型:星型模型、雪花模型、星座模型。 星型模式核心一个大的事实表,周围小的维度,形状如星星。 雪花模型是对星型模型的扩展,他的维度表可以向外连接多个详细的子维度类别表 多个星型构成一个星座,分离的事实表,共用维度表,像是宇宙星辰 DIM层和DWD层需要构建维度模型,一般采用星型模型,呈现的状态一般为星座模型。 维度建模一般按照四个步骤:选择业务过程-->声明粒度-->确认维度-->确认事实。 选择业务过程: 根据业务需求挑选业务线,一条业务线对应一张事实表。 声明粒度: 数据粒度指数据仓库的数据中保存数据的细化程度或者综合程度的级别。精确定义事实表中的一行数据表示什么,尽可能选最小粒度,以此应对各种各样的需求。 事实表和维度表的关联比较灵活,但是为了应对更复杂的业务需求,可以将能关联上的表尽量都关联上。 确认维度表和事实表。 DWS和DWT层统称宽表层。 ADS层对各大主题指标分别进行分析。 补充:时间维度是数据仓库中必须有的一个维度。
- 数仓运行环境
数仓采用hive on spark。主体是hive,底层计算引擎是spark。 hive引擎包括:默认MR,tez,spark hive on spark:hive既负责存储元数据又负责SQL的解析优化,语法是HQL语法,执行引擎变成了spark,spark采用rdd执行。生态更加完整。 spark on hive:hive只负责存储元数据,spark负责SQL的解析优化,语法是spark SQL语法,spark负责采用rdd执行。计算性能更好。 兼容性问题: 官网下载的hive3.1.2和spark3.0.0默认是不兼容的,因为hive3.1.2支持的spark版本是2.4.5,所以需要重新编译hive3.1.2版本。 解决办法:官网下载hive3.1.2源码,修改pom文件中引用的spark版本为3.0.0,如果编译通过,直接打包获取jar包,如果报错,根据提示修改相关方法,直到不报错,打包获取jar包。
- 注意事项
hive在执行load语句时默认会合并小文件,有些数据库中的索引文件也会被合并,导致出现异常数据,为了避免这类情况,可以更改hive设置,不合并小文件。 set hive.input.format=org.apache.hadoop.hive.ql.io.HiveInputFormat;
- 拉链表
拉链表,记录每条信息的生命周期,一旦一条信息的声明周期结束,就重新开始一条新的记录,并把当前日期放入生效开始日期。如果当前信息至今有效,在生效结束日期中填入一个极大值,如(9999-99-99)。 为什么要做拉链表?(更加高效地存储历史状态) 拉链表适合于:数据会发生变化,但是变化频率并不高的维度。(即:缓慢变化维)
- with as语法
with t as (select *, row_number()over(partition by id order by salary desc) ranking from tmp_learning_mary) select * from t where ranking = 1; with as 也叫做子查询部分,hive 可以通过with查询来提高查询性能,因为先通过with语法将数据查询到内存,然后后面其它查询可以直接使用。 with as就类似于一个视图或临时表,可以用来存储一部分的sql语句作为别名,不同的是with as 属于一次性的,而且必须要和其他sql一起使用才可以! 其最大的好处就是适当的提高代码可读性,而且如果with子句在后面要多次使用到,这可以大大的简化SQL;更重要的是:一次分析,多次使用,这也是为什么会提供性能的地方,达到了“少读”的目标。 使用注意事项: 1.with子句必须在引用的select语句之前定义,而且后面必须要跟select查询,否则报错。 2.with as后面不能加分号,with关键字在同级中只能使用一次,允许跟多个子句,用逗号隔开,最后一个子句与后面的查询语句之间只能用右括号分隔,不能用逗号。 with t1 as (select * from firstTable), t2 as (select * from secondTable), t3 as (select * from thirdTable) select * from t1,t2,t3; 3.前面的with子句定义的查询在后面的with子句中可以使用。但是一个with子句内部不能嵌套with子句。 with t1 as (select * from firstTable), t2 as (select t1.id from t1) #第二个子句t2中用了第一个子句的查询t1 select * from t2
- nvl与if用法
nvl (new_id,old_id)效果等同于 if(new_id is null,old_id,new_id) 如果第一个参数值为空,就取第二个值。如果不为空,就取第一个值。
- 日期函数date_add用法
date_add('2023-07-25',-1),返回前一天2023-07-24,返回值类型为date 在hive查询中一般用string类型表示时间,做一下转换 cast(date_add('2023-07-25',-1) as string) 转换类型目的是为了保持字段类型一致,做union合并的时候不报错。 union合并做去重,union all不去重。 next_day函数 取当前天的下一个周一 select next_day('2023-07-11','MO');周一到周日的英文,可以写全称,也可以写前两个字母或者前三个字母,都大写。 取当前天的这周一 select data_add(next_day('2023-07-11','MO'),-7); last_day函数,获取当前月最后一天日期 select last_day('2023-07-11')
- shell脚本
#!/bin/bash APP=gmall if[-n "$2"];then do_date=$2 else echo "请传入日期参数" exit fi
- shell单引号与双引号区别:
Shell 使用过程中,经常会用双引号或单引号将字符串括起来,也可以不使用引号来定义字符串变量。示例如下: str1="testString" #双引号 str2='testString' #单引号 str3=testString #无引号 单引号是全引用,被单引号括起的内容不管是常量还是变量都不会发生替换。 var=dablelv echo '$var' 输出 $var 双引号引用的内容,所见非所得。如果内容中有命令、变量等,会先把变量、命令解析出结果,然后在输出最终内容。双引号是部分引用,被双引号括起的内容常量还是常量,变量则会发生替换,替换成变量内容。 var=dablelv echo "$var" 输出 dablelv 不使用引号定义字符串时,字符串不能包含空白字符(如 Space 或 Tab),需要加引号。一般连续的字符串、数字、路径等可以不加引号。如果内容有命令、变量等,会先把变量、命令解析出结果,然后再输出最终内容。 str1="test String" str2='test String' str3=test String echo $str1 echo $str2 echo $str3 输出: test String test String (空) 可见,字符串含有空格时不使用引号括起来,将无法正常输出。 建议:字符串常量使用单引号括起来,如果字符串含有变量、命令等使用双引号括起来,不建议不加引号。
- Linux命令rz和sz
sz:将选定的文件发送(send)到本地 rz:运行该命令会弹出一个文件选择窗口,从本地选择文件上传到Linux服务器 安装命令:yum install lrzsz 从服务端发送文件到客户端:sz filename 从客户端上传文件到服务端:rz
- get_json_object函数
说明: 第一个参数填写json对象变量,第二个参数使用$表示json变量标识,然后用 . 或 [] 读取对象或数组;如果输入的json字符串无效,那么返回NULL。 每次只能返回一个数据项。 示例: select get_json_object('[{"name":"阿大","sex":"男","age":"25"},{"name":"阿二","sex":"男","age":"20"}]','$[0]');//$指代的是前面传入的JSON数组,下标0表示取第一个元素。 查询结果:{"name":"阿大","sex":"男","age":"25"} select get_json_object('[{"name":"阿大","sex":"男","age":"25"},{"name":"阿二","sex":"男","age":"20"}]','$[0].age'); 查询结果:25
- 窗口函数(开窗函数)
窗口函数是高阶函数,分为窗口和函数两个部分,窗口是限定函数的计算范围,函数表示是计算逻辑。 基本语法:函数 + over( [partition by ...] [order by ...] [窗口子句] ) over表示开窗,默认窗口大小会包含所有数据。 partition by表示根据字段再划分一个细窗口,相同字段进入同一个细窗口里面,每个窗口之间相互独立,窗口子句对于每个细窗口独立生效。 order by表示窗口内按什么排序,如果只有over表示直接最大窗口排序;如果有partition by每个细窗口单独排序。 窗口子句,可以进一步限定范围。 注:窗口函数是一行一行执行的。 哪些函数是窗口函数: 1)窗口函数 lag(col,n,default_val):往前第n行数据。 lead(col,n, default_val):往后第n行数据。 first_value (col,true/false):当前窗口下的第一个值,第二个参数为true,跳过空值。 last_value (col,true/false):当前窗口下的最后一个值,第二个参数为true,跳过空值。 2)聚合函数 max:最大值。 min:最小值。 sum:求和。 avg:平均值。 count:计数。 3)排名分析函数 rank:生成的排序序号从1开始,字段2数值相同的行,序号相同,且会在排序序号中留下空位。1 1 3 4 5 5 7 dense_rank:生成的排序序号从1开始,对于字段2数值相同的行,序号相同,但在排序序号中不会留下空位。1 1 2 3 4 5 5 6 row_number:生成的排序序号从1开始,按照顺序,生成分组内记录的序号,不存在相同序号。1 2 3 4 5 6 ntile:分组并给上组号。
- hive导入数据(insert 与 load data区别)
注意:使用,insert…select 往表中导入数据时,查询的字段个数必须和目标的字段个数相同,不能多,也不能少,否则会报错。但是如果字段的类型不一致的话,则会使用null值填充,不会报错。 使用load data形式往hive表中装载数据时,则不会检查。如果字段多了则会丢弃,少了则会null值填充。同样如果字段类型不一致,也是使用null值填充。 -- 分区插入 insert overwrite table day_table partition(dt='2010-07- 07') select * from tb_select1 ; -- 动态分区插入(先设置非严格模式) set hive.exec.dynamic.partition.mode=nonstrict; insert overwrite table tb_dy_part partition(sex,name) select * from tb_select1;
- uv与pv分别指的是什么
PV是指页面访问量,即Page View,用户每次对网站的访问均被记录,用户对同一页面的多次访问,是访问量的累计。 UV是指独立访问用户数,即Unique Visitor,访问网站的一台电脑客户端为一个访客,根据IP地址来区分访客数。