Elasticsearch 快速開始

Elasticsearch 是一個分佈式的 RESTful 風格的搜索和數據分析引擎。html

  • 查詢 : Elasticsearch 容許執行和合並多種類型的搜索 — 結構化、非結構化、地理位置、度量指標 — 搜索方式隨心而變。
  • 分析 : 找到與查詢最匹配的十個文檔是一回事。可是若是面對的是十億行日誌,又該如何解讀呢?Elasticsearch 聚合讓您可以從大處着眼,探索數據的趨勢和模式。
  • 速度 : Elasticsearch 很快。真的,真的很快。
  • 可擴展性 : 能夠在筆記本電腦上運行。 也能夠在承載了 PB 級數據的成百上千臺服務器上運行。
  • 彈性 : Elasticsearch 運行在一個分佈式的環境中,從設計之初就考慮到了這一點。
  • 靈活性 : 具有多個案例場景。數字、文本、地理位置、結構化、非結構化。全部的數據類型都歡迎。
  • HADOOP & SPARK : Elasticsearch + Hadoop

準備開始

Elasticsearch是一個高度可伸縮的開源全文搜索和分析引擎。它容許您快速和接近實時地存儲、搜索和分析大量數據。node

這裏有一些使用Elasticsearch的用例:git

  1. 你經營一個網上商店,你容許你的顧客搜索你賣的產品。在這種狀況下,您可使用Elasticsearch來存儲整個產品目錄和庫存,併爲它們提供搜索和自動完成建議。
  2. 你但願收集日誌或事務數據,並但願分析和挖掘這些數據,以查找趨勢、統計、彙總或異常。在這種狀況下,你可使用loghide (Elasticsearch/ loghide /Kibana堆棧的一部分)來收集、聚合和解析數據,而後讓loghide將這些數據輸入到Elasticsearch中。一旦數據在Elasticsearch中,你就能夠運行搜索和聚合來挖掘你感興趣的任何信息。
  3. 你運行一個價格警報平臺,容許精通價格的客戶指定以下規則:「我有興趣購買特定的電子設備,若是下個月任何供應商的產品價格低於X美圓,我但願獲得通知」。在這種狀況下,你能夠抓取供應商的價格,將它們推入到Elasticsearch中,並使用其反向搜索(Percolator)功能來匹配價格走勢與客戶查詢,並最終在找到匹配後將警報推送給客戶。
  4. 你有分析/業務智能需求,並但願快速調查、分析、可視化,並對大量數據提出特別問題(想一想數百萬或數十億的記錄)。在這種狀況下,你可使用Elasticsearch來存儲數據,而後使用Kibana (Elasticsearch/ loghide /Kibana堆棧的一部分)來構建自定義儀表板,以可視化對您來講很重要的數據的各個方面。此外,還可使用Elasticsearch聚合功能對數據執行復雜的業務智能查詢。

基本概念

Near Realtime (NRT)github

Elasticsearch是一個近乎實時的搜索平臺。這意味着從索引文檔到能夠搜索的時間只有輕微的延遲(一般是1秒)。json

Cluster數組

集羣是一個或多個節點(服務器)的集合,它們共同保存你的整個數據,並提供跨全部節點的聯合索引和搜索功能。一個集羣由一個惟一的名稱標識,默認這個惟一標識的名稱是"elasticsearch"。這個名稱很重要,由於若是節點被設置爲按其名稱加入集羣,那麼節點只能是集羣的一部分。服務器

確保不要在不一樣的環境中用相同的集羣名稱,不然可能致使節點加入到錯誤的集羣中。例如,你可使用"logging-dev", "logging-test", "logging-prod"分別用於開發、測試和正式集羣的名字。網絡

Nodeapp

節點是一個單獨的服務器,它是集羣的一部分,存儲數據,並參與集羣的索引和搜索功能。就像集羣同樣,節點由一個名稱來標識,默認狀況下,該名稱是在啓動時分配給節點的隨機通用惟一標識符(UUID)。若是不想用默認的節點名,能夠定義任何想要的節點名。這個名稱對於管理來講很重要,由於你但願識別網絡中的哪些服務器對應於你的Elasticsearch集羣中的哪些節點。curl

