在我们的用例中,我们得到的UTF-8文本数据格式如下:
Data1§Data2
Data3§Data4
现在我们希望将Data1和Data3放在一个列中,Data2和Data4放在Apache Hive的一列中 . 听起来很简单 .
但是,我们无法将§字符(即unicode U 00A7 "Section Sign"参见here)指定为字段分隔符 .
我们尝试了以下方法,没有任何结果可以达到 .
1)使用通过接近终止的正常字段
ROW FORMAT DELIMITED FIELDS TERMINATED BY '§'
返回(注意附加到每个单元格的?,在其他客户端中注明未识别标志的unicode标志)
+--------------------+--------------------+--+
| test.column1 | test.column2 |
+--------------------+--------------------+--+
| Data1? | Data2? |
| Data3? | Data4? |
+--------------------+--------------------+-
或八进制表示
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\247'
要么
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\304\247'
返回:
+--------------------+--------------------+--+
| test.column1 | test.column2 |
+--------------------+--------------------+--+
| Data1?Data2 | NULL |
| Data3?Data4 | NULL |
+--------------------+--------------------+--+
2)使用RegexSerDe
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "^([^\\]]+)\\\247([^\\]]+)$")
(将字段分隔符更改为/在某些测试源数据中并使用\ 057(八进制为/)会产生正确的结果,但更改源数据对我们来说是不可行的 . )
要么
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "^([^\\]]+)\\$([^\\]]+)$")
(在描述格式化的表语句中,这会产生:
input.regex ^([^\\]]+)\\\uFFFD\uFFFD([^\\]]+)$
其中\ uFFFD是未识别标志的unicode表示)
SELECT的结果总是一样的:
+--------------------+--------------------+--+
| test.column1 | test.column2 |
+--------------------+--------------------+--+
| NULL | NULL |
| NULL | NULL |
+--------------------+--------------------+--+
My research so far indicates the following:
1)Hive无法使用不可打印的ASCII字符,其中的八进制数高于177.在github上的其他一些代码here中,我的意外指向令我惊讶的是:
Hive可以在'\ ooo'形式中指定分隔符,其中ooo是介于000和177之间的三位八进制数 .
2)此外,我发现证据表明只有一个字节的字符可以用作BigSQL文档中的字段分隔here(但不在官方文档中),它说:
分隔符必须是单字节字符
至于我的研究§(unicode U 00A7)是一个2字节的字符(11000010:10100111)
Does this mean I can not use this delimiter or is there any other ways to use it?
小更新,如果这仍然没有解决,有人需要它:
我尝试了以下方法将数据暂存为单列表,然后将§转换为(逗号),然后用逗号分隔 . 这适用于小样本数据,但对于具有错误的200列的较大 生产环境 表失败 .
select
split(a.textcolumn, '\\,')[0] as column1
,split(a.textcolumn, '\\,')[1] as column2
from
(select translate(textcolumn, '§', ',') as textcolumn from database.stage) a;
这是错误:
SQL错误:java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException:错误评估translate(stagingstring,'§',';')java.io.IOException:org.apache.hadoop.hive .ql.metadata.HiveException:错误评估translate(stagingstring,'§',';')java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException:错误评估translate(stagingstring,'§' ,';')org.apache.hadoop.hive.ql.metadata.HiveException:错误评估translate(stagingstring,'§',';')org.apache.hadoop.hive.ql.metadata.HiveException:错误评估翻译(stagingstring,'§',';')java.lang.IllegalArgumentException:null
更新2:
上面的方法有效,但如果源数据不干净(有其他UTF-8问题),它将抛出上述错误 .
3 回答
你需要创建你的表
Fields Terminated by '-89'
'section sign'的DECIMAL代码是167 .
这个-89应该是你的分隔符 . Hive允许分隔符在-127到127之间 .
有关Cloudera的以下片段的进一步阅读 .
https://www.cloudera.com/documentation/enterprise/5-8-x/topics/impala_create_table.html
注意:CREATE TABLE子句FIELDS TERMINATED BY,ESCAPED BY和LINES TERMINATED BY对用于其参数的字符串文字具有特殊规则,因为它们都需要单个字符 . 您可以使用由单引号或双引号括起来的常规字符,八进制序列(如'\054'(表示逗号))或'-127' .. '128'范围内的整数(带引号但没有反斜杠),这被解释为单字节ASCII字符 . 从256减去负值;例如,FIELDS TERMINATED BY '-2'将字段分隔符设置为ASCII代码254,"Icelandic Thorn"字符用作某些数据格式的分隔符 .
答案是我对上述问题的更新 . 但是,如果数据不干净或包含我发现的其他有问题的字符,这将抛出错误 .
我知道这是一个很冷的案例,但是这个问题可以用MultiDelimitSerDe来解决 .
实际上,Hive默认SerDe(称为LazySimpleSerDe)仅支持单字节分隔符 . 正如alpcoder所说,这没有记录 . 你需要阅读源代码来计算它 .
MultiDelimitSerDe旨在支持多字符分隔符 . 幸运的是,它支持任何多字节字符 .