不少人剛剛接觸ELK都不知道如何使用它們來作分析,常常會碰到下面的問題:html
本篇就以一個完整的流程介紹下,數據從 讀取-->分析-->檢索-->應用
的全流程處理。在閱讀本篇以前,須要先安裝ELK,能夠參考以前整理安裝文檔:ELK5.0部署教程前端
在利用ELK作數據分析時,大體爲下面的流程:正則表達式
可能會根據第4步重複第2步的工做,調整分詞等規則。redis
我須要統計一個url對應的pv和uv,這個url須要支持全文檢索。天天同一個url都會產生一條數據。最後會按照特定的日期範圍對數據進行聚合。數據庫
下面就開始數據分析之路吧~json
在使用logstash前,須要對它有必定的瞭解。logstash的組件其實很簡單,主要包括input、filter、output、codec四個部分。api
理解上面的內容後,再看看logstash的使用方法。ruby
首先須要定義一個配置文件,配置文件中配置了對應的input,filter,output等,至少是一個input,output。app
如個人配置文件:elasticsearch
input { file { path => "C:\Users\Documents\workspace\elk\page.csv" start_position => "beginning" } } filter { grok { match => { "message" => "%{NOTSPACE:url}\s*%{NOTSPACE:date}\s*%{NOTSPACE:pvs}\s*%{NOTSPACE:uvs}\s*%{NOTSPACE:ips}\s*%{NOTSPACE:mems}\s*%{NOTSPACE:new_guests}\s*%{NOTSPACE:quits}\s*%{NOTSPACE:outs}\s*%{NOTSPACE:stay_time}" } } } output { stdout{codec => dots} elasticsearch { document_type => "test" index => "page" hosts => ["1.1.1.1:9200"] } }
上面的配置最不容易理解的就是Grok,其實它就是個正則表達式而已,你能夠把它理解成是一段正則表達式的佔位。至於grok都有哪些關鍵字,這些關鍵字對應的正則都是什麼,能夠直接參考logstash的源碼,目錄的位置爲:
logstash-5.2.2\vendor\bundle\jruby\1.9\gems\logstash-patterns-core-4.0.2\patterns
若是提供的話,能夠直接在grokdebug上面進行測試:
另一個技巧就是,若是開啓stdout而且codec爲rubydebug,會把數據輸出到控制檯,所以使用.
代替,便可省略輸出,又能檢測到如今是否有數據正在處理。並且每一個.是一個字符,若是把它輸出到文件,也能夠直接經過文件的大小,判斷處理了多少條。
這樣,數據的預處理作完了.....
雖說Es是一個文檔數據庫,可是它也是有模式的概念的。文檔中的每一個字段仍然須要定義字段的類型,使用者常常會遇到明明是數字,在kibana卻作不了加法;或者明明是IP,kibana裏面卻不認識。這都是由於Mapping有問題致使的。
在Elasticsearch中實際上是有動態映射這個概念的,在字段第一次出現時,ES會自動檢測你的字段是否屬於數字或者日期或者IP,若是知足它預約義的格式,就按照特殊格式存儲。一旦格式設置過了,以後的數據都會按照這種格式存儲。舉個例子,第一條數據進入ES時,字段檢測爲數值型;第二條進來的時候,倒是一個字符串,結果可能插不進去,也可能插進去讀不出來(不一樣版本處理的方式不一樣)。
所以,咱們須要事先就設定一下字段的Mapping,這樣以後使用的時候纔不會困惑。
另外,Mapping裏面不只僅有字段的類型,還有這個字段的分詞方式,好比使用標準standard分詞器,仍是中文分詞器,或者是自定義的分詞器,這個也是很關鍵的一個概念,稍後再講。
建立Mapping有兩種方式:
建立索引時,能夠直接指定它的配置和Mapping:
PUT index_name { "settings" : { "number_of_shards" : 1 }, "mappings" : { "type_name" : { "properties" : { "field_name" : { "type" : "text" } } } } }
# 先建立索引 PUT index_name {} # 而後建立Mapping PUT /index_name/_mapping/type_name { "properties": { "ip": { "type": "ip" } } } # 最後查詢建立的Mapping GET /index_name/_mapping/type_name
好比咱們上面的URL場景,能夠這麼創建索引:
PUT url/_mapping/test { "properties": { "url": { "type": "string", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "date": { "type": "date" }, "pvs": { "type": "integer" }, "uvs": { "type": "integer" } } }
PS,在上面的例子中,url須要有兩個用途,一個是做爲聚合的字段;另外一個是須要作全文檢索。在ES中全文檢索的字段是不能用來作聚合的,所以使用嵌套字段的方式,新增一個url.keyword字段,這個字段設置成keyword類型,不採用任何分詞(這是5.0的新特性,若是使用之前版本,能夠直接設置string對應的index屬性便可);而後自己的url字段則採用默認的標準分詞器進行分詞。
這樣,之後在搜索的時候能夠直接以query string
的方式檢索url
,聚合的時候則能夠直接使用url.keyword
若是字段爲https://www.elastic.co/guide/en/elasticsearch/reference/5.2
,使用standard標準分詞器,輸入elastic
卻收不到任何結果,是否是有點懷疑人生。
咱們作個小例子,首先建立一個空的索引:
PUT test1/test1/1 { "text":"https://www.elastic.co/guide/en/elasticsearch/reference/5.2" }
而後查詢這個字段被分解成了什麼鬼?
GET /test1/test1/1/_termvectors?fields=text
獲得的內容以下:
{ "_index": "test1", "_type": "test1", "_id": "1", "_version": 1, "found": true, "took": 1, "term_vectors": { "text": { "field_statistics": { "sum_doc_freq": 7, "doc_count": 1, "sum_ttf": 7 }, "terms": { "5.2": { "term_freq": 1, "tokens": [ { "position": 6, "start_offset": 56, "end_offset": 59 } ] }, "elasticsearch": { "term_freq": 1, "tokens": [ { "position": 4, "start_offset": 32, "end_offset": 45 } ] }, "en": { "term_freq": 1, "tokens": [ { "position": 3, "start_offset": 29, "end_offset": 31 } ] }, "guide": { "term_freq": 1, "tokens": [ { "position": 2, "start_offset": 23, "end_offset": 28 } ] }, "https": { "term_freq": 1, "tokens": [ { "position": 0, "start_offset": 0, "end_offset": 5 } ] }, "reference": { "term_freq": 1, "tokens": [ { "position": 5, "start_offset": 46, "end_offset": 55 } ] }, "www.elastic.co": { "term_freq": 1, "tokens": [ { "position": 1, "start_offset": 8, "end_offset": 22 } ] } } } } }
看到了吧,沒有elastic這個詞,天然是搜不出來的。若是你不理解這句話,回頭看看倒排索引的原理吧!或者看看個人這篇文章:分詞器的做用
那麼你可能很鬱悶,我就是要搜elastic怎麼辦!不要緊,換個分詞器就好了~好比elasticsearch爲咱們提供的simple
分詞器,就能夠簡單的按照符號進行切分:
POST _analyze { "analyzer": "simple", "text": "https://www.elastic.co/guide/en/elasticsearch/reference/5.2" }
獲得的結果爲:
{ "tokens": [ { "token": "https", "start_offset": 0, "end_offset": 5, "type": "word", "position": 0 }, { "token": "www", "start_offset": 8, "end_offset": 11, "type": "word", "position": 1 }, { "token": "elastic", "start_offset": 12, "end_offset": 19, "type": "word", "position": 2 }, { "token": "co", "start_offset": 20, "end_offset": 22, "type": "word", "position": 3 }, { "token": "guide", "start_offset": 23, "end_offset": 28, "type": "word", "position": 4 }, { "token": "en", "start_offset": 29, "end_offset": 31, "type": "word", "position": 5 }, { "token": "elasticsearch", "start_offset": 32, "end_offset": 45, "type": "word", "position": 6 }, { "token": "reference", "start_offset": 46, "end_offset": 55, "type": "word", "position": 7 } ] }
這樣你就能夠搜索elastic
了,可是前提是須要在Mapping裏面爲該字段指定使用simple分詞器,方法爲:
PUT url/_mapping/test { "properties": { "url": { "type": "string", "analyzer": "simple", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "date": { "type": "date" }, "pvs": { "type": "integer" }, "uvs": { "type": "integer" } }
修改Mapping前,須要先刪除索引,而後重建索引。刪除索引的命令爲:
DELETE url
不想刪除索引,只想改變Mapping?想得美....你當ES是孫悟空會72變?不過,你能夠建立一個新的索引,而後把舊索引的數據導入到新索引就好了,這也不失爲一種辦法。若是想這麼搞,能夠參考reindex api,若是版本是5.0以前,那麼你倒黴了!本身搞定吧!
ES裏面檢索是一個最基礎的功能了,不少人其實這個都是隻知其一;不知其二。因爲內容太多,我就結合Kibana講講其中的一小部分吧。
不少人安裝完kibana以後,登錄後不知道該幹啥。若是你的elasticsearch裏面已經有數據了,那麼此時你須要在Kiban新建對應的索引。
若是你的es的索引是name-2017-03-19
,name-2017-03-20
這種名字+時間後綴的,那麼能夠勾選1位置的選項,它會自動聚合這些索引。這樣在這一個索引中就能夠查詢多個索引的數據了,其實他是利用了索引的模式匹配的特性。若是你的索引僅僅是一個簡單的名字,那麼能夠不勾選1位置的選項,直接輸入名字,便可。
而後進入Kibana的首頁,在輸入框裏面就能夠任意輸入關鍵字進行查詢了。
_termvectors
分析出來的詞,差一個字母都不行!!!!!這個搜索框其實就是elasticsearch中的query string,所以全部的lucene查詢語法都是支持的!
若是想要了解更多的查詢語法,也能夠參考我以前整理的文章,Lucene查詢語法
另外,這個輸入框,其實也能夠輸入ES的DSL查詢語法,只不過寫法過於蛋疼,就不推薦了。
若是不使用kibana,想在本身的程序裏面訪問es操做,也能夠直接以rest api的方式查詢。
好比查詢某個索引的所有內容,默認返回10個:
GET /page/test/_search?pretty
再好比,增長一個特殊點的查詢:
GET /page/test/_search?pretty { "query": { "query_string" : { "default_field" : "url", "query" : "顏色" } }, "size": 10, }
在es中一個很重要的亮點,就是支持不少的聚合語法,若是沒有它,我想不少人會直接使用lucene吧。在ES中的聚合,大致上能夠爲兩類聚合方法,metric和bucket。metic能夠理解成avg、sum、count、max、min,bucket能夠理解爲group by 。有了這兩種聚合方法,就能夠對ES中的數據作不少處理了。
好比在kibana中,作一個最簡單的餅圖:
其實它在後臺發送的請求,就是這個樣子的:
{ "size": 0, "query": { "query_string": { "query": "顏色", "analyze_wildcard": true } }, "_source": { "excludes": [] }, "aggs": { "2": { "terms": { "field": "url.keyword", "size": 5, "order": { "_count": "desc" } } } } }
若是不適用kibana,本身定義聚合請求,那麼能夠這樣寫:
GET /page/test/_search?pretty { "query": { "query_string" : { "default_field" : "url", "query" : "顏色" } }, "size": 0, "aggs" : { "agg1" : { "terms" : { "field" : "url.keyword", "size" : 10 }, "aggs" : { "pvs" : { "sum" : { "field" : "pvs" } }, "uvs" : { "sum" : { "field" : "uvs" } } } } } }
另外,聚合也支持嵌套聚合,就是跟terms或者sum等agg並列寫一個新的aggs對象就行。
若是是本身使用elasticsearch,高亮也是一個很是重要的內容,它能夠幫助最後的使用者快速瞭解搜索的結果。
後臺的原理,是利用ES提供的highlight API,針對搜索的關鍵字,返回對應的字段。該字段中包含了一個自定義的標籤,前端能夠基於這個標籤高亮着色。
舉個簡單的例子:
GET /_search { "query" : { "match": { "content": "kimchy" } }, "highlight" : { "fields" : { "content" : {} } } }
上面的請求會針對content字段搜索kimchy。而且返回對應的字段,好比原來的字段內容時hello kimchy
,通過高亮後,會再搜索結果的hits中返回:
{ "took": 3, "timed_out": false, "_shards": { "total": 5, "successful": 5, "failed": 0 }, "hits": { "total": 30, "max_score": 13.945707, "hits": [ { "_index": "page", "_type": "test", "_id": "AVrvHh_kvobeDQC6Q5Sg", "_score": 13.945707, "_source": { "date": "2016-03-14", "pvs": "3", "url": "hello kimchy", "@timestamp": "2017-03-21T04:29:07.187Z", "uvs": "1", "@version": "1" }, "highlight": { "url": [ "hello <em>kimchy</em>" ] } } ] } }
這樣就能夠直接利用highlight中的字段作前端的顯示了。
另外,上面的<em>
標籤能夠自定義,好比:
GET /_search { "query" : { "match": { "user": "kimchy" } }, "highlight" : { "pre_tags" : ["<tag1>"], "post_tags" : ["</tag1>"], "fields" : { "_all" : {} } } }