我有大约1000 files
,每个文件的大小都是1GB
。我需要在所有这些1000 files
中找到一个字符串,以及哪些文件包含该特定的字符串。我正在使用Hadoop文件系统,所有这些1000 files
都在Hadoop文件系统中。
所有1000 files
都在真实文件夹下,所以如果我在下面这样做,我将获得所有1000 files
。我需要找到哪些文件包含真实文件夹下的特定字符串 hello 。
bash-3.00$ hadoop fs -ls /technology/dps/real
这是我在hdfs中的数据结构 -
row format delimited
fields terminated by '\29'
collection items terminated by ','
map keys terminated by ':'
stored as textfile
如何编写MapReduce作业来完成这个特定问题,以便找到哪些文件包含特定字符串?任何简单的例子对我都有很大的帮助。
更新: -
在Unix中使用grep我可以解决上面的问题场景,但它非常慢,需要很多时间才能得到实际的输出 -
hadoop fs -ls /technology/dps/real | awk '{print $8}' | while read f; do hadoop fs -cat $f | grep cec7051a1380a47a4497a107fecb84c1 >/dev/null && echo $f; done
所以这就是我寻找一些MapReduce工作来解决这个问题的原因......
答案 0 :(得分:4)
听起来你正在寻找类似grep的程序,使用Hadoop Streaming很容易实现(Hadoop Java API也可以):
首先,编写一个映射器,如果正在处理的行包含您的搜索字符串,则输出正在处理的文件的名称。我使用过Python,但任何语言都可以使用:
#!/usr/bin/env python
import os
import sys
SEARCH_STRING = os.environ["SEARCH_STRING"]
for line in sys.stdin:
if SEARCH_STRING in line.split():
print os.environ["map_input_file"]
此代码从SEARCH_STRING
环境变量中读取搜索字符串。在这里,我分割输入行并检查搜索字符串是否与任何分割匹配;你可以改变它来执行子字符串搜索或使用正则表达式来检查匹配。
接下来,使用此映射器运行Hadoop流式传输作业,而不使用reducer:
$ bin/hadoop jar contrib/streaming/hadoop-streaming-*.jar \
-D mapred.reduce.tasks=0
-input hdfs:///data \
-mapper search.py \
-file search.py \
-output /search_results \
-cmdenv SEARCH_STRING="Apache"
输出将分为几个部分;要获得匹配列表,您可以简单地捕获文件(假设它们不是太大):
$ bin/hadoop fs -cat /search_results/part-*
hdfs://localhost/data/CHANGES.txt
hdfs://localhost/data/CHANGES.txt
hdfs://localhost/data/ivy.xml
hdfs://localhost/data/README.txt
...
答案 1 :(得分:1)
要获取您当前正在处理的文件名,请执行以下操作:
((FileSplit) context.getInputSplit()).getPath().getName()
当您按记录搜索文件记录时,当您看到hello
时,会发出上述路径(也许是该行或其他任何内容)。
将减速器的数量设置为0,它们在这里没有做任何事情。
'row format delimited'是否意味着换行符分隔行?在这种情况下,TextInputFormat
和LineRecordReader
可以正常使用。
答案 2 :(得分:0)
你可以试试这样的东西,虽然我不确定它是否是一种有效的方法。让我知道它是否有效 - 我没有测试它或任何东西。
您可以像这样使用它: java SearchFiles / technology / dps / real hello 确保您从相应的目录运行它。
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
public class SearchFiles {
public static void main(String[] args) throws IOException {
if (args.length < 2) {
System.err.println("Usage: [search-dir] [search-string]");
return;
}
File searchDir = new File(args[0]);
String searchString = args[1];
ArrayList<File> matches = checkFiles(searchDir.listFiles(), searchString, new ArrayList<File>());
System.out.println("These files contain '" + searchString + "':");
for (File file : matches) {
System.out.println(file.getPath());
}
}
private static ArrayList<File> checkFiles(File[] files, String search, ArrayList<File> acc) throws IOException {
for (File file : files) {
if (file.isDirectory()) {
checkFiles(file.listFiles(), search, acc);
} else {
if (fileContainsString(file, search)) {
acc.add(file);
}
}
}
return acc;
}
private static boolean fileContainsString(File file, String search) throws IOException {
BufferedReader in = new BufferedReader(new FileReader(file));
String line;
while ((line = in.readLine()) != null) {
if (line.contains(search)) {
in.close();
return true;
}
}
in.close();
return false;
}
}