電商日誌流量分析
1. 網站點選流資料分析專案業務背景
1.1 什麼是點選流資料
1.1.1 WEB訪問日誌
即指使用者訪問網站時的所有訪問、瀏覽、點選行為資料。比如點選了哪一個連結,在哪個網頁停留時間最多,採用了哪個搜尋項、總體瀏覽時間等。而所有這些資訊都可被儲存在網站日誌中。通過分析這些資料,可以獲知許多對網站運營至關重要的資訊。採集的資料越全面,分析就能越精準。 日誌的生成渠道: 1)是網站的web伺服器所記錄的web訪問日誌; 2)是通過在頁面嵌入自定義的js程式碼來獲取使用者的所有訪問行為(比如滑鼠懸停的位置,點選的頁面元件等),然後通過ajax請求到後臺記錄日誌;這種方式所能採集的資訊最全面; 3)通過在頁面上埋點1畫素的圖片,將相關頁面訪問資訊請求到後臺記錄日誌; 日誌資料內容詳述: 在實際操作中,有以下幾個方面的資料可以被採集: 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。所以點選流資料是由網站日誌中整理得到的,它可以比網站日誌包含更多的資訊,從而使基於點選流資料統計得到的結果更加豐富和高效。![這裡寫圖片描述](https://img-blog.csdn.net/20180824003612994?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d1eGludGRyaA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
點選流模型生成
這就是點選流模型。當WEB日誌轉化成點選流資料的時候,很多網站分析度量的計算變得簡單了,這就是點選流的“魔力”所在。基於點選流資料我們可以統計出許多常見的網站分析度量
2 整體技術流程及架構
2.1 資料處理流程
該專案是一個純粹的資料分析專案,其整體流程基本上就是依據資料的處理流程進行,依此有以下幾個大的步驟:
1) 資料採集
首先,通過頁面嵌入JS程式碼的方式獲取使用者訪問行為,併發送到web服務的後臺記錄日誌
然後,將各伺服器上生成的點選流日誌通過實時或批量的方式匯聚到HDFS檔案系統中
當然,一個綜合分析系統,資料來源可能不僅包含點選流資料,還有資料庫中的業務資料(如使用者資訊、商品資訊、訂單資訊等)及對分析有益的外部資料。
2) 資料預處理
通過spark程式對採集到的點選流資料進行預處理,比如清洗,格式整理,濾除髒資料等
3) 資料入庫
將預處理之後的資料匯入到HIVE倉庫中相應的庫和表中
4) 資料分析
專案的核心內容,即根據需求開發ETL分析語句,得出各種統計結果
5) 資料展現
將分析所得資料進行視覺化
2.2 專案結構
由於本專案是一個純粹資料分析專案,其整體結構亦跟分析流程匹配,並沒有特別複雜的結構,如下圖:
其中,需要強調的是:
系統的資料分析不是一次性的,而是按照一定的時間頻率反覆計算,因而整個處理鏈條中的各個環節需要按照一定的先後依賴關係緊密銜接,即涉及到大量任務單元的管理排程,所以,專案中需要新增一個任務排程模組
2.3 資料展現
資料展現的目的是將分析所得的資料進行視覺化,以便運營決策人員能更方便地獲取資料,更快更簡單地理解資料
3 模組開發——資料採集
3.1 需求
資料採集的需求廣義上來說分為兩大部分。
1)是在頁面採集使用者的訪問行為,具體開發工作:
- 1、開發頁面埋點js,採集使用者訪問行為
- 2、後臺接受頁面js請求記錄日誌
此部分工作也可以歸屬為“資料來源”,其開發工作通常由web開發團隊負責
2)是從web伺服器上匯聚日誌到HDFS,是資料分析系統的資料採集,此部分工作由資料分析平臺建設團隊負責,具體的技術實現有很多方式:
- Shell指令碼
- 優點:輕量級,開發簡單
- 缺點:對日誌採集過程中的容錯處理不便控制
- Java採集程式
- 優點:可對採集過程實現精細控制
- 缺點:開發工作量大
- 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;
檔案體積達到256M,或時間間隔達到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目錄中
如下圖:
版本選擇:apache-flume-1.6.0
採集規則設計:
1、 採集源:nginx伺服器日誌目錄
2、 存放地:hdfs目錄/home/hadoop/weblogs/
採集規則配置詳情
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 主要目的:
過濾“不合規”資料
格式轉換和規整
根據後續的統計需求,過濾分離出各種不同主題(不同欄目path)的基礎資料
4.2 實現方式:
對源資料進行預處理
源表
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';
4.3 點選流模型資料梳理
由於大量的指標統計從點選流模型中更容易得出,所以在預處理階段,可以使用mr程式來生成點選流模型的資料
4.3.1 點選流模型pageviews表
點選流模型pageviews表 ods_click_pageviews
drop table if exists ods_click_pageviews;
create table ods_click_pageviews(
Session string,
remote_addr string,
remote_user 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';
4.3.2 點選流模型visit資訊表
注:“一次訪問”=“N次連續請求”
直接從原始資料中用hql語法得出每個人的“次”訪問資訊比較困難,可先用mapreduce程式分析原始資料得出“次”資訊資料,然後再用hql進行更多維度統計
用spark程式從pageviews資料中,梳理出每一次visit的起止時間、頁面資訊
然後,在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);
然後,將運算得到的visit資料匯入visit模型表
load data local inpath '/uardata/hivetest/weblog/visit.log' into table ods_click_visit partition(datestr='2013-03-18');
5 模組開發——資料倉庫設計
注:採用星型模型
5.1 事實表
5.2 維度表
6 模組開發——ETL
該專案的資料分析過程在hadoop叢集上實現,主要應用hive資料倉庫工具,因此,採集並經過預處理後的資料,需要載入到hive資料倉庫中,以進行後續的挖掘分析。
- 在hive倉庫中建貼源資料表 ods_weblog_origin
- 點選流模型pageviews表 ods_click_pageviews
- 點選流visit模型表 click_stream_visit
- 時間維表建立
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');
匯入點選流模型pageviews資料到ods_click_pageviews表
load data inpath '/weblog/clickstream/pageviews' overwrite into table ods_click_pageviews partition(datestr='2013-09-18');
匯入點選流模型visit資料到click_stream_visit表
Load data local inpath '/weblog/clickstream/visits' overwrite into table click_stream_visit partition(datestr='2013-09-18');
6.3 生成ODS層明細寬表
6.3.1 需求概述
整個資料分析的過程是按照資料倉庫的層次分層進行的,總體來說,是從ODS原始資料中整理出一些中間表(比如,為後續分析方便,將原始資料中的時間、url等非結構化資料作結構化抽取,將各種欄位資訊進行細化,形成明細表),然後再在中間表的基礎之上統計出各種指標資料
6.3.2 ETL實現
建表——明細表ods_weblog_detail (源:ods_weblog_origin) (目標:ods_weblog_detail)
#etl明細寬表
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_weblog_origin 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,6,2) as month,
substring(time_local,9,2) as day,
substring(time_local,12,2) as hour
From t_ods_tmp_referurl b;
以上語句可以改寫成:
insert into table ods_weblog_detail partition(datestr='2013-09-18')
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 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;