adventure项目案例分析

本文是对Adventure Works案例的一个总结,记录了整个项目需求分析与实现的过程,主要任务是使用Hive SQL完成ETL过程,并且连接到PowerBI实现可视化,最终将整个分析成果展示出来。再分析2020年11月的销售情况,并以PPT的形式展现。
本次项目的成果:
在这里插入图片描述在这里插入图片描述在这里插入图片描述

一、项目背景

Adventure Works Cycle是国内一家制造公司,该公司生产和销售金属和复合材料自行车在全国各个市场。销售方式主要有线上零售和线下批发或零售。

  • 产品介绍
    这家公司主要有下面四个产品线:
    Adventure Works Cycles生产的自行车;
    自行车部件,例如车轮,踏板或制动组件;
    从供应商处购买的自行车服装,用于转售给Adventure Works Cycles的客户;
    从供应商处购买的自行车配件,用于转售给Adventure Works Cycles的客户。

二、项目需求

随着线上业务的开展,需要增强公司数据化方面的治理,让前线的业务同学能够实现自主分析,从而能实现对市场的快速判断。因此,要求数据部门和业务部门沟通需求的自主分析的数据指标,从而实现可视化看板。
业务需求:查看最新的销量,销售额趋势以及商品的销售占比;获取当天,前一天,当月,当季,当年的各区域各城市销量和销售额,以及同比数据;对热销产品进行展示。

三、分析过程

1.需求分析

要想实现业务人员的自主分析,需满足以下两点:

  • 具有可视化的操作页面,方便直观分析
  • 数据每日自动化更新
    PowerBI可以实现用户的可视化操作,把相关的表聚合后连接到PowerBI做数据的可视化展示即可,但是聚合的表示固定的,需要将聚合表的操作部署到linux服务器上定时运行,从而实现每日更新数据。
    分析流程如下:
    在这里插入图片描述
2.mysql数据源中观察数据

根据业务需求,梳理出三张要用到的表:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

3.搭建指标体系

指标维度:
时间维度:今日、昨日、当月、当季、当年

地域维度:销售大区、省份、城市

产品维度:产品类别、产品占比、热销产品

经过分析需要聚合的3张数据表:
1)dw_order_by_day 每日环比表:

本表是对当日数据的一个汇总聚合,通过聚合“create_date”字段,获得当日总销量、总销售金额、并计算出客单价。计算每日销售金额与前日金额环比。通过“create_date”字段关联dim_date_df(日期维度表),方便后续对日、月、季度、年等时间维度的销售情况进行聚合展示。

2)dw_customer_order 时间地区产品聚合表:
提取当日维度下ods_sales_orders(订单明细表)和ods_customer(每日新增用户表),并通过“customer_key”字段关联两张表。提取订单主键、订单日期、客户编号、产品名、产品子类、产品类别、产品单价、所在区域、所在省份、所在城市这些字段,使用groupby方法对订单日期、产品名、产品子类、产品类别、所在区域、所在省份、所在城市的逐级聚合。获得相应的单总量、客户总量和销售总金额。

3)dw_amount_diff 当日维度表:
提取生成的的dw_order_by_day(每日环比表)的数据。通过“is_today”、“is_yesterday”、“is_current_year”、“is_last_year”等这些字段中的值:1和0来判断时间。对当日、昨日、月、季度、年等的销售金额,销售量和客单价聚合起来,完成同比计算。使用“amount”、“order“、”avg“标记销售金额,销售量和客单价的同比结果。

四. 聚合表的实现过程

1. Sqoop抽取mysql数据到hive数据库

通过sqoop工具将日期维度表、每日新增用户表、订单明细表将数据从mysql中抽取到hive数据库的ods层,通常将代码写在shell脚本上,在linux 系统中运行即可。
下面是部分shell脚本代码(sqoop_dim_date_df.sh),将日期维度表的内容提取到hive中:

