Hive regexp_extract weirdness

У меня возникают некоторые проблемы с regexp_extract:

Я запрашиваю файл с разделителями табуляции, столбец, который я проверяю, имеет строки, которые выглядят следующим образом:

abc.def.ghi

Теперь, если я это сделаю:

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

Выполняется MR-задание, оно работает, и я получаю "abc" из индекса 0.

Но теперь, если я хочу получить "def" из индекса 1:

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

Сбой с помощью:

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

Я делаю что-то принципиально неправильное здесь?

Спасибо, Марио

Ответ 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).

и он все еще возвращает буфер захвата 1 после {N} '-й итерации.

Здесь это сломано

^                # 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-библиотека, и это должно работать, сообщите мне об этом.