欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用storm统计英文版<<圣经>>的词频

程序员文章站 2022-07-12 19:17:11
...

我估计自己是疯掉了.....

刚入门storm,就先硬生生的来杠这部著作......

我先擦一把汗哈,然后呢,整个流程需要五个步骤,希望大家都可以得到属于自己的统计数据使用storm统计英文版<<圣经>>的词频使用storm统计英文版<<圣经>>的词频

1.下载圣经英文版,并修改一部分内容,例如标点

2.参考我的另一篇博客,那里面几乎是源码(只改两个类)

3.修改源码

4.准备枕头

5.抬头看结果


一.下载并修改
下载地址:http://www.o-bible.com/gb/dlb.html
修改:主要是外国人的习惯可能会使我们根据空格统计时把用标点符号连接的两个单词当做一个单词
  • 把所有逗号, 替换为""
  • 把所有句号. 替换为" "(注意有空格)
  • 把所有分号; 替换为""
  • 把所有问号? 替换为""
  • 把所有冒号: 替换为""
  • 把所有左括号( 替换为" "(注意有空格)
  • 把所有右括号) 替换为""(没有空格)
  • (进阶项):替换所有数字为 ""
  • (进阶项):替换所有表述为 "章节"含义的单词为""

二.参考博客

请先参考我的博客:http://blog.csdn.net/weixin_35757704/article/details/77246313

这篇博客思路很简单,十分基础,参考它是因为我的这个就是在那篇博客源码的基础上改进来的


三.修改源码

这里面有具体的代码,我们只需要简单修改两个类就可以:

CreateSpout 修改

import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichSpout;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Values;
import backtype.storm.utils.Utils;
import org.joda.time.DateTime;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Map;

/**
 * 创建数据源
 */
public class CreateSpout extends BaseRichSpout {

    private SpoutOutputCollector collector;
    private String[] sentences = null; //为数据的总容量
    String pathname;
    File filename;
    InputStreamReader reader;
    BufferedReader br;

    private String read() {

        try {
            String line = "";
            line = br.readLine();
            if (line != null) {
                return line;
            } else {
                Utils.sleep(200000000);
            }
        } catch (Exception e) {
        }
        return "null";
    }

    @Override
    public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
        this.collector = spoutOutputCollector;
        try {
            pathname = "C:\\storm\\storm_Pro\\kjv.txt";
            filename = new File(pathname);
            reader = new InputStreamReader(
                    new FileInputStream(filename));
            br = new BufferedReader(reader);

        } catch (Exception e) {

        }
    }

    @Override
    public void nextTuple() {
        sentences = new String[]{read()};
        /*storm会循环的调用这个方法*/
        /*线程进行休眠,10s发送一次数据,在这10s内,让其余工作进行*/
        Utils.sleep(100);
        //获得数据源
        System.out.println(new DateTime().toString("HH:mm:ss") + "--------------CreateSpout 开始发送数据----------");
        this.collector.emit(new Values(sentences));
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
        outputFieldsDeclarer.declare(new Fields("sentence"));
    }

}

对这个类的修改,就是把数据源修改一下,从本地文件 kjv.txt读取,这也是<<圣经>>英文版的txt文件.大家也可以从其他地方下载.

PrintBolt 修改

import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.tuple.Tuple;
import backtype.storm.utils.Utils;
import org.joda.time.DateTime;

import java.util.Map;

public class PrintBolt extends BaseRichBolt {
    @Override
    public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
    }

    @Override
    public void execute(Tuple input) {

        System.out.println(new DateTime().toString("HH:mm:ss") + "--------------------final bolt 开始运行--------------------");
        Map<String, Integer> counts = (Map<String, Integer>) input.getValue(0);
        /*最后一个阶段,可以持久到mysql等数据库中*/
        System.out.println(justForm(20 - 8) + "key" + justForm(20 - 8) + "      " + "value");
       
	try {
	   	 System.out.println("/////////////////////////////////////////////////////////");//与之前的打印信息分隔,直观的得到结果
 		for (Map.Entry<String, Integer> kv : counts.entrySet()) { /*这里的justForm()函数是为了保证格式一致*/
                System.out.println(kv.getKey() + justForm(kv.getKey().length()) + " 频数 : " + kv.getValue());
            }
       	} catch (Exception e) {
            System.out.println("/////////////////////////////////////////////////////////////////////得到一个错误的值");
        }
	try {
            Utils.sleep(60000);
        }catch (Exception e){

        }

    }

    private String justForm(int length) {
        for (int i = 0; i < 20 - length; i++) {
            System.out.print(" ");
        }
        return "";
    }

    @Override
    public void declareOutputFields(OutputFieldsDeclarer declarer) {

    }
}
对结果打印的代码进行修改是因为我们都知道,这种事情不是一时半会能完成的,因此这里设置一个等待的线程,不用实时的打印结果,只需要1分钟打印一次就好,不过我测试了一下,虚拟机win8.1+8G内存+SSD+i7-7700HQ的两个核心,也使用了20+分钟,下图是我在宿主机上截取的当时的数据:
使用storm统计英文版<<圣经>>的词频


四.准备枕头
点一下运行,能正常跑两分钟,观察是不是死循环,如果一切正常,就可以倒头睡觉了


五.抬头看结果
下图有点恐怖,密集型恐惧症患者请捂脸.....
我的编译器是Intellij IDEA,它可以在控制台保存相当多的数据,所以可以都得到,其他的编辑器我就不是很了解了,如果为了以防万一,可以直接打印到本地文件中
而且如果你能够观察到右侧滑块的位置的话,那么你就可以知道为什么会有第四步了.....
使用storm统计英文版<<圣经>>的词频

大家可能注意到了,有许多频数只是1,大致翻译就是不同篇章的第1节,第二节等,因此这个筛选条件是有很大的改进空间的.
期待大家可以得到更好的筛选结果.大笑