如何在Amazon EMR中添加含内联Shell脚本的MapReduce/Hive/Spark步骤?
解决EMR上Hive步骤无法执行嵌套命令的问题
我明白你遇到的问题了——在EMR主节点终端里能正常运行的嵌套Hive命令,放到EMR的Hive步骤里就不行。这是因为EMR的Hive步骤并不是在bash shell环境中执行的,它直接调用Hive的执行引擎,不支持bash的命令替换语法($())。下面给你几个可行的解决方案:
方案1:合并两个Hive脚本为一个(最推荐)
把两个脚本的逻辑整合到同一个HQL文件里,用Hive内置的变量赋值来传递结果,这样就能直接作为单个Hive步骤运行。
比如修改后的脚本Combined_JobDetails.hql:
-- 第一步:获取LatestLastUpdated的值(原GetNewJobDetails_LatestLastUpdated.hql的逻辑) SET hivevar:LatestLastUpdated = (SELECT max(last_updated) FROM your_source_table); -- 第二步:执行原GetNewJobDetails_SelectAndOverwrite.hql的逻辑,使用上面的变量 INSERT OVERWRITE TABLE your_target_table SELECT * FROM your_source_table WHERE last_updated > ${hivevar:LatestLastUpdated};
然后在EMR里添加Hive步骤,直接指向这个合并后的S3脚本路径即可。这个方案最简洁,也避免了跨步骤的依赖问题。
方案2:用EMR Shell步骤替代Hive步骤
既然终端的bash命令能运行,那可以把整个命令放到EMR的Shell步骤中执行——Shell步骤是在主节点的bash环境里运行的,完全支持命令替换语法。
在添加EMR步骤时,选择「Shell script」类型,然后输入以下命令内容:
hive -f s3://MyProjectXYZ/bin/GetNewJobDetails_SelectAndOverwrite.hql --hivevar LatestLastUpdated=$(hive -f s3://MyProjectXYZ/bin/GetNewJobDetails_LatestLastUpdated.hql)
注意要确保hadoop用户有访问S3脚本的权限,并且Hive的环境变量在Shell步骤中能正常加载(一般EMR默认已经配置好了)。
方案3:拆分步骤+临时存储传递结果
如果必须分开两个脚本,可以先运行第一个Hive步骤把结果存到临时位置,再用第二个步骤读取结果并执行第二个脚本:
- 第一个Hive步骤:修改
GetNewJobDetails_LatestLastUpdated.hql,把结果输出到S3的临时文件(比本地文件更可靠,避免主节点重启丢失):
INSERT OVERWRITE DIRECTORY 's3://MyProjectXYZ/tmp/latest_last_updated' ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t' STORED AS TEXTFILE SELECT max(last_updated) FROM your_source_table;
- 第二个Shell步骤:读取S3里的临时文件内容,再运行第二个Hive脚本:
# 从S3读取结果并去除换行符 LATEST=$(aws s3 cp s3://MyProjectXYZ/tmp/latest_last_updated/000000_0 - | tr -d '\n') # 执行第二个Hive脚本 hive -f s3://MyProjectXYZ/bin/GetNewJobDetails_SelectAndOverwrite.hql --hivevar LatestLastUpdated=$LATEST
记得在EMR步骤设置里,把第二个步骤依赖于第一个步骤,确保第一个步骤执行完成后再运行第二个。
内容的提问来源于stack exchange,提问作者CyberPlayerOne