一個節點能夠經過配置集羣名稱來加入到一個特定的集羣中。默認狀況下,每一個節點都被設置加入到一個名字叫"elasticsearch"的集羣中,這就意味着若是你啓動了不少個節點,而且假設它們彼此能夠互相發現,那麼它們將自動造成並加入到一個名爲"elasticsearch"的集羣中。

一個集羣能夠有任意數量的節點。此外,若是在你的網絡上當前沒有運行任何節點,那麼此時啓動一個節點將默認造成一個單節點的名字叫"elasticsearch"的集羣。

Index

索引是具備某種類似特徵的文檔的集合。例如,你能夠有一個顧客數據索引,產品目錄索引和訂單數據索引。索引有一個名稱(必須是小寫的)標識,該名稱用於在對其中的文檔執行索引、搜索、更新和刪除操做時引用索引。

Document

文檔是能夠被索引的基本信息單元。文檔用JSON表示。

Shards & Replicas

一個索引可能存儲大量數據,這些數據能夠超過單個節點的硬件限制。例如,一個包含10億條文檔佔用1TB磁盤空間的索引可能不適合在單個節點上,或者可能太慢而不能單獨處理來自單個節點的搜索請求。

爲了解決這個問題,Elasticsearch提供了將你的索引細分爲多個碎片(或者叫分片)的能力。在建立索引時,能夠簡單地定義所需的分片數量。每一個分片自己就是一個功能徹底獨立的「索引」,能夠駐留在集羣中的任何節點上。

分片之因此重要,主要有兩個緣由:

  • 它容許你水平地分割/擴展內容卷
  • 它容許你跨分片(可能在多個節點上)分佈和並行操做,從而提升性能和吞吐量

在一個網絡/雲環境中隨時都有可能出現故障,強烈推薦你有一個容災機制。Elasticsearch容許你將一個或者多個索引分片複製到其它地方,這被稱之爲副本。

複製之因此重要,有兩個主要緣由:

  • 它提供了在一個shard/node失敗是的高可用性。出於這個緣由,很重要的一個點是一個副本歷來不會被分配到與它複製的原始分片相同節點上。也就是說,副本是放到另外的節點上的。
  • 它容許擴展搜索量/吞吐量,由於搜索能夠在全部副本上並行執行。

總而言之,每一個索引均可以分割成多個分片。索引也能夠被複制零(意味着沒有副本)或更屢次。一旦被複制,每一個索引都將具備主分片(被複制的原始分片)和副本分片(主分片的副本)。在建立索引時,能夠爲每一個索引定義分片和副本的數量。建立索引後,您能夠隨時動態地更改副本的數量,但不能更改過後分片的數量。

在默認狀況下,Elasticsearch中的每一個索引都分配了5個主分片和1個副本,這意味着若是集羣中至少有兩個節點,那麼索引將有5個主分片和另外5個副本分片(PS:這5個副本分片組成1個完整副本),每一個索引總共有10個分片。

(畫外音:副本是針對索引而言的,同時須要注意索引和節點數量沒有關係,咱們說2個副本指的是索引被複制了2次,而1個索引可能由5個分片組成,那麼在這種狀況下,集羣中的分片數應該是 5 × (1 + 2) = 15 )

安裝

tar -zxf elasticsearch-6.3.2.tar.gz
cd elasticsearch-6.3.2/bin
./elasticsearch
注意:不能以root用戶運行elasticsearch

By default, Elasticsearch uses port 9200 to provide access to its REST API. This port is configurable if necessary.

檢查Elasticsearch是否正在運行:

curl http://localhost:9200/

The REST API

集羣健康

請求:

curl -X GET "localhost:9200/_cat/health?v"

響應:

epoch      timestamp cluster       status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1533625274 15:01:14  elasticsearch green           1         1      0   0    0    0        0             0                  -                100.0%

咱們能夠看到,咱們命名爲「elasticsearch」的集羣如今是green狀態。

不管什麼時候咱們請求集羣健康時,咱們會獲得green, yellow, 或者 red 這三種狀態。

  • Green : everything is good(一切都很好)(全部功能正常)
  • Yellow : 全部數據都是可用的,但有些副本尚未分配(全部功能正常)
  • Red : 有些數據不可用(部分功能正常)

