【问题标题】:Hive table data load with default SerDE使用默认 SerDE 加载 Hive 表数据
【发布时间】:2015-03-18 22:29:05
【问题描述】:

数据格式如下

a,"b,c",d, e

p,q,"e,r", t

a,s,"t,g", t

我想创建一个 Hive 表

Col1、Col2、Col3、Col4

a、b、c、d、e

p、q、e、r、t

a , s , t,g , t

如你所见,如果数据是用双引号封装的,那么在创建表数据时,不应该考虑中间的逗号。如果我使用默认的 SerDe,则忽略双引号并将 b,c 视为两个单独的列。

如果封装在双引号中,如何确保双引号将忽略两个元素之间的逗号

【问题讨论】:

    标签: hadoop hive


    【解决方案1】:

    如果可行且可行,我首先建议您探索一下是否可以通过使用逗号以外的其他内容作为字段分隔符的方式对输入数据进行清理。使用数据中可能自然出现的分隔模式总是很冒险。

    但如果这不可能,那么有这种基于正则表达式的方法来检测引号引起的:

    1. 首先将您的数据以单列行的形式提取到临时表中(整行到每一行中)。
    2. 检测引号之间出现的逗号并将其替换为人工占位符。
    3. 使用逗号作为分隔符拆分结果字符串。
    4. 将人工占位符替换为它们最初表示的逗号。

    作为一个人为的具体示例,我使用您的数据加载了以下单列临时表(步骤 #1):

    hive> DESCRIBE staging;
    OK
    rawline                     string
    Time taken: 0.238 seconds, Fetched: 1 row(s)
    hive> SELECT * FROM staging;
    OK
    a,"b,c",d, e
    p,q,"e,r", t
    a,s,"t,g", t
    Time taken: 0.277 seconds, Fetched: 3 row(s)
    

    接下来的查询会生成最终的目标表。

    DROP TABLE IF EXISTS test;
    CREATE TABLE test (
        Col1 STRING,
        Col2 STRING,
        Col3 STRING,
        Col4 STRING
      );
    INSERT INTO TABLE test SELECT
      regexp_replace(fields[0], "\\[QUOTEDCOMMA\\]", ","),  -- Step #4
      regexp_replace(fields[1], "\\[QUOTEDCOMMA\\]", ","),  -- Step #4
      regexp_replace(fields[2], "\\[QUOTEDCOMMA\\]", ","),  -- Step #4
      regexp_replace(fields[3], "\\[QUOTEDCOMMA\\]", ",")   -- Step #4
    FROM (
      SELECT split(  -- Step #2 and #3
        regexp_replace(rawline, "\"([^,]*),([^,]*)\"", "$1[QUOTEDCOMMA]$2"),
        ',') AS fields
      FROM staging
    ) t;
    

    这将生成以下最终表格test

    hive> SELECT * FROM test;
    OK
    a   b,c     d        e
    p   q       e,r      t
    a   s       t,g      t
    Time taken: 0.196 seconds, Fetched: 3 row(s)
    

    在此示例实现中,字符串[QUOTEDCOMMA] 被用作引号之间的逗号的人工占位符。选择是完全任意的,实际上,如果您走这条路,您需要确保您的占位符不会自然地出现在您的数据中。

    【讨论】:

    • (可选)您可以对来自外部的数据执行类似的清理,如果来自平面文件,则使用 sed 或其他东西,或者,如果您通过 sqoop 传输数据,则从另一个指定导入字段分隔符数据库,如果它们位于另一个可以解决双引号与逗号问题的数据库中。如果我没记错的话,Hive 使用了相当少见的字段分隔符 \001 或 ^A,这在此应用程序中应该是安全的。
    • @suiterdev 同意,​​这是一个很好的观点。当我提到清理输入数据时,我是故意笼统的,因为我不了解 OP 的环境,但你提出的观点都是潜在的解决方案。
    • @rchang - 如果用逗号分隔的单词数不是 2 并且是可变的,我该如何处理?即 a,"b,c,v,n", t,y 和 p,q, "e,r,y", u
    • @Vaya 那时最直接的选项可能包括升级到 0.14 以支持 CSV、自定义 UDF 或实现您自己的 SerDe。根据可能有多少不同的方向,如果你想沿着这条路线走,最好将它作为一个新问题(不同于这个问题)提出。其他人可能比我更了解它,如果这是一个新问题,更容易获得其他人的关注。
    【解决方案2】:

    Hive (LazySimple) 中的默认文本 serde 不支持正确的 CSV 语义。好消息是,在最新版本的 hive 中 - 0.14.0 - 有一个新的 serde 可以解决这个问题。如果您碰巧使用此版本,则可以使用 CSV serde 并指定双引号作为引号字符 - 从而正确解析数据,正如您在问题中指定的那样。

    有关 serde 及其使用方法的信息: https://cwiki.apache.org/confluence/display/Hive/CSV+Serde

    【讨论】:

    • 谢谢,这也是一个答案,但不幸的是我无法升级到 Hive 0.14。
    猜你喜欢
    • 2019-09-01
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-05
    • 1970-01-01
    • 2020-10-01
    • 1970-01-01
    相关资源
    最近更新 更多