在我们的用例中,我们将获取格式如下的 UTF-8 文本数据:
Data1§Data2
Data3§Data4
现在我们希望在 Apache Hive 中将 Data1 和 Data3 放在一列中,将 Data2 和 Data4 放在一列中。听起来很简单。
但是,我们无法将 § 字符(即 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" = "^([^\\]]+)\\$([^\\]]+)$")
(在 describe 格式化表语句中,这会产生:
input.regex ^([^\\]]+)\\\uFFFD\uFFFD([^\\]]+)$
其中\uFFFD 是未识别符号的 unicode 表示)
SELECT 的结果总是相同的:
+--------------------+--------------------+--+
| test.column1 | test.column2 |
+--------------------+--------------------+--+
| NULL | NULL |
| NULL | NULL |
+--------------------+--------------------+--+
到目前为止,我的研究表明:
1) Hive 无法使用八进制数高于 177 的不可打印的 ASCII 字符。指向此的指针在其他一些代码中令我感到惊讶 here在 github 上说:
Hive can specify delimiter characters in the form '\ooo' where ooo is a three-digit octal number between 000 and 177.
2) 我还发现只有一字节字符可以用作字段分隔符的证据 here在 BigSQL 的文档中(但不在官方文档中)它说:
Delimiters must be single-byte characters
根据我的研究,§ (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:评估翻译时出错(stagingstring,'§',';') java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException:评估翻译时出错(stagingstring,'§',';') java.io.IOException:org.apache.hadoop.hive.ql.metadata.HiveException:评估翻译时出错(stagingstring,'§',';') org.apache.hadoop.hive.ql.metadata.HiveException:评估翻译时出错(stagingstring,'§',';') org.apache.hadoop.hive.ql.metadata.HiveException:评估翻译时出错(stagingstring,'§',';') java.lang.IllegalArgumentException: null
更新 2:
上述方法可行,但如果源数据不干净(有其他 UTF-8 问题),则会抛出上述错误。
最佳答案
您需要使用
创建表格由“-89”终止的字段
'section sign' 的十进制代码是 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 对用于其参数的字符串文字有特殊规则,因为它们都需要一个字符。您可以使用由单引号或双引号括起来的常规字符、八进制序列,例如 '\054'(表示逗号),或范围在 '-127'..'128' 内的整数(带引号但不带引号)反斜杠),它被解释为单字节 ASCII 字符。 256减去负值;例如,FIELDS TERMINATED BY '-2' 将字段分隔符设置为 ASCII 代码 254,“Icelandic Thorn”字符用作某些数据格式的分隔符。
关于hadoop - Apache hive : How to use Unicode character (with octal above 177) as field delim,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40461000/