從上面的響應中咱們能夠看到,集羣"elasticsearch"總共有1個節點,0個分片由於尚未數據。

下面看一下集羣的節點列表:

請求:

curl -X GET "localhost:9200/_cat/nodes?v"

響應:

ip        heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
127.0.0.1           15          53   0    0.03    0.03     0.05 mdi       *      Px524Ts

能夠看到集羣中只有一個節點,它的名字是「Px524Ts」

查看所有索引

請求:

curl -X GET "localhost:9200/_cat/indices?v"

響應:

health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

上面的輸出意味着:咱們在集羣中沒有索引

建立一個索引

如今,咱們建立一個名字叫「customer」的索引,而後查看索引:

請求:

curl -X PUT "localhost:9200/customer?pretty"

(畫外音:pretty的意思是響應(若是有的話)以JSON格式返回)

響應:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "customer"
}

請求:

curl -X GET "localhost:9200/_cat/indices?v"

響應:

health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   customer rG5fxdruTNmD-bdYIF5zOg   5   1          0            0      1.1kb          1.1kb

結果的第二行告訴咱們,咱們如今有叫"customer"的索引,而且他有5個主分片和1個副本(默認是1個副本),有0個文檔。

可能你已經注意到這個"customer"索引的健康狀態是yellow。回想一下咱們以前的討論,yellow意味着一些副本(還沒有)被分配。

之因此會出現這種狀況,是由於Elasticsearch默認狀況下爲這個索引建立了一個副本。因爲目前咱們只有一個節點在運行,因此直到稍後另外一個節點加入集羣時,纔會分配一個副本(對於高可用性)。一旦該副本分配到第二個節點上,該索引的健康狀態將變爲green。

索引並查詢一個文檔

如今,讓咱們put一些數據到咱們的"customer"索引:

請求:

curl -X PUT "localhost:9200/customer/_doc/1?pretty" -H 'Content-Type: application/json' -d'{"name": "John Doe"}'

響應:

