hive中使用正则表达式不当导致运行奇慢无比

业务保障部有一个需求,需要用hive实时计算上一小时的数据,比如现在是12点,我需要计算11点的数据,而且必须在1小时之后运行出来,但是他们用hive实现的时候发现就单个map任务运行都超过了1小时,根本没法满足需求,后来打电话让我帮忙优化一下,以下是优化过程:

1、hql语句:

CREATE TABLE weibo_mobile_nginx AS SELECT
	split(split(log, '`') [ 0 ], '\\|')[ 0 ] HOST,
	split(split(log, '`') [ 0 ], '\\|')[ 1 ] time,
	substr(
		split(
			split(split(log, '`') [ 2 ], '\\?')[ 0 ], ' '
		)[ 0 ], 2
	)request_type,
	split(
		split(split(log, '`') [ 2 ], '\\?')[ 0 ], ' '
	)[ 1 ] interface,
	regexp_extract(
		log,
		’.*& ua =[^ _ ]* __([^ _ ]*)__([^ _ ]*)__([^ _ ]*)__<span style="font-family: Arial, Helvetica, sans-serif;">[^&]*</span>’,
		3
	)version,
	regexp_extract(
		log,
		’.*& ua =[^ _ ]* __([^ _ ]*)__([^ _ ]*)__([^ _ ]*)__.* ',1) systerm,regexp_extract(log,’.*&networktype=([^&%]*).*',
		1
	)net_type,
	split(log, '`')[ 4 ] STATUS,
	split(log, '`')[ 5 ] client_ip,
	split(log, '`')[ 6 ] uid,
	split(log, '`')[ 8 ] request_time,
	split(log, '`')[ 12 ] request_uid,
	split(log, '`')[ 13 ] http_host,
	split(log, '`')[ 15 ] upstream_response_time,
	split(log, '`')[ 16 ] idc
FROM
	ods_wls_wap_base_orig
WHERE
	dt = '20150311'
AND HOUR = '08'
AND(
	split(log, '`')[ 13 ]= 'api.weibo.cn'
	OR split(log, '`')[ 13 ]= 'mapi.weibo.cn’);

其实这个hql很简单,从一个只有一列数据的表ods_wls_wap_base_orig中获取数据,然后对每一行数据进行split或者正则表达式匹配得到需要的字段信息,最后通过输出的数据创建weibo_mobile_nginx表。

其中表ods_wls_wap_base_orig的一行数据格式如下:

web043.mweibo.yhg.sinanode.com|[11/Mar/2015:00:00:01 +0800]`-`"GET /2/remind/unread_count?v_f=2&c=android&wm=9847_0002&remind_version=0&with_settings=1&unread_message=1&from=1051195010&lang=zh_CN&skin=default&with_page_group=1&i=4acbdd0&s=6b2cd11c&gsid=4uQ15a2b3&ext_all=0&idc=&ua=OPPO-R8007__weibo__5.1.1__android__android4.3&oldwm=9893_0028
HTTP/1.1"`"R8007_4.3_weibo_5.1.1_android"`200`[121.60.78.23]`3226234350`"-"`0.063`351`-`121.60.78.23`1002792675011956002`api.weibo.cn`-`0.063`yhg
20150311    00

只有1列,列名是log。

2、既然hql实现很慢,我第一次优化的尝试就是写mapreduce

map代码如下:

public class Map extends Mapper<LongWritable, Text, Text, Text> {

  private Text outputKey = new Text();
  private Text outputValue = new Text();

  Pattern p_per_client = Pattern
      .compile(".*&ua=[^_]*__([^_]*)__([^_]*)__([^_]*)__[^&]*");
  Pattern net_type_parent = Pattern.compile(".*&networktype=([^&%]*).*");

  public void map(LongWritable key, Text value, Context context)
      throws IOException, InterruptedException {

    String[] arr = value.toString().split("`");
    if (arr[13].equals("api.weibo.cn") || arr[13].equals("mapi.weibo.cn")) {
      Matcher matcher = p_per_client.matcher(value.toString());
      String host = "";
      String time = "";
      String request_type = "";
      String interface_url = "";
      String version = "";
      String systerm = "";
      String net_type = "";
      String status = "";
      String client_ip = "";
      String uid = "";
      String request_time = "0";
      String request_uid = "";
      String http_host = "";
      String upstream_response_time = "0";
      String idc = "";

      host = arr[0].split("\\|")[0];
      time = arr[0].split("\\|")[1];
      request_type = arr[2].split("\\?")[0].split(" ")[0].substring(1);
      interface_url = arr[2].split("\\?")[0].split(" ")[1];

      if (matcher.find()) {
        version = matcher.group(1);
        systerm = matcher.group(2);
      }

      Matcher matcher_net = net_type_parent.matcher(value.toString());
      if (matcher_net.find()) {
        net_type = matcher_net.group(1);
      }

      status = arr[4];
      client_ip = arr[5];
      uid = arr[6];
      if (!arr[8].equals("-")) {
        request_time = arr[8];
      }
      request_uid = arr[12];
      http_host = arr[13];
      if (!arr[15].equals("-")) {
        upstream_response_time = arr[15];
      }
      idc = arr[16];

      outputKey.set(host + "\t" + time + "\t" + request_type + "\t"
          + interface_url + "\t" + version + "\t" + systerm + "\t" + net_type
          + "\t" + status + "\t" + client_ip + "\t" + uid + "\t" + request_uid
          + "\t" + http_host + "\t" + idc);
      outputValue.set(request_time + "\t" + upstream_response_time);

      context.write(outputKey, outputValue);
    }

  }

java代码其实也很简单,这里不多说。打包提交job,结果map最慢的运行了40分钟,平均map运行时间达到30分钟,虽然整个job在1小时内完成了,但是也很慢,这个问题看来不是用java改写就能好的问题。

3、最后检测正则表达式

改用java实现的mapreduce运行也很慢,看来问题还是其他原因,我看了一下hql中的正则表达式,修改了几个地方:

原来的:

regexp_extract(
                log,
                ’.*& ua =[^ _ ]* __([^ _ ]*)__([^ _ ]*)__([^ _ ]*)__[^&]*’,
                3
        )version,
        regexp_extract(
                log,
                ’.*& ua =[^ _ ]* __([^ _ ]*)__([^ _ ]*)__([^ _ ]*)__.* ',1)
        systerm,
regexp_extract(log,’.*&networktype=([^&%]*).*',
                1
        )net_type,

修改后:

	regexp_extract(
		log,
		'&ua=[^_]*__[^_]*__([^_]*)__[^_]*__',
		1
	)version,
	regexp_extract(
		log,
		'&ua=[^_]*__[^_]*__[^_]*__([^_]*)__',
		1
	)systerm,
	regexp_extract(
		log,
		'&networktype=([^&%]*)',
		1
	)net_type,

其实匹配目标很明确,所以我把正则表达式前后的".*"去掉了,同时去掉了没必要的group,索引都改成了1。

java代码的正则表达式也进行了修改:

Pattern p_per_client = Pattern
      .compile("&ua=[^_]*__[^_]*__([^_]*)__([^_]*)__");
  Pattern net_type_parent = Pattern.compile("&networktype=([^&%]*).");

分别提交测试了一下,速度ss的,修改后的hql和mapreduce整个作业6分钟运行完成,平均map运行时间2分钟,速度提升很大,满足了他们的速度要求。

总结:

1、正则表达式最前面包含“.*”,这样在匹配的时候需要从第一个字符开始匹配,速度非常非常慢,如果我们匹配的目标很明确的情况下,应该去掉“.*”

2、以后遇到这种问题的时候,一定要看看正则表达式是不是写得有问题,切记切记。

时间: 2024-11-10 17:05:37

hive中使用正则表达式不当导致运行奇慢无比的相关文章

python numpy中astype使用不当导致图像出现artifact

在网络训练中,发现生成的图像不对劲,如下面左图所示,文字完全不对.后来发现,是因为在python中把float类型的变量直接转成uint8的时候,负数部分就变成了极大的整数,变成了图中的白点.应该是采用截断的方法,把小于0大于255的都截断,然后再转换成uint8.得到的结果如右图所示. 一段验证性的代码,如果把a转成uint8,我们会发现-5就变成了(256-5)=251,而300就变成了(300-256)=44.所谓白色的地方出现了黑点,而黑字上也有了白点. import numpy as

Hive中跑MapReduce Job出现OOM问题分析及解决

一.引子 今天在跑一段很复杂而且涉及数据量10多年的N个表join的长SQL时,发生了OOM的异常. 由于一个map通常配置只有64MB或者128MB,则在Map阶段出现OOM的情况很少见.所以一般发生在reduce阶段. 但是今天这个异常详细的看后,会发现既不是map阶段,也不是reduce阶段,发现不是执行过程,而是driver提交job阶段就OOM了.Hive中XMLEncoder序列化MapredWork引发OutOfMemoryError XMLEncoder导致java.lang.O

C#中利用正则表达式实现字符串搜索

摘要:本文给出了在C#下利用正则表达式实现字符串搜索功能的方法,通过对.NET框架下的正则表达式的研究及实例分析,总结了正则表达式的元字符.规则.选项等.1.正则表达式简介正则表达式提供了功能强大.灵活而又高效的方法来处理文本.正则表达式的全面模式匹配表示法可以快速地分析大量的文本以找到特定的字符模式;提? ⒈嗉⑻婊换蛏境谋咀幼址?或将提取的字符串添加到集合以生成报告.对于处理字符串(例?HTML 处理.日志文件分析和 HTTP 标头分析)的许多应用程序而言,正则表达式是不可缺少的工具..

Coursera-Getting and Cleaning Data-week4-R语言中的正则表达式以及文本处理

Coursera-Getting and Cleaning Data-Week4 Thursday, January 29, 2015 补上第四周笔记,以及本次课程总结. 第四周课程主要针对text进行处理.里面包括 1.变量名的处理 2.正则表达式 3.日期处理(参见swirl lubridate包练习) 首先,变量名的处理,奉行两个原则,1)统一大小写tolower/toupper:2)去掉在导入数据时,因为特殊字符导致的合并变量 3)不要重复:4)少用代码缩写 使用的函数包括 替换查找:

