在我们的用例中,我们得到的UTF-8文本数据格式如下:
Data1§Data2
Data3§Data4
现在我们想有Data1和Data3在一列,Data2和Data4在Apache Hive的一列。听起来很简单。
但是,我们不能指定§字符(unicode U+00A7"Section Sign"见这里)作为字段分隔符。
我们试了以下几种方法,结果都不好。
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 '304247'
返回:+--------------------+--------------------+--+
| 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([^\]]+)$")
(在一些测试源数据中更改字段分隔符,例如为/,并使用 57(八进制为/)产生正确的结果,但更改源数据对我们来说是不可行的。)
或
ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
"input.regex" = "^([^\]]+)\$([^\]]+)$")
(在一个描述格式的表语句中,这会产生:
input.regex ^([^\]]+)\uFFFDuFFFD([^\]]+)$
其中uFFFD是无法识别的符号的unicode表示)
SELECT的结果总是相同的:
+--------------------+--------------------+--+
| test.column1 | test.column2 |
+--------------------+--------------------+--+
| NULL | NULL |
| NULL | NULL |
+--------------------+--------------------+--+
我目前的研究结果如下:
1) Hive不能使用八进制数大于177的不可打印ASCII字符。让我惊讶的是,在github上的一些其他代码中,它说:
Hive可以以'ooo'的形式指定分隔符,ooo在其中在000到177之间的三位八进制数。
2)我也发现了证据,只有一个字节的字符可以用作BigSQL文档中的字段分隔符(但不是在官方文档中),它说:
分隔符必须是单字节字符
和我的研究§(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 Error: java.io.IOException: org.apache.hadoop.hive.ql.metadata.HiveException: Error evaluation 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。翻译错误(stagingstring, '§',';')java.lang.IllegalArgumentException:空
更新2:
上面的方法可以工作,但是如果源数据不干净(有其他UTF-8问题),它将抛出上述错误。
您需要使用
创建您的表 Fields Terminated by '-89'
"section符号"的十进制代码为167。
167 - 256 = -89
这个-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对其参数使用的字符串字面值有特殊的规则,因为它们都需要一个字符。您可以使用被单引号或双引号包围的常规字符,八进制序列,如' 54'(表示逗号),或'-127'范围内的整数。'128'(带引号但没有反斜杠),它被解释为单字节ASCII字符。256减去负值;例如,FIELDS以'-2'终止将字段分隔符设置为ASCII码254,即某些数据格式使用的"冰岛荆棘"字符作为分隔符。
我知道这是一个冷案例,但这个问题可以使用MultiDelimitSerDe来解决。
实际上,Hive默认的SerDe(称为LazySimpleSerDe)只支持单字节分隔符。正如alpcoder所说,这是没有记录的。你需要阅读源代码来计算它。
MultiDelimitSerDe被设计为支持多字符分隔符。幸运的是,它支持任何多字节字符。
答案在我对上面问题的更新中。但是,如果数据不干净或包含我发现的其他有问题的字符,这将抛出和错误。