本文共 6344 字,大约阅读时间需要 21 分钟。
打开微信扫一扫,关注微信公众号【数据与算法联盟】
转载请注明出处:
博主微博:
Github:
代码下载地址:
--------------------------------------------------------------------------------------------------------------------------------------------------
这篇文章应该是有史以来写的时间最长的一篇文章,我记得是今年暑假之前开始的,后来因为种种原因吧(找工作,开始工作,电脑重装,换工作等等),导致现在才写完,算是一篇迟到了二个月的文章,实在是不好意思,曾经也想过不写了,但是后来还是坚持了下来,只想分享给大家
整片博客分为这几个部分 :
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函数:更多代码点击
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 Mappath = new HashMap (); //创建一个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中读取数据 Mapmap = new TreeMap (); 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; }}
结果是这样的: