【问题标题】:hive regexp_extract weirdnesshive regexp_extract 怪异
【发布时间】:2011-12-13 22:26:05
【问题描述】:

我在使用 regexp_extract 时遇到了一些问题:

我正在查询一个制表符分隔的文件,我正在检查的列的字符串如下所示:

abc.def.ghi

现在,如果我这样做:

select distinct regexp_extract(name, '[^.]+', 0) from dummy;

MR 作业运行,它工作,我从索引 0 得到“abc”。

但是现在,如果我想从索引 1 中获取“def”:

select distinct regexp_extract(name, '[^.]+', 1) from dummy;

Hive 失败:

2011-12-13 23:17:08,132 Stage-1 map = 0%,  reduce = 0%
2011-12-13 23:17:28,265 Stage-1 map = 100%,  reduce = 100%
Ended Job = job_201112071152_0071 with errors
FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.MapRedTask

日志文件说:

java.lang.RuntimeException: org.apache.hadoop.hive.ql.metadata.HiveException: Hive Runtime Error while processing row

我在这里做错了什么吗?

谢谢, 马里奥

【问题讨论】:

    标签: regex hive


    【解决方案1】:

    从文档https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF 看来,regexp_extract() 是您希望提取的数据的记录/行提取。

    它似乎适用于第一次发现(然后退出)而不是全局。因此索引引用了捕获组。

    0 = 整场比赛
    1 = 捕获组 1
    2 = 捕获组 2 等...

    引自手册:

    regexp_extract('foothebar', 'foo(.*?)(bar)', 2)
                                      ^    ^   
                   groups             1    2
    
    This returns 'bar'.
    

    因此,在您的情况下,要获取点之后的文本,可能会起作用:
    regexp_extract(name, '\.([^.]+)', 1)
    或者这个
    regexp_extract(name, '[.]([^.]+)', 1)

    编辑

    我对此重新感兴趣,仅供参考,可能有适合您的捷径/解决方法。

    看起来您想要一个用点. 字符分隔的特定段,这几乎就像拆分。
    如果多次量化,则使用的正则表达式引擎很可能会覆盖一个组。
    您可以通过以下方式利用这一点:

    返回第一段:abc.def.ghi
    regexp_extract(name, '^(?:([^.]+)\.?){1}', 1)

    返回第二段:abc.def.ghi
    regexp_extract(name, '^(?:([^.]+)\.?){2}', 1)

    返回第三段:abc.def.ghi
    regexp_extract(name, '^(?:([^.]+)\.?){3}', 1)

    索引没有变化(因为索引仍然指向捕获组 1),只有正则表达式重复发生变化。

    一些注意事项:

    • 这个正则表达式 ^(?:([^.]+)\.?){n} 有问题。
      它要求段中的点之间有一些东西,否则正则表达式将不匹配...

    • 可能是 ^(?:([^.]*)\.?){n},但即使点数少于 n-1,它也会匹配,
      包括空字符串。这可能是不可取的。

    有一种方法可以做到这一点,它不需要点之间的文本,但仍需要至少 n-1 个点。
    这使用前瞻断言和捕获缓冲区 2 作为标志。

    ^(?:(?!\2)([^.]*)(?:\.|$())){2},其他都一样。

    因此,如果它使用 java 风格的正则表达式,那么这应该可以工作。
    regexp_extract(name, '^(?:(?!\2)([^.]*)(?:\.|$())){2}', 1) 将 {2} 更改为所需的任何“段”(这会用于段 2)。

    在第 {N} 次迭代后它仍然返回捕获缓冲区 1。

    这里被分解了

    ^                # Begining of string
     (?:             # Grouping
        (?!\2)            # Assertion: Capture buffer 2 is UNDEFINED
        ( [^.]*)          # Capture buffer 1, optional non-dot chars, many times
        (?:               # Grouping
            \.                # Dot character
          |                 # or,
            $ ()              # End of string, set capture buffer 2 DEFINED (prevents recursion when end of string)
        )                 # End grouping
     ){3}            # End grouping, repeat group exactly 3 (or N) times (overwrites capture buffer 1 each time)
    

    如果它不做断言,那么这将不起作用!

    【讨论】:

      【解决方案2】:

      我认为您必须不设置“组”?

      select distinct regexp_extract(name, '([^.]+)', 1) from dummy;
      

      (未经测试)

      我认为它的行为类似于 java 库,这应该可以工作,但请告诉我。

      【讨论】:

      • 哈哈,很奇怪,MR 作业就是这样运行的,但它仍然返回索引 0 的内容!
      • 我刚刚尝试使用索引 2 踢球,然后它失败了 2011-12-13 23:33:41,377 Stage-1 map = 0%, reduce = 0% 2011-12-13 23:34:01,465 Stage-1 map = 100%, reduce = 100% Ended Job = job_201112071152_0074 with errors FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.MapRedTask 再次......怪怪怪怪的……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-26
      • 1970-01-01
      • 2021-12-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多