原文出自:https://www.2cto.com/database/201612/580142.html
ELK干貨:http://www.cnblogs.com/xing901022/p/4704319.html
自己存的東西 方便以后看
java里面debugger之后把查詢的格式放到 Console - Kibana 里查 工具:Console - Kibana
Elasticsearch 2.3.3 JAVA api說明文檔:https://www.blog-china.cn/template/documentHtml/1484101683485.html
這是官方對Elasticsearch的定位。通俗的講,Elasticsearch就是一款面向文檔的NoSQL數據庫,使用JSON作為文檔序列化格式。但是,它的高級之處在於,使用Lucene作為核心來實現所有索引和搜索的功能,使得每個文檔的內容都可以被索引、搜索、排序、過濾。同時,提供了豐富的聚合功能,可以對數據進行多維度分析。對外統一使用REST API接口進行溝通,即Client與Server之間使用HTTP協議通信。
首先,來看看在存儲上的基本概念,這里將其與MySQL進行了對比,從而可以更清晰的搞清楚每個概念的意義。
Elasticsearch | MySQL |
---|---|
index(索引,名詞) | database |
doc type(文檔類型) | table |
document(文檔) | row |
field(字段) | column |
mapping(映射) | schema |
query DSL(查詢語言) | SQL |
然后,來看看倒排索引的概念(官方解釋)。倒排索引是搜索引擎的基石,也是Elasticsearch能實現快速全文搜索的根本。歸納起來,主要是對一個文檔內容做兩步操作:分詞、建立“單詞-文檔”列表。舉個例子,假如有下面兩個文檔:
1. {"content": "The quick brown fox jumped over the lazy dog"}
2. {"content": "Quick brown foxes leap over lazy dogs in summer"}
Elasticsearch會使用分詞器對content字段的內容進行分詞,再根據單詞在文檔中是否出現建立如下所示的列表,√表示單詞在文檔中有出現。假如我們想搜索“quick brown”,只需要找到每個詞在哪個文檔中出現即可。如果有多個文檔匹配,可以根據匹配的程度進行打分,找出相關性高的文檔。
Term | Doc_1 | Doc_2 |
---|---|---|
Quick | √ | |
The | √ | |
brown | √ | √ |
dog | √ | |
dogs | √ | |
fox | √ | |
foxes | √ | |
in | √ | |
jumped | √ | |
lazy | √ | √ |
leap | √ | |
over | √ | √ |
quick | √ | |
summer | √ | |
the | √ |
最后,我們再回過頭看看上面的映射的概念。類似於MySQL在db schema中申明每個列的數據類型、索引類型等,Elasticsearch中使用mapping來做這件事。常用的是,在mapping中申明字段的數據類型、是否建立倒排索引、建立倒排索引時使用什么分詞器。默認情況下,Elasticsearch會為所有的string類型數據使用standard分詞器建立倒排索引。
查看mapping:GET https://localhost:9200/<index name="">/_mapping NOTE: 這里的index是blog,doc type是test { "blog": { "mappings": { "test": { "properties": { "activity_type": { "type": "string", "index": "not_analyzed" }, "address": { "type": "string", "analyzer": "ik_smart" }, "happy_party_id": { "type": "integer" }, "last_update_time": { "type": "date", "format": "yyyy-MM-dd HH:mm:ss" } } } } } }</index>
數據插入
在MySQL中,我們需要先建立database和table,申明db schema后才可以插入數據。而在Elasticsearch,可以直接插入數據,系統會自動建立缺失的index和doc type,並對字段建立mapping。因為半結構化數據的數據結構通常是動態變化的,我們無法預知某個文檔中究竟有哪些字段,如果每次插入數據都需要提前建立index、type、mapping,那就失去了其作為NoSQL的優勢了。
1 直接插入數據:POST https://localhost:9200/blog/test 2 { 3 "count": 5, 4 "desc": "hello world" 5 } 6 7 查看索引:GET https://localhost:9200/blog/_mapping 8 { 9 "blog": { 10 "mappings": { 11 "test": { 12 "properties": { 13 "count": { 14 "type": "long" 15 }, 16 "desc": { 17 "type": "string" 18 } 19 } 20 } 21 } 22 } 23 }
然而這種靈活性是有限,比如上文我們提到,默認情況下,Elasticsearch會為所有的string類型數據使用standard分詞器建立倒排索引,那么如果某些字段不想建立倒排索引怎么辦。Elasticsearch提供了dynamic template的概念來針對一組index設置默認mapping,只要index的名稱匹配了,就會使用該template設置的mapping進行字段映射。
??下面所示即創建一個名稱為blog的template,該template會自動匹配以”blog_”開頭的index,為其自動建立mapping,對文檔中的所有string自動增加一個.raw字段,並且該字段不做索引。 這也是ELK中的做法,可以查看ELK系統中Elasticsearch的template,會發現有一個名為logstash的template。
1 創建template:POST https://localhost:9200/_template/blog 2 { 3 "template": "blog_*", 4 "mappings": { 5 "_default_": { 6 "dynamic_templates": [{ 7 "string_fields": { 8 "mapping": { 9 "type": "string", 10 "fields": { 11 "raw": { 12 "index": "not_analyzed", 13 "ignore_above": 256, 14 "type": "string" 15 } 16 } 17 }, 18 "match_mapping_type": "string" 19 } 20 }], 21 "properties": { 22 "timestamp": { 23 "doc_values": true, 24 "type": "date" 25 } 26 }, 27 "_all": { 28 "enabled": false 29 } 30 } 31 } 32 } 33 34 直接插入數據:POST https://localhost:9200/blog_2016-12-25/test 35 { 36 "count": 5, 37 "desc": "hello world" 38 }
插入問題還有個話題就是批量插入。Elasticsearch提供了bulk API用來做批量的操作,你可以在該API中自由組合你要做的操作和數據,一次性發送給Elasticsearch進行處理,其格式是這樣的。
1 action_and_meta_data\n 2 optional_source\n 3 action_and_meta_data\n 4 optional_source\n 5 .... 6 action_and_meta_data\n 7 optional_source\n 8 9 比如: 10 { "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } } 11 { "field1" : "value1" } 12 { "delete" : { "_index" : "test", "_type" : "type1", "_id" : "2" } } 13 { "create" : { "_index" : "test", "_type" : "type1", "_id" : "3" } } 14 { "field1" : "value3" } 15 { "update" : {"_id" : "1", "_type" : "type1", "_index" : "test"} } 16 { "doc" : {"field2" : "value2"} }
如果是針對相同的index和doc type進行操作,則在REST API中指定index和type即可。批量插入的操作舉例如下:
1 批量插入:POST https://localhost:9200/blog_2016-12-24/test/_bulk 2 {"index": {}} 3 {"count": 5, "desc": "hello world 111"} 4 {"index": {}} 5 {"count": 6, "desc": "hello world 222"} 6 {"index": {}} 7 {"count": 7, "desc": "hello world 333"} 8 {"index": {}} 9 {"count": 8, "desc": "hello world 444"} 10 11 查看插入的結果:GET https://localhost:9200/blog_2016-12-24/test/_search
數據查詢
Elasticsearch的查詢語法(query DSL)分為兩部分:query和filter,區別在於查詢的結果是要完全匹配還是相關性匹配。filter查詢考慮的是“文檔中的字段值是否等於給定值”,答案在“是”與“否”中;而query查詢考慮的是“文檔中的字段值與給定值的匹配程度如何”,會計算出每份文檔與給定值的相關性分數,用這個分數對匹配了的文檔進行相關性排序。
??在實際使用中,要注意兩點:第一,filter查詢要在沒有做倒排索引的字段上做,即上面mapping中增加的.raw字段;第二,通常使用filter來縮小查詢范圍,使用query進行搜索,即二者配合使用。舉例來看,注意看三個不同查詢在寫法上的區別:
1 1. 只使用query進行查詢: 2 POST https://localhost:9200/user_action/_search 3 查詢的結果是page_name字段中包含了wechat所有文檔 4 這里使用size來指定返回文檔的數量,默認Elasticsearch是返回前100條數據的 5 { 6 "query": { 7 "bool": { 8 "must": [{ 9 "match": { 10 "page_name": "wechat" 11 } 12 }, 13 { 14 "range": { 15 "timestamp": { 16 "gte": 1481218631, 17 "lte": 1481258231, 18 "format": "epoch_second" 19 } 20 } 21 }] 22 } 23 }, 24 "size": 2 25 } 26 27 2. 只使用filter進行查詢: 28 POST https://localhost:9200/user_action/_search 29 查詢的結果是page_name字段值等於"example.cn/wechat/view.html"的所有文檔 30 { 31 "filter": { 32 "bool": { 33 "must": [{ 34 "term": { 35 "page_name.raw": "example.cn/wechat/view.html" 36 } 37 }, 38 { 39 "range": { 40 "timestamp": { 41 "gte": 1481218631, 42 "lte": 1481258231, 43 "format": "epoch_second" 44 } 45 } 46 }] 47 } 48 }, 49 "size": 2 50 } 51 52 3. 同時使用query與filter進行查詢: 53 POST https://localhost:9200/user_action/_search 54 查詢的結果是page_name字段值等於"example.cn/wechat/view.html"的所有文檔 55 { 56 "query": { 57 "bool": { 58 "filter": [{ 59 "bool": { 60 "must": [{ 61 "term": { 62 "page_name.raw": "job.gikoo.cn/wechat/view.html" 63 } 64 }, 65 { 66 "range": { 67 "timestamp": { 68 "gte": 1481218631, 69 "lte": 1481258231, 70 "format": "epoch_second" 71 } 72 } 73 }] 74 } 75 }] 76 } 77 }, 78 "size": 2 79 }
聚合分析
類似於MySQL中的聚合由分組和聚合計算兩種,Elasticsearch的聚合也有兩部分組成:Buckets與Metrics。Buckets相當於SQL中的分組group by,而Metrics則相當於SQL中的聚合函數COUNT,SUM,MAX,MIN等等。聚合分析自然離不開對多個字段值進行分組,在MySQL中,我們只要使用“group by c1, c2, c3”就可以完成這樣的功能,但是Elasticsearch沒有這樣的語法。Elasticsearch提供了另一種方法,即Buckets嵌套,仔細想想,似乎這種設計更加符合人的思維方式。舉例來看具體操作方法:
1. 最簡單的聚合查詢 POST https://localhost:9200/user_action/_search 為了簡單,這里刪除了query的條件描述 將符合條件的文檔按照公司進行聚合 這里有兩個size,和aggs並列的size=0表示返回結果不包含查詢結果,只返回聚合結果,terms里面的size表示返回的聚合結果數量 { "aggs": { "company_terms": { "terms": { "field": "company", "size": 2 } } }, "size": 0 } 2. Buckets與Metric配合 POST https://localhost:9200/user_action/_search 將符合條件的文檔按照公司進行聚合,並獲取每個公司最近一次操作的時間 { "aggs": { "company_terms": { "terms": { "field": "company", "size": 2 }, "aggs": { "latest_record": { "max": { "field": "timestamp" } } } } }, "size": 0 } 3. Buckets嵌套 POST https://localhost:9200/user_action/_search 將符合條件的文檔先按照公司進行聚合,再對每個公司下的門店進行聚合,並獲取每個門店最近一次操作的時間 { "aggs": { "company_terms": { "terms": { "field": "company", "size": 1 }, "aggs": { "store_terms": { "terms": { "field": "store", "size": 2 }, "aggs": { "latest_record": { "max": { "field": "timestamp" } } } } } } }, "size": 0 }