Имеет ли NULLIF в Hive известную проблему реализации в определенных версиях?

Я использую EMR 5.19 Hive 2.3.3, и у меня возникла проблема с Nullif, не преобразующим Java String в Hadoop Text или наоборот. Источник: CloudTrail Serde От AWS, кажется, написано твердо. Похоже, что проблема связана со встроенным UDF NULLIF, как вы можете прочитать в сообщении об ошибке:

Я проверяю, является ли результат извлечения регулярного выражения пустой строкой, и если да, то я хотел бы иметь нулевое значение, поэтому мой столбец выглядит немного как NULLIF(REGEXP_EXTRACT(key,'([^/]+)(/d+)?(/.*)', 1), '') AS key_prefix Но я получаю ошибки, как NULLIF(REGEXP_EXTRACT(key,'([^/]+)(/d+)?(/.*)', 1), '') AS key_prefix ниже:

2020-02-11 11:06:34,034 INFO [IPC Server handler 26 on 43627] org.apache.hadoop.mapred.TaskAttemptListenerImpl: Diagnostics report from attempt_1574116917806_1754132_r_000008_3: Error: java.lang.RuntimeException: org.apache.hadoop.hive.ql.metadata.HiveException: Error evaluating NULLIF(regexp_extract(_col2, '(^[^/]*)/(d/)?([^/][^/]+)', 1),'')
    at org.apache.hadoop.hive.ql.exec.mr.ExecReducer.reduce(ExecReducer.java:257)
    at org.apache.hadoop.mapred.ReduceTask.runOldReducer(ReduceTask.java:445)
    at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:393)
    at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:175)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAs(Subject.java:422)
    at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1844)
    at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:169)
Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: Error evaluating NULLIF(regexp_extract(_col2, '(^[^/]*)/(d/)?([^/][^/]+)', 1),'')
    at org.apache.hadoop.hive.ql.exec.SelectOperator.process(SelectOperator.java:93)
    at org.apache.hadoop.hive.ql.exec.Operator.forward(Operator.java:897)
    at org.apache.hadoop.hive.ql.exec.CommonJoinOperator.internalForward(CommonJoinOperator.java:820)
    at org.apache.hadoop.hive.ql.exec.CommonJoinOperator.genUniqueJoinObject(CommonJoinOperator.java:834)
    at org.apache.hadoop.hive.ql.exec.CommonJoinOperator.genUniqueJoinObject(CommonJoinOperator.java:837)
    at org.apache.hadoop.hive.ql.exec.CommonJoinOperator.checkAndGenObject(CommonJoinOperator.java:938)
    at org.apache.hadoop.hive.ql.exec.JoinOperator.endGroup(JoinOperator.java:264)
    at org.apache.hadoop.hive.ql.exec.mr.ExecReducer.reduce(ExecReducer.java:196)
    ... 7 more
Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to org.apache.hadoop.io.Text
    at org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableStringObjectInspector.getPrimitiveWritableObject(WritableStringObjectInspector.java:41)
    at org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils.comparePrimitiveObjects(PrimitiveObjectInspectorUtils.java:421)
    at org.apache.hadoop.hive.ql.udf.generic.GenericUDFNullif.evaluate(GenericUDFNullif.java:93)

Всего 2 ответа


Возможно, нет прямого ответа на ваш вопрос, но надеюсь, что это поможет.

  1. regexp_extract возвращает пустую строку '' если регулярное выражение не совпадает, оно может вернуть null только если исходная строка равна null . Таким образом, использование NULLIF здесь выглядит некорректно
  2. Используйте двойную обратную косую черту для экранирования специальных символов, таких как \d в регулярном выражении Hive.
  3. / - не является специальным символом и не нуждается в экранировании / экранировании.

Я хотел бы предложить макрос, как это:

CREATE TEMPORARY MACRO normalize_null(s string) CASE WHEN s!='' THEN s END;

Он преобразует пустые строки в NULL, NULL и все остальное как есть.


Замена NULLIF макросом, который делает то, что говорит NULLIF, избегает исключения и работает так же хорошо:

CREATE TEMPORARY MACRO NULLIFY(s string) if(s = '', null, s);
SELECT
  NULLIFY(REGEXP_EXTRACT(LSRC.key, '(^[^\/]*)\/(\d\/)?([^\/][^\/]+)', 1)) AS a_schema_name,
  NULLIFY(REGEXP_EXTRACT(LSRC.key, '(^[^\/]*)\/(\d\/)?([^\/][^\/]+)', 3)) AS a_table_name,
  NULLIFY(REGEXP_EXTRACT(LSRC.key, '(^[^/]*)/(\d/)?([^/][^/]+)', 1)) AS b_schema_name,
  NULLIFY(REGEXP_EXTRACT(LSRC.key, '(^[^/]*)/(\d/)?([^/][^/]+)', 3)) AS b_table_name,
  NULLIFY(REGEXP_EXTRACT(LSRC.key, "(^[^/]*)/(d/)?([^/][^/]+)", 1)) AS c_schema_name,
  NULLIFY(REGEXP_EXTRACT(LSRC.key, "(^[^/]*)/(d/)?([^/][^/]+)", 3)) AS c_table_name,
  NULLIFY(LSRC.key) AS key
FROM (SELECT 'db/1/table/part/file' key) LSRC;

В результате:

db      table   db      table   NULL    NULL    db/1/table/part/file

Пока с несоответствующей строкой:

NULL    NULL    NULL    NULL    NULL    NULL    non-matching

Вместо неудобного результата с пустыми строками

                                                db/1/table/part/file

Есть идеи?

10000