{
  "_index" : "customer",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

從上面的響應能夠看到,咱們在"customer"索引下成功建立了一個文檔。這個文檔還有一個內部id爲1,這是咱們在建立的時候指定的。

須要注意的是,Elasticsearch並不要求你在索引文檔以前就先建立索引,而後才能將文檔編入索引。在前面的示例中,若是事先不存在"customer"索引,Elasticsearch將自動建立"customer"索引。

(畫外音:也就是說,在新建文檔的時候若是指定的索引不存在則會自動建立相應的索引)

如今,讓我從新檢索這個文檔:

請求:

curl -X GET "localhost:9200/customer/_doc/1?pretty"

響應:

{
  "_index" : "customer",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "found" : true,
  "_source" : {
    "name" : "John Doe"
  }
}

能夠看到除了"found"字段外沒什麼不一樣,"_source"字段返回了一個完整的JSON文檔。

刪除一個索引

如今,讓咱們刪除前面建立的索引,而後查看所有索引

請求:

curl -X DELETE "localhost:9200/customer?pretty"

響應:

{
  "acknowledged" : true
}

接下來,查看一下

curl -X GET "localhost:9200/_cat/indices?v"
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size

到如今爲止,咱們已經學習了建立/刪除索引、索引/查詢文檔這四個命令

curl -X PUT "localhost:9200/customer"
curl -X PUT "localhost:9200/customer/_doc/1" -H 'Content-Type: application/json' -d'{"name": "John Doe"}'
curl -X GET "localhost:9200/customer/_doc/1"
curl -X DELETE "localhost:9200/customer"

若是咱們仔細研究上面的命令,咱們實際上能夠看到如何在Elasticsearch中訪問數據的模式。這種模式能夠歸納以下:

<REST Verb> /<Index>/<Type>/<ID>

修改數據

更新文檔

事實上,每當咱們執行更新時,Elasticsearch就會刪除舊文檔,而後索引一個新的文檔。

下面這個例子展現瞭如何更新一個文檔(ID爲1),改變name字段爲"Jane Doe",同時添加一個age字段:

請求:

curl -X POST "localhost:9200/customer/_doc/1/_update?pretty" -H 'Content-Type: application/json' -d'
{
  "doc": { "name": "Jane Doe", "age": 20 }
}
'

響應:

{
  "_index" : "customer",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 2,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 1,
  "_primary_term" : 1
}

下面這個例子用腳原本將age增長5

請求:

curl -X POST "localhost:9200/customer/_doc/1/_update?pretty" -H 'Content-Type: application/json' -d'
{
  "script" : "ctx._source.age += 5"
}
'

在上面例子中,ctx._source引用的是當前源文檔

響應:

{
  "_index" : "customer",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 3,
  "result" : "updated",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 2,
  "_primary_term" : 1
}

刪除文檔

刪除文檔至關簡單。這個例子展現瞭如何從"customer"索引中刪除ID爲2的文檔:

請求:

curl -X DELETE "localhost:9200/customer/_doc/2?pretty"

響應:

{
  "_index" : "customer",
  "_type" : "_doc",
  "_id" : "2",
  "_version" : 1,
  "result" : "not_found",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

批處理

除了可以索引、更新和刪除單個文檔以外,Elasticsearch還可使用_bulk API批量執行上述任何操做。

這個功能很是重要,由於它提供了一種很是有效的機制,能夠在儘量少的網絡往返的狀況下儘量快地執行多個操做。

下面的例子,索引兩個文檔(ID 1 - John Doe 和 ID 2 - Jane Doe)

請求:

curl -X POST "localhost:9200/customer/_doc/_bulk?pretty" -H 'Content-Type: application/json' -d'
{"index":{"_id":"1"}}
{"name": "John Doe" }
{"index":{"_id":"2"}}
{"name": "Jane Doe" }
'

響應:

{
  "took" : 5,
  "errors" : false,
  "items" : [
    {
      "index" : {
        "_index" : "customer",
        "_type" : "_doc",
        "_id" : "1",
        "_version" : 4,
        "result" : "updated",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 3,
        "_primary_term" : 1,
        "status" : 200
      }
    },
    {
      "index" : {
        "_index" : "customer",
        "_type" : "_doc",
        "_id" : "2",
        "_version" : 1,
        "result" : "created",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 1,
        "_primary_term" : 1,
        "status" : 201
      }
    }
  ]
}

接下來的例子展現了,更新第一個文檔(ID爲1),刪除第二個文檔(ID爲2):

請求:

curl -X POST "localhost:9200/customer/_doc/_bulk?pretty" -H 'Content-Type: application/json' -d'
{"update":{"_id":"1"}}
{"doc": { "name": "John Doe becomes Jane Doe" } }
{"delete":{"_id":"2"}}
'

響應:

{
  "took" : 8,
  "errors" : false,
  "items" : [
    {
      "update" : {
        "_index" : "customer",
        "_type" : "_doc",
        "_id" : "1",
        "_version" : 5,
        "result" : "updated",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 4,
        "_primary_term" : 1,
        "status" : 200
      }
    },
    {
      "delete" : {
        "_index" : "customer",
        "_type" : "_doc",
        "_id" : "2",
        "_version" : 2,
        "result" : "deleted",
        "_shards" : {
          "total" : 2,
          "successful" : 1,
          "failed" : 0
        },
        "_seq_no" : 2,
        "_primary_term" : 1,
        "status" : 200
      }
    }
  ]
}

如今,咱們來從新查看一下索引文檔

curl -X GET "localhost:9200/customer/_doc/1?pretty"

檢索數據

示例數據

如今咱們已經瞭解了基礎知識,讓咱們嘗試處理一個更真實的數據集。我準備了一個關於客戶銀行帳戶信息的虛構JSON文檔示例。每一個文檔都有如下格式:

{
    "account_number": 0,
    "balance": 16623,
    "firstname": "Bradshaw",
    "lastname": "Mckenzie",
    "age": 29,
    "gender": "F",
    "address": "244 Columbus Place",
    "employer": "Euron",
    "email": "bradshawmckenzie@euron.com",
    "city": "Hobucken",
    "state": "CO"
}

加載示例數據

你能夠從這裏下載示例數據

提取它到咱們的當前目錄,而且加載到咱們的集羣中:

新建一個文件accounts.json,而後將數據複製粘貼到該文件中,保存退出

在這個accounts.json文件所在目錄下執行以下命令:

curl -H "Content-Type: application/json" -XPOST "localhost:9200/bank/_doc/_bulk?pretty&refresh" --data-binary "@accounts.json"

此時,accounts.json中的文檔數據便被索引到"bank"索引下

讓咱們查看一下索引:

請求:

curl "localhost:9200/_cat/indices?v"

響應:

health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   customer DoM-O7QmRk-6f3Iuls7X6Q   5   1          1            0      4.5kb          4.5kb
yellow open   bank     59jD3B4FR8iifWWjrdMzUg   5   1       1000            0    474.7kb        474.7kb

能夠看到,如今咱們的集羣中有兩個索引,分別是"customer"和"bank"

"customer"索引,1個文檔,"bank"索引有1000個文檔

The Search API

如今讓咱們從一些簡單的搜索開始。運行搜索有兩種基本方法:一種是經過REST請求URI發送檢索參數,另外一種是經過REST請求體發送檢索參數。

(畫外音:一種是把檢索參數放在URL後面,另外一種是放在請求體裏面。至關於HTTP的GET和POST請求)

請求體方法容許你更有表現力,也能夠用更可讀的JSON格式定義搜索。

用於搜索的REST API可從_search端點訪問。下面的例子返回"bank"索引中的全部文檔:

curl -X GET "localhost:9200/bank/_search?q=*&sort=account_number:asc&pretty"

讓咱們來剖析一下上面的請求。

咱們在"bank"索引中檢索,q=*參數表示匹配全部文檔;sort=account_number:asc表示每一個文檔的account_number字段升序排序;pretty參數表示返回漂亮打印的JSON結果。

響應結果看起來是這樣的:

{
  "took" : 96,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1000,
    "max_score" : null,
    "hits" : [
      {
        "_index" : "bank",
        "_type" : "_doc",
        "_id" : "0",
        "_score" : null,
        "_source" : {
          "account_number" : 0,
          "balance" : 16623,
          "firstname" : "Bradshaw",
          "lastname" : "Mckenzie",
          "age" : 29,
          "gender" : "F",
          "address" : "244 Columbus Place",
          "employer" : "Euron",
          "email" : "bradshawmckenzie@euron.com",
          "city" : "Hobucken",
          "state" : "CO"
        },
        "sort" : [
          0
        ]
      },
      {
        "_index" : "bank",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : null,
        "_source" : {
          "account_number" : 1,
          "balance" : 39225,
          "firstname" : "Amber",
          "lastname" : "Duke",
          "age" : 32,
          "gender" : "M",
          "address" : "880 Holmes Lane",
          "employer" : "Pyrami",
          "email" : "amberduke@pyrami.com",
          "city" : "Brogan",
          "state" : "IL"
        },
        "sort" : [
          1
        ]
      },
      {
        "_index" : "bank",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : null,
        "_source" : {
          "account_number" : 2,
          "balance" : 28838,
          "firstname" : "Roberta",
          "lastname" : "Bender",
          "age" : 22,
          "gender" : "F",
          "address" : "560 Kingsway Place",
          "employer" : "Chillium",
          "email" : "robertabender@chillium.com",
          "city" : "Bennett",
          "state" : "LA"
        },
        "sort" : [
          2
        ]
      },
 	......
 	]
 }

能夠看到,響應由下列幾部分組成:

  • took : Elasticsearch執行搜索的時間(以毫秒爲單位)
  • timed_out : 告訴咱們檢索是否超時
  • _shards : 告訴咱們檢索了多少分片,以及成功/失敗的分片數各是多少
  • hits : 檢索的結果
  • hits.total : 符合檢索條件的文檔總數
  • hits.hits : 實際的檢索結果數組(默認爲前10個文檔)
  • hits.sort : 排序的key(若是按分值排序的話則不顯示)
  • hits._score 和 max_score 如今咱們先忽略這些字段

下面是一個和上面相同,可是用請求體的例子:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": [
    { "account_number": "asc" }
  ]
}
'

