1. 程式人生 > >初識Elasticsearch

初識Elasticsearch

本文僅是個人的學習筆記,有問題請指正。

一、簡介

在大資料領域,自從有了 Hadoop 以後,大家漸漸習慣收集日誌到 HDFS 中,然後每天執行 MapReduce 任務做統計報表。但是,面對諸如“新上線的版本過去幾分鐘在各地反饋如何”,“昨天23:40左右這個投訴使用者有沒有異常”這種即時的開放性問題,傳統的日誌處理方案顯得非常的笨拙和低效。複雜多變的實時資料分析需求,需要的是靈活快捷的響應處理,Elasticsearch的出現讓這個問題得到了很好的解決!

Elasticsearch是一個基於Apache Lucene的實時分散式搜尋和分析引擎。它讓你以前所未有的速度處理大資料成為可能。

Elasticsearch以全文搜尋、結構化搜尋、分析或將這三者混合使用來提供強大的功能,目前已經有很多企業在使用它:

  1. 國外有Wikipedia、StackOverflow、Github、Facebook、Quora、LinkedIn、Netflix等公司都在使用Elasticsearch。

    • Wikipedia使用 ES 提供全文搜尋並高亮關鍵字,以及輸入實時搜尋(search-as-you-type)和搜尋糾錯(did-you-mean)等搜尋建議功能。
    • StackOverflow結合全文搜尋與地理位置查詢,以及more-like-this功能來找到相關的問題和答案。
    • Github使用Elasticsearch檢索1300億行的程式碼。
    • ……
  2. 國內像百度、阿里巴巴、騰訊、新浪等公司都在使用

    • 百度在casio、雲分析、網盟、預測、文庫、直達號、錢包、風控等業務上都應用了ES,單叢集每天匯入30TB+資料,總共每天60TB+。
    • ……

Elasticsearch,簡單點理解,就是在Lucene的基礎上封裝了一層分散式架構,它有如下特點:

  • 處理方式靈活。Elasticsearch 是實時全文索引,不需要像 storm 那樣預先程式設計才能使用;
  • 配置簡易上手。Elasticsearch 全部採用 JSON 介面,目前業界通用的配置語法設計;
  • 叢集線性擴充套件。Elasticsearch 叢集可以擴充套件到上百臺伺服器,處理PB級結構化或非結構化資料;
  • 檢索效能高效。雖然每次查詢都是實時計算,但是優秀的設計和實現基本可以達到百億級資料查詢的秒級響應;

二、基本概念

2.1 索引(Index)

ElasticSearch把資料存放到一個或者多個索引中。如果用關係型資料庫模型對比,索引的地位與資料庫例項(Database)相當。索引存放和讀取的基本單元是文件(Document)。ElasticSearch內部用Apache Lucene實現索引中資料的讀寫。要知道,在ElasticSearch中被視為單獨的一個索引,在Lucene中可能不止一個。這是因為在分散式體系中,ElasticSearch會用到分片(shards)和備份(replicas)機制將一個索引儲存多份。

2.2 文件(Document)

