利用storm实现简单的单词统计

                WordReader类( spout读取 txt 文档,按行发射给 bolt)

public class WordReader implements IRichSpout{

/**
*  序列化
*/
private static final long serialVersionUID = 1L;
private FileInputStream is;
private InputStreamReader isr;
private BufferedReader br;
private String line = "";
private SpoutOutputCollector collector;
/**
*  此方法用于声明当前 Spout 的 Tuple 发送流的域名字,即一个 backtype.storm.tuple.Fields 对象。
*  这个对象和 public void nextTuple() 接口中 emit 的 backtype.storm.tuple.Values
*  共同组成了一个元组对象( backtype.storm.tuple.Tuple )
*  供后面接收该数据的 Blot 使用
*  运行 TopologyBuilder 的 createTopology() 时调用此方法
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("line"));
}
/**
*  运行 TopologyBuilder 的 createTopology() 时调用此方法
*  用于输出特定于 Spout 和 Bolt 实例的配置参数值对
*  此方法用于声明针对当前组件的特殊的 Configuration 配置,在需要的情况下会进行配置。
*/
@Override
public Map<String, Object> getComponentConfiguration() {
// 设置 Topology 中当前组件的线程数量上限为 3
// Map<String, Object> ret = new HashMap<String, Object>();
// ret.put(Config.TOPOLOGY_MAX_TASK_PARALLELISM, 3);
// return ret;
return null;
}
/**
*  当一个 Task 被初始化的时候会调用此 open 方法。
*  在这里要将 SpoutOutputCollector spoutOutputCollector 对象保存下来,
*  供后面的 public void nextTuple() 接口使用,还可以执行一些其他的操作。
*  例如这里将 txt 文档转换成流,也就是初始化操作。
*  里面接收了三个参数,第一个是创建 Topology 时的配置,
*  第二个是所有的 Topology 数据,第三个是用来把 Spout 的数据发射给 bolt
*/
@Override
public void open(Map conf, TopologyContext context,
SpoutOutputCollector collector) {
try {
this.collector = collector;
this.is = new FileInputStream("E:\\words.txt");
this.isr = new InputStreamReader(is,"utf-8");
this.br = new BufferedReader(isr);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*  当 thread 运行完 spout 实例的 open() 方法之后,
*  该 spout 实例处于 deactivated (失效)模式,
*  过段时间会变成 activated (激活)模式,此时会调用 Spout 实例的 activate() 方法
*/
@Override
public void activate() {
}
/**
*  接口该接口实现具体的读取数据源的方法。
*  当该方法被调用时,要求 SpoutOutputCollector 喷射 tuple 。
*  在本例中, nextTuple() 方法是负责对 txt 文档转换成的流进行逐行读取。
*  将获取的数据 emit (发射)出去。
* emit 的对象是通过 public Values createValues(String line) 方法
*  生成的 backtype.storm.tuple.Values 对象。
*  该方法从数据源的一行数据中,选取的若干个目标值组成一个 backtype.storm.tuple.Values 对象。
*  这个对象中可以存储不同类型的对象,例如你可以同时将 String 对象,
* Long 对象存取在一个 backtype.storm.tuple.Values 中 emit 出去。
*  实际上只要实现了 Storm 要求的序列化接口的对象都可以存储在里面。
* emit 该值得时候需要注意,
*  他的内容要和 declareOutputFields 中声明的 backtype.storm.tuple.Fields 对象相匹配,必须一一对应。
*  他们被共同组成一个 backtype.storm.tuple.Tuple 元组对象,被后面接收该数据流的对象使用。
*/
@Override
public void nextTuple() {
try {
while ((this.line = this.br.readLine()) != null) {
// 数据过滤
// 发射数据
this.collector.emit(new Values(this.line),UUID.randomUUID());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*  从此 spout 发射的带有 messageID 的 tuple 处理成功时调用此方法。
*  该方法的一个典型实现是把消息从队列中移走,避免被再次处理。
*/
@Override
public void ack(Object msgId) {
System.out.println("OK:" + msgId);
}
/**
*  从此 spout 发射的带有 messageID 的 tuple 处理失败时调用此方法。
*/
@Override
public void fail(Object msgId) {
System.out.println("FAIL:" + msgId);
}
/**
* topology 终止时,执行此方法
*  在本例子中,可以在这个阶段释放资源
*/
@Override
public void close() {
try {
this.br.close();
this.isr.close();
this.is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
*  在 Topology 运行过程中,通过客户端执行 deactivate 命令,
*  禁用指定的 Topology 时,被禁用的 Topology 的 spout 实例会变成 deactivate (失效),
*  并且会调用 spout 实例 deactivate() 方法
*/
@Override
public void deactivate() {
}

}

----------------------------------------------------------------------------------------------------------------------------------

            WordNormalizer类(  解析 spout 发射的 tuple ,拆分成一个个单词发射给下一个 bolt)

public class WordNormalizer implements IRichBolt{
/**
*  序列化
*/
private static final long serialVersionUID = 1L;
private OutputCollector collector;
private String line;
private String[] words;
/**
*  当这个组件的 task 在集群中的一台 worker 内被初始化的时候,该函数被调用。
*  它向 bolt 提供了该 bolt 执行的环境
* (
* 里面接收了三个参数,
* 第一个是创建 Topology 时的配置,
* 第二个是所有的 Topology 数据,
* 第三个是用来把 Bolt 的数据发射给下一个 bolt
* )
*  在这里要将 OutputCollector collector 对象保存下来
*/
@Override
public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.collector = collector;
}
/**
*  处理输入的一个单一 tuple 。
*  每次接收到元组时都会被调用一次,还会再发布若干个元组
*/
@Override
public void execute(Tuple input) {
// line = (String)input.getValue(0);
line = (String)input.getValueByField("line");// 与上面等价
words = line.split("\t");
for(String word : words){
collector.emit(new Values(word));
}
// 成功,提示从此 spout 喷出的带有 messageID 的 tuple 已被完全处理,把消息从队列中移走,避免被再次处理。
this.collector.ack(input);
}
/**
* Topology 执行完毕的清理工作,比如关闭连接、释放资源等操作都会写在这里
* topology 终止时,执行此方法
*  注意:
* 由于 cleanup 方法并不可靠,它只在 local mode 下生效, Storm 集群模式下 cleanup 不会被调用执行。很多资源得不到释放
* 所以,在 kill topology 之前,先 deactivate 相应的 topology 。
* bolt 中判断接收的数据为 ”shutDown” 就调用 cleanup() 方法。在 cleanup() 方法中释放需要释放的资源。
*/
@Override
public void cleanup() {
}
/**
*  此方法用于声明当前 bolt 的 Tuple 发送流的域名字,即一个 backtype.storm.tuple.Fields 对象。
*  这个对象和 public void execute(Tuple input) 接口中 emit 的 backtype.storm.tuple.Values
*  共同组成了一个元组对象( backtype.storm.tuple.Tuple )
*  供后面接收该数据的 Blot 使用
*/
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
/**
*  用于输出特定于 Spout 和 Bolt 实例的配置参数值对
*  此方法用于声明针对当前组件的特殊的 Configuration 配置,在需要的情况下会进行配置。
*/
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}

}

----------------------------------------------------------------------------------------------------------------------------------

                    WordCounter类( 接收 WordNormalizer 发射的单词,进行计数)

public class WordCounter implements IRichBolt{

/**
*  序列化
*/
private static final long serialVersionUID = 1L;
Integer id;
String name;
Map<String, Integer> counters;
private OutputCollector collector;
@Override
public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.counters = new HashMap<String, Integer>();
this.collector = collector;
this.name = context.getThisComponentId();
this.id = context.getThisTaskId();
}
@Override
public void execute(Tuple input) {
String word = input.getString(0);
// 计数
if(!counters.containsKey(word)){
counters.put(word, 1);
}else{
Integer c = counters.get(word) + 1;
counters.put(word, c);
}
// 成功,提示从此 spout 喷出的带有 messageID 的 tuple 已被完全处理,把消息从队列中移走,避免被再次处理。
this.collector.ack(input);
}
/**
* Topology 执行完毕的清理工作,比如关闭连接、释放资源等操作都会写在这里
* topology 终止时,执行此方法
*  注意:
* 由于 cleanup 方法并不可靠,它只在 local mode 下生效, Storm 集群模式下 cleanup 不会被调用执行。很多资源得不到释放
* 所以,在 kill topology 之前,先 deactivate 相应的 topology 。
* bolt 中判断接收的数据为 ”shutDown” 就调用 cleanup() 方法。在 cleanup() 方法中释放需要释放的资源。
*
*  因为这只是个 Demo ,我们用它来打印我们的计数器
*/
@Override
public void cleanup() {
System.out.println("-- Word Counter [" + name + "-" + id + "] --");
for(Map.Entry<String, Integer> entry : counters.entrySet()){
System.out.println(entry.getKey() + ": " + entry.getValue());
}
counters.clear();
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// 不再向外发射数据,此处不写代码
}
@Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}



猜你喜欢

转载自blog.csdn.net/csdn_hzx/article/details/80685064