hive -e "drop table if exists ods.dim_date_df" # 删除hive原有的旧表
sqoop import \ 
--hive-import \ 
## 告诉jdbc,连接mysql的url
--connect jdbc:mysql://IP:3306/adventure_ods \  
--username ##### \      ## 连接mysql的用户名
--password ##### \   ## 连接mysql的密码
--query \  ## 构建表达式<sql语句 >执行
"select * from dim_date_df where "'$CONDITIONS'" " \ ##注意:必须要加上where"$CONDITIONS", 否则报错
--fetch-size 50000 \  ## 一次从数据库读取 n 个实例,即n条数据
--hive-table ods.dim_date_df \ ## 创建dim_date_df表(默认也会自动创建表)
--hive-drop-import-delims \  ## 在导入数据到hive时,去掉数据中的\r\n\013\010这样的字符
--delete-target-dir \  ## 如果目标文件已存在就把它删除
--target-dir /user/hadoop/sqoop/dim_date_df \ 
-m 1  ## 迁移过程使用1个map(开启一个线程)

sqoop_ods_sales_orders.sh、sqoop_ods_customer.sh与上述方式相同,这里不再赘述。

2. 在hive数据库中做数据聚合表

编写hive sql从hive数据仓库ods层的日期维度表、每日新增用户表、订单明细表中读取数据进行聚合,完成dw_order_by_day 每日环比表、dw_customer_order 时间地区产品聚合表、dw_amount_diff 当日维度表的聚合操作。

聚合每日环比表(create_dw_order_by_day.sh)脚本:

#!/bin/sh

hive -v -e "
drop table if exists ods.dw_order_by_day;  ## 删除原有的旧表

CREATE TABLE ods.dw_order_by_day(    ## 创建表结构
  create_date string,
  is_current_year bigint,
  is_last_year bigint,
  is_yesterday bigint,
  is_today bigint,
  is_current_month bigint,
  is_current_quarter bigint,
  sum_amount double,
  sum_order bigint);

## 这里的插入语句,因为做聚合需要关联多张表做聚合,这里使用with查询来提高查询性能
with dim_date as
(select create_date,
            is_current_year,
            is_last_year,
            is_yesterday,
            is_today,
            is_current_month,
            is_current_quarter
            from ods.dim_date_df),
sum_day as
(select create_date,
        sum(unit_price) as sum_amount,
        count(customer_key) as sum_order
        from ods.ods_sales_orders
        group by create_date)

insert into ods.dw_order_by_day
    select b.create_date,
    b.is_current_year,
    b.is_last_year,
    b.is_yesterday,
    b.is_today,
    b.is_current_month,
    b.is_current_quarter,
    a.sum_amount,
    a.sum_order
from sum_day as a
inner join dim_date as b
on a.create_date=b.create_date;

聚合时间地区产品聚合表(create_customer_order.sh) 脚本:

#!/bin/bash

hive -v -e "
use ods;

drop table if exists dw_customer_order;

CREATE TABLE dw_customer_order(
  create_date string,
  product_name string,
  cpzl_zw string,
  cplb_zw string,
  order_num bigint,
  customer_num bigint,
  sum_amount double,
  is_current_year bigint,
  is_last_year bigint,
  is_yesterday bigint,
  is_today bigint,
  is_current_month bigint,
  is_current_quarter bigint,
  chinese_province string,
  chinese_city string,
  chinese_province_city string,
  chinese_territory string);

drop table sales_customer1;
create table sales_customer1 as 
select 
  b.create_date,
  b.chinese_province,
  b.chinese_city ,
  b.chinese_province_city ,
  b.chinese_territory,
  a.unit_price,
  a.sales_order_key,
  a.customer_key,
  a.english_product_name,
  a.cpzl_zw,
  a.cplb_zw
from ods_customer as b 
inner join ods_sales_orders as  a 
on a.customer_key=b.customer_key;

drop table sales_customer;
create table sales_customer as 
select 
  create_date,
  chinese_province,
  chinese_city ,
  chinese_province_city ,
  chinese_territory,
  sum(unit_price) as sum_amount,
  count(sales_order_key) as order_num,
  count(distinct customer_key) as customer_num ,
  english_product_name,
  cpzl_zw,
  cplb_zw