在ElasticSearch的世界中,文件(Document)是主要的存在實體(在Lucene中也是如此)。所有的ElasticSearch應用需求到最後都可以統一建模成一個檢索模型:檢索相關文件。文件(Document)由一個或者多個域(Field)組成,每個域(Field)由一個域名(此域名非彼域名)和一個或者多個值組成(有多個值的值稱為多值域(multi-valued))。在ElasticSeach中,每個文件(Document)都可能會有不同的域(Field)集合;也就是說文件(Document)是沒有固定的模式和統一的結構。文件(Document)之間保持結構的相似性即可(Lucene中的文件(Document)也秉持著相同的規定)。實際上,ElasticSearch中的文件(Document)就是Lucene中的文件(Document)。從客戶端的角度來看,文件(Document)就是一個JSON物件(關於JSON格式的相關資訊,請參看hhtp://en.wikipedia.org/wiki/JSON)。

2.3 文件型別(Type)

每個文件在ElasticSearch中都必須設定它的型別。文件型別使得同一個索引中在儲存結構不同文件時,只需要依據文件型別就可以找到對應的引數對映(Mapping)資訊,方便文件的存取。

2.4 節點(Node)

單獨一個ElasticSearch伺服器例項稱為一個節點。對於許多應用場景來說,部署一個單節點的ElasticSearch伺服器就足夠了。但是考慮到容錯性和資料過載,配置多節點的ElasticSearch叢集是明智的選擇。

2.5 叢集(Cluster)

叢集是多個ElasticSearch節點的集合。這些節點齊心協力應對單個節點無法處理的搜尋需求和資料儲存需求。叢集同時也是應對由於部分機器(節點)執行中斷或者升級導致無法提供服務這一問題的利器。ElasticSearch提供的叢集各個節點幾乎是無縫連線(所謂無縫連線,即叢集對外而言是一個整體,增加一個節點或者去掉一個節點對使用者而言是透明的<個人理解,僅供參考>)。在ElasticSearch中配置一個叢集非常簡單,在我們看來,這是在與同類產品中競爭所體現出的最大優勢。

2.6 分片(Shard)

前面已經提到,叢集能夠儲存超出單機容量的資訊。為了實現這種需求,ElasticSearch把資料分發到多個儲存Lucene索引的物理機上。這些Lucene索引稱為分片索引,這個分發的過程稱為索引分片(Sharding)。在ElasticSearch叢集中,索引分片(Sharding)是自動完成的,而且所有分片索引(Shard)是作為一個整體呈現給使用者的。需要注意的是,儘管索引分片這個過程是自動的,但是在應用中需要事先調整好引數。因為叢集中分片的數量需要在索引建立前配置好,而且伺服器啟動後是無法修改的,至少目前無法修改。

2.7 副本(Replica)

通過索引分片機制(Sharding)可以向ElasticSearch叢集中匯入超過單機容量的資料,客戶端操作任意一個節點即可實現對叢集資料的讀寫操作。當叢集負載增長,使用者搜尋請求阻塞在單個節點上時,通過索引副本(Replica)機制就可以解決這個問題。索引副本(Replica)機制的的思路很簡單:為索引分片建立一份新的拷貝,它可以像原來的主分片一樣處理使用者搜尋請求。同時也順便保證了資料的安全性。即如果主分片資料丟失,ElasticSearch通過索引副本使得資料不丟失。索引副本可以隨時新增或者刪除,所以使用者可以在需要的時候動態調整其數量。

2.8 時間之門(Gateway)

在執行的過程中,ElasticSearch會收集叢集的狀態、索引的引數等資訊。這些資料被儲存在Gateway中。

三、文件操作

3.1 插入Doc

curl -XPUT 'http://localhost:9200/{index}/{type}/{id}' -d 
'{
    "field" : "content",
    ...
}'

在插入的過程中index會自動建立,一個Doc由_index_type_id唯一指定(如果不指定ID,則會自動生成)。另外,在插入的過程中可以通過?version=?timestamp=?ttl=指定一些引數。具體參看《Index API

3.2 獲取Doc

一個Document是由_index_type_id三個屬性唯一標識。

curl -XGET 'http://localhost:9200/website/blog/001'

還可以通過/_source只顯示Doc的內容:

curl -XGET 'http://localhost:9200/website/blog/1/_source'

{
  "title": "My first blog entry",
  "text":  "Just trying this out...",
  "date":  "2014/01/01"
}

pretty
在任意的查詢字串中增加pretty引數。會讓Elasticsearch美化輸出JSON結果以便更加容易閱讀

3.3 刪除Doc

curl -XDELETE 'http://localhost:9200/twitter/tweet/1'

3.4 更新Doc

執行PUT操作,如果已經存在,就相當於更新操作:

curl -XPUT 'http://localhost:9200/website/blog/001' -d
'{
  "field": "value",
  ...
}'

可以看到輸出結果:

{
"_index": "website",
"_type": "blog",
"_id": "001",
"_version": 2,
"created": false
}

created: false建立失敗, 是因為已經存在指定文件。

在內部,Elasticsearch已經標記舊文件為刪除並添加了一個完整的新文件。舊版本文件不會立即消失,但你也不能去訪問它。Elasticsearch會在你繼續索引更多資料時清理被刪除的文件。

