hive2mysql的udf_通过Hive及其Udf函数进行Nginx日志分析

需求

nginx日志格式:

'$remote_addr - $remote_user [$time_local] "$request" '

'$status $body_bytes_sent "$http_referer" '

'"$http_user_agent" "$http_x_forwarded_for"';

(暂且不将$remote_addr与$remote_user之间的-看做一个字段,所以一共有9个字段)

举个栗子:

180.173.250.74 - - [08/Jan/2015:12:38:08 +0800] "GET /avatar/xxx.png HTTP/1.1" 200 968 "https://www.iteblog.com/archives/994" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36" "180.173.250.01"

(不同字段之间以空格分隔)

具体需求

将nginx的日志按照nginx.conf中定义的字段解析至hive中,偏向于用udf实现。

环境

Hadoop2.6.3三节点(2个slave)

Hive-1.2.1

MySQL-5.1.73

实现

方案一(非Udf)

思路

反思

上述方法是通过hive自带的RegexSerDe(需要在hive中加入hive-contrib-.jar*,类似下文添加Udf jar包的方式),通常情况下我们会通过

ROW FORMAT DELIMITED FIELDS TERMINATED BY '某个分隔符'

默认情况下,Hive的分隔符是'\u0001',同时似乎在默认情况下,如果指定多个分隔符,比如'###',hive在实际使用中并不支持。

详情请见:

hive分隔符支持多个字符吗?

而这种方案使用的RegexSerDe,我的理解就是一个高逼格的,不是原先单一的,同时较原先复杂的,在某种意义上也可以理解为多分隔符的正则实现

方案二(Udf)

思路

建三张表:

nginx_origin:只有一个String类型的content字段,用它去关联Hdfs上的nginx原始日志,字段值即为那举个栗子中的内容

建表语句

CREATE EXTERNAL TABLE nginx_origin(content string) location 'Hdfs上的nginx日志所在目录的路径';

nginx_temp:

表结构和nginx_origin一样,但是字段里的值为经过Udf函数处理过后,结构化后的值。

建表语句:

create table nginx_temp STORED AS TEXTFILE as select structed(*) from nginx_origin;

Udf函数:

public class StructedNginxLog extends UDF {

//通过正则将nginx日志转换为String类型数组

public String[] structedNginxLog(String logEntryLine){

Pattern pattern = Pattern.compile(

"(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s\\W\\s(.*)\\s(\\[[^\\[\\]]+\\])\\s(\".*\")\\s(\\d{3})\\s(\\d+)\\s(\".*\")\\s(\".*\")\\s(\".*\")");

Matcher matcher = pattern.matcher(logEntryLine);

if(matcher.groupCount()==9){

String[] logArray = new String[9];

while (matcher.find()) {

for (int i = 1; i <= logArray.length; i++) {

logArray[i-1] = matcher.group(i);

}

}

return logArray;

}else{

return null;

}

}

//将结构化在数组中的各字段值重新拼接成temp表里的字段值

public String evaluate(String logEntryLine){

String[] logArray = structedNginxLog(logEntryLine);

if(logArray==null){

return null;

}

else{

StringBuilder constructLogBuilder = new StringBuilder();

for(int i = 0 ;i

if(i

constructLogBuilder.append(logArray[i]+"\u0002");//需要注意分隔符

}

else{

constructLogBuilder.append(logArray[i]);

}

}

return constructLogBuilder.toString();

}

}

}

Hive添加jar包:

①临时生效:add jar {udf jar包路径}

②永久生效:

修改hive-env.sh,修改最后一行的#export HIVE_AUX_JARS_PATH=为exportHIVE_AUX_JARS_PATH=udf的jar文件目录路径来实现

创建临时函数

create temporary function structed as {继承自UDF的类名};

nginx_push

主要是在建该表时,指定好Udf结构化的那个分隔符,然后指向nginx_temp的hdfs目录即可

建表语句

create external table nginx_push

(remote_addr STRING,remote_user STRING,

time_local STRING, request STRING,

status STRING, body_bytes_sent STRING,

http_referer STRING, http_user_agent STRING,

http_x_forwarded_for STRING)

ROW FORMAT DELIMITED FIELDS TERMINATED BY '\u0002' STORED AS TEXTFILE

location 'nginx temp表的hdfs目录路径';

反思

起初是将字段之间的分隔符,通过'\u0001'定义,但是后来发现,Hive默认的分隔符就是这个,所以如果指定这个的话,temp表中的那个唯一的字段的值就仅仅是原来一长串中的开头——IP地址,后来通过将分隔符修改为\u0002来解决,也想过用'|',但是尽量越不常见越好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值