小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Elasticsearch使用總結(jié)

 株野 2017-05-25

最初接觸Elasticsearch是在ELK日志系統(tǒng)的建設中,隨著對日志數(shù)據(jù)的消費越來越多,被其強大的數(shù)據(jù)搜索和分析能力所吸引;后來,在用戶行為數(shù)據(jù)采集系統(tǒng)中,使用Elasticsearch做核心數(shù)據(jù)存儲和實時聚合分析;再后來,使用Elasticsearch搭建了產(chǎn)品的搜索服務。目前來看,Elasticsearch在這三個系統(tǒng)中表現(xiàn)都很靈活和優(yōu)異,沒有讓我們失望,而在系統(tǒng)建設中,我們也遇到過不少問題,有基本概念的迷惑、操作方法、部署、性能等等各個方面。本文著重對Elasticsearch在應用層面上的使用進行總結(jié),搞清楚WHAT和HOW兩個層面,即是什么怎么用。
NOTE:本文所述的概念和方法均在Elasticsearch2.3版本下。

基本概念

Elasticsearch is a distributed, RESTful search and analytics engine capable of solving a growing number of use cases. As the heart of the Elastic Stack, it centrally stores your data so you can discover the expected and uncover the unexpected.

這是官方對Elasticsearch的定位。通俗的講,Elasticsearch就是一款面向文檔的NoSQL數(shù)據(jù)庫,使用JSON作為文檔序列化格式。但是,它的高級之處在于,使用Lucene作為核心來實現(xiàn)所有索引和搜索的功能,使得每個文檔的內(nèi)容都可以被索引、搜索、排序、過濾。同時,提供了豐富的聚合功能,可以對數(shù)據(jù)進行多維度分析。對外統(tǒng)一使用REST API接口進行溝通,即Client與Server之間使用HTTP協(xié)議通信。
首先,來看看在存儲上的基本概念,這里將其與MySQL進行了對比,從而可以更清晰的搞清楚每個概念的意義。

Elasticsearch MySQL
index(索引,名詞) database
doc type(文檔類型) table
document(文檔) row
field(字段) column
mapping(映射) schema
query DSL(查詢語言) SQL


然后,來看看倒排索引的概念(官方解釋)。倒排索引是搜索引擎的基石,也是Elasticsearch能實現(xiàn)快速全文搜索的根本。歸納起來,主要是對一個文檔內(nèi)容做兩步操作:分詞建立“單詞-文檔”列表。舉個例子,假如有下面兩個文檔:

1
2
1. {"content": "The quick brown fox jumped over the lazy dog"}
2. {"content": "Quick brown foxes leap over lazy dogs in summer"}

Elasticsearch會使用分詞器對content字段的內(nèi)容進行分詞,再根據(jù)單詞在文檔中是否出現(xiàn)建立如下所示的列表,√表示單詞在文檔中有出現(xiàn)。假如我們想搜索“quick brown”,只需要找到每個詞在哪個文檔中出現(xiàn)即可。如果有多個文檔匹配,可以根據(jù)匹配的程度進行打分,找出相關性高的文檔。

Term Doc_1 Doc_2
Quick  
The  
brown
dog  
dogs  
fox  
foxes  
in  
jumped  
lazy
leap  
over
quick  
summer  
the  


最后,我們再回過頭看看上面的映射的概念。類似于MySQL在db schema中申明每個列的數(shù)據(jù)類型、索引類型等,Elasticsearch中使用mapping來做這件事。常用的是,在mapping中申明字段的數(shù)據(jù)類型、是否建立倒排索引、建立倒排索引時使用什么分詞器。默認情況下,Elasticsearch會為所有的string類型數(shù)據(jù)使用standard分詞器建立倒排索引。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
查看mapping:GET http://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>

數(shù)據(jù)插入

