Hive:用SQL对数据进行操作,导入数据、清洗脏数据、统计数据订单、优化结果输出等等
文章目录
- 1、准备数据
- 2、了解数据
- 3、将数据导入hive
- 4、如何清洗第一行的脏数据?
- 4.1 方式一:shell命令
- 4.2 方式二:HQL (hive sql)
- 4.3 方式三:更新表,过滤首行(个人建议用这个SQL命令)
- 5、每个用户有多少个订单? (分组)
- 6、每个用户一个订单平均是多少商品?
- 6.1 一个订单有多少个商品?
- 6.2 一个用户有多少商品?
- 6.3 针对步骤6.2,进行用户对应的商品数量 sum求和。
- 6.4 一个用户平均一个订单有多少个商品?
- 6.5 每个用户在一周中的购买订单的分布?
- 6.6 查看 在12点时间段每个用户购买了哪些商品?
- 7、一个用户平均每个购买天中,购买的商品数量
- 8、每个用户最喜爱购买的三个商品product是什么?
- 8.1 每个用户购买的商品的次数
- 8.2 对购买的商品次数进行rank
- 8.3 优化输出结果格式
① Hive 数据管理、内外表、安装模式操作
② Hive:用SQL对数据进行操作,导入数据、清洗脏数据、统计数据订单
③ Hive:多种方式建表,需求操作
④ Hive:分区原因、创建分区、静态分区 、动态分区
⑤ Hive:分桶的简介、原理、应用、创建
⑥ Hive:优化 Reduce,查询过程;判断数据倾斜,MAPJOIN
⑦ Hive:数据进行替换切分后的结果保存为新表,新表进行分词
1、准备数据
百度网盘链接:https://pan.baidu.com/s/1QDlf7SoGPWliagV2ettMOQ
提取码:3jcn
2、了解数据
head -10 orders.csv
order_id:订单号
user_id:用户id
eval_set:订单的行为(历史产生的或者训练所需要的)
order_number:用户购买订单的先后顺序
order_dow:order day of week ,订单在星期几进行购买的(0-6)
order_hour_of_day:订单在哪个小时段产生的(0-23)
days_since_prior_order:表示后一个订单距离前一个订单的相隔天数
head -10 order_products__train.csv
order_id:订单号
product_id:商品ID
add_to_cart_order:加入购物车的位置
reordered:这个订单是否重复购买(1 表示是 0 表示否)
head -10 products.csv
(数据仓库定位:商品维度表)
product_id:商品ID
product_name:商品名称
aisle_id:货架id
department_id:该商品数据属于哪个品类,日用品,或者生活用品等
departments.csv(品类维度表)
department_id:部门id, 品类id
department: 品类名称department_id,department
1,frozen
2,other
3,bakeryorder_products__prior.csv(用户历史行为数据)order_id,product_id,add_to_cart_order,reordered
2,33120,1,1
2,28985,2,1
2,9327,3,0
3、将数据导入hive
对于orders.csv,我们指导他是以‘,’ 作为字段分割符,行与行之间数据是‘\n’是分割。
在hive数据库创建orders表
create table badou.orders(
order_id string
,user_id string
,eval_set string
,order_number string
,order_dow string
,order_hour_of_day string
,days_since_prior_order string
)
row format delimited fields terminated by ','
lines terminated by '\n';
可以得知,创建orders表成功;接下来我们要把orders.csv
数据加载到orders表中。
加载数据到hive,有两种方式:
- 加载本地数据到Hive,overwrite 覆盖, into 追加
load data local inpath 'day3/orders.csv' overwrite into table orders;
- HDFS数据加载到Hive (没有 local,要保证HDFS有数据)
load data inpath 'day3/orders.csv'
overwrite into table orders;
我们这里选择从本地加载数据。
load data local inpath 'day3/orders.csv' overwrite into table orders;select * from orders limit 10;
可以发现,第一行数据是脏数据。
我们要自动显示下每个数据的字段名称。
进入 hive-site.xml
,在(master)进行配置:
vi hive-site.xml
<!--Hive第一行显示列名称-->
<property><name>hive.cli.print.header</name><value>true</value><description>显示列名称</description>
</property>
exit; 退出hive,再重新进入hive。
use badou;
select * from orders limit 10;
创建trains表,加载order_products__train.csv
也是如此操作。
4、如何清洗第一行的脏数据?
4.1 方式一:shell命令
思想:在load加载数据之前,针对异常数据进行处理,用 sed '1d' orders.csv
。
测试:
head -10 orders.csv > tmp.csv
cat tmp.csv
sed '1d' tmp.csv > tmp_res.csv
cat tmp_res.csv
4.2 方式二:HQL (hive sql)
insert overwrite table orders
select * from orders where order_id !='order_id';
4.3 方式三:更新表,过滤首行(个人建议用这个SQL命令)
alter table trains set tblproperties('skip.header.line.count'='1');
5、每个用户有多少个订单? (分组)
我们知道,user_id为用户ID,order_id为订单ID,count(order_id) 统计订单数。
select user_id, count(distinct order_id) as order_cnt
from orders group by user_id
limit 20;
distinct :表示去重
as:把count的结果作为order_cnt
对order_cnt进行从大到小排序的话。
select user_id, count(distinct order_id) as order_cnt from ordersgroup by user_idorder by order_cnt desc
limit 10;
6、每个用户一个订单平均是多少商品?
先创建priors表,加载order_products__prior.csv
数据。
create table priors(
order_id string,
product_id string,
add_to_cart_order string,
reordered string
)
row format delimited fields terminated by ','
lines terminated by '\n';load data local inpath 'day3/order_products__prior.csv'
overwrite into table priors;过滤脏数据
alter table priors set tblproperties('skip.header.line.count'='1');
6.1 一个订单有多少个商品?
在priors 表对订单order_id分组,我们选择订单ID和产品数量,产品数量as pro_cnt。
select order_id,count(distinct product_id) as pro_cnt from priors
group by order_id
limit 10;
6.2 一个用户有多少商品?
在orders表有用户ID,priors表有商品ID,这两个表同时有 订单ID order_id,可以把表连接起来,把7.1的结果 as t,在t表我们就有 order_id 和 pro_cnt 两个字段。
(select order_id, count(distinct product_id)
as pro_cnt from priorsgroup by order_idlimit 10000
) as t
select user_id,pro_cnt from orders as od
inner join t
on od.order_id=t.order_id
limit 10;
完整SQL语句:
select od.user_id, t.pro_cnt from orders as od
inner join (select order_id, count(distinct product_id) as pro_cntfrom priorsgroup by order_idlimit 10000
) as t
on od.order_id=t.order_id
limit 10;
as 是可以省略的;
结果应该有用户ID与商品数量 od.user_id, t.pro_cnt
。
6.3 针对步骤6.2,进行用户对应的商品数量 sum求和。
对商品数量t.pro_cnt进行求和,即sum(t.pro_cnt)
。
【注意】: 使用聚合函数(count、sum、avg、max、min )的时候要结合group by 进行使用。
从 7.2代码进行修改:
select od.user_id, sum(t.pro_cnt) as sum_prods from orders od
inner join (select order_id, count(distinct product_id) as pro_cntfrom priorsgroup by order_idlimit 10000
) as t
on od.order_id=t.order_id
group by od.user_id
limit 10;
我们,修改 sum(t.pro_cnt) as sum_prods
后,需要进行group by操作,即group by od.user_id
。显示结果有 od.user_id sum_prods
。
6.4 一个用户平均一个订单有多少个商品?
即 用户的商品数量 / 用户的订单数量 == sum(t.pro_cnt)/count(t.order_id) as sc_prod,
也可以用平均产品数量avg,avg(pro_cnt) as avg_prod
select od.user_id
,sum(t.pro_cnt)/count(t.order_id) as sc_prod
,avg(pro_cnt) as avg_prod
from orders od inner join (select order_id, count(distinct product_id) as pro_cntfrom priorsgroup by order_idlimit 10000
) t
on od.order_id=t.order_id
group by od.user_id
limit 10;
6.5 每个用户在一周中的购买订单的分布?
在 orders表中,的列order_dow,代表购买订单是在一周的星期几,0-6 代表周一到周日。
查询:
head -30 orders.csvselect * from orders limit 30;
思路: 要输出的是用户id,与星期几一天的总订单量。即需要sum(星期几订单),判断if order_dow='0'/ '1'/ '2'/ '3'/ '4'/ '5'/ '6' --> true 为1, false 为0
,把结果sum,则得出:星期几一天的总订单量。例如:
user_id order_dow 1 0 sum=0+1=11 0 sum=1+1=21 1 sum=0+1=12 1 sum=0+1=1
由上面数据可知,用户id为1,星期一(0),有2个订单;星期二(1),有1个订单;
用户id为2,星期二(1),有1个订单;
【注意】: 实际开发中,一定是最先开始使用小批量数据进行验证,验证代码逻辑的正确性,然后全量跑!!,提高工作效率。
方式一:用case when 语句
select user_id
, sum(case when order_dow='0' then 1 else 0 end) dow0
, sum(case when order_dow='1' then 1 else 0 end) dow1
, sum(case when order_dow='2' then 1 else 0 end) dow2
, sum(case when order_dow='3' then 1 else 0 end) dow3
, sum(case when order_dow='4' then 1 else 0 end) dow4
, sum(case when order_dow='5' then 1 else 0 end) dow5
, sum(case when order_dow='6' then 1 else 0 end) dow6
from orders
where user_id in ('1','2','3')
group by user_id;
方式二:用 if 语句
select user_id
, sum(if(order_dow='0',1,0)) as dow0
, sum(if(order_dow='1',1,0)) dow1
, sum(if(order_dow='2',1,0)) dow2
, sum(if(order_dow='3',1,0)) dow3
, sum(if(order_dow='4',1,0)) dow4
, sum(if(order_dow='5',1,0)) dow5
, sum(if(order_dow='6',1,0)) dow6
from orders
where user_id in ('1','2','3')
group by user_id;
我们验证数据:从上下图可知: 用户id为1: 星期一没有订单,星期二有3个订单。从下图可知验证正确。
。小批量验证完成,我们可以取消 where语句,进行全部量操作。
6.6 查看 在12点时间段每个用户购买了哪些商品?
分析:需要 用户ID:user_id, 商品ID:product_id, 时间:order_hour_of_day;
orders表有 : order_id, user_id;
trains表有:order_id, product_id;
把两个表连接起来 inner join。
SQL语句:
select od.user_id, tr.product_id from orders od inner join trains tron od.order_id=tr.order_idwhere order_hour_of_day = '12'limit 10;
由图可知,在12点,‘21’ 用户 购买了 ‘25740、12683、44632、10957、32645、16615’ 等商品。
7、一个用户平均每个购买天中,购买的商品数量
orders 表中的 days_since_prior_order 等价于购买天数。
我们要用户ID,商品数量,购买天数。
orders 表与priors表 连接可以得到 “用户ID,商品数量,购买天数。”
- 6.1中可以求得一个订单有多少个商品,结果保存为pri 表;
- 从orders表把 order_id, user_id, days_since_prior_order 结果存储为 ord;
- 用 join 连接,查找出
select user_id, sum(商品数量) / count(购买天数) from ord join pri on ord.order_id=pri.order_id group by ord.user_id
输出结果
-- ord表,对购买天数的数值需要进行空处理
(select order_id, user_id, if(days_since_prior_order='','-1',days_since_prior_order) as days_since_prior_order
from orders
where eval_set='prior' limit 10000
) ord-- pro_cnt 为商品数量
select order_id, count(1) as pro_cnt from priors
group by order_id
limit 10000
) pri
完整代码:
select ord.user_id, sum(pri.pro_cnt) / count(distinct days_since_prior_order) avg_prod
from
( select order_id, user_id,
if(days_since_prior_order='','-1',days_since_prior_order) as days_since_prior_order
from orders
where eval_set='prior' limit 10000
) ord
join (
select order_id, count(1) as pro_cnt from priors
group by order_id
limit 10000
) pri
on ord.order_id=pri.order_id
group by ord.user_id
limit 10;
由图结果可知:由用户ID,平均一天商品购买数量。
8、每个用户最喜爱购买的三个商品product是什么?
最喜欢购买就是 购买的商品最多。
因此要先求 每个用户购买的商品的次数,再对次数排序,前三个。
8.1 每个用户购买的商品的次数
select ord.user_id, pri.product_id, count(1) as top_cnt
from
(select * from orders where eval_set='prior'
) ord
join (
select * from priors limit 1000
) pri
on ord.order_id=pri.order_id
group by ord.user_id,pri.product_id
limit 20;-- 可以 用 partition by 替换 group by。
select ord.user_id, pri.product_id,
count(1) over(partition by ord.user_id,pri.product_id) as top_cnt
from
(select * from orders where eval_set='prior'
) ord
join (
select * from priors limit 1000
) pri
on ord.order_id=pri.order_id-- group by ord.user_id,pri.product_id
limit 20;
8.2 对购买的商品次数进行rank
--用with关键字 把每个用户购买的商品的次数结果为rank_tmp
with rank_tmp as (select ord.user_id, pri.product_id,
count(1) over(partition by ord.user_id,pri.product_id) as top_cnt
from
(select * from orders where eval_set='prior'
) ord
join (
select * from priors limit 1000
) pri
on ord.order_id=pri.order_id
)
在操作排名,排序常用函数 row_number()
,用于给数据库表中的记录进行标号,在使用的时候,其后还跟着一个函数 over(),而函数 over() 的作用是将表中的记录进行分组和排序。
row_number() over() --分组排序功能;
--语法格式:
row_number() over(partition by 分组列 order by 排序列 desc)
在使用 row_number() over()函数时候,over()里头的分组以及排序的执行晚于 where 、group by、 order by 的执行。
这里我们要:row_number(), 是对用户id分组,对商品次数进行降序排序。
select * from
(
select user_id, product_id,
row_number() over(partition by user_id order by top_cnt desc) as row_num
from rank_tmp
-- 排序结果保存为t表
) t
--得出排序结果,where取前三个
where row_num <= 3
limit 20;
可以发现,每个用户最喜爱购买的三个商品。
8.3 优化输出结果格式
要的显示结果:user1 [100_3,101_2,102_1]
user1 [100_3,101_2,102_1]
100代表商品id,_3 中的3是第三个喜欢的意思
像 101_2,2是第二个喜欢的商品。把转为列表形式用collect_list()函数;
concat_ws('-',列名1,列名2) = 列名1-列名2
如果列名2是整型要cast为string类型。
--即:
collect_list(concat_ws('_',product_id, cast(row_num as string))) as pro_top3
我们要以上面的列表格式化输出,列表里面的数据为 最喜欢的前三名商品。
同样把上面8.2的结果用 with 进行保存为 rank_result。
with rank_tmp as (select ord.user_id, pri.product_id,
count(1) over(partition by ord.user_id,pri.product_id) as top_cnt
from
(select * from orders where eval_set='prior'
) ord
join (
select * from priors limit 1000
) pri
on ord.order_id=pri.order_id
),
-- 要with嵌套,注意这里用逗号分割
rank_result as ( -- 注意这里没有with
select user_id, product_id,
row_number() over(partition by user_id order by top_cnt desc) as row_num
from rank_tmp
)
-- 正式查询语句,与上面的with as直接没有符号分割
select user_id, collect_list(concat_ws('_',product_id, cast(row_num as string))) as pro_top3,
-- size 返回列表中元素的个数
size(collect_list(product_id)) as top_size
from rank_result
where row_num <= 3
group by user_id
limit 20;
发现上图结果满足,用户的最喜欢商品以列表形式返回,商品id后的‘_1’ 代表 第一个喜欢商品,size返回列表商品个数。
Hive:用SQL对数据进行操作,导入数据、清洗脏数据、统计数据订单、优化结果输出等等相关推荐
- 利用SQL语句对数据进行操作:插入、更新与删除数据行
My目录 前言 一.T-SQL的组成 二.插入数据行 1.一次插入一行数据 2.一次插入多行数据 三.更新数据行 四.删除数据行 前言 结构化查询语言(Structured Query Languag ...
- php页面导入excel表格,php页面导入excel表格数据:php导入excel 怎么获取excel表格数据...
导入excel文件,后端php处理导入的数据并存入数据库,需要前后端结合的demo! thinkphp3.2phpexcel导入最基本用法 先整个最基础的代码,理解了这个,后面非常简单了 $file_ ...
- php实现的统计数据,【后端开发】PHP实现的统计数据功能详解
这篇文章主要介绍了PHP实现的统计数据功能,结合实例形式分析了php数据查询与显示处理的相关操作技巧,需要的朋友可以参考下 本文实例讲述了PHP实现的统计数据功能.分享给大家供大家参考,具体如下: 统 ...
- 几万条数据的excel导入到mysql_excel十几万行数据快速导入数据库研究(转,下面那个方法看看还是可以的)...
先贴原来的导入数据代码: 8 import os os.environ.setdefault("DJANGO_SETTINGS_MODULE", "www.setting ...
- access 一亿条数据_操作用户只能看到自己本部门的数据功能
↑↑↑点击上方图片,了解详情 功能描述: 以Access快速开发一日通报销管理课程的报销明细为例: [张志MVP]Access快速开发一日通视频教程[Access软件网]http://www.acce ...
- Oracle数据库----表中数据的操作(插入、更新、删除数据)
文章目录 一.插入数据 插入多行数据的简单方法: 1.将表一的全部数据添加到表二中 创建副本Courses1,只复制Courses的结构 将Courses表中的数据拷贝到Courses1中 创建副本的 ...
- graphpad数据小数点_教你如何用graphpad统计数据,值得一看
很多初搞科研的菜鸟都对数据后期的整理头疼,今天就用简洁明了的方式教教大家怎么用graphpad软件统计并分析数据 工具/材料 graphpad软件 操作方法 01 打卡graphpad后打击上方的ne ...
- python数据导入与清洗_Python学习之 数据清洗之增删改查
数据准备 工具包导入及工作路径设置: 数据导入: 为了方便读者实操,这里附上原表:jingdian1.csv 增 增加列 增加列的方法有多种,这里列举两种. 增加"评级"列,lev ...
- (Java数据库编程基础操作)Statement实现数据查询操作
Statement实现数据查询操作 在整个数据库的开发过程之中数据的查询操作是最复杂的,因为查询会牵扯到各种复杂查询的管理,例如:多表查询.子查询.统计查询.集合操作等等,但是从现代的开发来讲,对于数 ...
- matlab复制txt里的一列,将txt格式里的两列数据复制粘贴导入excel 后全都在同一列里,怎样让它们分成两列?...
将txt格式里的两列数据复制粘贴导入excel 后全都在同一列里,怎样让它们分成两列?以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起 ...
最新文章
- 基于Struct的云和租房系统(简单房屋出租)
- jquery PHP大文件上传,Jquery和BigFileUpload实现大文件上传及进度条显示
- int数组初始化_Java中到底有没有多维数组
- opengl加载显示3D模型AMF类型文件
- 关于Java中的HashMap
- vfp报表纸张设置_Excel表格美化十四招,让你的报表不再那么丑
- POJ 1065 Wooden Sticks(LIS,最少链划分)
- Ruby中的类与对象(一)
- 1.3使用command-line runners
- (一)PyQt5系列教程:使用PyQt5创建一个简单的demo
- eeupdate使用说明_Fedora如何修改网络接口名称?Fedora修改网络接口名称的方法
- qq linux五笔输入法下载官网,QQ五笔输入法下载_QQ五笔输入法下载2021官方下载-太平洋下载中心...
- 有趣好玩恶搞的C语言程序,有趣搞笑的整人VBS小脚本(整菜鸟专用)
- Atlas中间件实现Mysql读写分离
- 2019-11-29奈奎斯特和香农定理
- 计算机室火灾隐患表现,消防控制室存在的火灾隐患及对策
- DXF文件格式——DXF 格式
- k8s iptable升级到ipvs
- 解决C盘存储空间不足
- 生日悖论与Hash函数的攻击