摘要:欲練數據神功,必先揮刀……,嗯,先紮好馬步吧!編寫SQL語句,是數據統計分析最基本的能力了。以爲SQL的自定義功能太弱了,或者你以爲就算是Hive調用外部腳本也麻煩了,那麼咱們上當前最熱的Spark
00 引言
2016就要來了,避不及,躲不開。新一年來以前,仍是有一件值得高興的事情,那即是年終獎了。java
公司大了,什麼樣的人都有。嗯嗯……,說錯了,是人大了,什麼樣的公司都進。嗯嗯……,仍是不對。是公司大了,員工多了,要統計每一個員工每一年寫的代碼數量。以此來分配年終獎了。python
假設有以下數據示例,第一列爲員工的ID,第二列爲年份,第三列爲代碼數。sql
126882,2005,5
126882,2013,16
127305,2010,2
127305,2014,29
128194,2012,1
128194,2013,161shell
欲練數據神功,必先揮刀……,嗯,先紮好馬步吧。下面的7個步驟,是練好數據基本功的一些方法。數據庫
01 MySQL版本
編寫SQL語句,是數據統計分析最基本的能力了。通常統計分析中,掌握好join語句分析便可,其它數據庫相關的備份、恢復、存儲過程之類的,基本上不多用到。編程
用一個join來實現需求,取出數據:數組
select a.* from table as a join table as b on a.id=b.id where a.count>b.count;
本例中是本身和本身join,最簡單的inner join,將兩個表中按id相同的行進行關聯起來,最後按條件進行篩選須要的數據便可。須要注意,MySQL中的臨時表,是沒有辦法本身join本身的。ruby
02 Bash版本
咱們一般會以SQL爲經常使用工具,若是SQL不能知足你的需求,或者實現起來比較麻煩,你能夠導出成csv格式的文本文件。bash
Shell命令比一般想像的要強大,用好Shell命令,不少時候也能夠方便的處理問題。數據結構
join -t',' -1 1 -2 1 data.csv data.csv | awk -F',' '$3>$5{print $1,$4,$5}'
這條命令看起來估計算最簡潔了的,但仍是用了兩個命令。join也是一個很是神奇的命令,能夠完成關係數據庫的join功能,包括left join,right join,outer join,inner join。
本例中指定了鏈接的字段,參數「-1 1 -2 1」分別指定第一個、第二個文件的第1個字段做爲關聯字段。將鏈接的數據使用awk進行簡單的過濾處理。join命令至關於SQL中的join的功能,而附帶的awk至關於SQL中的where條件,進行數據篩選。
03 Awk版本
在shell命令行下,還有一個強大的數據處理工具:AWK,強大到能獨立完成不少數據處理和分析的任務,後面會有單獨的篇章來介紹,請持續關注。
#!/usr/local/bin/awk -f BEGIN{FS=","} { id = int($1) year = int($2) count = int($3) print id,year,count if(yc[id]["count"] < count){ yc[id]["year"] = year yc[id]["count"] = count } } END{ for(x in yc){ printf("%s,%s,%s\n", x, yc[x]["year"], yc[x]["count"]) } }
上面一段簡單的Awk代碼,把Awk的一些基本概念都用上了。也算是「麻雀雖小,五臟俱全」了。涉及Awk的三段式代碼結構,數組與賦值,條件判斷與循環等編程基礎概念。
由於awk是按行讀入文件,所以咱們的思想就是將當前的最大的值存儲起來,再讀入下一行,若是比當前最大值大,就更新,不然繼續讀入一行。
處理文件文件的方式,天然與數據庫的join思想不同,但你須要習慣這種方式,由於這種處理文件文件的方式,也是不少NoSQL的處理方式。
04 Python版本
前面幾篇文章都安利了Python,處理這種簡單的統計,咱們也能夠用Python來試試。
import sys last_id = None for line in sys.stdin: idx, year, count = line.strip().split(',') if idx == last_id: if count > most_count: most_year, most_count = year, count else: if last_id: print '%s,%s,%s' %(last_id, most_year, most_count) last_id = idx most_count = 0 if idx == last_id: print '%s,%s,%s' %(last_id, most_year, most_count)
處理的方式仍是同樣,按行讀取文件並存儲和記錄,但邏輯實現起來感受稍微有點繞而已。沒有用數組或字典之類的來存儲數據。
還須要注意,這個程序是須要對文件進行按id排序的,由於代碼處理的是連續的行,而且假定相同的id是在連續的行上。
固然,你確定會說,這個代碼寫得有些雜亂,不符合一般的思路。之因此寫成這樣,是由於咱們後面在分佈式環境中還要用。
05 Hive版本
也許你會想,若是文件很大,很大,很大(重要的說三遍嗎?),那麼如何處理呢?立刻就2016了,那麼你聽過安利嗎?哦不對,是大數據,一個已經被說到爛透了的詞。單機不能知足你的需求,那麼使用分佈式。
假設Facebook有20億用戶,統計每一個用戶在天天中,各自發的消息的最多的那天和發送的條數,假設全部用戶,天天都發消息。20億用戶,按Facebook上線10年算,3600天,共72000億條記錄,夠大了吧!分別找出每一個用戶發消息最多的那天和發消息的次數。
且來看看,由Facebook開源出來的Hive數據倉庫,如何處理!
-- 見MySQL版本
你沒有看錯,我也沒有騙你,還真是和MySQL用一樣的代碼。固然,Hive有本身的優化之類的,暫時先無論。
這個地方,有個前提,你只須要把那72000億條數據,存放到HDFS文件系統上,而後創建一個外部表和HDFS文件進行關聯,而後輸入和MySQL一樣的語句,Hive引擎會天然將SQL語句轉換爲下層的map-reduce代碼運行。
重要的是,你的Hadoop集羣有多強大,這個Hive語句就能達到多強大。還不用本身寫map-reduce程序,就是分析師最熟悉的SQL語句。
若是你以爲Hive也是SQL語句,有些自定義的函數或者方法比較麻煩,那麼Hive還能夠調用外部的腳本,只要是可執行腳本都行:python、ruby、bash、scala、java、lisp隨便你愛好。
06 Spark版本
若是你以爲用Hive太Low了,跟不上時代的步伐了。或者,你以爲SQL的自定義功能太弱了,或者你以爲就算是調用外部腳本也很麻煩,那麼咱們上當前最熱的Spark。
from pyspark import SparkContext sc = SparkContext() data = sc.textFile('data.csv') data = data.map(lambda x: x.split(',')).map(lambda x: (x[0], (x[1], int(x[2])))).groupByKey().mapValues(lambda value: sorted(value, lambda x, y: cmp(x[1], y[1]), reverse=True)[0]) for item in data.collect(): print '%s,%s,%s' % (item[0], item[1][0], item[1][1])
Spark支持幾種編程接口,Scala、Java、Python,最近也開始支持R了。
上面雖然連續用了好幾個map,但原理卻很是簡單,和python的map功能相似。惟一用了一個groupByKey功能,將相同的id聚合在一塊兒,剩下的屬性放在一個列表裏面。對這個列表進行排序,取count最多的次數和年份,最後輸出。
邏輯夠簡單,代碼也夠簡潔。Spark強大的便利利益於Scala強大的數據結構與數據處理能力。
07 map-reduce版本
若是你追求徹底的原生,或者追求徹底的可控性。但又不熟悉Java代碼,那麼仍是能夠用Python來寫map-reduce程序。
# mapper.py見python版本 # reducer.py見python版本
又一個大騙子!
經過Hadoop的Streaming接口來進行調用,只須要自定義mapper和reducer程序便可。上面的mapper和reducer能夠直接用純粹Python的單機版本。
輸入是一些id,year,count行,輸出仍是一樣的數據結構。只是在程序中,把當前這個程序的輸入中,每一個id最多的count和year找出來了。數據量已經減小了,每一個id只會保留最大的一條數據。
分佈式最基本的原理就是數據分塊,在map階段,對每一個塊的數據調用mapper程序,求出當前塊裏面每一個id的最大count和year找出來。把這些輸出做爲reducer的輸入,再求一次最大值,那麼找出的即是全局的最大值。
08 結尾
數據分析基本功,按上面七個方面,紮好了馬步,離數據神功第一層也不遠了。
不要興奮,也許會忽然冒出來一個小姑娘,告訴你說:切,上面的功能我用Excel也能夠完美的實現。
固然能夠了,聰明如你,Excel還能實現比這強大得多的功能。
理論上來講,上面全部工具都能完成任何統計分析需求。只是不一樣的地方,實現的方式各有不一樣,有的複雜,有的簡單,有的快,有的慢而已。選擇你以爲最簡單的方式,搞定任務便可。