區別在於,咱們沒有在URI中傳遞q=*,而是向_search API提供json風格的查詢請求體

很重要的一點是,一旦返回搜索結果,Elasticsearch就徹底完成了對請求的處理,不會在結果中維護任何類型的服務器端資源或打開遊標。這是許多其餘平臺如SQL造成鮮明對比。

查詢語言

Elasticsearch提供了一種JSON風格的語言,您可使用這種語言執行查詢。這被成爲查詢DSL。

查詢語言很是全面,乍一看可能有些嚇人,但實際上最好的學習方法是從幾個基本示例開始。

回到咱們上一個例子,咱們執行這樣的查詢:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} }
}
'

查詢部分告訴咱們查詢定義是什麼,match_all部分只是咱們想要運行的查詢類型。這裏match_all查詢只是在指定索引中搜索全部文檔。

除了查詢參數外,咱們還能夠傳遞其餘參數來影響搜索結果。在上面部分的例子中,咱們傳的是sort參數,這裏咱們傳size:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "size": 1
}
'

注意:若是size沒有指定,則默認是10

下面的例子執行match_all,並返回第10到19條文檔:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "from": 10,
  "size": 10
}
'

from參數(從0開始)指定從哪一個文檔索引開始,而且size參數指定從from開始返回多少條。這個特性在分頁查詢時很是有用。

