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);
}
}