在我们的用例中,我们得到的utf-8文本数据的格式如下:
Data1§Data2
Data3§Data4
现在我们希望在ApacheHive中将data1和data3放在一列中,将data2和data4放在一列中。听起来很简单。
但是,我们无法指定§ 字符(unicode u+00a7“段号”见此处)作为字段分隔符。
我们试过以下几种方法,但都没有达到可以接受的效果。
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" = "^([^\\]]+)\\$([^\\]]+)$")
(在DESCRIPE格式的table语句中,这将产生:
input.regex ^([^\\]]+)\\\uFFFD\uFFFD([^\\]]+)$
其中\ufffd是不可识别符号的unicode表示形式)
选择的结果总是相同的:
+--------------------+--------------------+--+
| test.column1 | test.column2 |
+--------------------+--------------------+--+
| NULL | NULL |
| NULL | NULL |
+--------------------+--------------------+--+
我目前的研究表明:
1) 配置单元不能使用八进制数高于177的不可打印ascii字符。在github上的一些其他代码中,指向这一点的指针让我感到惊讶,它说:
配置单元可以指定格式为“\ooo”的分隔符字符,其中ooo是介于000和177之间的三位八进制数。
2) 我还发现,在bigsql的文档(但在官方文档中没有)中,只有一个字节的字符可以用作字段delim,其中说明:
分隔符必须是单字节字符
至于我的研究§ (unicode u+00a7)是一个2字节字符(11000010:10100111)
这是不是意味着我不能使用这个分隔符,或者有其他方法可以使用它?
小更新,如果此问题未解决且有人需要它:
我尝试了以下方法:将数据暂存为一列表,然后进行转换§ 到,(逗号),然后用逗号分开。这适用于小样本数据,但对于包含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时出错(staginstring,'§', ';') java.io.ioexception:org.apache.hadoop.hive.ql.metadata.hiveexception:计算translate时出错(staginstring,'§', ';') java.io.ioexception:org.apache.hadoop.hive.ql.metadata.hiveexception:计算translate时出错(staginstring,'§', ';') org.apache.hadoop.hive.ql.metadata.hiveexception:计算translate时出错(staginString,'§', ';') org.apache.hadoop.hive.ql.metadata.hiveexception:error evaluating 翻译(staginstring,'§', ';') java.lang.illegalargumentexception:空
更新2:
上面的方法是可行的,但是如果源数据不干净(有其他utf-8问题),它将抛出上面的错误。
3条答案
按热度按时间hlswsv351#
答案在我对上述问题的更新中。但是,如果数据不干净或包含我发现的其他有问题的字符,这将引发错误。
blpfk2vs2#
您需要使用创建表
Fields Terminated by '-89'
“剖面符号”的十进制代码是167。这个-89应该是您的分隔符。配置单元允许范围为-127到127的分隔符。
进一步阅读cloudera的以下片段。
https://www.cloudera.com/documentation/enterprise/5-8-x/topics/impala_create_table.html
注意:CREATETABLE子句字段终止于、转义于和行终止于具有用于其参数的字符串文字的特殊规则,因为它们都需要单个字符。可以使用由单引号或双引号包围的常规字符、八进制序列(如“\054”(表示逗号)或范围为“-127”…“128”(带引号但不带反斜杠)的整数,这些字符被解释为单字节ascii字符。从256中减去负值;例如,以“-2”结尾的字段将字段分隔符设置为ascii代码254,“冰岛刺”字符用作某些数据格式的分隔符。
brgchamk3#
我知道这是一个冷的情况,但这个问题可能会解决使用多个服务器。
实际上,配置单元默认serde(称为lazysimpleserde)只支持单字节分隔符。正如alpcoder所说,这是没有记录的。你需要阅读源代码来理解它。
MultiDelimiterSerde旨在支持多字符分隔符。幸运的是,它支持任何多字节字符。