在MySQL中,我們需要先建立database和table,申明db schema后才可以插入數(shù)據(jù)。而在Elasticsearch,可以直接插入數(shù)據(jù),系統(tǒng)會自動建立缺失的index和doc type,并對字段建立mapping。因為半結(jié)構化數(shù)據(jù)的數(shù)據(jù)結(jié)構通常是動態(tài)變化的,我們無法預知某個文檔中究竟有哪些字段,如果每次插入數(shù)據(jù)都需要提前建立index、type、mapping,那就失去了其作為NoSQL的優(yōu)勢了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
直接插入數(shù)據(jù):POST http://localhost:9200/blog/test
{
    "count": 5,
    "desc": "hello world"
}
{
    "blog": {
        "mappings": {
            "test": {
                "properties": {
                    "count": {
                        "type": "long"
                    },
                    "desc": {
                        "type": "string"
                    }
                }
            }
        }
    }
}

然而這種靈活性是有限,比如上文我們提到,默認情況下,Elasticsearch會為所有的string類型數(shù)據(jù)使用standard分詞器建立倒排索引,那么如果某些字段不想建立倒排索引怎么辦。Elasticsearch提供了dynamic template的概念來針對一組index設置默認mapping,只要index的名稱匹配了,就會使用該template設置的mapping進行字段映射。
下面所示即創(chuàng)建一個名稱為blog的template,該template會自動匹配以”blog_”開頭的index,為其自動建立mapping,對文檔中的所有string自動增加一個.raw字段,并且該字段不做索引。 這也是ELK中的做法,可以查看ELK系統(tǒng)中Elasticsearch的template,會發(fā)現(xiàn)有一個名為logstash的template。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
創(chuàng)建template:POST http://localhost:9200/_template/blog
{
    "template": "blog_*",
    "mappings": {
        "_default_": {
            "dynamic_templates": [{
                "string_fields": {
                    "mapping": {
                        "type": "string",
                        "fields": {
                            "raw": {
                                "index": "not_analyzed",
                                "ignore_above": 256,
                                "type": "string"
                            }
                        }
                    },
                    "match_mapping_type": "string"
                }
            }],
            "properties": {
                "timestamp": {
                    "doc_values": true,
                    "type": "date"
                }
            },
            "_all": {
                "enabled": false
            }
        }
    }
}
直接插入數(shù)據(jù):POST http://localhost:9200/blog_2016-12-25/test
{
    "count": 5,
    "desc": "hello world"
}

插入問題還有個話題就是批量插入。Elasticsearch提供了bulk API用來做批量的操作,你可以在該API中自由組合你要做的操作和數(shù)據(jù),一次性發(fā)送給Elasticsearch進行處理,其格式是這樣的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
action_and_meta_data\n
optional_source\n
action_and_meta_data\n
optional_source\n
....
action_and_meta_data\n
optional_source\n
比如:
{ "index" : { "_index" : "test", "_type" : "type1", "_id" : "1" } }
{ "field1" : "value1" }
{ "delete" : { "_index" : "test", "_type" : "type1", "_id" : "2" } }
{ "create" : { "_index" : "test", "_type" : "type1", "_id" : "3" } }
{ "field1" : "value3" }
{ "update" : {"_id" : "1", "_type" : "type1", "_index" : "test"} }
{ "doc" : {"field2" : "value2"} }

如果是針對相同的index和doc type進行操作,則在REST API中指定index和type即可。批量插入的操作舉例如下:

1
2
3
4
5
6
7
8
9
10
11
{"index": {}}
{"count": 5, "desc": "hello world 111"}
{"index": {}}
{"count": 6, "desc": "hello world 222"}
{"index": {}}
{"count": 7, "desc": "hello world 333"}
{"index": {}}
{"count": 8, "desc": "hello world 444"}
查看插入的結(jié)果:GET http://localhost:9200/blog_2016-12-24/test/_search

數(shù)據(jù)查詢

