2024年职业院校中职组ZZ052大数据应用与服务赛项赛题
第01套【子任务三和四】
(一)任务一:数据获取与清洗
1.子任务一:数据获取
(1) 启动Hadoop集群,使用HDFS Shell指令,在HDFS根目录下级联创建一个名为/behavior/origin_log的目录,用于存储采集到的用户行为日志;
-- 如果集群没启动则
都在master节点操作:
启动HDFS
start-dfs.sh
启动YARN
start-yarn.sh
启动历史服务
mapred --daemon start historyserver
或
mr-jobhistory-daemon.sh start historyserver
创建目录
hdfs dfs -mkdir -p /behavior/origin_log
(2) 目录创建完成,使用HDFS Shell指令,将本地/root/eduhq/data/app_log/behavior目录下的所有用户行为日志文件采集至HDFS的/behavior/origin_log目录下;
hdfs dfs -put /root/eduhq/data/app_log/behavior/* /behavior/origin_log/
(3) 采集完成,在本机打开浏览器,访问http://本机主机名:9870或http://本机IP地址:9870进入HDFS WebUI界面,查看是否成功将数据采集到HDFS上。
2.子任务二:数据清洗
(1) 使用Windows操作系统上的Excel软件,打开名为"behavior2023-01-01.csv"的文件;
鼠标双击点开即可!
(2) 对数据进行清洗,专注处理名为"behavior2023-01-01.csv"的文件中的"time"列。将时间日期格式进行分列,分别处理为日期和时间两列。
暂无此文件 暂时不做解析!
(二)任务二:数据标注
1.开 发 一 个 简 单 的 Java 类 IpToLocUdf , 继 承org.apache.hadoop.hive.ql.udf.generic.GenericUDF ,重载 initialize()、 evaluate()和 getDisplayString()方
法;该类需要实现通过 IP 从/root/eduhq/data/area.json文件中随机获取“省份”和“城市”信息,完成数据的分类标注。
package Bigdata;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class IpToLocUdf extends GenericUDF {
public StringObjectInspector ipString;
public ArrayList<String> dataList = new ArrayList<>();
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 用于初始化UDF,检查传入参数的类型和数量。
if (arguments.length != 1) {
throw new UDFArgumentLengthException("arguments only takes 1 arguments: String");
}
// 传入的参数必须是string
ObjectInspector first = arguments[0];
if (!(first instanceof StringObjectInspector)) {
throw new UDFArgumentException("first argument must be a string");
}
this.ipString = (StringObjectInspector) first;
//从指定文件中读取地区信息
String FilePath = "/root/eduhq/data/area.json";
try {
Scanner sc = new Scanner(new FileReader(FilePath));
while (sc.hasNext()) {
String lineData = sc.nextLine();
this.dataList.add(lineData);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
}
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
//获取传入的携带IP地址字符串参数
String ip = ipString.getPrimitiveJavaObject(arguments[0].get());
//使用ip里面最小的数字当做随机索引
String[] parts = ip.split("\\.");
int min = Integer.parseInt(parts[0]);
for (int i = 1; i < parts.length; i++) {
int value = Integer.parseInt(parts[i]);
if (value < min) {
min = value;
}
}
//返回随机一条的city和province
String s = dataList.get(min); //{"city":"绥化","province":"黑龙江"}
//暴力切分
String[] arr = s.replaceAll("\"", "").split(",");
String city = arr[0].split(":")[1];
String province = arr[1].split(":")[1].replace("}","");
return city + "," + province;
}
@Override
public String getDisplayString(String[] children) {
return "_FUNC_(" + children[0] + ")";
}
}
2.开 发 一 个 简 单 的 Java 类 UrlTransUdf , 继 承org.apache.hadoop.hive.ql.udf.generic.GenericUDF ,重载 initialize()、 evaluate()和 getDisplayString()方
法;该类需要实现通过URL协议转化为统一为“http”。
package Bigdata;
import org.apache.hadoop.hive.ql.exec.UDFArgumentException;
import org.apache.hadoop.hive.ql.exec.UDFArgumentLengthException;
import org.apache.hadoop.hive.ql.metadata.HiveException;
import org.apache.hadoop.hive.ql.udf.generic.GenericUDF;
import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory;
import org.apache.hadoop.hive.serde2.objectinspector.primitive.StringObjectInspector;
public class UrlTransUdf extends GenericUDF {
public StringObjectInspector URL;
@Override
public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException {
// 用于初始化UDF,检查传入参数的类型和数量。
if (arguments.length != 1) {
throw new UDFArgumentLengthException("arguments only takes 1 arguments: String");
}
// 传入的参数必须是string
ObjectInspector first = arguments[0];
if (!(first instanceof StringObjectInspector)) {
throw new UDFArgumentException("first argument must be a string");
}
this.URL = (StringObjectInspector) first;
return PrimitiveObjectInspectorFactory.javaStringObjectInspector;
}
@Override
public Object evaluate(DeferredObject[] arguments) throws HiveException {
//获取传入的URL
String inPut = URL.getPrimitiveJavaObject(arguments[0].get());
return convertHttpsToHttp(inPut);
}
public static String convertHttpsToHttp(String input) {
// 正则表达式匹配 HTTPS URL
String regex = "https://";
// 替换 HTTPS 为 HTTP
String replacement = "http://";
return input.replaceAll(regex, replacement);
}
@Override
public String getDisplayString(String[] children) {
return "_FUNC_(" + children[0] + ")";
}
}
(三)任务三:数据统计
1.子任务一:HDFS 文件上传下载
( 1 ) 将 包 “ com.hive.udf ” 导 出 为 名 为 hive-udf-behavior-1.0.0.jar 的 JAR 文 件 , 并 保 存 在 本 地 的/root/eduhq/udf_jars 目录中;
在mvaen中点击package
使用mv命令修改jar包名称
mkdir /root/eduhq/udf_jars
mv maven打包的jar名称 /root/eduhq/udf_jars/hive-udf-behavior-1.0.0.jar
(2)将打包文件 hive-udf-behavior-1.0.0.jar 上传到HDFS 的/hive/udf_jars 目录下;
hdfs dfs -mkdir -p /hive/udf_jars
hdfs dfs -put /root/eduhq/udf_jars/hive-udf-behavior-1.0.0.jar /hive/udf_jars
(3)在 Hive 客户端,创建永久函数 url_trans 和get_city_by_ip,并将它们与开发好的 class 相关联;
在hive中添加HDFS上面的jar包
add Jar hdfs:///hive/udf_jars/hive-udf-behavior-1.0.0.jar;
创建永久函数
create function get_city_by_ip AS 'Bigdata.IpToLocUdf'; -- 后面是全类名
create function url_trans AS 'Bigdata.UrlTransUdf'; -- 后面是全类名
(4)在 Hive 客户端,使用 select 语句测试 url_trans和 get_city_by_ip 函数;
-- 测试get_city_by_ip
select get_city_by_ip("192.168.45.25");
-- 测试url_trans
select url_trans("https://baidu.com");
(5)启动 Hive 的动态分区功能,并将 Hive 设置为非严格模式;
set hive.exec.dynamic.partition.mode=nostrict;
(6)使用 insert overwrite … select …子句将ods_behavior_log 表中数据插入分区表 dwd_behavior_log中,并实现根据 dt 进行动态分区。
insert overwrite table comm.dwd_behavior_log partition(dt)
SELECT
jt.client_ip,
jt.device_type,
jt.type,
jt.device,
url_trans(jt.url) as url ,
split(get_city_by_ip(jt.client_ip),",")[1] as province,
split(get_city_by_ip(jt.client_ip),",")[0] as city,
jt.ts,
dt
FROM comm.ods_behavior_log
LATERAL VIEW json_tuple(line, 'client_ip', 'device_type', 'type', 'device', 'url', 'time') jt AS client_ip, device_type, type, device, url, ts;
-- 如果出现报错找不到路径 则需要将/root/eduhq/data/area.json数据分发到slave1和slave2 分布式处理每台节点需要有一份数据
2.子任务二:数据统计
(1) 查看dwd_behavior_log表的所有现有分区;
show partitions comm.dwd_behavior_log;
(2) 查看外部表dwd_behavior_log的前3行数据,并验证URL协议是否被统一为“http”,以及通过IP是否能够获取到“省份”和“城市”信息;
select * from comm.dwd_behavior_log limit 3;
-- 验证URL协议是否被统一为“http”
select count(*) from comm.dwd_behavior_log where url like "%https%";
-- 结果为0则验证成功
-- 通过IP是否能够获取到“省份”和“城市”信息
select count(*) from comm.dwd_behavior_log where city is null or province is null;
-- 结果为0则验证成功
(3) 统计外部表dwd_behavior_log数据总行数。
select count(*) from comm.dwd_behavior_log;
-- 结果为140000
四、模块三:业务分析与可视化
(一)任务一:数据可视化
1.子任务一:数据分析
(1) 在 comm 数 据 库 下 创 建 一 个 名 为dws_behavior_log的外部表,如果表已存在,则先删除;分区字段为dt,即根据日期进行分区;另外,要求指定表的存储路径为HDFS的/behavior/dws/dws_behavior_log目录,存储文件类型为“orc”,文件的压缩类型为“snappy”;字段类型如下表所示;
-- 如果表已存在,则先删除
drop table if exists comm.dws_behavior_log;
-- 创 建 一 个 名 为dws_behavior_log的外部表
create external table comm.dws_behavior_log (
client_ip string,
device_type string,
type string,
device string,
url string,
province string,
city string
)
partitioned by (dt string)
stored as orc
location '/behavior/dws/dws_behavior_log'
tblproperties ('orc.compress'='SNAPPY');
(2) 启动Hive的动态分区功能,并将Hive设置为非严格模式;
set hive.exec.dynamic.partition.mode=nostrict;
(3) 使用insert overwrite … select …子句将dwd_behavior_log表中数据插入分区表dws_behavior_log中,并实现根据dt进行动态分区;
insert overwrite table comm.dws_behavior_log partition(dt)
select
client_ip,device_type,type,device,url,province, city, dt
from comm.dwd_behavior_log;
(4) 查看dws_behavior_log表的所有现有分区、前3行数据,并统计统计表数据总行数;
-- 查看dws_behavior_log表的所有现有分区
show partitions comm.dws_behavior_log;
-- 前3行数据
select * from comm.dws_behavior_log limit 3;
-- 统计表数据总行数
select count(*) from comm.dws_behavior_log;
--总数为140000
(5) 在comm数据库下创建一个名为dim_date的外部表,如果表已存在,则先删除;另外,要求指定表的存储路径为HDFS的/behavior/dim/dim_date目录,字段分隔符为“\t”,建表时添加TBLPROPERTIES(‘skip.header.line.count’=‘1’) 语 句 让 Hive 读 取 外 表 数据时跳过文件行首(表头);字段类型如下表所示;
-- 如果表已存在,则先删除
drop table if exists comm.dim_date;
-- 创 建 一 个 名 为dim_date的外部表
create external table comm.dim_date (
date_id string,
week_id string,
week_day string,
day string,
month string,
quarter string,
year string,
is_workday string,
holiday_id string
)
row format delimited fields terminated by '\t'
location '/behavior/dim/dim_date'
tblproperties('skip.header.line.count'='1');
(6) 在comm数据库下创建一个名为dim_area的外部表,如果表已存在,则先删除;另外,要求指定表的存储路径为HDFS的/behavior/dim/dim_area目录,字段分隔符为“\t”;字段类型如下表所示;
-- 如果表已存在,则先删除
drop table if exists comm.dim_area;
-- 创 建 一 个 名 为dim_area的外部表
create external table comm.dim_area (
city string,
province string,
are string
)
row format delimited fields terminated by '\t'
location '/behavior/dim/dim_area';
(7) 使用load data子句将本地/root/eduhq/data目录下的“dim_date_2023.txt”和“dim_area.txt”文件分别加载到外部表dim_date和dim_area中;
load data local inpath '/root/eduhq/data/dim_date_2023.txt' into table comm.dim_date;
load data local inpath '/root/eduhq/data/dim_area.txt' into table comm.dim_area;
(8) 分别查看外部表dim_date和dim_area的前3行数据;
select * from comm.dim_date limit 3;
select * from comm.dim_area limit 3;
(9) 分别统计外部表dim_date和dim_area数据总行数;
select count(*) from comm.dim_date;
-- 结果为365
select count(*) from comm.dim_area;
-- 结果为829
(10) 统计不同省份用户访问量;将统计结果导出到本地文件系统的/root/eduhq/result/ads_user_pro目录下,并指定列的分隔符为逗号(特别注意:因为省份是随机取的,所以结果会有所差异);
-- 第一步将查询结果写入临时表
create table default.ads_user_pro
row format delimited fields terminated by ','
as
select
province,
count(*) as cnt
from comm.dwd_behavior_log
group by province;
-- 第二步创建本地目标目录
mkdir -p /root/eduhq/result/ads_user_pro
-- 第三步将hdfs上面结果文件导入到本地
hdfs dfs -get /user/hive/warehouse/ads_user_pro/* /root/eduhq/result/ads_user_pro/
(11) 统计不同时间段的网页浏览量将统计结果导出到 本 地 文 件 系 统 的 /root/eduhq/result/ads_user_hour 目录下,并指定列的分隔符为逗号;
-- 第一步将查询结果写入临时表
create table default.ads_user_hour
row format delimited fields terminated by ','
as
select
hour(from_utc_timestamp(ts,"yyyy-MM-dd HH:mm:ss")) as diff_hour,
count(*) as cnt
from comm.dwd_behavior_log
group by hour(from_utc_timestamp(ts,"yyyy-MM-dd HH:mm:ss")) ;
-- 第二步创建本地目标目录
mkdir -p /root/eduhq/result/ads_user_hour
-- 第三步将hdfs上面结果文件导入到本地
hdfs dfs -get /user/hive/warehouse/ads_user_hour/* /root/eduhq/result/ads_user_hour/
(12) 不同网站访客的设备类型统计;将统计结果导出到本地文件系统的/root/eduhq/result/ads_visit_mode目录下,并指定列的分隔符为逗号;
-- 第一步将查询结果写入临时表
create table default.ads_visit_mode
row format delimited fields terminated by ','
as
select
url,
count(distinct device_type) as cnt
from comm.dwd_behavior_log
group by url ;
-- 第二步创建本地目标目录
mkdir -p /root/eduhq/result/ads_visit_mode
-- 第三步将hdfs上面结果文件导入到本地
hdfs dfs -get /user/hive/warehouse/ads_visit_mode/* /root/eduhq/result/ads_visit_mode/
(13) 不同网站的上网模式统计;将统计结果导出到本地 文 件 系 统 的 /root/eduhq/result/ads_online_type 目 录下,并指定列的分隔符为逗号;
-- 第一步将查询结果写入临时表
create table default.ads_online_type
row format delimited fields terminated by ','
as
select
url,
count(distinct type) as cnt
from comm.dwd_behavior_log
group by url ;
-- 第二步创建本地目标目录
mkdir -p /root/eduhq/result/ads_online_type
-- 第三步将hdfs上面结果文件导入到本地
hdfs dfs -get /user/hive/warehouse/ads_online_type/* /root/eduhq/result/ads_online_type/