<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                [TOC] ## 概況 ### 背景 這個項目的背景是起源于,我有一個2G左右的網站訪問日志。我想看看訪問網站的人都來自哪里,于是我想開始想辦法來分析這日志。當時正值大數據火熱的時候,便想拿著Hadoop來做這樣一件事。 ### ShowCase 最后的效果如下圖如示: ![](https://box.kancloud.cn/2015-10-25_562c592347759.jpg) Demo 這是一個Web生成的界面,通過Elastic.js向搜索引擎查詢數據,將再這些數據渲染到地圖上。 ### Hadoop + Pig + Jython + AmMap + ElasticSearch 我們使用的技術棧有上面這些,他們的簡介如下: * Hadoop是一個由Apache基金會所開發的分布式系統基礎架構。用戶可以在不了解分布式底層細節的情況下,開發分布式程序。充分利用集群的威力進行高速運算和存儲。 * Pig 是一個基于Hadoop的大規模數據分析平臺,它提供的SQL-LIKE語言叫Pig Latin,該語言的編譯器會把類SQL的數據分析請求轉換為一系列經過優化處理的MapReduce運算。 * Jython是一種完整的語言,而不是一個Java翻譯器或僅僅是一個Python編譯器,它是一個Python語言在Java中的完全實現。Jython也有很多從CPython中繼承的模塊庫。 * AmMap是用于創建交互式Flash地圖的工具。您可以使用此工具來顯示您的辦公室地點,您的行程路線,創建您的經銷商地圖等。 * ElasticSearch是一個基于Lucene 構建的開源,分布式,RESTful 搜索引擎。 設計用于云計算中,能夠達到搜索實時、穩定、可靠和快速,并且安裝使用方便。 ## 步驟 總的步驟并不是很復雜,可以分為: * 搭建基礎設施 * 解析access.log * 轉換IP為GEO信息 * 展示數據到地圖上 ### Step 1: 搭建基礎設施 在這一些系列的實戰中,比較麻煩的就是安裝這些工具,我們需要安裝上面提到的一系列工具。對于不同的系統來說,都有相似的安裝工具: * Windows上可以使用Chocolatey * Ubuntu / Mint上可以使用aptitude * CentOS / OpenSUSE上可以使用yum安裝 * Mac OS上可以使用brew安裝 如下是Mac OS下安裝Hadoop、Pig、Elasticsearch、Jython的方式 ~~~ brew install hadoop brew install pig brew install elasticsearch brew install jython ~~~ 對于其他操作系統也可以使用相似的方法來安裝。接著我們還需要安裝一個Hadoop的插件,用于連接Hadoop和ElasticSearch。 下載地址:[https://github.com/elastic/elasticsearch-hadoop](https://github.com/elastic/elasticsearch-hadoop) 復制其中的`elasticsearch-hadoop-*.jar`、`elasticsearch-hadoop-pig-*.jar`到你的pig庫的目錄,如我的是:`/usr/local/Cellar/pig/0.14.0`。 由于我使用提早期的版本,所以這里我的文件名是:`elasticsearch-hadoop-2.1.0.Beta3.jar`、`elasticsearch-hadoop-pig-2.1.0.Beta3.jar`。 下面我們就可以嘗試去解析我們的日志了。 ### Step 2: 解析access.log 在開始解析之前,先讓我們來看看幾條Nginx的日志: ~~~ 106.39.113.203 - - [28/Apr/2016:10:40:31 +0000] "GET / HTTP/2.0" 200 0 "https://www.phodal.com/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36" - 66.249.65.119 - - [28/Apr/2016:10:40:51 +0000] "GET /set_device/default/?next=/blog/use-falcon-peewee-build-high-performance-restful-services-wordpress/ HTTP/1.1" 302 5 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" - ~~~ 而上面的日志實際上是有對應的格式的,這個格式寫在我們的Nginx配置文件中。如下是上面的日志的格式: ~~~ log_format access $remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" $http_x_forwarded_for'; ~~~ 在最前面的是訪問者的IP地址,然后是訪問者的當地時間、請求的類型、狀態碼、訪問的URL、用戶的User Agent等等。隨后,我們就可以針對上面的格式編寫相應的程序,這些代碼如下所示: ~~~ register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/piggybank.jar; register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/elasticsearch-hadoop-pig-2.1.0.Beta3.jar; RAW_LOGS = LOAD 'data/access.log' USING TextLoader as (line:chararray); LOGS_BASE = FOREACH RAW_LOGS GENERATE FLATTEN( REGEX_EXTRACT_ALL(line, '(\\S+) - - \\[([^\\[]+)\\]\\s+"([^"]+)"\\s+(\\d+)\\s+(\\d+)\\s+"([^"]+)"\\s+"([^"]+)"\\s+-') ) AS ( ip: chararray, timestamp: chararray, url: chararray, status: chararray, bytes: chararray, referrer: chararray, useragent: chararray ); A = FOREACH LOGS_BASE GENERATE ToDate(timestamp, 'dd/MMM/yyyy:HH:mm:ss Z') as date, ip, url,(int)status,(int)bytes,referrer,useragent; --B = GROUP A BY (timestamp); --C = FOREACH B GENERATE FLATTEN(group) as (timestamp), COUNT(A) as count; --D = ORDER C BY timestamp,count desc; STORE A INTO 'nginx/log' USING org.elasticsearch.hadoop.pig.EsStorage(); ~~~ 在第1~2行里,我們使用了自定義的jar文件。接著在第4行,載入了log文件,并其值賦予RAW_LOGS。隨后的第6行里,我們取出RAW_LOGS中的每一個值 ,根據下面的正則表達式,取出其對應的值到對象里,如`- -`前面的(\S+)對應的是ip,最后將這些值賦給LOGS_BASE。 接著,我們就可以對值進行一些特殊的處理,如A是轉化時間戳后的結果。B是按時間戳排序后的結果。最后,我們再將這些值存儲到ElasticSearch對應的索引`nginx/log`中。 ### Step 3: 轉換IP為GEO信息 在簡單地完成了一個Demo之后,我們就可以將IP轉換為GEO信息了,這里我們需要用到一個名為pygeoip的庫。GeoIP是一個根據IP地址查詢位置的API的集成。它支持對國家、地區、城市、緯度和經度的查詢。實際上,就是在一個數據庫中有對應的國家和地區的IP段,根據這個IP段,我們就可以獲取對應的地理位置。 由于使用Java來實現這個功能比較麻煩,這里我們就使用Jython來實現。大部分的過程和上面都是一樣的,除了注冊了一個自定義的庫,并在這個庫里使用了解析GEO的方法,代碼如下所示: ~~~ register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/piggybank.jar; register file:/usr/local/Cellar/pig/0.14.0/libexec/lib/elasticsearch-hadoop-pig-2.1.0.Beta3.jar; register utils.py using jython as utils; RAW_LOGS = LOAD 'data/access.log' USING TextLoader as (line:chararray); LOGS_BASE = FOREACH RAW_LOGS GENERATE FLATTEN( REGEX_EXTRACT_ALL(line, '(\\S+) - - \\[([^\\[]+)\\]\\s+"([^"]+)"\\s+(\\d+)\\s+(\\d+)\\s+"([^"]+)"\\s+"([^"]+)"\\s+-') ) AS ( ip: chararray, timestamp: chararray, url: chararray, status: chararray, bytes: chararray, referrer: chararray, useragent: chararray ); A = FOREACH LOGS_BASE GENERATE ToDate(timestamp, 'dd/MMM/yyyy:HH:mm:ss Z') as date, utils.get_country(ip) as country, utils.get_city(ip) as city, utils.get_geo(ip) as location,ip, url, (int)status,(int)bytes,referrer,useragent; STORE A INTO 'nginx/log' USING org.elasticsearch.hadoop.pig.EsStorage(); ~~~ 在第三行里,我們注冊了`utils.py`并將其中的函數作為utils。接著在倒數第二行里,我們執行了四個utils函數。即: * get_country從IP中解析出國家 * get_city從IP中解析出城市 * get_geo從IP中解析出經緯度信息 其對應的Python代碼如下所示: ~~~ #!/usr/bin/python import sys sys.path.append('/Users/fdhuang/test/lib/python2.7/site-packages/') import pygeoip gi = pygeoip.GeoIP("data/GeoLiteCity.dat") @outputSchema('city:chararray') def get_city(ip): try: city = gi.record_by_name(ip)["city"] return city except: pass @outputSchema('country:chararray') def get_country(ip): try: city = gi.record_by_name(ip)["country_name"] return city except: pass @outputSchema('location:chararray') def get_geo(ip): try: geo = str(gi.record_by_name(ip)["longitude"]) + "," + str(gi.record_by_name(ip)["latitude"]) return geo except: pass ~~~ 代碼相應的簡單,和一般的Python代碼也沒有啥區別。這里一些用戶自定義函數,在函數的最前面有一個`outputSchema`,用于返回輸出的結果。 ### Step 4: 展示數據到地圖上 現在,我們終于可以將數據轉化到可視化界面了。開始之前,我們需要幾個庫 * jquery 地球人都知道 * elasticsearch.jquery即用于搜索功能 * ammap用于制作交互地圖。 添加這些庫到html文件里: ~~~ <script src="bower_components/jquery/dist/jquery.js"></script> <script src="bower_components/elasticsearch/elasticsearch.jquery.js"></script> <script src="bower_components/ammap/dist/ammap/ammap.js" type="text/javascript"></script> <script src="bower_components/ammap/dist/ammap/maps/js/worldLow.js" type="text/javascript"></script> <script src="bower_components/ammap/dist/ammap/themes/black.js" type="text/javascript"></script> <script src="scripts/latlng.js"></script> <script src="scripts/main_ammap.js"></script> ~~~ 生成過程大致如下所示: * 獲取不同國家的全名,用于解析出全名,如US -> “United States” * 查找ElasticSearch搜索引擎中的數據,并計算訪問量 * 再將數據渲染到地圖上 對應的main文件如下所示: ~~~ var client = new $.es.Client({ hosts: 'localhost:9200' }); // 創建ElasticSearch搜索條件 var query = { index: 'nginx', type: 'log', size: 200, body: { query: { query_string: { query: "*" } }, aggs: { 2: { terms: { field: "country", size: 200, order: { _count: "desc" } } } } } }; // 獲取到country.json后生成數據 $(document).ready(function () { $.ajax({ type: "GET", url: "country.json", success: function (data) { generate_info(data) } }); }); // 根據數據中的國家名,來計算不同國家的訪問量大小。 var generate_info = function(data){ var mapDatas = []; client.search(query).then(function (results) { $.each(results.aggregations[2].buckets, function(index, bucket){ var mapData; $.each(data, function(index, country){ if(country.name.toLowerCase() === bucket.key) { mapData = { code: country.code, name: country.name, value: bucket.doc_count, color: "#eea638" }; } }); if(mapData !== undefined){ mapDatas.push(mapData); } }); create_map(mapDatas); }); }; var create_map = function(mapData){ var map; var minBulletSize = 3; var maxBulletSize = 70; var min = Infinity; var max = -Infinity; AmCharts.theme = AmCharts.themes.black; for (var i = 0; i < mapData.length; i++) { var value = mapData[i].value; if (value < min) { min = value; } if (value > max) { max = value; } } map = new AmCharts.AmMap(); map.pathToImages = "bower_components/ammap/dist/ammap/images/"; map.areasSettings = { unlistedAreasColor: "#FFFFFF", unlistedAreasAlpha: 0.1 }; map.imagesSettings = { balloonText: "<span style='font-size:14px;'><b>[[title]]</b>: [[value]]</span>", alpha: 0.6 }; var dataProvider = { mapVar: AmCharts.maps.worldLow, images: [] }; var maxSquare = maxBulletSize * maxBulletSize * 2 * Math.PI; var minSquare = minBulletSize * minBulletSize * 2 * Math.PI; for (var i = 0; i < mapData.length; i++) { var dataItem = mapData[i]; var value = dataItem.value; // calculate size of a bubble var square = (value - min) / (max - min) * (maxSquare - minSquare) + minSquare; if (square < minSquare) { square = minSquare; } var size = Math.sqrt(square / (Math.PI * 2)); var id = dataItem.code; dataProvider.images.push({ type: "circle", width: size, height: size, color: dataItem.color, longitude: latlong[id].longitude, latitude: latlong[id].latitude, title: dataItem.name, value: value }); } map.dataProvider = dataProvider; map.write("mapdiv"); }; ~~~ 我們可以看到比較麻煩的地方就是生成地圖上的數量點,也就是create_map函數。 ### 練習建議
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看