注意:若是沒有指定from,則默認從0開始

這個示例執行match_all,並按照賬戶餘額降序對結果進行排序,並返回前10個(默認大小)文檔。

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "sort": { "balance": { "order": "desc" } }
}
'

搜索

繼續學習查詢DSL。首先,讓咱們看一下返回的文檔字段。默認狀況下,會返回完整的JSON文檔(PS:也就是返回全部字段)。這被成爲source(hits._source)

若是咱們不但願返回整個源文檔,咱們能夠從源文檔中只請求幾個字段來返回。

下面的例子展現了只返回文檔中的兩個字段:account_number 和 balance字段

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match_all": {} },
  "_source": ["account_number", "balance"]
}
'

(畫外音:至關於SELECT account_number, balance FROM bank)

如今讓咱們繼續查詢部分。之前,咱們已經看到了如何使用match_all查詢匹配全部文檔。如今讓咱們引入一個名爲match query的新查詢,它能夠被看做是基本的字段搜索查詢(即針對特定字段或字段集進行的搜索)。

下面的例子返回account_number爲20的文檔

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match": { "account_number": 20 } }
}
'

(畫外音:至關於SELECT * FROM bank WHERE account_number = 20)

下面的例子返回address中包含"mill"的帳戶:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match": { "address": "mill" } }
}
'

(畫外音:至關於SELECT * FROM bank WHERE address LIKE '%mill%')

下面的例子返回address中包含"mill"或者"lane"的帳戶:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": { "match": { "address": "mill lane" } }
}
'

(畫外音:至關於SELECT * FROM bank WHERE address LIKE '%mill' OR address LIKE '%lane%')

讓咱們來引入bool查詢,bool查詢容許咱們使用布爾邏輯將較小的查詢組合成較大的查詢。

下面的例子將兩個match查詢組合在一塊兒,返回address中包含"mill"和"lane"的帳戶:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}
'

(畫外音:至關於SELECT * FROM bank WHERE address LIKE '%mill%lane%')

上面是bool must查詢,下面這個是bool shoud查詢:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "should": [
        { "match": { "address": "mill" } },
        { "match": { "address": "lane" } }
      ]
    }
  }
}
'

(畫外音:must至關於and,shoud至關於or,must_not至關於!)

(畫外音:邏輯運算符:與/或/非,and/or/not,在這裏就是must/should/must_not)

咱們能夠在bool查詢中同時組合must、should和must_not子句。此外,咱們能夠在任何bool子句中編寫bool查詢,以模擬任何複雜的多級布爾邏輯。

下面的例子是一個綜合應用:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": [
        { "match": { "age": "40" } }
      ],
      "must_not": [
        { "match": { "state": "ID" } }
      ]
    }
  }
}
'

(畫外音:至關於SELECT * FROM bank WHERE age LIKE '%40%' AND state NOT LIKE '%ID%')

過濾

分數是一個數值,它是文檔與咱們指定的搜索查詢匹配程度的相對度量(PS:類似度)。分數越高,文檔越相關,分數越低,文檔越不相關。