3.5 檢查文件是否存在

$ curl -i -XHEAD 'http://localhost:9200/website/blog/001'

HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Content-Length: 0

3.6 Multi Get

Multi Get使用關鍵字_mget,可以一次獲取多個文件,而且這些文件可以跨索引、跨型別。

curl 'localhost:9200/_mget' -d '{
    "docs" : [
        {
            "_index" : "INDEX1",
            "_type" : "type",
            "_id" : "3"
        },
        {
            "_index" : "INDEX2",
            "_type" : "type",
            "_id" : "1"
        }
    ]
}'
curl 'localhost:9200/{index}/_mget' -d '{
    "docs" : [
        {
            "_type" : "type",
            "_id" : "1"
        },
        {
            "_type" : "type",
            "_id" : "2"
        }
    ]
}'
curl 'localhost:9200/{index}/{type}/_mget' -d '{
    "ids" : ["1", "2"]
}'

3.7 Bulk

Bulk API使用關鍵字_bulk,允許我們通過一次請求來實現多個文件的create、index、update或delete。

bulk的請求結構如下:

{ action: { metadata }}\n
{ request body        }\n
{ action: { metadata }}\n
{ request body        }\n
...

加入我們把一個批量請求寫在一個檔案bulk_format中:

{"create":{"_index":"website","_type":"blog","_id":"004"}}
{"title":"The Hero","text":"I have been watching the TV Series...","date":"2015/09/11"}
{"delete":{"_index":"website","_type":"blog","_id":"001"}}

執行批量請求(--data-binary保留換行符):

$ curl -s -XPOST localhost:9200/_bulk --data-binary @bulk_format

四、索引操作

4.1 建立索引

$ curl -XPUT 'http://localhost:9200/twitter/'

$ curl -XPUT 'http://localhost:9200/twitter/' -d '{
    "settings" : {
        "number_of_shards" : 3,
        "number_of_replicas" : 2
    }
}'

curl -XPUT localhost:9200/test -d '{
    "settings" : {
        "number_of_shards" : 1
    },
    "mappings" : {
        "type1" : {
            "_source" : { "enabled" : false },
            "properties" : {
                "field1" : { "type" : "string", "index" : "not_analyzed" }
            }
        }
    }
}'

4.2 刪除索引

$ curl -XDELETE 'http://localhost:9200/twitter/'

4.3 獲取索引資訊

$ curl -XGET localhost:9200/movie

$ curl -XGET localhost:9200/movie/_aliases

$ curl -XGET localhost:9200/movie/_mapping

$ curl -XGET localhost:9200/movie/_setting

Get到的是索引的aliasesmappingssetting等資訊。

4.4 Open/Close索引

關閉一個索引之後,將不能read/write。

curl -XPOST 'localhost:9200/my_index/_close'

curl -XPOST 'localhost:9200/my_index/_open'

五、檢索

5.1 概述

ElasticSearch中的檢索主要分為兩類:確切值、全文檢索

  • 確切值:這類檢索就是給定某個field的一個確定的值或一個範圍,進行完全匹配。
  • 全文檢索:全文檢索會計算每個文件與查詢語句的相關性,會給出一個相關性評分_score

在Elasticsearch中,每一個欄位的資料都是預設被索引的,用於快速檢索。欄位是否被索引由"index"引數控制,它的取值有三個:

解釋
analyzed 首先分析這個字串,然後索引。換言之,以全文形式索引此欄位。
not_analyzed 索引這個欄位,使之可以被搜尋,但是索引內容和指定值一樣。不分析此欄位。
no 不索引這個欄位。這個欄位不能為搜尋到。

string型別欄位預設值是analyzed,用於全文檢索。其他簡單型別——longdoubledate等只能取nonot_analyzed,它們的值不能被分析。

對於string型欄位,在被分析之後,所得的結果(單詞)會用來建立倒排索引。在進行檢索時,檢索字串也會經過相同的分析器,然後用所得的結果在倒排索引中進行匹配,匹配的越多相關性_score打分越高。

$ curl -XGET 'localhost:9200/_analyze?analyzer=standard&pretty' -d 'The quick brown foxes jumped over the lazy dog'