from sales_customer1
group by create_date,
  cpzl_zw,
  cplb_zw,
  english_product_name,
  chinese_province,
  chinese_city ,
  chinese_province_city,
  chinese_territory;

with dim_date as
(select create_date,
            is_current_year,
            is_last_year,
            is_yesterday,
            is_today,
            is_current_month,
            is_current_quarter
            from ods.dim_date_df) 

insert into dw_customer_order
  select b.create_date,
  a.english_product_name as product_name,
  a.cpzl_zw,
  a.cplb_zw,
  a.order_num,
  a.customer_num,
  a.sum_amount,
  b.is_current_year,
  b.is_last_year,
  b.is_yesterday,
  b.is_today,
  b.is_current_month,
  b.is_current_quarter,
  a.chinese_province,
  a.chinese_city ,
  a.chinese_province_city ,
  a.chinese_territory

  from sales_customer as a 
  inner join dim_date as b
  on  a.create_date=b.create_date;

drop table sales_customer;  
drop table sales_customer1;  
"

聚合当日维度表(create_amount_diff.sh) 脚本:

#!/bin/sh

hive -v -e "
drop table if exists ods.dw_amount_diff;

CREATE TABLE ods.dw_amount_diff(
  category string,
  d_amount   double,
  d_order    double,
  d_avg      double
  );


with dw_order as
(select 
*,
add_months(from_unixtime(unix_timestamp(create_date, 'yyyy-MM-dd'), 'yyyy-MM-dd'), -12) as before_lastyear_date
from ods.dw_order_by_day),
select dw_order_by_day as(
select * from ods.dw_order_by_day)
insert into ods.dw_amount_diff
        select
        t.category,
        t.d_amount,
        t.d_order,
        t.d_avg
        from(
select
'day' as category,
((sum(a.sum_amount)/sum(b.sum_amount))-1) as d_amount,
((sum(a.sum_order)/sum(b.sum_order))-1) as d_order,
((sum(a.sum_amount) / sum(a.sum_order))/ (sum(b.sum_amount) /sum(b.sum_order)) -1) as d_avg
from
(select * from dw_order where is_today=1) a
left join dw_order_by_day b
on a.before_lastyear_date = b.create_date
union all
select 
'yesterday' as category,
((sum(a.sum_amount)/sum(b.sum_amount))-1) as d_amount,
((sum(a.sum_order)/sum(b.sum_order))-1) as d_order,
((sum(a.sum_amount) / sum(a.sum_order))/ (sum(b.sum_amount) /sum(b.sum_order)) -1) as d_avg
from
(select * from dw_order where is_yesterday=1) a
left join dw_order_by_day b
on a.before_lastyear_date = b.create_date
union all
select
'month' as category,
((sum(a.sum_amount)/sum(b.sum_amount))-1) as d_amount,
((sum(a.sum_order)/sum(b.sum_order))-1) as d_order,
((sum(a.sum_amount) / sum(a.sum_order))/ (sum(b.sum_amount) /sum(b.sum_order)) -1) as d_avg
from
(select * from dw_order where is_current_month=1) a
left join dw_order_by_day b
on a.before_lastyear_date = b.create_date
union all
select
'quarter' as category,
((sum(a.sum_amount)/sum(b.sum_amount))-1) as d_amount,
((sum(a.sum_order)/sum(b.sum_order))-1) as d_order,
((sum(a.sum_amount) / sum(a.sum_order))/ (sum(b.sum_amount) /sum(b.sum_order)) -1) as d_avg
from
(select * from dw_order where is_current_quarter=1) a
left join dw_order_by_day b
on a.before_lastyear_date = b.create_date
union all
select
'year' as category,
((sum(a.sum_amount)/sum(b.sum_amount))-1) as d_amount,
((sum(a.sum_order)/sum(b.sum_order))-1) as d_order,
((sum(a.sum_amount) / sum(a.sum_order))/ (sum(b.sum_amount) /sum(b.sum_order)) -1) as d_avg
from
(select * from dw_order where is_current_year=1) a
left join dw_order_by_day b
on a.before_lastyear_date = b.create_date) t;
"

