为什么要优化?
营销活动指标体系需要用日志数据进行多维度分析,其中一个维度就是通过IP段获取到用户的所属地域进行分析,但IP段与其它字段的映射方式不同,IP段是一个范围,关联时是一对多关系,在资源集中使用时段,1万左右的数据量的耗时可达一小时以上,严重影响指标的及时性,所以要进行优化,来解决任务耗时高的问题。
优化手段
1 减少参与计算的数据量
当前IP表中记录总数为 772845 条,但中国所使用的IP段仅有 91374 条,因此在统计时计,限制 country_name = '中国',能够有效的减少任务执行时间;
2 任务层面优化
数据仓库的计算引擎是MR,下面简单介绍下MapReduce计算模型
MapReduce计算模型
MapReduce是作为计算引擎出现的,在处理超大规模的数据集上,MapReduce性能可观,通过分布式计算,将大规模数据计算任务分解,MapReduce计算模型是由Map任务和Reduce任务组成,各自承担不同的功能
优化原理
思路:通过增加Map任务的数量,提高任务计算速度
通常来讲,表的一个分区就对应物理存储(HDFS)的一个文件(上图中的block块),也就对应一个Map任务;
这次优化就是通过构建表的二级、三级分区来增加物理存储文件的数量,从而间接的增加Map任务数量,让Map并行计算少量的数据,达到优化目的
二级分区:ip_category,将start_ip(起始IP)和end_ip(结束IP)按照固定范围划分,分区值A、B、C、D、E
三级分区:ip_seg1,取start_ip(起始IP)的第一段作为分区,分区值 198、199、202 ...
优化如下所示:
优化后的表结构
CREATE TABLE IF NOT EXISTS ip_location_mapping_dispose_mf
(
dw_gmt_create DATETIME COMMENT '数据仓库创建时间',
gmt_modified DATETIME COMMENT '记录修改时间',
gmt_create DATETIME COMMENT '记录创建时间',
id BIGINT COMMENT '自增id,主键',
start_ip STRING COMMENT 'IP段起始IP地址',
end_ip STRING COMMENT 'IP段结束IP地址',
start_ip_long BIGINT COMMENT 'IP段起始IP十进制数',
end_ip_long BIGINT COMMENT 'IP段结束IP十进制数',
start_ip_seg BIGINT COMMENT 'start_ip片段',
country_name STRING COMMENT 'IP所属国家',
province_name STRING COMMENT 'IP所属省份',
city_name STRING COMMENT 'IP所属城市',
isp_name STRING COMMENT '网络服务提供商',
ext0 STRING COMMENT '扩展字段',
ext1 STRING COMMENT '扩展字段',
ext2 STRING COMMENT '扩展字段',
ext3 STRING COMMENT '扩展字段',
ext4 STRING COMMENT '扩展字段'
)
COMMENT 'IP所属地映射表-月表'
PARTITIONED BY
(
ms STRING COMMENT '日期分区, 格式:yyyymm',
ip_category STRING COMMENT 'ip分类:A B C D E',
ip_seg1 BIGINT COMMENT 'ip第1段分区'
);
构建分区的sql
WITH t_clear_ip_location_mapping AS (
SELECT gmt_modified
,gmt_create
,id
,start_ip
,end_ip
,start_ip_long
,end_ip_long
,start_ip_seg
,country_name
,province_name
,city_name
,isp_name
,ext0
,ext1
,ext2
,ext3
,ext4
,CASE WHEN start_ip_long >= 16777216 AND end_ip_long <= 2147483647 THEN 'A'
WHEN start_ip_long >= 2147483648 AND end_ip_long <= 3221225471 THEN 'B'
WHEN start_ip_long >= 3221225472 AND end_ip_long <= 3758096383 THEN 'C'
WHEN start_ip_long >= 3758096384 AND end_ip_long <= 4026531839 THEN 'D'
WHEN start_ip_long >= 4026531840 AND end_ip_long <= 4160749567 THEN 'E'
END AS ip_category
,IF(SPLIT_PART(start_ip,'.',1) <> CAST(SPLIT_PART(end_ip,'.',1) AS BIGINT),'N','Y') AS is_equal_ipseg1
FROM ip_location_mapping_mf
WHERE ms = '${before_month_str}'
AND record_status = 0
AND country_name = '中国'
)
INSERT OVERWRITE TABLE ip_location_mapping_dispose_mf PARTITION (ms = '${before_month_str}',ip_category,ip_seg1)
SELECT GETDATE() AS dw_gmt_create
,gmt_modified
,gmt_create
,id
,start_ip
,end_ip
,start_ip_long
,end_ip_long
,start_ip_seg
,country_name
,province_name
,city_name
,isp_name
,ext0
,ext1
,ext2
,ext3
,ext4
,ip_category
,CAST(SPLIT_PART(start_ip,'.',1) AS INT) AS ip_seg1
FROM t_clear_ip_location_mapping
WHERE is_equal_ipseg1 = 'N'
UNION ALL
SELECT GETDATE() AS dw_gmt_create
,gmt_modified
,gmt_create
,id
,start_ip
,end_ip
,start_ip_long
,end_ip_long
,start_ip_seg
,country_name
,province_name
,city_name
,isp_name
,ext0
,ext1
,ext2
,ext3
,ext4
,ip_category
,CAST(SPLIT_PART(end_ip,'.',1) AS INT) AS ip_seg1
FROM t_clear_ip_location_mapping
WHERE is_equal_ipseg1 = 'N'
UNION ALL
SELECT GETDATE() AS dw_gmt_create
,gmt_modified
,gmt_create
,id
,start_ip
,end_ip
,start_ip_long
,end_ip_long
,start_ip_seg
,country_name
,province_name
,city_name
,isp_name
,ext0
,ext1
,ext2
,ext3
,ext4
,ip_category
,CAST(SPLIT_PART(start_ip,'.',1) AS INT) AS ip_seg1
FROM t_clear_ip_location_mapping
WHERE is_equal_ipseg1 = 'Y'
;
优化后的关联方式
select *
from(
SELECT MAX(buss_line) AS buss_line
,app_id
,MAX(product_name) AS app_name
,cookie_id
,uid
,MAX(channel) AS channel
,MAX(os) AS os
,MAX(device_brand) AS device_brand
,SPLIT_PART(MAX(ip),',',1,1) AS ip
,MAX(ip_long) AS ip_long
,MIN(spm_time) AS first_spm_time
,MAX(spm_time) AS last_spm_time
,COUNT(CASE WHEN action = '2' THEN 1 ELSE NULL END) AS visit_cnt
,COUNT(CASE WHEN action = '1' THEN 1 ELSE NULL END) AS click_cnt
,DATEDIFF(MAX(spm_time),MIN(spm_time),'ss') AS during_time
,SUM(CASE WHEN action = '4' AND events_id LIKE '%activity_during_visit%' AND events_params["duration_time"] >= '3' THEN 1 ELSE 0 END) AS is_exsit_3s_spm
,MAX(CASE WHEN ip_long >= 16777216 AND ip_long <= 2147483647 THEN 'A' WHEN ip_long >= 2147483648 AND ip_long <= 3221225471 THEN 'B' WHEN ip_long >= 3221225472 AND ip_long <= 3758096383 THEN 'C' WHEN ip_long >= 3758096384 AND ip_long <= 4026531839 THEN 'D' WHEN ip_long >= 4026531840 AND ip_long <= 4160749567 THEN 'E' END) AS ip_category
,MAX(CAST(SPLIT_PART(ip,'.',1) AS INT)) AS ip_seg1
FROM (
SELECT buss_line
,app_id
,product_name
,cookie_id
,uid
,channel
,os
,device_brand
,ip
,spm_time
,action
,events_id
,events_params
,CAST(GETIPFROMSTRING(SPLIT_PART(ip,',',1,1)) AS INT) AS ip_long
FROM dw_d2v_spm_markactivity_detail_hi
WHERE ds = '${before_hour_date_str}'
AND hs = '${before_hour}'
)
GROUP BY app_id
,uid
,cookie_id
) s
LEFT JOIN (
SELECT *
FROM ip_location_mapping_dispose_mf
WHERE ms = SUBSTR('${before_32day_date_str}',1,6)
) s_ip
ON s.ip_category = s_ip.ip_category
AND s.ip_seg1 = s_ip.ip_seg1
WHERE s.ip_long >= s_ip.start_ip_long
AND s.ip_long <= s_ip.end_ip_long
优化效果
分别对3万、30万、50万、80万的数据量进行了测试,对比优化前,综合效率提升35 ~ 40倍,优化效果明显