巧用 Hive 模拟分布式 grep
grep 由于内置高效的字符串搜索算法,兼容各种风格的正则,且功能众多,有着 linux 下字符串处理三剑客之一的称号,但是到了如今的大数据/分布式时代,这种单机时代的工具显得有些廉颇老矣。。。
1、需求背景
我们经常会遇到需要在 hadoop 上查找原始日志,校对 ETL 数据的情况,往往很多同学直接用的老办法:
hadoop fs -cat /M_track/$yesterday/* | grep ooxx | wc -l
这种情况下是要把分布在整个集群上的日志都拉到单机上 grep 然后 wc,这是一件极其痛苦的事情,瓶颈很显然卡在了网络 IO 上,一百多 G 的日志,一个简单的 grep 往往半小时都出不来结果。。。
好在数据在 hadoop 上,那我们为了执行分布式查询,自然可以想到写 mr 来解决,但是一个简单的统计查询,也太重量级了,整个编写打包上传流程走下来,时间成本太高,那我们自然想到了 hive, 使用 hive 直接解析,查询原始日志。
hive 中的 like 支持的是通配,和 mysql 一样,RLIKE/REGEXP 支持的是正则,这样大部分的 grep 正则、通配 + awk 能干的事情,hive 也都可以干了,而且是分分钟的事情。
2、流程与案例
2.1 首先针对整个原始日志建表
create EXTERNAL table IF NOT EXISTS ext_M_track (
line string
)
PARTITIONED BY (statDate STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ' 01'
COLLECTION ITEMS TERMINATED BY ' 02'
MAP KEYS TERMINATED BY ' 03'
LINES TERMINATED BY 'n'
STORED AS TEXTFILE
LOCATION '/M_track'
;
友情提示:建议所建的表属性是 “external 扩展表”,否则 hive 默认会移动并接管原日志。
2.2 添加分区
ALTER TABLE ext_M_track ADD PARTITION (statDate='20140903') LOCATION '/M_track/20140903';
2.3 案例分析
2.3.1 查找包含某个字符串的记录总数
select count(1) from ext_M_track where statDate='20140903' and line like '%tag=pvstatall%';
2.3.2 按小时统计全天的流量分布
-- 分
select regexp_extract(line, "(03/Sep/2014:\d{2})", 1) hour, count(1) pv from ext_M_track where statDate='20140903' and line like '%tag=pvstatall%' group by regexp_extract(line, "(03/Sep/2014:\d{2})", 1);
-- 秒
select regexp_extract(line, "(09/Mar/2015:\d{2}:\d{2}:\d{2})", 1) second, count(1) pv from ext_M_track where statDate='20150309' group by regexp_extract(line, "(09/Mar/2015:\d{2}:\d{2}:\d{2})", 1);
03/Sep/2014:22 40867
03/Sep/2014:21 38951
03/Sep/2014:13 35113
03/Sep/2014:14 34285
03/Sep/2014:15 34120
03/Sep/2014:20 33852
03/Sep/2014:12 33308
03/Sep/2014:10 32644
03/Sep/2014:11 32362
03/Sep/2014:16 32284
03/Sep/2014:09 30031
03/Sep/2014:17 29023
03/Sep/2014:23 28247
03/Sep/2014:19 28125
03/Sep/2014:18 26250
03/Sep/2014:08 24452
03/Sep/2014:07 17456
03/Sep/2014:00 16103
03/Sep/2014:01 11679
03/Sep/2014:06 11074
03/Sep/2014:02 7262
03/Sep/2014:05 5367
03/Sep/2014:03 5047
4666
03/Sep/2014:04 4221
2.3.3 按不同的 cookie 来源统计 pv、uv
set hive.cli.print.header=true;
select count(split(line, " ")[0]) totalPv, count(distinct split(line, " ")[0]) totalUv, count(split(split(line, " ")[0], "@@##")[0]) idwbPv, count(distinct split(split(line, " ")[0], "@@##")[0]) idwbUv, count(split(split(line, " ")[0], "@@##")[1]) idmPv, count(distinct split(split(line, " ")[0], "@@##")[1]) idmUv from ext_M_track where statDate='20140903' and line like '%tag=pvstatall%';
totalpv totaluv idwbpv idwbuv idmpv idmuv
5967 386 5967 378 5921 363
2.3.4 查看异常日志多少
select count(1) from ext_M_track where statDate='20140903' and line like '%tag=pvstatall%' and (split(line, " ")[0]='-' or (instr(line, 'trackURL={') > 0 and instr(line, '}&rand_id=') = 0) or size(split(line, """)) != 9);
16
select count(1) from ext_M_track where statDate='20140903' and line like '%tag=pvstatall%' and instr(line, '&smsc={') > 0;
517
2.4 如何流程化
步骤 2.2 中我们对某天的日志进行了手动处理,我们实际使用当中,很容易流程化,将下面的脚本用 crontab 定期调度即可:
#!/bin/bash
# 为库 tmpdb 表 ext_M_track 每天建立分区
yesterday=`date -d '1 days ago' +'%Y%m%d'`
hive -e "use tmpdb; ALTER TABLE ext_M_track ADD PARTITION (statDate='$yesterday') LOCATION '/M_track/$yesterday';"
3、Refer:
[1] LanguageManual UDF
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
[2] archive-analysis
https://github.com/vinaygoel/archive-analysis/tree/master/hive/cdx
[3] hive分析窗口函数
http://lxw1234.com/archives/tag/hive-window-functions
- Spring AOP中 args和arg-names的区别
- Golong 语言开发 go-websocket-sample 测试值得拥有
- Java面试系列23-spring(2)-配置数据库驱动、依赖、Mapping等
- 【Golang语言社区】 Go语言中使用 Protobuf
- Java面试系列21-xml
- tensorflow载入数据的三种方式 之 TF生成数据的方法
- JS游戏开发 可移动地图的实现
- Java面试系列-多线程
- pymongo.errors:Sort operation used more than the maximum 33554432 bytes of RAM. Add an index,
- PG学习初体验--源码安装和简单命令(r8笔记第97天)
- Pymongo: TypeError: if no direction is specified, key_or_list must be an instance of list
- Java面试系列19-Struts2
- JS游戏开发,让你的静态人物动起来(来自网路)
- Golang语言websocket源码
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Tensorflow on HDFS 的实践
- MPI on Kubernetes
- Tensorflow Serving模型指向s3地址,Could not find base path?
- Python之turtle模块初体验
- tcsetpgrp failed重新编译tini
- s3cmd ls之迷惑
- 构建pyflink镜像
- apt-get update遇到NO_PUBKEY
- 遇到mpi worker exited on signal 9
- 容器共享GPU时查看容器使用的GPU编号
- oci runtime error: exec failed: container_linux.go:247: starting container process caused “exec: “/
- R|UpSet-集合可视化
- 美国队长的盾(一) 同心圆
- R|clusterProfiler-富集分析
- R|fastqcr QC数据处理