打开微信扫一扫,关注微信公众号【数据与算法联盟】
转载请注明出处:http://blog.youkuaiyun.com/gamer_gyt
博主微博:http://weibo.com/234654758
Github:https://github.com/thinkgamer
代码下载地址:点击查看
--------------------------------------------------------------------------------------------------------------------------------------------------
写在前边的话
这篇文章应该是有史以来写的时间最长的一篇文章,我记得是今年暑假之前开始的,后来因为种种原因吧(找工作,开始工作,电脑重装,换工作等等),导致现在才写完,算是一篇迟到了二个月的文章,实在是不好意思,曾经也想过不写了,但是后来还是坚持了下来,只想分享给大家
整片博客分为这几个部分 :
1:微博热词跟踪系统概述
2:需求分析
3:算法模型
4:架构设计
5:程序实现
6:结果可视化
另外需要注意的是本文所有数据均为测试数据,只是为了验证代码的可用性和整个流程是否能够走通
一:微博热词跟踪系统概述
微博是当今社会消息传播的主要途径,汇集了社会各层人士,能充分代表人们的呼声和社会发展的趋势,其具备了新闻的时效性和广泛性,那么对于微博内容,传播的分析在一定程度上能得到更大价值,比如看些图展示的是“老九门”这个此最近一个月出现的频率,即hot程度
那么接下来我们将要实现的就是类似于上图这样的一个功能
二:需求分析
现假设我们的数据源是这样的,一天的微博信息在一个文件夹下,每个小时内的微博内容在一个文件内,如图:
最终我们要得到的数据要存入Hive数据库,处于方便我们这里选用分区表,以天和小时作为分区依据,表每行有四个字段,分别是day,hour,word,num(时间点精确到小时),类似于以下的,非真实数据(最后一列为分区字段):
表的 描述如下:
三:算法模型
采用的是hadoop作为计算模型,计算结果保存在hive数据库中,中间所有的任务作为串行流在mainJob中执行。
当运行代码的时候,会提示输入你想查看的关键词走势:eg,佳能
然后运行程序,显示出折线图
四:架构设计
整个代码函数的目录为:
mainJob作为主函数,首先调用JobWorker作为计算,在JobWorker中会调用hdfsGYT(这是我封装的一个java操作hdfs的库,感兴趣的朋友可以看下之前关于他的文章:点击阅读),然后调用inHive函数将计算结果保存在hive中,最后调用lineCharts从hive数据仓库中读取数据,画出折线图
PS:读到这里,许多朋友可能会想,你这样做岂不是太麻烦了,完全可以直接将计算结果传给LineCharts进行可视化,加了一个inHive岂不是多此一举,的确是那样,但是换一个角度想,本篇博客只是为了学习,搞明白这样的一个流程,而并不是这些代码就可以用在真实的生产环境中,所以,当我们抱着学习的态度去理解整个代码,我们对整个项目便有了清楚的了解。
五:程序实现
1:hadoop词频统计和过滤实现
main函数:更多代码点击github地址
package org.apache.mr.hotword;
/**
* Created by thinkgamer on 16-9-22.
*/
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
public class mainJob {
public static final String HDFS = "hdfs://127.0.0.1:9000";
// public static final Pattern DELIMITER = Pattern.compile("[\t,]");
public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException {
// TODO Auto-generated constructor stub
Map<String,String> path = new HashMap<String,String>(); //创建一个Map对象
path.put("input", HDFS+"/file/weibo");
path.put("output", HDFS+"/file/weibo/output");
JobWorker.run(path); //针对输入的key_word进行统计
inHive.run(path); //调用inHive的run方法,将运行的结果写入hive表
LineCharts.run(); //将计算的结果以折线的形式画出
}
}
2:创建hive表,并将数据导入
创建表语句:
create table hot_world_table(
time int,
word string,
num int)
comment 'this hot words table'
Partitioned by (day string, hour string)
row format delimited fields terminated by "\t";
将数据导入数据库
#从本地加载
load data local inpath "/home/thinkgamer/桌面/20160221-r-00000" into table hot_word_table partition(timeday='20160221');
#从hdfs加载
load data inpath "/mr/hot_word/output/20160221-r-00000" into table hot_word_table partition(timeday="20160221")
六:结果可视化
可视化部分有LineCharts控制,主要利用的是java的jfreechart进行画图
package org.apache.mr.hotword;
/**
* Created by thinkgamer on 16-9-22.
*/
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
import java.util.Map;
import java.util.TreeMap;
public class LineCharts extends ApplicationFrame {
public LineCharts(String s) {
super(s);
setContentPane(createDemoLine());
}
public static void run() {
LineCharts fjc = new LineCharts("热词走势图");
fjc.pack();
RefineryUtilities.centerFrameOnScreen(fjc);
fjc.setVisible(true);
}
// 生成显示图表的面板
public static JPanel createDemoLine() {
JFreeChart jfreechart = createChart(createDataset());
return new ChartPanel(jfreechart);
}
// 生成图表主对象JFreeChart
public static JFreeChart createChart(DefaultCategoryDataset linedataset) {
//定义图表对象
JFreeChart chart = ChartFactory.createLineChart("热词走势图", // chart title
"时间", // domain axis label
"数量", // range axis label
linedataset, // data
PlotOrientation.VERTICAL, // orientation
true, // include legend
true, // tooltips
false // urls
);
CategoryPlot plot = chart.getCategoryPlot();
// customise the range axis...
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());
rangeAxis.setAutoRangeIncludesZero(true);
rangeAxis.setUpperMargin(0.20);
rangeAxis.setLabelAngle(Math.PI / 2.0);
return chart;
}
//生成数据
public static DefaultCategoryDataset createDataset() {
//从Hive中读取数据
Map<String, String> map = new TreeMap<String, String>();
map = inHive.getResult();
for(int i=1;i<13;i++){
if(map.get(Integer.toString(i))==null){
map.put(Integer.toString(i),"0");
}
}
DefaultCategoryDataset linedataset = new DefaultCategoryDataset();
// 各曲线名称
String series1 = "热词";
// 横轴名称(列名称)
String type1 = "1:00";
String type2 = "2:00";
String type3 = "3:00";
String type4 = "4:00";
String type5 = "5:00";
String type6 = "6:00";
String type7 = "7:00";
String type8 = "8:00";
String type9 = "9:00";
String type10 = "10:00";
String type11 = "11:00";
String type12 = "12:00";
linedataset.addValue(Integer.parseInt(map.get("1")), series1, type1);
linedataset.addValue(Integer.parseInt(map.get("2")), series1, type2);
linedataset.addValue(Integer.parseInt(map.get("3")), series1, type3);
linedataset.addValue(Integer.parseInt(map.get("4")), series1, type4);
linedataset.addValue(Integer.parseInt(map.get("5")), series1, type5);
linedataset.addValue(Integer.parseInt(map.get("6")), series1, type6);
linedataset.addValue(Integer.parseInt(map.get("7")), series1, type7);
linedataset.addValue(Integer.parseInt(map.get("8")), series1, type8);
linedataset.addValue(Integer.parseInt(map.get("9")), series1, type9);
linedataset.addValue(Integer.parseInt(map.get("10")), series1, type10);
linedataset.addValue(Integer.parseInt(map.get("11")), series1, type11);
linedataset.addValue(Integer.parseInt(map.get("12")), series1, type12);
return linedataset;
}
}
结果是这样的: