13_离线计算系统_第12-13天(离线综合案例day1-2)
課程目標
v?理解網站點擊流數據分析的業務背景
v?理解網站點擊流數據分析中常用分析指標的業務含義
v?掌握網站點擊流數據分析系統的技術架構
v?掌握網站點擊流數據分析系統中各環節的技術實現
v?能獨立設計完成一個初步的網站點擊流數據分析系統
網站點擊流數據分析,業務知識,推薦書籍:
《網站分析實戰——如何以數據驅動決策,提升網站價值》王彥平,吳盛鋒編著
1.?網站點擊流數據分析項目業務背景
1.1 什么是點擊流數據
1.1.1 WEB訪問日志
即指用戶訪問網站時的所有訪問、瀏覽、點擊行為數據。比如點擊了哪一個鏈接,在哪個網頁停留時間最多,采用了哪個搜索項、總體瀏覽時間等。而所有這些信息都可被保存在網站日志中。通過分析這些數據,可以獲知許多對網站運營至關重要的信息。采集的數據越全面,分析就能越精準。
2?日志的生成渠道:
1)是網站的web服務器所記錄的web訪問日志;
2)是通過在頁面嵌入自定義的js代碼來獲取用戶的所有訪問行為(比如鼠標懸停的位置,點擊的頁面組件等),然后通過ajax請求到后臺記錄日志;這種方式所能采集的信息最全面;
3)通過在頁面上埋點1像素的圖片,將相關頁面訪問信息請求到后臺記錄日志;
2?日志數據內容詳述:
在實際操作中,有以下幾個方面的數據可以被采集:
1)?訪客的系統屬性特征。比如所采用的操作系統、瀏覽器、域名和訪問速度等。
2)?訪問特征。包括停留時間、點擊的URL等。
3)?來源特征。包括網絡內容信息類型、內容分類和來訪URL等。
4)?產品特征。包括所訪問的產品編號、產品類別、產品顏色、產品價格、產品利潤、產品數量和特價等級等。
以電商某東為例,其點擊日志格式如下:
| GET /log.gif?t=item.010001&m=UA-J2011-1&pin=-&uid=1679790178&sid=1679790178|12&v=je=1$sc=24-bit$sr=1600x900$ul=zh-cn$cs=GBK$dt=【云南白藥套裝】云南白藥 牙膏 180g×3 (留蘭香型)【行情 報價 價格 評測】-京東$hn=item.jd.com$fl=16.0 r0$os=win$br=chrome$bv=39.0.2171.95$wb=1437269412$xb=1449548587$yb=1456186252$zb=12$cb=4$usc=direct$ucp=-$umd=none$uct=-$ct=1456186505411$lt=0$tad=-$sku=1326523$cid1=1316$cid2=1384$cid3=1405$brand=20583$pinid=-&ref=&rm=1456186505411 HTTP/1.1 |
1.1.2 點擊流數據模型
點擊流概念
點擊流這個概念更注重用戶瀏覽網站的整個流程,網站日志中記錄的用戶點擊就像是圖上的“點”,而點擊流更像是將這些“點”串起來形成的“線”。也可以把“點”認為是網站的Page,而“線”則是訪問網站的Session。所以點擊流數據是由網站日志中整理得到的,它可以比網站日志包含更多的信息,從而使基于點擊流數據統計得到的結果更加豐富和高效。
點擊流模型生成
點擊流數據在具體操作上是由散點狀的點擊日志數據梳理所得,從而,點擊數據在數據建模時應該存在兩張模型表(Pageviews和visits):
1、用于生成點擊流的訪問日志表
| 時間戳 | IP地址 | Cookie | Session | 請求URL | Referal |
| 2012-01-01 12:31:12 | 101.0.0.1 | User01 | S001 | /a/... | somesite.com |
| 2012-01-01 12:31:16 | 201.0.0.2 | User02 | S002 | /a/... | - |
| 2012-01-01 12:33:06 | 101.0.0.2 | User03 | S002 | /b/... | baidu.com |
| 2012-01-01 15:16:39 | 234.0.0.3 | User01 | S003 | /c/... | google.com |
| 2012-01-01 15:17:11 | 101.0.0.1 | User01 | S004 | /d/... | /c/... |
| 2012-01-01 15:19:23 | 101.0.0.1 | User01 | S004 | /e/... | /d/.... |
2、頁面點擊流模型Pageviews表
| Session | userid | 時間 | 訪問頁面URL | 停留時長 | 第幾步 |
| S001 | User01 | 2012-01-01 12:31:12 | /a/.... | 30 | 1 |
| S002 | User02 | 2012-01-01 12:31:16 | /a/.... | 10 | 1 |
| S002 | User02 | 2012-01-01 12:33:06 | /b/.... | 110 | 2 |
| S002 | User02 | 2012-01-01 12:35:06 | /e/.... | 30 | 3 |
3、點擊流模型Visits表
| Session | 起始時間 | 結束時間 | 進入頁面 | 離開頁面 | 訪問頁面數 | IP | cookie | referal |
| S001 | 2012-01-01 12:31:12 | 2012-01-01 12:31:12 | /a/... | /a/... | 1 | 101.0.0.1 | User01 | somesite.com |
| S002 | 2012-01-01 12:31:16 | 2012-01-01 12:35:06 | /a/... | /e/... | 3 | 201.0.0.2 | User02 | - |
| S003 | 2012-01-01 12:35:42 | 2012-01-01 12:35:42 | /c/... | /c/... | 1 | 234.0.0.3 | User03 | baidu.com |
| S003 | 2012-01-01 15:16:39 | 2012-01-01 15:19:23 | /c/... | /e/... | 3 | 101.0.0.1 | User01 | google.com |
| …… | …… | …… | …… | …… | …… | …… | …… | …… |
這就是點擊流模型。當WEB日志轉化成點擊流數據的時候,很多網站分析度量的計算變得簡單了,這就是點擊流的“魔力”所在。基于點擊流數據我們可以統計出許多常見的網站分析度量
1.2網站流量數據分析的意義
網站流量統計分析,可以幫助網站管理員、運營人員、推廣人員等實時獲取網站流量信息,并從流量來源、網站內容、網站訪客特性等多方面提供網站分析的數據依據。從而幫助提高網站流量,提升網站用戶體驗,讓訪客更多的沉淀下來變成會員或客戶,通過更少的投入獲取最大化的收入。
如下表:
| 網站的眼睛 | 網站的神經 | 網站的大腦 |
| 訪問者來自哪里? 訪問者在尋找什么? 哪些頁面最受歡迎? 訪問者從哪里進入? | 網頁布局合理嗎? 網站導航清晰嗎? 哪些功能存在問題 網站內容有效嗎 轉化路徑靠譜嗎? | 如何分解目標? 如何分配廣告預算? 如何衡量產品表現? 哪些產品需要優化? 哪些指標需要關注? |
點擊流分析的意義可分為兩大方面:
1、技術上? ?
可以合理修改網站結構及適度分配資源,構建后臺服務器群組,比如
輔助改進網絡的拓撲設計,提高性能
在有高度相關性的節點之間安排快速有效的訪問路徑
幫助企業更好地設計網站主頁和安排網頁內容
2、業務上
1)?幫助企業改善市場營銷決策,如把廣告放在適當的Web頁面上。
2)?優化頁面及業務流程設計,提高流量轉化率。
3)?幫助企業更好地根據客戶的興趣來安排內容。
4)?幫助企業對客戶群進行細分,針對不同客戶制定個性化的促銷策略等。
終極目標是:改善網站(電商、社交、電影、小說)的運營,獲取更高投資回報率(ROI)
1.3 如何進行網站流量分析
流量分析整體來說是一個內涵非常豐富的體系,其整體過程是一個金字塔結構:
?
1.3.1 流量分析模型舉例
通常有以下幾大類的分析需求:
1)網站流量質量分析
流量對于每個網站來說都是很重要,但流量并不是越多越好,應該更加看重流量的質量,換句話來說就是流量可以為我們帶來多少收入。
?
2)網站流量多維度細分
細分是指通過不同維度對指標進行分割,查看同一個指標在不同維度下的表現,進而找出有問題的那部分指標,對這部分指標進行優化。
3)網站內容及導航分析
對于所有網站來說,頁面都可以被劃分為三個類別:
v?導航頁
v?功能頁
v?內容頁
首頁和列表頁都是典型的導航頁;
站內搜索頁面、注冊表單頁面和購物車頁面都是典型的功能頁,
而產品詳情頁、新聞和文章頁都是典型的內容頁。
比如從內容導航分析中,以下兩類行為就是網站運營者不希望看到的行為:
第一個問題:訪問者從導航頁進入,在還沒有看到內容頁面之前就從導航頁離開網站,需要分析導航頁造成訪問者中途離開的原因。
第二個問題:訪問者從導航頁進入內容頁后,又返回到導航頁,說明需要分析內容頁的最初設計,并考慮中內容頁提供交叉的信息推薦
4)網站轉化及漏斗分析
所謂轉化,即網站業務流程中的一個封閉渠道,引導用戶按照流程最終實現業務目標(比如商品成交);而漏斗模型則是指進入渠道的用戶在各環節遞進過程中逐漸流失的形象描述;
對于轉化渠道,主要進行兩部分的分析:
訪問者的流失和迷失
1、阻力和流失
?
造成流失的原因很多,如:
不恰當的商品或活動推薦
對支付環節中專業名詞的解釋、幫助信息等內容不當
2、迷失
造成迷失的主要原因是轉化流量設計不合理,訪問者在特定階段得不到需要的信息,并且不能根據現有的信息作出決策
?
總之,網站流量分析是一門內容非常豐富的學科,本課程中主要關注網站分析過程中的技術運用,更多關于網站流量分析的業務知識可學習推薦資料。
1.3.2 流量分析常見指標
課程中涉及的分析指標主要位于以下幾大方面:
1)基礎分析(PV,IP,UV)
- 趨勢分析:根據選定的時段,提供網站流量數據,通過流量趨勢變化形態,為您分析網站訪客的訪問規律、網站發展狀況提供參考。
- 對比分析:根據選定的兩個對比時段,提供網站流量在時間上的縱向對比報表,幫您發現網站發展狀況、發展規律、流量變化率等。
- 當前在線:提供當前時刻站點上的訪客量,以及最近15分鐘流量、來源、受訪、訪客變化情況等,方便用戶及時了解當前網站流量狀況。
- 訪問明細:提供最近7日的訪客訪問記錄,可按每個PV或每次訪問行為(訪客的每次會話)顯示,并可按照來源、搜索詞等條件進行篩選。 通過訪問明細,用戶可以詳細了解網站流量的累計過程,從而為用戶快速找出流量變動原因提供最原始、最準確的依據。
- 來源分類:提供不同來源形式(直接輸入、搜索引擎、其他外部鏈接、站內來源)、不同來源項引入流量的比例情況。通過精確的量化數據,幫助用戶分析什么類型的來路產生的流量多、效果好,進而合理優化推廣方案。
- 搜索引擎:提供各搜索引擎以及搜索引擎子產品引入流量的比例情況。從搜索引擎引入流量的的角度,幫助用戶了解網站的SEO、SEM效果,從而為制定下一步SEO、SEM計劃提供依據。
- 搜索詞:提供訪客通過搜索引擎進入網站所使用的搜索詞,以及各搜索詞引入流量的特征和分布。幫助用戶了解各搜索詞引入流量的質量,進而了解訪客的興趣關注點、網站與訪客興趣點的匹配度,為優化SEO方案及SEM提詞方案提供詳細依據。
- 最近7日的訪客搜索記錄,可按每個PV或每次訪問行為(訪客的每次會話)顯示,并可按照訪客類型、地區等條件進行篩選。為您搜索引擎優化提供最詳細的原始數據。
- 來路域名:提供具體來路域名引入流量的分布情況,并可按“社會化媒體”、“搜索引擎”、“郵箱”等網站類型對來源域名進行分類。 幫助用戶了解哪類推廣渠道產生的流量多、效果好,進而合理優化網站推廣方案。
- 來路頁面:提供具體來路頁面引入流量的分布情況。 尤其對于通過流量置換、包廣告位等方式從其他網站引入流量的用戶,該功能可以方便、清晰地展現廣告引入的流量及效果,為優化推廣方案提供依據。
- 來源升降榜:提供開通統計后任意兩日的TOP10000搜索詞、來路域名引入流量的對比情況,并按照變化的劇烈程度提供排行榜。 用戶可通過此功能快速找到哪些來路對網站流量的影響比較大,從而及時排查相應來路問題。
2)來源分析
3)受訪分析
- 受訪域名:提供訪客對網站中各個域名的訪問情況。 一般情況下,網站不同域名提供的產品、內容各有差異,通過此功能用戶可以了解不同內容的受歡迎程度以及網站運營成效。
- 受訪頁面:提供訪客對網站中各個頁面的訪問情況。 站內入口頁面為訪客進入網站時瀏覽的第一個頁面,如果入口頁面的跳出率較高則需要關注并優化;站內出口頁面為訪客訪問網站的最后一個頁面,對于離開率較高的頁面需要關注并優化。
- 受訪升降榜:提供開通統計后任意兩日的TOP10000受訪頁面的瀏覽情況對比,并按照變化的劇烈程度提供排行榜。 可通過此功能驗證經過改版的頁面是否有流量提升或哪些頁面有巨大流量波動,從而及時排查相應問題。
- 熱點圖:記錄訪客在頁面上的鼠標點擊行為,通過顏色區分不同區域的點擊熱度;支持將一組頁面設置為"關注范圍",并可按來路細分點擊熱度。 通過訪客在頁面上的點擊量統計,可以了解頁面設計是否合理、廣告位的安排能否獲取更多傭金等。
- 用戶視點:提供受訪頁面對頁面上鏈接的其他站內頁面的輸出流量,并通過輸出流量的高低繪制熱度圖,與熱點圖不同的是,所有記錄都是實際打開了下一頁面產生了瀏覽次數(PV)的數據,而不僅僅是擁有鼠標點擊行為。
- 訪問軌跡:提供觀察焦點頁面的上下游頁面,了解訪客從哪些途徑進入頁面,又流向了哪里。 通過上游頁面列表比較出不同流量引入渠道的效果;通過下游頁面列表了解用戶的瀏覽習慣,哪些頁面元素、內容更吸引訪客點擊。
4)訪客分析
- 地區運營商:提供各地區訪客、各網絡運營商訪客的訪問情況分布。 地方網站、下載站等與地域性、網絡鏈路等結合較為緊密的網站,可以參考此功能數據,合理優化推廣運營方案。
- 終端詳情:提供網站訪客所使用的瀏覽終端的配置情況。 參考此數據進行網頁設計、開發,可更好地提高網站兼容性,以達到良好的用戶交互體驗。
- 新老訪客:當日訪客中,歷史上第一次訪問該網站的訪客記為當日新訪客;歷史上已經訪問過該網站的訪客記為老訪客。 新訪客與老訪客進入網站的途徑和瀏覽行為往往存在差異。該功能可以輔助分析不同訪客的行為習慣,針對不同訪客優化網站,例如為制作新手導航提供數據支持等。
- 忠誠度:從訪客一天內回訪網站的次數(日訪問頻度)與訪客上次訪問網站的時間兩個角度,分析訪客對網站的訪問粘性、忠誠度、吸引程度。 由于提升網站內容的更新頻率、增強用戶體驗與用戶價值可以有更高的忠誠度,因此該功能在網站內容更新及用戶體驗方面提供了重要參考。
- 活躍度:從訪客單次訪問瀏覽網站的時間與網頁數兩個角度,分析訪客在網站上的活躍程度。 由于提升網站內容的質量與數量可以獲得更高的活躍度,因此該功能是網站內容分析的關鍵指標之一。
5)轉化路徑分析
轉化定義
·訪客在您的網站完成了某項您期望的活動,記為一次轉化,如注冊或下載。
目標示例
·獲得用戶目標:在線注冊、創建賬號等。
·咨詢目標:咨詢、留言、電話等。
·互動目標:視頻播放、加入購物車、分享等。
·收入目標:在線訂單、付款等。
轉化數據的應用
·在報告的自定義指標中勾選轉化指標,實時掌握網站的推廣及運營情況。
·結合“全部來源”、“轉化路徑”、“頁面上下游”等報告分析訪問漏斗,提高轉化率。
·對“轉化目標”設置價值,預估轉化收益,衡量ROI。
路徑分析:根據設置的特定路線,監測某一流程的完成轉化情況,算出每步的轉換率和流失率數據,如注冊流程,購買流程等。
轉化類型:
1、頁面
2、事件
2 整體技術流程及架構
2.1 數據處理流程
該項目是一個純粹的數據分析項目,其整體流程基本上就是依據數據的處理流程進行,依此有以下幾個大的步驟:
1)?數據采集
首先,通過頁面嵌入JS代碼的方式獲取用戶訪問行為,并發送到web服務的后臺記錄日志
然后,將各服務器上生成的點擊流日志通過實時或批量的方式匯聚到HDFS文件系統中
當然,一個綜合分析系統,數據源可能不僅包含點擊流數據,還有數據庫中的業務數據(如用戶信息、商品信息、訂單信息等)及對分析有益的外部數據。
2)?數據預處理
通過mapreduce程序對采集到的點擊流數據進行預處理,比如清洗,格式整理,濾除臟數據等
3)?數據入庫
將預處理之后的數據導入到HIVE倉庫中相應的庫和表中
4)?數據分析
項目的核心內容,即根據需求開發ETL分析語句,得出各種統計結果
5)?數據展現
將分析所得數據進行可視化
2.2 項目結構
由于本項目是一個純粹數據分析項目,其整體結構亦跟分析流程匹配,并沒有特別復雜的結構,如下圖:
其中,需要強調的是:
系統的數據分析不是一次性的,而是按照一定的時間頻率反復計算,因而整個處理鏈條中的各個環節需要按照一定的先后依賴關系緊密銜接,即涉及到大量任務單元的管理調度,所以,項目中需要添加一個任務調度模塊
2.3 數據展現
數據展現的目的是將分析所得的數據進行可視化,以便運營決策人員能更方便地獲取數據,更快更簡單地理解數據
3 模塊開發——數據采集
3.1 需求
數據采集的需求廣義上來說分為兩大部分。
1)是在頁面采集用戶的訪問行為,具體開發工作:
1、開發頁面埋點js,采集用戶訪問行為
2、后臺接受頁面js請求記錄日志
此部分工作也可以歸屬為“數據源”,其開發工作通常由web開發團隊負責
2)是從web服務器上匯聚日志到HDFS,是數據分析系統的數據采集,此部分工作由數據分析平臺建設團隊負責,具體的技術實現有很多方式:
2?Shell腳本
優點:輕量級,開發簡單
缺點:對日志采集過程中的容錯處理不便控制
2?Java采集程序
優點:可對采集過程實現精細控制
缺點:開發工作量大
2?Flume日志采集框架
成熟的開源日志采集系統,且本身就是hadoop生態體系中的一員,與hadoop體系中的各種框架組件具有天生的親和力,可擴展性強
3.2 技術選型
在點擊流日志分析這種場景中,對數據采集部分的可靠性、容錯能力要求通常不會非常嚴苛,因此使用通用的flume日志采集框架完全可以滿足需求。
本項目即使用flume來實現日志采集。
3.3 Flume日志采集系統搭建
1、數據源信息
本項目分析的數據用nginx服務器所生成的流量日志,存放在各臺nginx服務器上,如:
/var/log/httpd/access_log.2015-11-10-13-00.log
/var/log/httpd/access_log.2015-11-10-14-00.log
/var/log/httpd/access_log.2015-11-10-15-00.log
/var/log/httpd/access_log.2015-11-10-16-00.log
2、數據內容樣例
數據的具體內容在采集階段其實不用太關心。
| 58.215.204.118 - - [18/Sep/2013:06:51:35 +0000] "GET /wp-includes/js/jquery/jquery.js?ver=1.10.2 HTTP/1.1" 304 0 "http://blog.fens.me/nodejs-socketio-chat/" "Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0" |
字段解析:
1、訪客ip地址: ??58.215.204.118
2、訪客用戶信息: ?- -
3、請求時間:[18/Sep/2013:06:51:35 +0000]
4、請求方式:GET
5、請求的url:/wp-includes/js/jquery/jquery.js?ver=1.10.2
6、請求所用協議:HTTP/1.1
7、響應碼:304
8、返回的數據流量:0
9、訪客的來源url:http://blog.fens.me/nodejs-socketio-chat/
10、訪客所用瀏覽器:Mozilla/5.0 (Windows NT 5.1; rv:23.0) Gecko/20100101 Firefox/23.0
3、日志文件生成規律
基本規律為:
當前正在寫的文件為access_log;
文件體積達到64M,或時間間隔達到60分鐘,即滾動重命名切換成歷史日志文件;
形如: access_log.2015-11-10-13-00.log
當然,每個公司的web服務器日志策略不同,可在web程序的log4j.properties中定義,如下:
| log4j.appender.logDailyFile = org.apache.log4j.DailyRollingFileAppender log4j.appender.logDailyFile.layout = org.apache.log4j.PatternLayout log4j.appender.logDailyFile.layout.ConversionPattern = [%-5p][%-22d{yyyy/MM/dd HH:mm:ssS}][%l]%n%m%n log4j.appender.logDailyFile.Threshold = DEBUG log4j.appender.logDailyFile.ImmediateFlush = TRUE log4j.appender.logDailyFile.Append = TRUE log4j.appender.logDailyFile.File = /var/logs/access_log? log4j.appender.logDailyFile.DatePattern = '.'yyyy-MM-dd-HH-mm'.log' log4j.appender.logDailyFile.Encoding = UTF-8 |
4、Flume采集實現
Flume采集系統的搭建相對簡單:
1、在個web服務器上部署agent節點,修改配置文件
2、啟動agent節點,將采集到的數據匯聚到指定的HDFS目錄中
如下圖:
2?版本選擇:apache-flume-1.6.0
2?采集規則設計:
1、?采集源:nginx服務器日志目錄
2、?存放地:hdfs目錄/home/hadoop/weblogs/
2?采集規則配置詳情
| agent1.sources = source1 agent1.sinks = sink1 agent1.channels = channel1 # Describe/configure spooldir source1 #agent1.sources.source1.type = spooldir #agent1.sources.source1.spoolDir = /var/logs/nginx/ #agent1.sources.source1.fileHeader = false # Describe/configure tail -F source1 #使用exec作為數據源source組件 agent1.sources.source1.type = exec #使用tail -F命令實時收集新產生的日志數據 agent1.sources.source1.command = tail -F /var/logs/nginx/access_log agent1.sources.source1.channels = channel1 #configure host for source #配置一個攔截器插件 agent1.sources.source1.interceptors = i1 agent1.sources.source1.interceptors.i1.type = host #使用攔截器插件獲取agent所在服務器的主機名 agent1.sources.source1.interceptors.i1.hostHeader = hostname #配置sink組件為hdfs agent1.sinks.sink1.type = hdfs #a1.sinks.k1.channel = c1 #agent1.sinks.sink1.hdfs.path=hdfs://hdp-node-01:9000/weblog/flume-collection/%y-%m-%d/%H%M%S #指定文件sink到hdfs上的路徑 agent1.sinks.sink1.hdfs.path= hdfs://hdp-node-01:9000/weblog/flume-collection/%y-%m-%d/%H-%M_%hostname #指定文件名前綴 agent1.sinks.sink1.hdfs.filePrefix = access_log agent1.sinks.sink1.hdfs.maxOpenFiles = 5000 #指定每批下沉數據的記錄條數 agent1.sinks.sink1.hdfs.batchSize= 100 agent1.sinks.sink1.hdfs.fileType = DataStream agent1.sinks.sink1.hdfs.writeFormat =Text #指定下沉文件按1G大小滾動 agent1.sinks.sink1.hdfs.rollSize = 1024*1024*1024 #指定下沉文件按1000000條數滾動 agent1.sinks.sink1.hdfs.rollCount = 1000000 #指定下沉文件按30分鐘滾動 agent1.sinks.sink1.hdfs.rollInterval = 30 #agent1.sinks.sink1.hdfs.round = true #agent1.sinks.sink1.hdfs.roundValue = 10 #agent1.sinks.sink1.hdfs.roundUnit = minute agent1.sinks.sink1.hdfs.useLocalTimeStamp = true # Use a channel which buffers events in memory #使用memory類型channel agent1.channels.channel1.type = memory agent1.channels.channel1.keep-alive = 120 agent1.channels.channel1.capacity = 500000 agent1.channels.channel1.transactionCapacity = 600 # Bind the source and sink to the channel agent1.sources.source1.channels = channel1 agent1.sinks.sink1.channel = channel1 |
啟動采集
在部署了flume的nginx服務器上,啟動flume的agent,命令如下:
bin/flume-ng agent --conf ./conf -f ./conf/weblog.properties.2 -n agent
注意:啟動命令中的 -n 參數要給配置文件中配置的agent名稱
4 模塊開發——數據預處理
4.1 主要目的:
過濾“不合規”數據
格式轉換和規整
根據后續的統計需求,過濾分離出各種不同主題的基礎數據
4.2 實現方式:
開發一個mr程序WeblogPreProcess(內容太長,見工程代碼)
| public class WeblogPreProcess { static class WeblogPreProcessMapper extends Mapper<LongWritable, Text, Text, NullWritable> { Text k = new Text(); NullWritable v = NullWritable.get(); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString(); WebLogBean webLogBean = WebLogParser.parser(line); //WebLogBean productWebLog = WebLogParser.parser2(line); //WebLogBean bbsWebLog = WebLogParser.parser3(line); //WebLogBean cuxiaoBean = WebLogParser.parser4(line); if (!webLogBean.isValid()) return; k.set(webLogBean.toString()); context.write(k, v); //k.set(productWebLog); //context.write(k, v); } } public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); Job job = Job.getInstance(conf); job.setJarByClass(WeblogPreProcess.class); job.setMapperClass(WeblogPreProcessMapper.class); job.setOutputKeyClass(Text.class); job.setOutputValueClass(NullWritable.class); FileInputFormat.setInputPaths(job, new Path(args[0])); FileOutputFormat.setOutputPath(job, new Path(args[1])); job.waitForCompletion(true); } } |
l?運行mr對數據進行預處理
| hadoop jar weblog.jar ?cn.itcast.bigdata.hive.mr.WeblogPreProcess /weblog/input /weblog/preout |
4.3 點擊流模型數據梳理
由于大量的指標統計從點擊流模型中更容易得出,所以在預處理階段,可以使用mr程序來生成點擊流模型的數據
4.3.1 點擊流模型pageviews表
Pageviews表模型數據生成
| 代碼見工程 hadoop jar weblogpreprocess.jar ?\ cn.itcast.bigdata.hive.mr.ClickStreamThree ??\ /user/hive/warehouse/dw_click.db/test_ods_weblog_origin/datestr=2013-09-20/ /test-click/pageviews/ |
表結構:
(表定義及數據導入見6.2節)
4.3.2 點擊流模型visit信息表
注:“一次訪問”=“N次連續請求”
直接從原始數據中用hql語法得出每個人的“次”訪問信息比較困難,可先用mapreduce程序分析原始數據得出“次”信息數據,然后再用hql進行更多維度統計
用MR程序從pageviews數據中,梳理出每一次visit的起止時間、頁面信息
| 代碼見工程 hadoop jar weblogpreprocess.jar cn.itcast.bigdata.hive.mr.ClickStreamVisit /weblog/sessionout /weblog/visitout |
然后,在hive倉庫中建點擊流visit模型表
| drop table if exist click_stream_visit; create table click_stream_visit( session ????string, remote_addr string, inTime ?????string, outTime ????string, inPage ?????string, outPage ????string, referal ????string, pageVisits ?int) partitioned by (datestr string); |
然后,將MR運算得到的visit數據導入visit模型表
| load data inpath '/weblog/visitout' into table click_stream_visit partition(datestr='2013-09-18'); |
5 模塊開發——數據倉庫設計
注:采用星型模型 ???????????????????????????????????????????
5.1?事實表
| 原始數據表:t_origin_weblog | ||
| valid | string | 是否有效 |
| remote_addr | string | 訪客ip |
| remote_user | string | 訪客用戶信息 |
| time_local | string | 請求時間 |
| request | string | 請求url |
| status | string | 響應碼 |
| body_bytes_sent | string | 響應字節數 |
| http_referer | string | 來源url |
| http_user_agent | string | 訪客終端信息 |
| ETL中間表:t_etl_referurl | ||
| valid | string | 是否有效 |
| remote_addr | string | 訪客ip |
| remote_user | string | 訪客用戶信息 |
| time_local | string | 請求時間 |
| request | string | 請求url |
| request_host | string | 請求的域名 |
| status | string | 響應碼 |
| body_bytes_sent | string | 響應字節數 |
| http_referer | string | 來源url |
| http_user_agent | string | 訪客終端信息 |
| valid | string | 是否有效 |
| remote_addr | string | 訪客ip |
| remote_user | string | 訪客用戶信息 |
| time_local | string | 請求時間 |
| request | string | 請求url |
| status | string | 響應碼 |
| body_bytes_sent | string | 響應字節數 |
| http_referer | string | 外鏈url |
| http_user_agent | string | 訪客終端信息 |
| host | string | 外鏈url的域名 |
| path | string | 外鏈url的路徑 |
| query | string | 外鏈url的參數 |
| query_id | string | 外鏈url的參數值 |
| 訪問日志明細寬表:t_ods_access_detail | ||
| valid | string | 是否有效 |
| remote_addr | string | 訪客ip |
| remote_user | string | 訪客用戶信息 |
| time_local | string | 請求時間 |
| request | string | 請求url整串 |
| request_level1 | string | 請求的一級欄目 |
| request_level2 | string | 請求的二級欄目 |
| request_level3 | string | 請求的三級欄目 |
| status | string | 響應碼 |
| body_bytes_sent | string | 響應字節數 |
| http_referer | string | 來源url |
| http_user_agent | string | 訪客終端信息 |
| valid | string | 是否有效 |
| remote_addr | string | 訪客ip |
| remote_user | string | 訪客用戶信息 |
| time_local | string | 請求時間 |
| request | string | 請求url |
| status | string | 響應碼 |
| body_bytes_sent | string | 響應字節數 |
| http_referer | string | 外鏈url |
| http_user_agent | string | 訪客終端信息整串 |
| http_user_agent_browser | string | 訪客終端瀏覽器 |
| http_user_agent_sys | string | 訪客終端操作系統 |
| http_user_agent_dev | string | 訪客終端設備 |
| host | string | 外鏈url的域名 |
| path | string | 外鏈url的路徑 |
| query | string | 外鏈url的參數 |
| query_id | string | 外鏈url的參數值 |
| daystr | string | 日期整串 |
| tmstr | string | 時間整串 |
| month | string | 月份 |
| day | string | 日 |
| hour | string | 時 |
| minute | string | 分 |
| ## | ## | ## |
| mm | string | 分區字段--月 |
| dd | string | 分區字段--日 |
5.2?維度表
| 時間維度 v_year_month_date |
| year |
| month |
| day |
| hour |
| minute |
| 訪客地域維度t_dim_area |
| 北京 |
| 上海 |
| 廣州 |
| 深圳 |
| 河北 |
| 河南 |
| 終端類型維度t_dim_termination |
| uc |
| firefox |
| chrome |
| safari |
| ios |
| android |
| 網站欄目維度 t_dim_section |
| 跳蚤市場 |
| 房租信息 |
| 休閑娛樂 |
| 建材裝修 |
| 本地服務 |
| 人才市場 |
6 模塊開發——ETL??
該項目的數據分析過程在hadoop集群上實現,主要應用hive數據倉庫工具,因此,采集并經過預處理后的數據,需要加載到hive數據倉庫中,以進行后續的挖掘分析。
6.1創建原始數據表
--在hive倉庫中建貼源數據表
| drop table if exists ods_weblog_origin; create table ods_weblog_origin( valid string, remote_addr string, remote_user string, time_local string, request string, status string, body_bytes_sent string, http_referer string, http_user_agent string) partitioned by (datestr string) row format delimited fields terminated by '\001'; |
點擊流模型pageviews表
| drop table if exists ods_click_pageviews; create table ods_click_pageviews( Session string, remote_addr string, time_local string, request string, visit_step string, page_staylong string, http_referer string, http_user_agent string, body_bytes_sent string, status string) partitioned by (datestr string) row format delimited fields terminated by '\001'; |
時間維表創建
| drop table dim_time if exists ods_click_pageviews; create table dim_time( year string, month string, day string, hour string) row format delimited fields terminated by ','; |
6.2導入數據
| 導入清洗結果數據到貼源數據表ods_weblog_origin load data inpath '/weblog/preprocessed/16-02-24-16/' overwrite into table ods_weblog_origin partition(datestr='2013-09-18'); 0: jdbc:hive2://localhost:10000> show partitions ods_weblog_origin; +-------------------+--+ | ????partition ????| +-------------------+--+ | timestr=20151203 ?| +-------------------+--+ 0: jdbc:hive2://localhost:10000> select count(*) from ods_origin_weblog; +--------+--+ | ?_c0 ??| +--------+--+ | 11347 ?| +--------+--+ 導入點擊流模型pageviews數據到ods_click_pageviews表 0: jdbc:hive2://hdp-node-01:10000> load data inpath '/weblog/clickstream/pageviews' overwrite into table ods_click_pageviews partition(datestr='2013-09-18'); 0: jdbc:hive2://hdp-node-01:10000> select count(1) from ods_click_pageviews; +------+--+ | _c0 ?| +------+--+ | 66 ??| +------+--+ 導入點擊流模型visit數據到ods_click_visit表 導入時間維表: load data inpath '/dim_time.txt' into table dim_time; |
6.3 生成ODS層明細寬表?
6.3.1 需求概述? ? ?
?
?
整個數據分析的過程是按照數據倉庫的層次分層進行的,總體來說,是從ODS原始數據中整理出一些中間表(比如,為后續分析方便,將原始數據中的時間、url等非結構化數據作結構化抽取,將各種字段信息進行細化,形成明細表),然后再在中間表的基礎之上統計出各種指標數據
6.3.2 ETL實現
建表——明細表???(源:ods_weblog_origin) ??(目標:ods_weblog_detail)
| drop table ods_weblog_detail; create table ods_weblog_detail( valid ??????????string, --有效標識 remote_addr ????string, --來源IP remote_user ????string, --用戶標識 time_local ?????string, --訪問完整時間 daystr ?????????string, --訪問日期 timestr ????????string, --訪問時間 month ??????????string, --訪問月 day ????????????string, --訪問日 hour ???????????string, --訪問時 request ????????string, --請求的url status ?????????string, --響應碼 body_bytes_sent string, --傳輸字節數 http_referer ???string, --來源url ref_host ???????string, --來源的host ref_path ???????string, --來源的路徑 ref_query ??????string, --來源參數query ref_query_id ???string, --來源參數query的值 http_user_agent string --客戶終端標識 ) partitioned by(datestr string); |
--抽取refer_url到中間表 ?"t_ods_tmp_referurl"?
--將來訪url分離出host ?path ?query ?query id
| drop table if exists t_ods_tmp_referurl; create table t_ ods _tmp_referurl as SELECT a.*,b.* FROM ods_origin_weblog a LATERAL VIEW parse_url_tuple(regexp_replace(http_referer, "\"", ""), 'HOST', 'PATH','QUERY', 'QUERY:id') b as host, path, query, query_id;? |
--抽取轉換time_local字段到中間表明細表 ”t_ ods _detail”
| drop table if exists t_ods_tmp_detail; create table t_ods_tmp_detail as select b.*,substring(time_local,0,10) as daystr, substring(time_local,11) as tmstr, substring(time_local,5,2) as month, substring(time_local,8,2) as day, substring(time_local,11,2) as hour From?t_?ods?_tmp_referurl b; |
以上語句可以改寫成:
| insert into table zs.ods_weblog_detail partition(datestr='$day_01') select c.valid,c.remote_addr,c.remote_user,c.time_local, substring(c.time_local,0,10) as daystr, substring(c.time_local,12) as tmstr, substring(c.time_local,6,2) as month, substring(c.time_local,9,2) as day, substring(c.time_local,11,3) as hour, c.request,c.status,c.body_bytes_sent,c.http_referer,c.ref_host,c.ref_path,c.ref_query,c.ref_query_id,c.http_user_agent from (SELECT a.valid,a.remote_addr,a.remote_user,a.time_local, a.request,a.status,a.body_bytes_sent,a.http_referer,a.http_user_agent,b.ref_host,b.ref_path,b.ref_query,b.ref_query_id FROM zs.ods_weblog_origin a LATERAL VIEW parse_url_tuple(regexp_replace(http_referer, "\"", ""), 'HOST', 'PATH','QUERY', 'QUERY:id') b as ref_host, ref_path, ref_query, ref_query_id) c " 0: jdbc:hive2://localhost:10000> show partitions ods_weblog_detail; +---------------------+--+ | ?????partition ?????| +---------------------+--+ | dd=18%2FSep%2F2013 ?| +---------------------+--+ 1 row selected (0.134 seconds) |
7 模塊開發——統計分析
注:每一種統計指標都可以跟各維度表進行叉乘,從而得出各個維度的統計結果 ?
篇幅限制,叉乘的代碼及注釋信息詳見項目工程代碼文件 ???????????????????
為了在前端展示時速度更快,每一個指標都事先算出各維度結果存入mysql ????
提前準備好維表數據,在hive倉庫中創建相應維表,如:
時間維表:
| create table v_time(year string,month string,day string,hour string) row format delimited fields terminated by ','; load data local inpath '/home/hadoop/v_time.txt' into table v_time; |
在實際生產中,究竟需要哪些統計指標通常由相關數據需求部門人員提出,而且會不斷有新的統計需求產生,以下為網站流量分析中的一些典型指標示例。
1.?PV統計
1.1 多維度統計PV總量
1. 時間維度
| --計算指定的某個小時pvs select count(*),month,day,hour from dw_click.ods_weblog_detail group by month,day,hour; --計算該處理批次(一天)中的各小時pvs drop table dw_pvs_hour; create table dw_pvs_hour(month string,day string,hour string,pvs bigint) partitioned by(datestr string); insert into table dw_pvs_hour partition(datestr='2016-03-18') select a.month as month,a.day as day,a.hour as hour,count(1) as pvs from ods_weblog_detail a where ?a.datestr='2016-03-18' ?group by a.month,a.day,a.hour; 或者用時間維表關聯 |
維度:日
| drop table dw_pvs_day; create table dw_pvs_day(pvs bigint,month string,day string); insert into table dw_pvs_day select count(1) as pvs,a.month as month,a.day as day ?from dim_time a join ods_weblog_detail b on b.dd='18/Sep/2013' and a.month=b.month and a.day=b.day group by a.month,a.day; --或者,從之前算好的小時結果中統計 Insert into table dw_pvs_day Select sum(pvs) as pvs,month,day from dw_pvs_hour group by month,day having day='18'; 結果如下: |
維度:月
| drop table t_display_pv_month; create table t_display_pv_month (pvs bigint,month string); insert into table t_display_pv_month select count(*) as pvs,a.month from t_dim_time a join t_ods_detail_prt b on a.month=b.month group by a.month; |
2. 按終端維度統計pv總量
注:探索數據中的終端類型
| select distinct(http_user_agent) from ods_weblog_detail where http_user_agent like '%Mozilla%' limit 200; |
終端維度:uc
| drop table t_display_pv_terminal_uc; create table t_display_pv_ terminal_uc (pvs bigint,mm string,dd string,hh string); |
終端維度:chrome
| drop table t_display_pv_terminal_chrome; create table t_display_pv_ terminal_ chrome (pvs bigint,mm string,dd string,hh string); |
終端維度:safari
| drop table t_display_pv_terminal_safari; create table t_display_pv_ terminal_ safari (pvs bigint,mm string,dd string,hh string); |
3. 按欄目維度統計pv總量
欄目維度:job
欄目維度:news
欄目維度:bargin
欄目維度:lane
1.2 人均瀏覽頁數
需求描述:比如,今日所有來訪者,平均請求的頁面數
--總頁面請求數/去重總人數
| drop table dw_avgpv_user_d; create table dw_avgpv_user_d( day string, avgpv string); insert into table dw_avgpv_user_d select '2013-09-18',sum(b.pvs)/count(b.remote_addr) from (select remote_addr,count(1) as pvs from ods_weblog_detail where datestr='2013-09-18' group by remote_addr) b; |
1.3 按referer維度統計pv總量
需求:按照來源及時間維度統計PVS,并按照PV大小倒序排序
-- 按照小時粒度統計,查詢結果存入:( "dw_pvs_referer_h" )
| drop table dw_pvs_referer_h; create table dw_pvs_referer_h(referer_url string,referer_host string,month string,day string,hour string,pv_referer_cnt bigint) partitioned by(datestr string); insert into table dw_pvs_referer_h partition(datestr='2016-03-18') select http_referer,ref_host,month,day,hour,count(1) as pv_referer_cnt from ods_weblog_detail group by http_referer,ref_host,month,day,hour having ref_host is not null order by hour asc,day asc,month asc,pv_referer_cnt desc; |
按天粒度統計各來訪域名的訪問次數并排序
| drop table dw_ref_host_visit_cnts_h; create table dw_ref_host_visit_cnts_h(ref_host string,month string,day string,hour string,ref_host_cnts bigint) partitioned by(datestr string); insert into table dw_ref_host_visit_cnts_h partition(datestr='2016-03-18') select ref_host,month,day,hour,count(1) as ref_host_cnts from ods_weblog_detail group by ref_host,month,day,hour having ref_host is not null order by hour asc,day asc,month asc,ref_host_cnts desc; |
注:還可以按來源地域維度、訪客終端維度等計算
1.4 統計pv總量最大的來源TOPN
需求描述:按照時間維度,比如,統計一天內產生最多pvs的來源topN
需要用到row_number函數
以下語句對每個小時內的來訪host次數倒序排序標號,
select ref_host,ref_host_cnts,concat(month,hour,day),
row_number() over (partition by concat(month,hour,day) order by ref_host_cnts desc) as od
from dw_ref_host_visit_cnts_h
效果如下:
根據上述row_number的功能,可編寫Hql取各小時的ref_host訪問次數topn
| drop table dw_pvs_refhost_topn_h; create table dw_pvs_refhost_topn_h( hour string, toporder string, ref_host string, ref_host_cnts string ) partitioned by(datestr string); insert into table zs.dw_pvs_refhost_topn_h partition(datestr='2016-03-18') select t.hour,t.od,t.ref_host,t.ref_host_cnts from ?(select ref_host,ref_host_cnts,concat(month,day,hour) as hour, row_number() over (partition by concat(month,day,hour) order by ref_host_cnts desc) as od from zs.dw_ref_host_visit_cnts_h) t where od<=3; |
結果如下:
注:還可以按來源地域維度、訪客終端維度等計算
2.?受訪分析
統計每日最熱門的頁面top10
| drop table dw_pvs_d; create table dw_pvs_d(day string,url string,pvs string); insert into table dw_pvs_d select '2013-09-18',a.request,a.request_counts from (select request as request,count(request) as request_counts from ods_weblog_detail where datestr='2013-09-18' group by request having request is not null) a order by a.request_counts desc limit 10; 結果如下: |
注:還可繼續得出各維度交叉結果
3.?訪客分析
3.1 獨立訪客
需求描述:按照時間維度比如小時來統計獨立訪客及其產生的pvCnts
對于獨立訪客的識別,如果在原始日志中有用戶標識,則根據用戶標識即很好實現;
此處,由于原始日志中并沒有用戶標識,以訪客IP來模擬,技術上是一樣的,只是精確度相對較低
時間維度:時
| drop table dw_user_dstc_ip_h; create table dw_user_dstc_ip_h( remote_addr string, pvs ?????bigint, hour ????string); insert into table dw_user_dstc_ip_h select remote_addr,count(1) as pvs,concat(month,day,hour) as hour from ods_weblog_detail Where datestr='2013-09-18' group by concat(month,day,hour),remote_addr; |
在此結果表之上,可以進一步統計出,每小時獨立訪客總數,每小時請求次數topn訪客等
如每小時獨立訪客總數:
| select count(1) as dstc_ip_cnts,hour from dw_user_dstc_ip_h group by hour; |
| 練習: 統計每小時請求次數topn的獨立訪客 |
時間維度:月
| select remote_addr,count(1) as counts,month from ods_weblog_detail group by month,remote_addr; |
時間維度:日
| select remote_addr,count(1) as counts,concat(month,day) as day from ods_weblog_detail Where dd='18/Sep/2013' group by concat(month,day),remote_addr; |
注:還可以按來源地域維度、訪客終端維度等計算
3.2 每日新訪客
需求描述:將每天的新訪客統計出來
實現思路:創建一個去重訪客累積表,然后將每日訪客對比累積表
時間維度:日
| --歷日去重訪客累積表 drop table dw_user_dsct_history; create table dw_user_dsct_history( day string, ip string ) partitioned by(datestr string); --每日新用戶追加到累計表 drop table dw_user_dsct_history; create table dw_user_dsct_history( day string, ip string ) partitioned by(datestr string); --每日新用戶追加到累計表 insert into table dw_user_dsct_history partition(datestr='2013-09-19') select tmp.day as day,tmp.today_addr as new_ip from ( select today.day as day,today.remote_addr as today_addr,old.ip as old_addr from (select distinct remote_addr as remote_addr,"2013-09-19" as day from ods_weblog_detail where datestr="2013-09-19") today left outer join dw_user_dsct_history old on today.remote_addr=old.ip ) tmp where tmp.old_addr is null; |
驗證:
| select count(distinct remote_addr) from ods_weblog_detail; -- 1005 select count(1) from dw_user_dsct_history where prtflag_day='18/Sep/2013'; --845 select count(1) from dw_user_dsct_history where prtflag_day='19/Sep/2013'; --160 |
時間維度:月
| 類似日粒度算法 |
注:還可以按來源地域維度、訪客終端維度等計算
4.?Visit分析(點擊流模型)
4.2 回頭/單次訪客統計
需求描述:查詢今日所有回頭訪客及其訪問次數
實現思路:上表中出現次數>1的訪客,即回頭訪客;反之,則為單次訪客
| drop table dw_user_returning; create table dw_user_returning( day string, remote_addr string, acc_cnt string) partitioned by (datestr string); insert overwrite table dw_user_returning partition(datestr='2013-09-18') select tmp.day,tmp.remote_addr,tmp.acc_cnt from (select '2013-09-18' as day,remote_addr,count(session) as acc_cnt from click_stream_visit group by remote_addr) tmp where tmp.acc_cnt>1; |
4.3 人均訪問頻次
需求:統計出每天所有用戶訪問網站的平均次數(visit)
總visit數/去重總用戶數
| select sum(pagevisits)/count(distinct remote_addr) from click_stream_visit partition(datestr='2013-09-18'); |
5. Visit分析另一種實現方式
5.1?mr程序識別出訪客的每次訪問
a.) 首先開發MAPREDUCE程序:UserStayTime
| 注:代碼略長,見項目工程代碼 |
b.) 提交MAPREDUCE程序進行運算
| [hadoop@hdp-node-01 ~]$ hadoop jar weblog.jar cn.itcast.bigdata.hive.mr.UserStayTime /weblog/input /weblog/stayout4 --導入hive表("t_display_access_info")中 drop table ods_access_info; create table ods_access_info(remote_addr string,firt_req_time string,last_req_time string,stay_long string) partitioned by(prtflag_day string) row format delimited fields terminated by '\t'; load data inpath '/weblog/stayout4' into table ods_access_info partition(prtflag_day='18/Sep/2013'); 創建表時stay_long使用的string類型,但是在后續過程中發現還是用bigint更好,進行表修改 alter table ods_access_info change column stay_long stay_long bigint; |
5.2 將mr結果導入訪客訪問信息表 "t_display_access_info"
由于有一些訪問記錄是單條記錄,mr程序處理處的結果給的時長是0,所以考慮給單次請求的停留時間一個默認市場30秒
| drop table dw_access_info; create table dw_access_info(remote_addr string,firt_req_time string,last_req_time string,stay_long string) partitioned by(prtflag_day string); insert into table dw_access_info partition(prtflag_day='19/Sep/2013') select remote_addr,firt_req_time,last_req_time, case stay_long when 0 then 30000 else stay_long end as stay_long from ods_access_info where prtflag_day='18/Sep/2013'; |
在訪問信息表的基礎之上,可以實現更多指標統計,如:
統計所有用戶停留時間平均值,觀察用戶在站點停留時長的變化走勢
select prtflag_day as dt,avg(stay_long) as avg_staylong
from dw_access_info group by prtflag_day;
5.3 回頭/單次訪客統計
注:從上一步驟得到的訪問信息統計表“dw_access_info”中查詢
--回頭訪客訪問信息表 "dw_access_info_htip"
| drop table dw_access_info_htip; create table dw_access_info_htip(remote_addr string, firt_req_time string, last_req_time string, stay_long string,acc_counts string) partitioned by(prtflag_day string); insert into table dw_access_info_htip partition(prtflag_day='18/Sep/2013') select b.remote_addr,b.firt_req_time,b.last_req_time,b.stay_long,a.acc_counts from (select remote_addr,count(remote_addr) as acc_counts from dw_access_info where prtflag_day='18/Sep/2013' group by remote_addr having acc_counts>1) a join dw_access_info b on a.remote_addr = b.remote_addr; |
--單次訪客訪問信息表 "dw_access_info_dcip"
| drop table dw_access_info_dcip; create table dw_access_info_dcip(remote_addr string, firt_req_time string, last_req_time string, stay_long string,acc_counts string) partitioned by(prtflag_day string); insert into table dw_access_dcip partition(prtflag_day='18/Sep/2013') select b.remote_addr,b.firt_req_time,b.last_req_time,b.stay_long,a.acc_counts from (select remote_addr,count(remote_addr) as acc_counts from dw_access_info where prtflag_day='18/Sep/2013' group by remote_addr having acc_counts<2) a join dw_access_info b on a.remote_addr = b.remote_addr; |
在回頭/單詞訪客信息表的基礎之上,可以實現更多統計指標,如:
--當日回頭客占比
| drop table dw_htpercent_d; create table dw_htpercent_d(day string,ht_percent float); Insert into table dw_htpercent_d select '18/Sep/2013',(tmp_ht.ht/tmp_all.amount)*100 from (select count( distinct a.remote_addr) as ht from dw_access_info_htip a where prtflag_day='18/Sep/2013') tmp_ht Join (select count(distinct b.remote_addr) as amount from dw_access_info b where prtflag_day='18/Sep/2013') tmp_all; |
5.4 人均訪問頻度
--總訪問次數/去重總人數,從訪客次數匯總表中查詢
| select avg(user_times.counts) as user_access_freq from (select remote_addr,counts from t_display_htip union all select remote_addr,counts from t_display_access_dcip) user_times; --或直接從 訪問信息表 t_display_access_info 中查詢 select avg(a.acc_cts) from (select remote_addr,count(*) as acc_cts from dw_access_info group by remote_addr) a; |
6.關鍵路徑轉化率分析——漏斗模型
轉化:在一條指定的業務流程中,各個步驟的完成人數及相對上一個步驟的百分比
6.1 需求分析
6.2 模型設計
定義好業務流程中的頁面標識,下例中的步驟為:
Step1、 ?/item%
Step2、 ?/category
Step3、 ?/order
Step4、 ?/index
6.3 開發實現
分步驟開發:
1、查詢每一個步驟的總訪問人數
| create table route_numbs as select 'step1' as step,count(distinct remote_addr) ?as numbs from ods_click_pageviews where request like '/item%' union select 'step2' as step,count(distinct remote_addr) as numbs from ods_click_pageviews where request like '/category%' union select 'step3' as step,count(distinct remote_addr) as numbs from ods_click_pageviews where request like '/order%' union select 'step4' as step,count(distinct remote_addr) ?as numbs from ods_click_pageviews where request like '/index%'; |
2、查詢每一步驟相對于路徑起點人數的比例
思路:利用join
| select rn.step as rnstep,rn.numbs as rnnumbs,rr.step as rrstep,rr.numbs as rrnumbs ?from route_num rn inner join route_num rr |
| select tmp.rnstep,tmp.rnnumbs/tmp.rrnumbs as ratio from ( select rn.step as rnstep,rn.numbs as rnnumbs,rr.step as rrstep,rr.numbs as rrnumbs ?from route_num rn inner join route_num rr) tmp where tmp.rrstep='step1'; |
3、查詢每一步驟相對于上一步驟的漏出率
| select tmp.rrstep as rrstep,tmp.rrnumbs/tmp.rnnumbs as ration from ( select rn.step as rnstep,rn.numbs as rnnumbs,rr.step as rrstep,rr.numbs as rrnumbs ?from route_num rn inner join route_num rr) tmp where cast(substr(tmp.rnstep,5,1) as int)=cast(substr(tmp.rrstep,5,1) as int)-1 |
4、匯總以上兩種指標
| select abs.step,abs.numbs,abs.ratio as abs_ratio,rel.ratio as rel_ratio from ( select tmp.rnstep as step,tmp.rnnumbs as numbs,tmp.rnnumbs/tmp.rrnumbs as ratio from ( select rn.step as rnstep,rn.numbs as rnnumbs,rr.step as rrstep,rr.numbs as rrnumbs ?from route_num rn inner join route_num rr) tmp where tmp.rrstep='step1' ) abs left outer join ( select tmp.rrstep as step,tmp.rrnumbs/tmp.rnnumbs as ratio from ( select rn.step as rnstep,rn.numbs as rnnumbs,rr.step as rrstep,rr.numbs as rrnumbs ?from route_num rn inner join route_num rr) tmp where cast(substr(tmp.rnstep,5,1) as int)=cast(substr(tmp.rrstep,5,1) as int)-1 ) rel on abs.step=rel.step |
8 模塊開發——結果導出
報表統計結果,由sqoop從hive表中導出,示例如下,詳見工程代碼
| sqoop export \ --connect jdbc:mysql://hdp-node-01:3306/webdb --username root --password root ?\ --table click_stream_visit ?\ --export-dir /user/hive/warehouse/dw_click.db/click_stream_visit/datestr=2013-09-18 \ --input-fields-terminated-by '\001' |
9 模塊開發——工作流調度
注:將整個項目的數據處理過程,從數據采集到數據分析,再到結果數據的導出,一系列的任務分割成若干個oozie的工作流,并用coordinator進行協調
工作流定義示例
Ooize配置片段示例,詳見項目工程
1、日志預處理mr程序工作流定義
| <workflow-app name="weblogpreprocess" xmlns="uri:oozie:workflow:0.4"> <start to="firstjob"/> <action name="firstjob"> <map-reduce> <job-tracker>${jobTracker}</job-tracker> <name-node>${nameNode}</name-node> <prepare> <delete path="${nameNode}/${outpath}"/> </prepare> <configuration> <property> <name>mapreduce.job.map.class</name> <value>cn.itcast.bigdata.hive.mr.WeblogPreProcess$WeblogPreProcessMapper</value> </property> <property> <name>mapreduce.job.output.key.class</name> <value>org.apache.hadoop.io.Text</value> </property> <property> <name>mapreduce.job.output.value.class</name> <value>org.apache.hadoop.io.NullWritable</value> </property> <property> <name>mapreduce.input.fileinputformat.inputdir</name> <value>${inpath}</value> </property> <property> <name>mapreduce.output.fileoutputformat.outputdir</name> <value>${outpath}</value> </property> <property> <name>mapred.mapper.new-api</name> <value>true</value> </property> <property> <name>mapred.reducer.new-api</name> <value>true</value> </property> </configuration> </map-reduce> <ok to="end"/> <error to="kill"/> |
2、數據加載etl工作流定義:
| <workflow-app xmlns="uri:oozie:workflow:0.5" name="hive2-wf"> <start to="hive2-node"/> <action name="hive2-node"> <hive2 xmlns="uri:oozie:hive2-action:0.1"> <job-tracker>${jobTracker}</job-tracker> <name-node>${nameNode}</name-node> <configuration> <property> <name>mapred.job.queue.name</name> <value>${queueName}</value> </property> </configuration> <jdbc-url>jdbc:hive2://hdp-node-01:10000</jdbc-url> <script>script.q</script> <param>input=/weblog/outpre2</param> </hive2> <ok to="end"/> <error to="fail"/> </action> <kill name="fail"> <message>Hive2 (Beeline) action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message> </kill> <end name="end"/> </workflow-app> |
3、數據加載工作流所用hive腳本:
| create database if not exists dw_weblog; use dw_weblog; drop table if exists t_orgin_weblog; create table t_orgin_weblog(valid string,remote_addr string, remote_user string, time_local string, request string, status string, body_bytes_sent string, http_referer string, http_user_agent string) row format delimited fields terminated by '\001'; load data inpath '/weblog/preout' overwrite into table t_orgin_weblog; drop table if exists t_ods_detail_tmp_referurl; create table t_ods_detail_tmp_referurl as SELECT a.*,b.* FROM t_orgin_weblog a LATERAL VIEW parse_url_tuple(regexp_replace(http_referer, "\"", ""), 'HOST', 'PATH','QUERY', 'QUERY:id') b as host, path, query, query_id; drop table if exists t_ods_detail; create table t_ods_detail as select b.*,substring(time_local,0,11) as daystr, substring(time_local,13) as tmstr, substring(time_local,4,3) as month, substring(time_local,0,2) as day, substring(time_local,13,2) as hour from t_ods_detail_tmp_referurl b; drop table t_ods_detail_prt; create table t_ods_detail_prt( valid ?????????????????string, remote_addr ???????????string, remote_user ???????????string, time_local ????????????string, request ???????????????string, status ????????????????string, body_bytes_sent ???????string, http_referer ??????????string, http_user_agent ???????string, host ??????????????????string, path ??????????????????string, query ?????????????????string, query_id ??????????????string, daystr ????????????????string, tmstr ?????????????????string, month ?????????????????string, day ???????????????????string, hour ??????????????????string) partitioned by (mm string,dd string); insert into table t_ods_detail_prt partition(mm='Sep',dd='18') select * from t_ods_detail where daystr='18/Sep/2013'; insert into table t_ods_detail_prt partition(mm='Sep',dd='19') select * from t_ods_detail where daystr='19/Sep/2013'; |
更多工作流及hql腳本定義詳見項目工程
工作流單元測試
1、工作流定義配置上傳
| [hadoop@hdp-node-01 wf-oozie]$ hadoop fs -put hive2-etl /user/hadoop/oozie/myapps/ [hadoop@hdp-node-01 wf-oozie]$ hadoop fs -put hive2-dw /user/hadoop/oozie/myapps/ [hadoop@hdp-node-01 wf-oozie]$ ll total 12 drwxrwxr-x. 2 hadoop hadoop 4096 Nov 23 16:32 hive2-dw drwxrwxr-x. 2 hadoop hadoop 4096 Nov 23 16:32 hive2-etl drwxrwxr-x. 3 hadoop hadoop 4096 Nov 23 11:24 weblog [hadoop@hdp-node-01 wf-oozie]$ export OOZIE_URL=http://localhost:11000/oozie |
2、工作流單元提交啟動
oozie job -D inpath=/weblog/input -D outpath=/weblog/outpre -config weblog/job.properties ?-run
啟動etl的hive工作流
oozie job -config hive2-etl/job.properties ?-run
啟動pvs統計的hive工作流
oozie job -config hive2-dw/job.properties ?-run
3、工作流coordinator配置(片段)
多個工作流job用coordinator組織協調:
| [hadoop@hdp-node-01 hive2-etl]$ ll total 28 -rw-rw-r--. 1 hadoop hadoop ?265 Nov 13 16:39 config-default.xml -rw-rw-r--. 1 hadoop hadoop ?512 Nov 26 16:43 coordinator.xml -rw-rw-r--. 1 hadoop hadoop ?382 Nov 26 16:49 job.properties drwxrwxr-x. 2 hadoop hadoop 4096 Nov 27 11:26 lib -rw-rw-r--. 1 hadoop hadoop 1910 Nov 23 17:49 script.q -rw-rw-r--. 1 hadoop hadoop ?687 Nov 23 16:32 workflow.xml |
l?config-default.xml
| <configuration> <property> <name>jobTracker</name> <value>hdp-node-01:8032</value> </property> <property> <name>nameNode</name> <value>hdfs://hdp-node-01:9000</value> </property> <property> <name>queueName</name> <value>default</value> </property> </configuration> |
l?job.properties
| user.name=hadoop oozie.use.system.libpath=true oozie.libpath=hdfs://hdp-node-01:9000/user/hadoop/share/lib oozie.wf.application.path=hdfs://hdp-node-01:9000/user/hadoop/oozie/myapps/hive2-etl/ |
l?workflow.xml
| <workflow-app xmlns="uri:oozie:workflow:0.5" name="hive2-wf"> <start to="hive2-node"/> <action name="hive2-node"> <hive2 xmlns="uri:oozie:hive2-action:0.1"> <job-tracker>${jobTracker}</job-tracker> <name-node>${nameNode}</name-node> <configuration> <property> <name>mapred.job.queue.name</name> <value>${queueName}</value> </property> </configuration> <jdbc-url>jdbc:hive2://hdp-node-01:10000</jdbc-url> <script>script.q</script> <param>input=/weblog/outpre2</param> </hive2> <ok to="end"/> <error to="fail"/> </action> <kill name="fail"> <message>Hive2 (Beeline) action failed, error message[${wf:errorMessage(wf:lastErrorNode())}]</message> </kill> <end name="end"/> </workflow-app> |
l?coordinator.xml
| <coordinator-app name="cron-coord" frequency="${coord:minutes(5)}" start="${start}" end="${end}" timezone="Asia/Shanghai" xmlns="uri:oozie:coordinator:0.2"> <action> <workflow> <app-path>${workflowAppUri}</app-path> <configuration> <property> <name>jobTracker</name> <value>${jobTracker}</value> </property> <property> <name>nameNode</name> <value>${nameNode}</value> </property> <property> <name>queueName</name> <value>${queueName}</value> </property> </configuration> </workflow> </action> </coordinator-app> |
10 模塊開發——數據展示
在企業的數據分析系統中,前端展現工具有很多,
l?獨立部署專門系統的方式:以Business Objects(BO,Crystal Report),Heperion(Brio),Cognos等國外產品為代表的,它們的服務器是單獨部署的,與應用程序之間通過某種協議溝通信息
l?有WEB程序展現方式:通過獨立的或者嵌入式的java web系統來讀取報表統計結果,以網頁的形式對結果進行展現,如,100%純Java的潤乾報表
本日志分析項目采用自己開發web程序展現的方式
u?Web展現程序采用的技術框架:
Jquery + Echarts + springmvc + spring + mybatis + mysql
u?展現的流程:
Web程序工程結構
采用maven管理工程,引入SSH框架依賴及jquery+echarts的js庫
Web程序的實現代碼
采用典型的MVC架構實現
| 頁面 | HTML + JQUERY + ECHARTS |
| Controller | SpringMVC |
| Service | Service |
| DAO | Mybatis |
| 數據庫 | Mysql |
代碼詳情見項目工程
代碼示例:ChartServiceImpl?
| @Service("chartService") public class ChartServiceImpl implements IChartService { @Autowired IEchartsDao iEchartsDao; public EchartsData getChartsData() { List<Integer> xAxiesList = iEchartsDao.getXAxiesList(""); List<Integer> pointsDataList = iEchartsDao.getPointsDataList(""); EchartsData data = new EchartsData(); ToolBox toolBox = EchartsOptionUtil.getToolBox(); Serie serie = EchartsOptionUtil.getSerie(pointsDataList); ArrayList<Serie> series = new ArrayList<Serie>(); series.add(serie); List<XAxi> xAxis = EchartsOptionUtil.getXAxis(xAxiesList); List<YAxi> yAxis = EchartsOptionUtil.getYAxis(); HashMap<String, String> title = new HashMap<String, String>(); title.put("text", "pvs"); title.put("subtext", "超級pvs"); HashMap<String, String> tooltip = new HashMap<String, String>(); tooltip.put("trigger", "axis"); HashMap<String, String[]> legend = new HashMap<String, String[]>(); legend.put("data", new String[]{"pv統計"}); data.setTitle(title); data.setTooltip(tooltip); data.setLegend(legend); data.setToolbox(toolBox); data.setCalculable(true); data.setxAxis(xAxis); data.setyAxis(yAxis); data.setSeries(series); return data; } public List<HashMap<String, Integer>> getGaiKuangList(String date) throws ParseException{ HashMap<String, Integer> gaiKuangToday = iEchartsDao.getGaiKuang(date); SimpleDateFormat sf = new SimpleDateFormat("MMdd"); Date parse = sf.parse(date); Calendar calendar = Calendar.getInstance(); calendar.setTime(parse); calendar.add(Calendar.DAY_OF_MONTH, -1); Date before = calendar.getTime(); String beforeString = sf.format(before); System.out.println(beforeString); HashMap<String, Integer> gaiKuangBefore = iEchartsDao.getGaiKuang(beforeString); ArrayList<HashMap<String, Integer>> gaiKuangList = new ArrayList<HashMap<String, Integer>>(); gaiKuangList.add(gaiKuangToday); gaiKuangList.add(gaiKuangBefore); return gaiKuangList; } public static void main(String[] args) { ChartServiceImpl chartServiceImpl = new ChartServiceImpl(); EchartsData chartsData = chartServiceImpl.getChartsData(); Gson gson = new Gson(); String json = gson.toJson(chartsData); System.out.println(json); } } |
Web程序的展現效果
網站概況
流量分析
來源分析
訪客分析
總結
以上是生活随笔為你收集整理的13_离线计算系统_第12-13天(离线综合案例day1-2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java Ipv6格式化冒分十六进制 工
- 下一篇: 国外大佬的 4 个项目 yyds