本篇的思想:對HDFS獲取的數據進行兩種不同的可視化圖表處理方式。第一種JFreeChar可視化處理生成圖片文件查看。第二種AJAX+JSON+ECharts實現可視化圖表,並呈現於瀏覽器上。
對此,給出代碼示例,通過網絡爬蟲技術,將上傳到HDFS的新浪網新聞信息實現熱詞統計功能,通過圖表的柱狀圖來顯示出來。
------>
目錄:
1、JFreeChart可視化處理(生成本地圖片)
【1】HDFS文件讀取
【2】JDFreeChart庫應用
2、AJAX+JSON+EChart生成可視化圖表(網頁呈現圖表)
【1】EChart基本方法
【2】JSON數據格式
【3】AJAX技術
【4】熱詞統計示例
3、總結
------>
1、JFreeChart可視化處理
【1】HDFS文件讀取
保存時,我們數據使用了兩種方式保存:
1) 純文本方式:適合整體讀取數據,並按行將內容讀取出來處理。
2) MapFileFormat的方式:適合按key來查找value
這里可以使用FSDataInputStream來直接讀入文本方式的數據。
代碼呈現:
1 public class TestReadData { 2 3 public static void main(String[] args) throws Exception { 4 Configuration conf = new Configuration(); 5 FileSystem fs = null; 6 Path path = new Path("hdfs://localhost:9000/output/part-00000"); 7 fs = path.getFileSystem(conf); 8 FSDataInputStream is = fs.open(path); 9 // 使用一個緩沖流或者內存流來整體讀入數據 10 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 11 String line = null; 12 while ((line = br.readLine()) != null) { 13 String[] strs = line.split("\t"); 14 System.out.println(strs[0] + " --> " + strs[1]); 15 } 16 } 17 }
下面我們想從這些詞里提取出出現頻率最高的10個詞。
這里就需要使用插入排序的方法來完成。
因此我們這里編寫一個工具類,來幫助我們完成排序功能。
同時,為了方便進行對象的保存和傳遞,建議編寫一個vo類來保存關鍵字和出現次數。
代碼呈現:
1 public class MyKeyValue { 2 3 private String key; 4 private Integer value; 5 6 public MyKeyValue() { 7 } 8 9 public MyKeyValue(String key, Integer value) { 10 this.key = key; 11 this.value = value; 12 } 13 14 public String getKey() { 15 return key; 16 } 17 18 public void setKey(String key) { 19 this.key = key; 20 } 21 22 public Integer getValue() { 23 return value; 24 } 25 26 public void setValue(Integer value) { 27 this.value = value; 28 } 29 30 public int compare(MyKeyValue other) { 31 if (this.value >= other.value) { 32 return 1; 33 } else { 34 return -1; 35 } 36 } 37 }
此時需要修改TestReadData類,添加vo對象,以及排除一些熱詞:
1 public class TestReadData { 2 3 private static Set<String> allNoKeyword = new HashSet<>(); 4 5 static { 6 allNoKeyword.add("新聞"); 7 allNoKeyword.add("新浪網"); 8 allNoKeyword.add("新浪"); 9 allNoKeyword.add("聚合"); 10 allNoKeyword.add("中國"); 11 allNoKeyword.add("視頻"); 12 allNoKeyword.add("圖片"); 13 allNoKeyword.add("圖集"); 14 allNoKeyword.add("最新"); 15 allNoKeyword.add("閱讀"); 16 } 17 18 public static void main(String[] args) throws Exception { 19 Configuration conf = new Configuration(); 20 FileSystem fs = null; 21 Path path = new Path("hdfs://localhost:9000/output/part-00000"); 22 fs = path.getFileSystem(conf); 23 FSDataInputStream is = fs.open(path); 24 // 使用一個緩沖流或者內存流來整體讀入數據 25 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 26 String line = null; 27 // 建立工具類 28 ValueSortList list = new ValueSortList(); 29 while ((line = br.readLine()) != null) { 30 String[] strs = line.split("\t"); 31 // 建立vo對象 32 if (!allNoKeyword.contains(strs[0]) && strs[0].length() > 1) { 33 MyKeyValue keyValue = new MyKeyValue(strs[0], 34 Integer.parseInt(strs[1])); 35 list.add(keyValue); 36 } 37 } 38 39 System.out.println(list); 40 } 41 }
【2】JFreeChart庫應用
JFreeChart是由Java提供的免費不開源的數據可視化的庫。
首先將支持包加入到項目中。
之后可以通過以下固定的步驟,來根據數據,生成圖表。
1) 創建數據集合
2) 向集合中添加數據
3) 建立圖表對象(根據需要選擇不同的圖表)
4) 設置圖表的參數
5) 將圖表輸出
餅狀圖(這里還支持環狀和3D效果):
1 public class PieDemo { 2 3 public static void main(String[] args) throws Exception { 4 // 數據集 5 DefaultPieDataset dataset = new DefaultPieDataset(); 6 7 // 添加數據 8 ValueSortList list = TestReadData.getValues(); 9 10 for (MyKeyValue keyValue : list.getList()) { 11 dataset.setValue(keyValue.getKey(), keyValue.getValue()); 12 } 13 14 // 創建對象 15 JFreeChart chart = ChartFactory.createPieChart("新浪新聞熱詞分析", dataset, 16 true, true, false); 17 18 // 設置屬性 19 20 // 輸出 21 ChartUtilities.saveChartAsPNG(new File("E:/pie.png"), chart, 500, 500); 22 23 } 24 25 }
柱狀圖和線型圖:(還支持線、3D柱、3D線、區域)
1 public class BarDemo { 2 3 public static void main(String[] args) throws Exception { 4 DefaultCategoryDataset dataset = new DefaultCategoryDataset(); 5 6 ValueSortList list = TestReadData.getValues(); 7 8 for (MyKeyValue keyValue : list.getList()) { 9 dataset.addValue(keyValue.getValue(), keyValue.getKey(), ""); 10 } 11 12 JFreeChart chart = ChartFactory.createBarChart("熱詞分析", "詞", "次數", 13 dataset, PlotOrientation.VERTICAL, true, true, false); 14 15 ChartUtilities.saveChartAsPNG(new File("E:/bar.png"), chart, 1000, 500); 16 17 } 18 }
2、AJAX+JSON+ECharts生成可視化圖表
【1】ECharts基本使用
ECharts最早是有一些開源的工程師來開發的免費使用的圖表工具,在 1 和 2版本時都是放在github上。之后ECharts被百度投資收購,加入了百度的開源產品中。
如果想使用ECharts這種的開源工具,必須先去其官網下載開發包。
下載時,建議將完整版和開發版都下載下來,開發版用於開發時進行調試,完整版用於上線提升性能。
下面就需要了解怎樣完成一個簡單的ECharts圖表(此也為官網給出的代碼示例)。
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Document</title> 6 <script type="text/javascript" src="echarts.js"></script> 7 <script type="text/javascript"> 8 function initChart() { 9 // 初始化要顯示的圖標div 10 var myChart = echarts.init(document.getElementById('my_chart')); 11 var option = { 12 title: { 13 text: 'ECharts 入門示例' 14 }, 15 tooltip: { 16 trigger:"axis", 17 label:"銷量" 18 }, 19 legend: { 20 data:['銷量','價格'] 21 }, 22 xAxis: { 23 data: ["襯衫","羊毛衫","雪紡衫","褲子","高跟鞋","襪子"] 24 }, 25 yAxis: {}, 26 series: [{ 27 name: '銷量', 28 type: 'bar', 29 data: [5, 20, 36, 10, 10, 20] 30 },{ 31 name: '價格', 32 type: 'line', 33 data: [30, 40, 32, 15, 80, 30] 34 }] 35 }; 36 37 myChart.setOption(option); 38 } 39 40 </script> 41 </head> 42 <body onload="initChart();"> 43 44 <div id="my_chart" style="width:600px;height:400px;"></div> 45 46 </body> 47 </html>
【2】JSON數據格式
JSON:JavaScript Object Notation,是ECMAScript的標准語法
這個語法是現在所有AJAX或者說數據傳輸的最常用的語法格式。
使用該語法的原因是語法格式簡單,沒有關鍵字來干擾或者占用內存。
解析時各種語言都有很容易的解析方法。
特別是JavaScript,可以直接通過自帶的eval()方法來完成字符串轉換對象或數組的操作。
JSON語法很簡單:
1) 對象:{}
a) 屬性: 屬性名:屬性值,多個屬性之間逗號分隔
b) 方法: 方法名:function(){}
2) 數組:[]
a) 每個元素使用逗號分隔。
【3】AJAX技術
AJAX:Asynchronous JavaScript And Xml,異步的JavaScript和XML,不是新技術,是基於JS和XML技術的應用,但是現在XML一般都被JSON替代了,所以實際上AJAX已經變成了純JS的技術了。
通過AJAX技術,可以在頁面不刷新的情況下,讓前端溝通后台來獲取數據,數據通過JSON格式來返回進行處理。
這樣前后台分離就更徹底了,后台只需要專注於后台接口的開發即可,通過接口返回JSON數據。
前台則是接收了返回的數據后,根據數據完成各種頁面效果的展示。
AJAX技術已經很成熟了,通過固定的4個步驟就可以溝通后台接收結果。
1、 建立核心配置對象XMLHttpRequest
2、 建立與后台的連接
3、 設置返回時的回調函數
當后台執行完結果返回數據時,前台必須有個方法可以接收這個數據,並進行處理,這個方法就是回調函數(Callback)
【4】熱詞統計生成可視化圖表
基於ECharts,我們來把熱詞統計功能,通過這個ECharts圖表的柱狀圖來顯示出來。
1 var xmlHttp ; 2 3 function createXMLHttp() { 4 if (window.XMLHttpRequest != null) { 5 xmlHttp = new XMLHttpRequest(); 6 } else { 7 xmlHttp = new ActiveXObject("Microsoft.xmlhttp"); 8 } 9 } 10 11 function initChart() { 12 // 初始化要顯示的圖標div 13 var myChart = echarts.init(document.getElementById('my_chart')); 14 15 // 這里就需要通過AJAX技術,來調用后台數據操作,接收返回的JSON格式數據 16 // 1 17 createXMLHttp(); 18 // 2 19 xmlHttp.open("get","<%=basePath%>ajax.do"); 20 // 3 21 xmlHttp.onreadystatechange = chartCallback; 22 // 4 23 xmlHttp.send(); 24 } 25 26 function chartCallback() { 27 28 }
之后,需要在后台的ajax.do中進行HDFS的操作,將需要的數據取得,並通過JSON的格式來返回頁面。
@RequestMapping(value = "/ajax.do") public void ajax(HttpServletRequest request, HttpServletResponse response) throws Exception { // 讀取HDFS中的文本數據 ValueSortList list = HDFSUtils.getValues(); StringBuilder builder = new StringBuilder( "{ title: {text: '新浪新聞熱詞分析'},tooltip: {trigger:'axis'},"); builder.append("legend: {data:['詞頻']},xAxis: {data: ["); StringBuilder tempSeries = new StringBuilder(); tempSeries.append("series: [{name:'詞頻',type:'bar',data:["); for (MyKeyValue kv : list.getList()) { builder.append("'"); builder.append(kv.getKey()); builder.append("',"); tempSeries.append(kv.getValue()); tempSeries.append(","); } // 需要把最后一段截取掉 String resultStr = builder.substring(0, builder.length() - 1) + "]}, yAxis: {},"; resultStr += tempSeries.substring(0, tempSeries.length() - 1) + "]}]}"; // 結果返回需要通過PrintWriter來輸出 // 需要先處理返回亂碼 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html"); PrintWriter writer = response.getWriter(); writer.print(resultStr); writer.close(); }
之后編寫頁面回調函數就可以顯示圖表了。
1 function chartCallback() { 2 // 判斷結果是否真正返回 3 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { 4 var resultStr = xmlHttp.responseText; 5 // 轉換為對象 6 var option = eval("("+resultStr+")"); 7 myChart.setOption(option); 8 } 9 }
但是我們會發現,拼寫JSON字符串太麻煩了,因此實際開發中會有很多java用的json數據處理的庫,可以幫助我們簡單的拼寫出json字符串。
例如:org.json
1 @RequestMapping(value = "/ajax.do") 2 public void ajax(HttpServletRequest request, HttpServletResponse response) 3 throws Exception { 4 // 讀取HDFS中的文本數據 5 ValueSortList list = HDFSUtils.getValues(); 6 7 JSONObject obj = new JSONObject(); 8 9 10 JSONObject titleObj = new JSONObject(); 11 titleObj.put("text", "新浪新聞熱詞分析"); 12 obj.put("title", titleObj); 13 14 JSONObject tooltipsObj = new JSONObject(); 15 tooltipsObj.put("trigger", "axis"); 16 obj.put("tooltip", tooltipsObj); 17 18 JSONObject legendObj = new JSONObject(); 19 legendObj.put("data", "詞頻"); 20 obj.put("legend", legendObj); 21 22 obj.put("yAxis", new JSONObject()); 23 24 JSONObject xObj = new JSONObject(); 25 JSONArray seArr = new JSONArray(); 26 JSONObject seObj = new JSONObject(); 27 seObj.put("name", "詞頻"); 28 seObj.put("type", "bar"); 29 JSONArray xDataArr = new JSONArray(); 30 JSONArray seDataArr = new JSONArray(); 31 32 for (MyKeyValue kv : list.getList()) { 33 xDataArr.put(kv.getKey()); 34 seDataArr.put(kv.getValue()); 35 } 36 37 xObj.put("data", xDataArr); 38 seObj.put("data", seDataArr); 39 seArr.put(seObj); 40 41 obj.put("xAxis", xObj); 42 obj.put("series", seArr); 43 44 // 結果返回需要通過PrintWriter來輸出 45 // 需要先處理返回亂碼 46 response.setCharacterEncoding("UTF-8"); 47 response.setContentType("text/html"); 48 PrintWriter writer = response.getWriter(); 49 writer.print(obj.toString()); 50 writer.close(); 51 }
對於這種熱詞分析,前台最好的展示方式應該是文字雲,因此我們這里直接使用文字雲的插件來完成。
首先也要導入js文件。
1 <script type="text/javascript" src="echarts/echarts.js"></script> 2 <script type="text/javascript" src="echarts/echarts-wordcloud.js"></script> 3 <script type="text/javascript"> 4 var xmlHttp ; 5 6 var myChart ; 7 8 var option ; 9 10 function createXMLHttp() { 11 if (window.XMLHttpRequest != null) { 12 xmlHttp = new XMLHttpRequest(); 13 } else { 14 xmlHttp = new ActiveXObject("Microsoft.xmlhttp"); 15 } 16 } 17 18 function initChart() { 19 // 初始化要顯示的圖標div 20 myChart = echarts.init(document.getElementById('my_chart')); 21 22 option = { 23 tooltip: {}, 24 series: [{ 25 type: 'wordCloud', 26 gridSize: 2, 27 sizeRange: [12, 50], 28 rotationRange: [-90, 90], 29 shape: 'pentagon', 30 width: 600, 31 height: 400, 32 drawOutOfBound: true, 33 textStyle: { 34 normal: { 35 color: function () { 36 return 'rgb(' + [ 37 Math.round(Math.random() * 160), 38 Math.round(Math.random() * 160), 39 Math.round(Math.random() * 160) 40 ].join(',') + ')'; 41 } 42 }, 43 emphasis: { 44 shadowBlur: 10, 45 shadowColor: '#333' 46 } 47 } 48 }] 49 }; 50 51 // 這里就需要通過AJAX技術,來調用后台數據操作,接收返回的JSON格式數據 52 // 1 53 createXMLHttp(); 54 // 2 55 xmlHttp.open("get","<%=basePath%>ajax_cloud.do"); 56 // 3 57 xmlHttp.onreadystatechange = chartCallback; 58 // 4 59 xmlHttp.send(); 60 } 61 這里為了簡化后台拼寫JSON,將固定的內容提前設置到option對象中。
之后在后台完成數據的拼寫。
1 @RequestMapping(value="/ajax_cloud.do") 2 public void ajaxCloud(HttpServletRequest request, 3 HttpServletResponse response) throws Exception { 4 ValueSortList list = HDFSUtils.getValues(); 5 6 JSONArray array = new JSONArray(); 7 for (MyKeyValue kv : list.getList()) { 8 JSONObject obj = new JSONObject(); 9 obj.put("name", kv.getKey()); 10 obj.put("value", kv.getValue()); 11 array.put(obj); 12 } 13 14 response.setCharacterEncoding("UTF-8"); 15 response.setContentType("text/html"); 16 PrintWriter writer = response.getWriter(); 17 writer.print(array.toString()); 18 writer.close(); 19 }
最后在回調函數中進行設置處理。
1 function chartCallback() { 2 // 判斷結果是否真正返回 3 if (xmlHttp.readyState == 4 && xmlHttp.status == 200) { 4 var resultStr = xmlHttp.responseText; 5 // 轉換為對象 6 option.series[0].data = eval("("+resultStr+")"); 7 myChart.setOption(option); 8 } 9 }
結果呈現(柱狀圖):
總結:
從前面闡述的網絡爬蟲、HDFS數據讀取、MR數據分析、Lucene垂直搜索引擎,到現在的可視化圖表呈現,一個簡單的大數據處理框架也漸浮水面。
1、數據獲取數據記錄
2、提取清潔數據標注
3、整合聚集數據表達
4、建立模型數據分析
5、合理解釋可視化
雖然並不如真正的大數據處理的數據量之大、之復雜,可視化的程度也僅限於熱詞統計,不過既然授之以漁,而且也算是對此有了一個基本的了解了。
關於本篇給出的兩種可視化處理方法,其實還有很多方式。我只闡述了EFreeChart和ECharts兩種方式,一種生成本地圖片文件類型,一種結合AJAX+JSON可以在網頁上呈現可視化圖表。不過見解很淺薄,僅借本文能夠讓未知的讀者實現一個簡單的圖表展現方式,給內功深厚的高手淡然一笑,我也就心滿意足了。