• 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非常easy,从一个仅仅有一列数据的表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 + "	" + time + "	" + request_type + "	"
              + interface_url + "	" + version + "	" + systerm + "	" + net_type
              + "	" + status + "	" + client_ip + "	" + uid + "	" + request_uid
              + "	" + http_host + "	" + idc);
          outputValue.set(request_time + "	" + upstream_response_time);
    
          context.write(outputKey, outputValue);
        }
    
      }

    java代码事实上也非常easy,这里不多说。打包提交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、以后遇到这样的问题的时候。一定要看看正則表達式是不是写得有问题,切记切记。



           




  • 相关阅读:
    Python数据分析的几种绘图方式——数据可视化(附源码)
    Python GUI项目实战:主窗体的界面设计与实现
    Python Scrapy框架:数据爬取全流程
    python来爬取煎蛋网随手拍小姐姐图片
    有意思的逻辑小练习:函数做参数进行传递
    python值*args和**kwargs的总结思考
    数据类型的基础知识补充,字典的并交集、空集合、可作为字典元组的元素、删除字典中的元素
    python里面为什么shell和保存文件运行结果不一样的相关思考(内存相关)
    代码:购物车(待修改)
    python里面为什么shell和保存文件运行结果不一样?
  • 原文地址:https://www.cnblogs.com/yutingliuyl/p/7159300.html
Copyright © 2020-2023  润新知