wordcount业务需要的执行步骤
- 在hdfs中读取文件:一次读取一行
- 调用一个方法对每一行进行业务处理
- 将处理的结果放入一个缓存当中
- 最后将缓存中的统计结果输出到HDFS中的结果文件内
HDFS的客户端
//可以使用反射等方式从配置文件读取应该初始化的Handler的类型
//或者直接初始化
WordCountHandler wcHandler = new WordCountHandler();
//获取文件系统
FileSystem fs = FileSystem.get(new URI("PATH"),new Configuration(),"root");
// 列举目录下所有文件内容
RemoteIterator<LocatedFileStatus> iter = fs.ListFiles(new PATH("/wordcount/input"), false);
// 初始化上下文
Context context = new Context();
// 遍历所有的文件做处理
while(iter.hasNext()) {
LocalFileStatus file = iter.next();
//打开文件的流
FSDateInputStream in = fs.open(file.getPath());
BufferReader br = new BufferedReader(new InputStreamReader(in));
String line = null;
//逐行阅读
while((line = br.readLine()) != null) {
// 调用接口
wcHandler.map(line , context);
}
br.close();
in.close();
HashMap<Object, Object> contextMap = context.getContextMap();
if(fs.exists(output)){
throw new RuntimeException("指定的输出目录已存在,请更换......!");
}
FSDataOutputStream out = fs.create(new Path(output,new Path("res.dat")));
Set<Entry<Object, Object>> entrySet = contextMap.entrySet();
for (Entry<Object, Object> entry : entrySet) {
out.write((entry.getKey().toString()+"\t"+entry.getValue()+"\n").getBytes());
}
out.close();
fs.close();
System.out.println("恭喜!数据统计完成.....");
}
接口的设计
接口每次调用就是往接口内包含的上下文里面写入需要处理的信息,比较通用。
public interface Handler {
public void handle(String line , Context context);
}
public class WordCountHandler implements Handler{
@override
public void map(String line, Context context) {
String[] words = line.split(" ");
for(String word : words) {
Object value = context.get(word);
if(null == value) {
context.write(word, 1);
} else {
context.write(word , (int) value + 1);
}
}
}
}
上下文设计
public class Context {
public HashMap<Object , Object> map = new HashMap<>();
public void Write(Object key , Object value) {
map.put(key , value);
}
public Object Get(Object key) {
return map.get(key);
}
}