聚合之后数据仓库ods层中的表数据如下:
在这里插入图片描述

3. Sqoop导出聚合表到mysql

Sqoop export 导出:将数据从Hadoop(如hive等)导入关系型数据库当中。
注意:在我们导出数据到mysql前,我们必须要确保表在mysql中已经创建好了,sqoop 底层并不会帮我们创建表。

  • 在mysql中先创建dw_order_by_day:
CREATE TABLE `hive_dw_order_by_day` (

   `create_date` date DEFAULT NULL,
   `is_current_year` int(11) DEFAULT NULL,
   `is_last_year` int(11) DEFAULT NULL,
   `is_yesterday` int(11) DEFAULT NULL,
   `is_today` int(11) DEFAULT NULL,
   `is_current_month` int(11) DEFAULT NULL,
   `is_current_quarter` int(11) DEFAULT NULL,
   `sum_amount` double DEFAULT NULL,
     `sum_order` bigint(20) DEFAULT NULL
  
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
  • 将每日环比表导出到mysql中(export_dw_order_by_day.sh)脚本:

!/bin/bash

sqoop export \
--connect jdbc:mysql://IP:3306/adventure_dw\
--username ##### \
--password ##### \
--table hive_dw_order_by_day \
--export-dir /user/hive/warehouse/ods.db/dw_order_by_day \
--input-null-string "\\\\N" \
--input-null-non-string "\\\\N"  \
--input-fields-terminated-by "\001"  \
--input-lines-terminated-by "\\n"  \
--columns  create_date,is_current_year,is_last_year,is_yesterday,is_today,is_current_month,is_current_quarter,sum_amount,sum_order \  ## 选择列并控制它们的排序
-m 1

export_dw_customer_order.sh和export_dw_amount_diff.sh与上述方式相同,这里不再赘述。

4.在linux服务器上做定时部署

利用服务器,每日6时左右自动执行代码,完成表的聚合工作,实现数据自动化更新。
linux内置的cron进程能帮我们实现定时任务, cron是一个linux下的定时执行工具,可以在无需人工干预的情况下运行作业。
(1)编写schedule.sh文件,按照执行顺序添加文件:

#!/bin/bash
sh /home/adventure/sqoop_dim_date_df.sh
sh /home/adventure/sqoop_ods_sales_orders.sh
sh /home/adventure/sqoop_ods_customer.sh

sh /home/adventure/create_dw_order_by_day.sh
sh /home/adventure/create_customer_order.sh
sh /home/adventure/create_amount_diff.sh

sh /home/adventure/export_dw_order_by_day.sh
sh /home/adventure/export_dw_customer_order.sh
sh /home/adventure/export_dw_amount_diff.sh

(2)添加定时任务,设定每天早上6点执行任务
编辑crontab文件,vi /etc/crontab

# For details see man 4 crontabs

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name  command to be executed
0 6 * * * root /home/adventure/schedule.sh

五. PowerBI部署展示

可视化报表一共有三页:主页、时间趋势图、区域分布图。

  • 主页展示内容:
    1.销售指标:销售金额、订单量、客单价以及同比去年的数据;
    2.从时间维度分析销售情况(今日、昨日、月、季度、年维度);
    3.销售排名前十的产品;
    4.各个品类订单量占比情况;
    5.各个省份销量情况;
    6.区域、城市的切片器。
    在这里插入图片描述
  • 时间趋势图展示内容:
    展示近14天的销量完成情况、销量趋势图和销售金额趋势图。
    在这里插入图片描述
  • 区域分布图展示内容:
    1.各区域的销售金额、销量、客户数情况;
    2.各城市的销售金额、销量、客户数情况;
    3.各区域销售金额占比情况;
    4.各个省份销售金额排行;
    5.时间、区域、城市、产品的切片器。
    在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值