在Hadoop文件系统中跨多个文件进行grep

21

我正在使用Hadoop,需要找出位于我的Hadoop文件系统中的100个文件中包含特定字符串的文件。

我可以像这样查看要搜索的文件:

bash-3.00$ hadoop fs -ls /apps/mdhi-technology/b_dps/real-time

..which 返回多个类似于这样的条目:

-rw-r--r--   3 b_dps mdhi-technology 1073741824 2012-07-18 22:50 /apps/mdhi-technology/b_dps/HADOOP_consolidated_RT_v1x0_20120716_aa
-rw-r--r--   3 b_dps mdhi-technology 1073741824 2012-07-18 22:50 /apps/mdhi-technology/b_dps/HADOOP_consolidated_RT_v1x0_20120716_ab

我该如何找到这些字符串中包含bcd4bc3e1380a56108f486a4fffbc8dc的那个?一旦我知道了,我就可以手动编辑它们。


问题在于,这不是一个UNIX文件系统,而是一个Hadoop文件系统。每当我尝试像这样做bash-3.00$ cd /apps/hdmi-technology/b_dps/real-time bash: cd: /apps/hdmi-technology/b_dps/real-time: 没有那个文件或目录时,我会得到“没有这样的文件或目录”的错误提示。因此,我需要其他方法来解决这个问题。 - arsenal
5个回答

37

这是一个Hadoop“文件系统”,而不是POSIX文件系统,因此请尝试以下操作:

hadoop fs -ls /apps/hdmi-technology/b_dps/real-time | awk '{print $8}' | \
while read f
do
  hadoop fs -cat $f | grep -q bcd4bc3e1380a56108f486a4fffbc8dc && echo $f
done

这个应该会起作用,但它是串行的,所以可能会很慢。如果您的集群能承受压力,我们可以并行化处理:

hadoop fs -ls /apps/hdmi-technology/b_dps/real-time | awk '{print $8}' | \
  xargs -n 1 -I ^ -P 10 bash -c \
  "hadoop fs -cat ^ | grep -q bcd4bc3e1380a56108f486a4fffbc8dc && echo ^"

请注意 xargs 命令的 -P 10 选项:这是我们将同时下载和搜索的文件数。从一个较低的数字开始逐渐增加,直到您饱和磁盘 I/O 或网络带宽,以适合您的配置条件。

编辑: 鉴于您使用的是SunOS(略有些脑残),请尝试以下操作:

hadoop fs -ls /apps/hdmi-technology/b_dps/real-time | awk '{print $8}' | while read f; do hadoop fs -cat $f | grep bcd4bc3e1380a56108f486a4fffbc8dc >/dev/null && echo $f; done

你确定这个目录存在吗?你能将它挂载到一个位置,然后进入该目录吗? - plast1K
谢谢phs提供的解决方案,那么我可以直接将上述命令复制粘贴到bash提示符中,对吗?还是需要做些其他的事情? - arsenal
尝试了您给我的第二个命令后,我得到了以下错误信息- bash-3.00$ hadoop fs -ls /apps/hdmi-technology/b_apdpds/real-time | awk '{print $8}' | \ xargs -n 1 -I ^ -P 10 bash -c \ "hadoop fs -cat ^ | grep -q bcd4bc3e1380a56108f486a4fffbc8dc && echo ^" bash: : command not found 不知道为什么会出现“command not found”的错误。 - arsenal
天哪,你使用的是什么操作系统? - phs
顺便提一下,您还可以在调用awk之前通过将-C传递给ls命令来避免这种情况:hadoop fs -ls -C /apps/hdmi-technology/b_dps/real-time - Alvaro Mendez
显示剩余6条评论

2
您想在HDFS文件夹上应用grep命令。
hdfs dfs -cat /user/coupons/input/201807160000/* | grep -c null

这里的“cat”递归地遍历了文件夹中的所有文件,我使用了“grep”来查找计数。

0

在 HDFS 位置内递归查找所有带有任何扩展名的文件:

hadoop fs -find  hdfs_loc_path  -name ".log"

是的,我每天都使用它。而且有很多种方法可以使用这个命令。 - Gourav Goutam

0
hadoop fs -find /apps/mdhi-technology/b_dps/real-time  -name "*bcd4bc3e1380a56108f486a4fffbc8dc*"

hadoop fs -find /apps/mdhi-technology/b_dps/real-time  -name "bcd4bc3e1380a56108f486a4fffbc8dc"

只是为了澄清:此答案提供了在文件路径/文件名中搜索字符串bcd4bc3e1380a56108f486a4fffbc8dc的解决方案,而不是在文件内容中进行搜索。尽管如此,仍然有用 :)。对于后者,请参考上面的phs' answer - gnsb

0

如果你只有两个1GB的文件,使用hadoop fs -cat(或更通用的hadoop fs -text)可能是可行的。但如果有100个文件,我会使用streaming-api,因为它可以用于即席查询,而不必诉诸于完整的mapreduce作业。例如,在您的情况下,创建一个名为get_filename_for_pattern.sh的脚本:

#!/bin/bash
grep -q $1 && echo $mapreduce_map_input_file
cat >/dev/null # ignore the rest

请注意,为了避免出现“java.io.IOException:Stream closed”异常,您必须读取整个输入。
然后发出命令。
hadoop jar $HADOOP_HOME/hadoop-streaming.jar\
 -Dstream.non.zero.exit.is.failure=false\
 -files get_filename_for_pattern.sh\
 -numReduceTasks 1\
 -mapper "get_filename_for_pattern.sh bcd4bc3e1380a56108f486a4fffbc8dc"\
 -reducer "uniq"\
 -input /apps/hdmi-technology/b_dps/real-time/*\
 -output /tmp/files_matching_bcd4bc3e1380a56108f486a4fffbc8dc
hadoop fs -cat /tmp/files_matching_bcd4bc3e1380a56108f486a4fffbc8dc/*

在更新的发行版中,应该使用mapred streaming而不是hadoop jar $HADOOP_HOME/hadoop-streaming.jar。在后一种情况下,您必须正确设置$HADOOP_HOME以便找到jar文件(或直接提供完整路径)。
对于简单的查询,您甚至不需要脚本,只需直接向-mapper参数提供命令即可。但对于稍微复杂的任何内容,最好使用脚本,因为正确转义可能很麻烦。
如果您不需要减少阶段,请向相应的-reduce选项提供符号NONE参数(或仅使用-numReduceTasks 0)。但在您的情况下,有一个减少阶段是有用的,以便将输出合并到单个文件中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接