5.2 檢索API

搜尋的關鍵字是_search,我們可以跨索引、跨型別進行搜尋(假設gbus是索引,user,tweet是型別):

/_search         # 在所有索引的所有型別中搜索

/gb/_search      # 在索引gb的所有型別中搜索

/gb,us/_search   # 在索引gb和us的所有型別中搜索

/g*,u*/_search   # 在以g或u開頭的索引的所有型別中搜索

/gb/user/_search  # 在索引gb的型別user中搜索

/gb,us/user,tweet/_search  # 在索引gb和us的型別為user和tweet中搜索

/_all/user,tweet/_search   # 在所有索引中的搜尋型別user和tweet的文件

利用字串查詢

通過查詢字串進行搜尋就是 通過HTTP引數傳遞查詢的關鍵字:

$ curl -XGET localhost:9200/movie/_search?q=runtime:90
  • q:查詢
  • fields:指定返回的欄位
  • timeout:指定超時時間
  • size:指定返回的結果數
  • sort:指定按某欄位排序,fieldName:desc/asc
  • analyzer:指定分析器

利用DSL查詢(結構化查詢語句)

所謂結構化查詢語句是指通過JSON請求體來指定查詢條件。

curl -XGET localhost:9200/movie/info/_search -d '{
  "query": {
    "term": {
      "runtime": 90
    }
  }
}'

Elasticsearch檢索分為兩部分:QueryFilter。兩者的區別在於:filter是不計算相關性的,同時可以cache。因此,filter速度要快於query。

  • from/size:用於結果分頁,預設from 0 , size 10
  • sort:根據一個或多個欄位進行排序
  • fields:只返回每個結果的指定欄位

常用的查詢過濾語句:

  • query

    • term : 主要用於精確匹配哪些值,比如數字,日期,布林值或 not_analyzed的字串(未經分析的文字資料型別)
    • terms : 跟 term 類似,但 terms 允許指定多個匹配條件。 如果某個欄位指定了多個值,那麼文件需要一起去做匹配。
    • match : 標準查詢,不管你需要全文字查詢還是精確查詢基本上都可以用它。
    • multi_match:在match查詢的基礎上同時搜尋多個欄位
    • match_all : 空查詢,返回所有文件
    • range : 範圍查詢
    • regexp :正則匹配
    • prefix : 字首匹配
    • ids:根據id查詢文件
    • filtered:通過 filtered 可以在請求體中同時包含 "query""filter" 子句。
    • bool : 一種複合查詢,把其餘型別的查詢包裹進來。支援must(相當於AND),must_not(相當於NOT),should(相當於OR)。
  • filter

    • 同上
    • and
    • or
    • not

5.3. 聚合(Aggregation)

假設有一個索引 movie 儲存了一組電影相關資訊,格式如下:

{
    "name": "Avengers: Age of Ultron",
    "rating": 7.8,
    "description": "When Tony Stark and Bruce Banner try to jump-start a dormant peacekeeping...",
    "stars": ["Joss Whedon","Robert Downey Jr","Chris Evans","Mark Ruffalo"],
    "type": ["Action","Adventure","Sci-Fi"],
    "runtime": 141
}
  • Min Aggregation:找出播放時間最短的電影
$ curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "min_runtime": { 
            "min" : {
                "field":"runtime"
            }
        }
    }
}'
  • Max Aggregation:找出評分最高的電影
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "max_rating": { 
            "max" : {
                "field":"rating"
            }
        }
    }
}'
  • Sum Aggregation:求所有電影的播放時間的總和
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "intraday_return": { 
            "sum" : {
                "field":"runtime"
            }
        }
    }
}'
  • Avg Aggregation:求所有電影的平均評分
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "avg_rating": { 
            "avg" : {
                "field":"rating"
            }
        }
    }
}'
  • Stats Aggregation:統計所有電影的rating欄位,包括min,max,sum,avg.
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "ratings_stats": { 
            "stats" : {
                "field":"rating"
            }
        }
    }
}'
  • Filter Aggregation:先條件過濾再求平均。(搜尋+聚合)
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "runtime_products": {
            "filter":{"term":{"runtime":90}}, 
            "aggs" : {
                "avg_rating":{
                    "avg":{"field":"rating"}
                }
            }
        }
    }
}'
  • Terms Aggregation:統計各種型別的電影的數量。
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "types": { 
            "terms" : {
                "field":"type"
            }
        }
    }
}'
  • Range Aggregation:統計評分在小於3、3到5、5到8、8到10的電影的數量。
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "rating_ranges": { 
            "range" : {
                "field":"rating",
                "ranges":[
                    {"to":3},
                    {"from":3,"to":5},
                    {"from":5,"to":8},
                    {"from":8,"to":10}
                ]
            }
        }
    }
}'
  • Histogram Aggregation:以3為步長,統計評分在0-3、3-6、6-9、9-12的電影的數量。
