Pig MapReduce输出异常排查及Hive查询结果文件实现方法
Pig脚本处理分隔符文件异常问题排查
问题背景
现有名为test.txt的文件,字段分隔符为制表符,内容如下:
"1" "a" "x" "2" "b" "y" "3" "c" "z"
编写的Pig脚本test.pig内容如下:
a=LOAD '/Analytics/warehouse/SF/test.txt' as (fullrecord:chararray); b=FOREACH a generate REPLACE($0,'\t',','); STORE b INTO 'hdfs://localhost:9000/Analytics/warehouse/SF/sf.out' USING PigStorage(',');
执行命令 pig -x mapreduce test.pig 运行脚本后,输出路径.../warehouse/SF/sf.out下的part-m-0000文件仅保留了第一列内容:
"1" "2" "3"
问题解答
Q1:其余字段丢失的原因是什么?
- Pig的
LOAD语句如果不指定加载函数,会默认调用PigStorage('\t'),自动按制表符切割每一行的字段,不会把整行内容读入你声明的fullrecord字段。 - 你只声明了
fullrecord:chararray一个字段来接收加载结果,因此切割后的第二、第三个字段没有对应的变量接收,直接被丢弃,最终a别名下每一行就只有第一列的内容。
Q2:为何脚本中的制表符未被替换为逗号?
- 核心原因是加载阶段制表符已经被默认的PigStorage当作字段分隔符处理掉了,你拿到的
$0本身就只是第一列的纯值,不包含任何制表符,REPLACE函数自然找不到匹配的替换目标。 - 这个场景和转义符写法无关,即使你调整转义写法,也无法解决字段已经被切割的问题。
Q3:如何调整脚本实现目标输出?
目标输出格式为逗号分隔的文本:
"1","a","x" "2","b","y" "3","c","z"
推荐两种实现方案,任选其一即可:
- 方案1:整行读入后替换分隔符(适合字段数量不固定的场景)
-- 用TextLoader加载,强制把整行内容作为单个chararray字段读入,不做自动切割 a = LOAD '/Analytics/warehouse/SF/test.txt' USING TextLoader() as (fullrecord:chararray); -- 将整行中的所有制表符替换为逗号 b = FOREACH a GENERATE REPLACE(fullrecord, '\t', ','); -- 存储结果,因为b只有一个整行字段,默认分隔符不会影响输出格式 STORE b INTO 'hdfs://localhost:9000/Analytics/warehouse/SF/sf.out' USING PigStorage();
- 方案2:按原分隔符加载字段后直接指定存储分隔符(适合字段固定的场景,性能更好)
-- 按默认制表符切割加载全部三个字段 a = LOAD '/Analytics/warehouse/SF/test.txt' AS (col1:chararray, col2:chararray, col3:chararray); -- 存储时指定逗号作为字段分隔符,Pig会自动拼接字段 STORE a INTO 'hdfs://localhost:9000/Analytics/warehouse/SF/sf.out' USING PigStorage(',');
Q4:得到目标结果后,如何使用Hive查询该结果文件?
按以下步骤操作即可:
- 确认结果文件存储在HDFS路径
hdfs://localhost:9000/Analytics/warehouse/SF/sf.out,格式为逗号分隔、字段带双引号包裹的文本文件。 - 启动Hive客户端,创建外部表指向该路径,推荐使用OpenCSVSerde自动处理双引号转义:
CREATE EXTERNAL TABLE test_sf( col1 string, col2 string, col3 string ) ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' WITH SERDEPROPERTIES ( "separatorChar" = ",", "quoteChar" = "\"" ) LOCATION 'hdfs://localhost:9000/Analytics/warehouse/SF/sf.out';
- 直接执行查询语句即可获取正确结果:
SELECT * FROM test_sf;
如果集群不支持OpenCSVSerde,也可以创建普通分隔表,查询时手动去除双引号:
CREATE EXTERNAL TABLE test_sf_plain( col1 string, col2 string, col3 string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION 'hdfs://localhost:9000/Analytics/warehouse/SF/sf.out'; -- 查询时替换掉字段包裹的双引号 SELECT REPLACE(col1, '"', ''), REPLACE(col2, '"', ''), REPLACE(col3, '"', '') FROM test_sf_plain;
内容的提问来源于stack exchange,提问作者Juan Carlos Castro Piedra
相关产品推荐
相关产品推荐