可是查詢並不老是須要產生分數,特別是當它們僅用於「過濾」文檔集時。Elasticsearch檢測到這些狀況並自動優化查詢執行,以便不計算無用的分數。

咱們在前一節中介紹的bool查詢還支持filter子句,該子句容許使用查詢來限制將由其餘子句匹配的文檔,而不改變計算分數的方式。

做爲一個例子,讓咱們引入range查詢,它容許咱們經過一系列值篩選文檔。這一般用於數字或日期過濾。

下面這個例子用一個布爾查詢返回全部餘額在20000到30000之間(包括30000,BETWEEN...AND...是一個閉區間)的帳戶。換句話說,咱們想要找到餘額大於等於20000而且小於等等30000的帳戶。

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "must": { "match_all": {} },
      "filter": {
        "range": {
          "balance": {
            "gte": 20000,
            "lte": 30000
          }
        }
      }
    }
  }
}
'

彙集

(畫外音:至關於SQL中的彙集函數,好比分組、求和、求平均數之類的)

首先,這個示例按state對全部賬戶進行分組,而後按照count數降序(默認)返回前10條(默認):

(畫外音:至關於按state分組,而後count(*),每一個組中按照COUNT(*)數取 top 10)

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      }
    }
  }
}
'

在SQL中,上面的彙集操做相似於:

SELECT state, COUNT(*) FROM bank GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;

響應:

{
    "took":50,
    "timed_out":false,
    "_shards":{
        "total":5,
        "successful":5,
        "skipped":0,
        "failed":0
    },
    "hits":{
        "total":1000,
        "max_score":0,
        "hits":[

        ]
    },
    "aggregations":{
        "group_by_state":{
            "doc_count_error_upper_bound":20,
            "sum_other_doc_count":770,
            "buckets":[
                {
                    "key":"ID",
                    "doc_count":27
                },
                {
                    "key":"TX",
                    "doc_count":27
                },
                {
                    "key":"AL",
                    "doc_count":25
                },
                {
                    "key":"MD",
                    "doc_count":25
                },
                {
                    "key":"TN",
                    "doc_count":23
                },
                {
                    "key":"MA",
                    "doc_count":21
                },
                {
                    "key":"NC",
                    "doc_count":21
                },
                {
                    "key":"ND",
                    "doc_count":21
                },
                {
                    "key":"ME",
                    "doc_count":20
                },
                {
                    "key":"MO",
                    "doc_count":20
                }
            ]
        }
    }
}

注意,咱們將size=0設置爲不顯示搜索結果,由於咱們只想看到響應中的聚合結果。

接下來的例子跟上一個相似,按照state分組,而後取balance的平均值

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "group_by_state": {
      "terms": {
        "field": "state.keyword"
      },
      "aggs": {
        "average_balance": {
          "avg": {
            "field": "balance"
          }
        }
      }
    }
  }
}
'

在SQL中,至關於:

SELECT state, COUNT(*), AVG(balance) FROM bank GROUP BY state ORDER BY COUNT(*) DESC LIMIT 10;

下面這個例子展現了咱們如何根據年齡段(20-29歲,30-39歲,40-49歲)來分組,而後根據性別分組,最後獲得平均帳戶餘額,每一個年齡等級,每一個性別:

curl -X GET "localhost:9200/bank/_search" -H 'Content-Type: application/json' -d'
{
  "size": 0,
  "aggs": {
    "group_by_age": {
      "range": {
        "field": "age",
        "ranges": [
          {
            "from": 20,
            "to": 30
          },
          {
            "from": 30,
            "to": 40
          },
          {
            "from": 40,
            "to": 50
          }
        ]
      },
      "aggs": {
        "group_by_gender": {
          "terms": {
            "field": "gender.keyword"
          },
          "aggs": {
            "average_balance": {
              "avg": {
                "field": "balance"
              }
            }
          }
        }
      }
    }
  }
}
'

 

先寫到這裏吧!!!

 

參考

https://www.elastic.co/guide/en/elasticsearch/reference/current/getting-started.html

發現有一本書叫《Elasticsearch: 權威指南

相關文章
相關標籤/搜索