curl 'localhost:9200/movie/_search?fields=aggregations&pretty' -d '
{
    "aggs" : {
        "ratings": { 
            "histogram" : {
                "field":"rating",
                "interval":3
            }
        }
    }
}'

六、叢集管理與監控

6.1 監控

cluster級別的API總是以http://localhost:9200/_cluster/開頭。

6.1.1、檢視叢集 health 狀態

curl -XGET 'http://localhost:9200/_cluster/health?pretty'

#也可以檢視某個索引的 health 狀態:

curl -XGET 'http://localhost:9200/_cluster/health/movie'

6.1.2、檢視叢集state

curl -XGET 'http://localhost:9200/_cluster/state'

該命令會輸出所有的nodes和shards的狀態資訊,但是由於太多,可讀性不高。

6.1.3. 檢視叢集的stats

$ curl -XGET localhost:9200/_cluster/stats

統計資訊包括shards、nodes、docs、store、還有作業系統CPU、記憶體、程序、JVM、檔案系統等相關統計資訊。

6.1.4. 檢視節點的stats

curl -XGET 'http://localhost:9200/_nodes/stats'

6.1.5. 檢視節點資訊

curl -XGET 'http://localhost:9200/_nodes'

6.2 格式化輸出

ElasticSearch提供了_cat命令用以格式化輸出,將JSON結果以列表的形式輸出。

輸出叢集健康狀態:

$ curl 'localhost:9200/_cat/health'

輸出當前的master節點:

$ curl 'localhost:9200/_cat/master'

輸出所有的nodes資訊:

$ curl 'localhost:9200/_cat/nodes'

輸出所有doc數:

$ curl 'localhost:9200/_cat/count'

輸出索引別名:

$ curl 'localhost:9200/_cat/aliases?v'

輸出所有索引的狀態和統計資料:

$ curl 'localhost:9200/_cat/indices'

輸出每個節點的shards分配情況:

$ curl 'localhost:9200/_cat/allocation'

輸出每個shard的統計資訊:

$ curl 'localhost:9200/_cat/shards'

輸出當前recovery的進度:

$ curl 'localhost:9200/_cat/recovery'

6.3 叢集管理

6.3.1、重定向(reroute)

重定向是指手動控制shard的分佈,包括三種操作:

  • 移動(move):把分片從一節點移動到另一個節點。可以指定索引名和分片號。
  • 取消(cancel):取消分配一個分片。可以指定索引名和分片號。node引數可以指定在那個節點取消正在分配的分片。allow_primary引數支援取消分配主分片。
  • 分配(allocate):分配一個未分配的分片到指定節點。可以指定索引名和分片號。node引數指定分配到那個節點。allow_primary引數可以強制分配主分片,不過這樣可能導致資料丟失。
$ curl -XPOST 'localhost:9200/_cluster/reroute' -d '
    {"commands":[{
        "move":{
            "index":"movie",
            "shard":2,
            "from_node":"eng1.lycc.eseng2.09",
            "to_node":"eng1.lycc.eseng2.08"
            }
        }]
    }'

6.3.2、關閉(shutdown)

關閉所有節點

curl -XPOST 'http://localhost:9200/_shutdown'

關閉指定節點

curl -XPOST 'http://localhost:9200/_cluster/nodes/nodeId1,nodeId2/_shutdown'

延遲關閉

curl -XPOST 'http://localhost:9200/_cluster/nodes/_local/_shutdown?delay=10s'