使用Sqoop,最终导入到hive中的数据和原数据库中数据不一致解决办法

Sqoop是一款开源的工具,主要用于在Hadoop(Hive)与传统的数据库(mysql.postgresql...)间进行数据的传递,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中. 1.问题背景 使用Sqoop把oracle数据库中的一张表,这里假定为student,当中的数据导入到hdfs中,然后再创建hive的external表,location到刚才保存到hdfs中数

Python学习-38.Python中的正则表达式(二)

在Python中,正则表达式还有较其他编程语言有特色的地方.那就是支持松散正则表达式了. 在某些情况,正则表达式会写得十分的长,这时候,维护就成问题了.而松散正则表达式就是解决这一问题的办法. 用上一次分组的代码作为例子: 1 import re 2 userinput = input("please input test string:") 3 m = re.match(r'(\d{3,4})-(\d{8})',userinput) 4 if m: 5 print('区号:' + m

sqoop 从oracle导数据到hive中,date型数据时分秒截断问题

oracle数据库中Date类型倒入到hive中出现时分秒截断问题解决方案 1.问题描述: 用sqoop将oracle数据表倒入到hive中,oracle中Date型数据会出现时分秒截断问题,只保留了‘yyyy-MM-dd',而不是’yyyy-MM-dd HH24:mi:ss'格式的,后面的‘HH24:mi:ss’被自动截断了,在对时间要求到秒级的分析处理中这种截断会产生问题. 2.解决方案: 在用sqoop倒入数据表是,添加--map-column-hive 和--map-column-jav

(转)关于android中bitmap过大导致的程序crash问题

第一种方法--及时回收bitmap内存: 一般而言,回收bitmap内存可以用到以下代码 if(bitmap != null && !bitmap.isRecycled()){ bitmap.recycle(); bitmap = null; } System.gc(); bitmap.recycle()方法用于回收该bitmap所占用的内存,接着将bitmap置空,最后,别忘了用System.gc()调用一下系统的垃圾回收器. 在这里要声明一下,bitmap可以有多个(以为着可以有多个i

Hive中的分桶

对于每一个表(table)或者分区, Hive可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分.Hive也是针对某一列进行桶的组织.Hive采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中. 把表(或者分区)组织成桶(Bucket)有两个理由: (1)获得更高的查询处理效率.桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构.具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接 (Map-side join)高效的实现.比