Elasticsearch的查詢語法(query DSL)分為兩部分:queryfilter,區(qū)別在于查詢的結(jié)果是要完全匹配還是相關性匹配。filter查詢考慮的是“文檔中的字段值是否等于給定值”,答案在“是”與“否”中;而query查詢考慮的是“文檔中的字段值與給定值的匹配程度如何”,會計算出每份文檔與給定值的相關性分數(shù),用這個分數(shù)對匹配了的文檔進行相關性排序。
在實際使用中,要注意兩點:第一,filter查詢要在沒有做倒排索引的字段上做,即上面mapping中增加的.raw字段;第二,通常使用filter來縮小查詢范圍,使用query進行搜索,即二者配合使用。舉例來看,注意看三個不同查詢在寫法上的區(qū)別:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
1. 只使用query進行查詢:
查詢的結(jié)果是page_name字段中包含了wechat所有文檔
這里使用size來指定返回文檔的數(shù)量,默認Elasticsearch是返回前100條數(shù)據(jù)的
{
    "query": {
        "bool": {
            "must": [{
                "match": {
                    "page_name": "wechat"
                }
            },
            {
                "range": {
                    "timestamp": {
                        "gte": 1481218631,
                        "lte": 1481258231,
                        "format": "epoch_second"
                    }
                }
            }]
        }
    },
    "size": 2
}
2. 只使用filter進行查詢:
查詢的結(jié)果是page_name字段值等于"example.cn/wechat/view.html"的所有文檔
{
    "filter": {
        "bool": {
            "must": [{
                "term": {
                    "page_name.raw": "example.cn/wechat/view.html"
                }
            },
            {
                "range": {
                    "timestamp": {
                        "gte": 1481218631,
                        "lte": 1481258231,
                        "format": "epoch_second"
                    }
                }
            }]
        }
    },
    "size": 2
}
3. 同時使用query與filter進行查詢:
查詢的結(jié)果是page_name字段值等于"example.cn/wechat/view.html"的所有文檔
{
    "query": {
        "bool": {
            "filter": [{
                "bool": {
                    "must": [{
                        "term": {
                            "page_name.raw": "job.gikoo.cn/wechat/view.html"
                        }
                    },
                    {
                        "range": {
                            "timestamp": {
                                "gte": 1481218631,
                                "lte": 1481258231,
                                "format": "epoch_second"
                            }
                        }
                    }]
                }
            }]
        }
    },
    "size": 2
}

聚合分析

類似于MySQL中的聚合由分組和聚合計算兩種,Elasticsearch的聚合也有兩部分組成:BucketsMetrics。Buckets相當于SQL中的分組group by,而Metrics則相當于SQL中的聚合函數(shù)COUNT,SUM,MAX,MIN等等。聚合分析自然離不開對多個字段值進行分組,在MySQL中,我們只要使用“group by c1, c2, c3”就可以完成這樣的功能,但是Elasticsearch沒有這樣的語法。Elasticsearch提供了另一種方法,即Buckets嵌套,仔細想想,似乎這種設計更加符合人的思維方式。舉例來看具體操作方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
1. 最簡單的聚合查詢
為了簡單,這里刪除了query的條件描述
將符合條件的文檔按照公司進行聚合
這里有兩個size,和aggs并列的size=0表示返回結(jié)果不包含查詢結(jié)果,只返回聚合結(jié)果,terms里面的size表示返回的聚合結(jié)果數(shù)量
{
    "aggs": {
        "company_terms": {
            "terms": {
                "field": "company",
                "size": 2
            }
        }
    },
    "size": 0
}
2. Buckets與Metric配合
將符合條件的文檔按照公司進行聚合,并獲取每個公司最近一次操作的時間
{
    "aggs": {
        "company_terms": {
            "terms": {
                "field": "company",
                "size": 2
            },
            "aggs": {
                "latest_record": {
                    "max": {
                        "field": "timestamp"
                    }
                }
            }
        }
    },
    "size": 0
}
3. Buckets嵌套
將符合條件的文檔先按照公司進行聚合,再對每個公司下的門店進行聚合,并獲取每個門店最近一次操作的時間
{
    "aggs": {
        "company_terms": {
            "terms": {
                "field": "company",
                "size": 1
            },
            "aggs": {
                "store_terms": {
                    "terms": {
                        "field": "store",
                        "size": 2
                    },
                    "aggs": {
                        "latest_record": {
                            "max": {
                                "field": "timestamp"
                            }
                        }
                    }
                }
            }
        }
    },
    "size": 0
}

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多