天天看點

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

ES被設計為處理海量資料的高性能搜尋場景。海量資料具體說至少應該是數億文檔,而高性能具體說就是從數億文檔中任意搜尋需要的資訊,應該在秒級傳回結果。既然ES的一切都是為了性能而設計,從邏輯設計和實體設計兩個角度考察ES的資料組織,對于了解ES的工作原理會有幫助。

  • 邏輯設計:用于索引和搜尋的基本機關是文檔,可以将其認為是關系資料庫裡的一行記錄。文檔以類型分組,類型包含若幹文檔,類似表中包含若幹行。最終,一個或多個類型存儲于同一索引中,索引是更大的容器,類似于SQL世界中的資料庫。ES6中類型的概念已經過時,并且将在7中徹底棄用。是以在我的環境中,ES索引和文檔就對應資料庫的表和記錄。
  • 實體設計:實體設計的配置方式決定了叢集的性能、可擴充性和可用性。ES将每個索引劃分為片,預設為5片,每份分片可以在叢集中不同的伺服器間遷移。通常,應用程式無須關心這些,因為無論ES是單台還是多台伺服器,應用和ES的互動基本保持不變。

圖1展示了這兩個方面:

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖1 ES邏輯設計與實體設計

一、邏輯設計

圖2所示為一個ES索引的邏輯結構。

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖2 ES資料的邏輯設計

在ES6中,一個索引中隻能有一個類型,預設名為_doc。索引-類型-文檔ID的組合唯一确定了一篇文檔,文檔ID可以是任意字元串。當進行搜尋的時候,可以查找特定的索引中的文檔,也可以跨多個索引進行搜尋,類似于單表或多表查詢。但和關系資料庫不同的是,ES并不支援關系資料庫中表之間的join,或者嵌套子查詢。

1. 文檔

ES是面向文檔的,索引和搜尋的最小機關是文檔。ES中文檔有幾個重要的屬性。

  • 它是自包含的。一篇文檔中同時包含字段和字段的取值。關系庫的表結構是中繼資料,與真正資料的存儲和管理方式是不同的。但ES中文檔資料本身就包含了字段名和字段值。
  • 它可以是層次的。文檔中可以包含其它文檔。一個字段可以是簡單的,如一個字元串,也可以包含其它字段和取值。
  • 它是無模式的。文檔不依賴于預先定義的模式,不同文檔的字段可以不同。

一篇文檔通常是資料的JSON表示。和ES溝通最為廣泛的方式是HTTP協定上的JSON。下面是個簡單文檔的例子:

{
  "name": "Elasticsearch Denver",
  "organizer": "Lee",
  "location": "Denver, Colorado, USA"
}           

複制

下面是一個層次型文檔的例子:

{
  "name": "Elasticsearch Denver",
  "organizer": "Lee",
  "location": {
    "name": "Denver, Colorado, USA",
    "geolocation": "39.7392, -104.9847"
  }
}           

複制

一個簡單的文檔也可以包含一組數值,例如:

{
  "name": "Elasticsearch Denver",
  "organizer": "Lee",
  "members": ["Lee", "Mike"]
}           

複制

ES中的文檔是無模式的,也就是說并非所有的文檔都需要擁有相同的字段,它們不是受限于同一個模式。盡管可以随意添加和忽略字段,但是每個字段的類型很重要。ES儲存字段和類型之間的映射以及其它設定,類似于表結構。

2. 類型

ES6中類型的概念已經過時。在ES6之前的版本中,類型是文檔的容器,類似于表格是行的容器。每個類型中字段的定義稱為映射(mapping),每種字段通過不同的方式進行處理。

既然ES是無模式的,為什麼每個文檔屬于一種類型,而且每個類型包含一個看上去很像模式的映射呢?我們說“無模式”是因為文檔不受模式的限制。它們并不需要擁有映射中所定義的所有字段,也能提出新的字段。這是如何運作的?首先,映射包含某個類型中目前索引的所有文檔的所有字段。但不是所有的文檔必須要有所有的字段。同樣,如果一篇新索引的文檔擁有一個映射中尚不存在的字段,ES會自動地将新字段加入映射。為了添加這個字段,ES需要确定它是什麼類型,于是ES會根據字段值進行猜測。例如,如果值是7,ES會假設字段是長整型。

這種對新字段的自動檢測也有缺點,因為ES可能猜得不對。例如,在索引了值7之後,可能想再索引hello world,這時由于它是text而不是long,索引就會失敗,對于線上環境,最安全的方式是在索引資料之前,就定義好所需的映射。從這個角度看很像資料庫,在加入資料前先建表。是以在實際應用中,常見的使用方式還是先仔細定義好映射,再裝載資料。

映射隻是将文檔進行邏輯劃分。從實體角度看,文檔寫入磁盤時不考慮它們所屬的類型。

3. 索引

索引是文檔的容器,一個ES索引非常像關系資料庫中的表,是獨立的大量文檔的集合。每個索引存儲在磁盤上的同組檔案中;索引存儲了所有字段的映射和資料,還有一些設定。例如,每個索引有一個稱為refresh_interval的設定,定義了新文檔對于搜尋可見的時間間隔。從性能的角度看,重新整理操作的代價是非常昂貴的。ES的索引資料是寫入到磁盤上的。但這個過程是分階段實作的,因為IO的操作比較費時。

  1. 先寫到記憶體中,此時不可搜尋。
  2. 預設經過 1s 之後會被寫入 lucene 的底層檔案 segment 中 ,此時可以搜尋到。
  3. refresh 之後才會寫入磁盤。

ES被稱為準實時的,指的就是這種重新整理過程。

二、實體設計

預設情況下,每個索引由5個分片組成,而每個分片又有一個副本,一共10個分片。如圖3所示。

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖3 一個有3個節點的叢集,索引被劃分為5個主分片,每個主分片有一個副本分片

技術上而言,一個分片是一個的檔案,Lucene用這些檔案存儲索引資料。分片也是ES将資料從一個節點遷移到另一個節點的最小機關。

1. 節點

一個節點是一個ES執行個體,多個節點可以加入同一叢集。在多節點的叢集上,同樣的資料可以在多台伺服器上傳播。如果每分片至少有一個副本,那麼任何一個節點都可以當機,而ES依然可以進行服務,傳回所有資料。對于應用程式,叢集中有1個還是多個節點是透明的。預設情況下,可以連接配接叢集中的任一節點并通路完整的資料集。

預設情況下,當索引一篇文檔時,系統首先根據文檔ID的散列值選擇一個主分片,并将文檔發送到該主分片。這個主分片可能位于另一個節點,如圖4中節點2上的主分片,不過對于應用程式這一點是透明的。

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖4 文檔被索引到随機的主分片和它們的副本分片。搜尋在完整的分片集合上運作,無論它們的狀态是主分片還是副本分片。

然後文檔被發送到該主分片的所有副本分片進行索引(如圖4的左邊)。這使得副本分片和主分片之間保持資料的同步。資料同步使得副本分片可以服務于搜尋請求,并在原主分片無法通路時自動更新為主分片。

當搜尋一個索引時,ES需要在該索引的完整集合中進行查找(見圖4的右邊)。這些分片可以是分片,也可以是副本分片。ES在索引的主分片和副本分片中進行搜尋請求的負載均衡,使得副本分片對于搜尋性能和容錯都有所幫助。

2. 主分片與副本分片

分片是ES最小的處理單元,一個分片是一個Lucene的索引:一個包含反向索引的檔案目錄。如圖5所示,get-together索引的首個主分片可能包含何種資訊。該分片稱為get-together0,它是一個Lucene索引、一個反向索引。它預設存儲原始文檔的内容,再加上一些額外的資訊,如詞條字典和詞頻。

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖5 Lucene索引中的詞條字典和詞頻

詞條字典将每個詞條和包含該詞條的文檔映射起來。搜尋的時候,ES沒必要為了某個詞條掃描所有文檔,而是根據這個字典快速識别比對的文檔。

詞頻使得ES可以快速地擷取謀篇文檔中某個詞條出現的次數。這對于計算結果的相關性得分非常重要。更高得分的文檔出現在結果清單的更前面。預設的排序算法是TF-IDF。

可以在任何時候改變每個分片的副本分片的數量,因為副本分片總是可以被建立和移除。但主分片的數量必須在建立索引之前确定,索引建立後主分片的數量不能修改。過少的分片将限制可擴充性,但過多的分片影響性能。預設設定的5份是個不錯的開始。

3. 分布式索引和搜尋

索引的過程如圖6所示。接受索引請求的ES節點首先選擇文檔索引到哪個分片。預設的,文檔在分片中均勻分布:對于每篇文檔,分片是通過其ID字元串的散列決定的。每個分片擁有相同的散列範圍,接收新文檔的機會均等。一旦目标分片确定,接受請求的節點将文檔轉發到該分片所在節點。随後,索引操作在所有目标分片的副本分片中進行。在所有可用副本分片完成文檔的索引後,索引指令就會傳回成功。

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖6 索引操作被轉發到相應的分片,然後轉發到它的副本分片。

在搜尋的時候,接受請求的節點将請求轉發到一組包含所有資料的分片。ES使用round-robin的輪詢機制選擇可用的分片(主分片或副本分片),并将搜尋請求轉發過去,其假設叢集中的所有節點是同樣快的。如圖7所示,ES然後從這些分片收集結果,将其聚集到單一的結果傳回給應用程式。

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖7 轉發搜尋請求到包含完整資料集合的主分片/副本分片,然後聚集結果并将其發送回用戶端。

三、索引資料

可以使用curl的PUT方法索引一個文檔,如:

curl -XPUT '172.16.1.127:9200/get-together/_doc/1?pretty' -H 'Content-Type: application/json' -d '
{
  "name": "Elasticsearch Denver",
  "organizer": "Lee"
}'           

複制

這句DSL語句的功能是向索引get-together中新增一個ID為1的文檔,類似于SQL的insert指令:

insert into get-together (id, name, organizer) values (1, 'Elasticsearch Denver', 'Lee');           

複制

輸出如下:

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

複制

回複中包含索引、類型和文檔ID。如果索引和類型不存在,則會自動建立。文檔ID也可以由ES自動生成。這裡還獲得了文檔的版本,它從1開始并随着每次的更新而增加。ES使用這個版本号實作并發更新時的樂觀鎖功能,防止類似關系資料庫中的第二類更新丢失問題。

這個curl指令之是以可以奏效,是因為ES自動建立了get-together和_doc類型,并為_doc類型建立了一個新的映射。映射包含字元串字段的定義。預設情況下ES處理所有這些,無需任何事先配置,就可以開始索引。

使用下面的指令查詢索引的映射:

curl '172.16.1.127:9200/get-together/_mapping?pretty'           

複制

傳回如下。可以看到,ES自動将name和organizer字段識别為text類型:

{
  "get-together" : {
    "mappings" : {
      "_doc" : {
        "properties" : {
          "name" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "organizer" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      }
    }
  }
}           

複制

映射類型包含與文檔相關的字段或屬性清單。ES預設将字元串資料映射為text和keyword。是以,可以對name和organizer字段執行全文搜尋,同時使用name.keyword或organizer.keyword執行原文比對和聚合。

可以手動建立索引:

curl -XPUT '172.16.1.127:9200/new-index?pretty'           

複制

類似于建立一個名為new-index的表,但這裡隻指定了索引名稱,傳回如下:

{
  "acknowledged" : true,
  "shards_acknowledged" : true,
  "index" : "new-index"
}           

複制

如果隻想建立字元串類型的反向索引搜尋字段,而不映射keyword字段,隻需要在建立索引時顯式指定mapping:

curl -XPUT '172.16.1.127:9200/myindex?pretty' -H 'Content-Type: application/json' -d '
{
  "mappings": {
    "_doc": {
      "properties": {
        "name": {
          "type": "text"
        },
        "organizer": {
          "type": "text"
        }
      }
    }
  }
}'

curl '172.16.1.127:9200/myindex/_mapping?pretty' 
{
  "myindex" : {
    "mappings" : {
      "_doc" : {
        "properties" : {
          "name" : {
            "type" : "text"
          },
          "organizer" : {
            "type" : "text"
          }
        }
      }
    }
  }
}           

複制

四、搜尋資料

下面的指令搜尋get-together索引中包含“elasticsearch”關鍵詞的文檔,但隻擷取最相關文檔的name和location_event.name字段。功能類似于SQL語句:

select name, location_event from get-together 
 where column1 like '%elasticsearch%' 
    or column2 like '%elasticsearch%'
    ...
    or columnn like '%elasticsearch%'
 order by _score
 limit 1;           

複制

下面兩種寫法是等價的,但後者的可讀性更好。這個例子中的搜尋條件沒有指定任何字段,意為在所有字段中搜尋。

curl "172.16.1.127:9200/get-together/_search?\
q=elasticsearch\
&_source=name,location_event.name\
&size=1\
&pretty"

curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "_source": [
    "name",
    "location_event.name"
  ],
  "query": {
    "query_string": {
      "query": "elasticsearch"
    }
  },
  "size": 1
}'           

複制

結果傳回:

{
  "took" : 6,
  "timed_out" : false,
  "_shards" : {
    "total" : 2,
    "successful" : 2,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 10,
    "max_score" : 1.4880564,
    "hits" : [
      {
        "_index" : "get-together",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.4880564,
        "_source" : {
          "name" : "Elasticsearch Denver"
        }
      }
    ]
  }
}           

複制

1. 在哪裡搜尋

可以指定ES在特定索引中進行查詢,但也可以在同一個索引的多個字段中搜尋、在多個索引或在所有索引中搜尋。

# 在多個索引中搜尋
curl "172.16.1.127:9200/get-together,myindex/_search?q=elasticsearch&pretty"

# ignore_unavailable=true會忽略不存在的索引,而不是傳回錯誤
curl "172.16.1.127:9200/get-together,myindex/_search?q=name:elasticsearch&pretty&ignore_unavailable=true"

# 為了在所有索引中搜尋,省略索引名稱
curl "172.16.1.127:9200/_search?q=name:elasticsearch&pretty"           

複制

這種關于“在哪裡搜尋”的靈活性,允許在多個索引中組織資料。例如,日志事件經常以基于時間的索引組織,如“logs-20190101”、“logs-20190102”等。可以隻搜尋最新的索引,也可以在多個索引或全量資料裡搜尋。

2. 回複的内容

(1)時間

除了和搜尋條件比對的文檔,搜尋回複還包含其它有價值的資訊,用于檢驗搜尋的性能或結果的相關性。ES的JSON應答包含了時間、分片、命中統計資料、文檔等。

took字段表示ES處理請求所花的時間,機關是毫秒。timed_out字段表示搜尋請求是否逾時,預設情況下,搜尋永遠不會逾時,但是可以通過timeout參數設定逾時時間。例如下面的搜尋在3秒後逾時:

curl "172.16.1.127:9200/get-together/_search?q=elasticsearch&pretty&timeout=3s"           

複制

如果搜尋逾時,timed_out的值就是true,而且隻能獲得逾時前所獲得的結果。

(2)分片

回複的下一部分是搜尋相關的分片資訊:

"_shards" : {
  "total" : 2,
  "successful" : 2,
  "skipped" : 0,
  "failed" : 0
}           

複制

get-together索引有兩個分片,所有分片都有傳回,是以成功(successful)的值是2,而失敗(failed)的值是0。圖8展示了一個擁有3個節點的叢集,每個節點隻有一份分片且沒有副本分片。如果某個節點當機了,就會丢失某些資料。在這種情況下,ES提供正常分片中的結果,并在failed字段中報告不可搜尋的分片數量。

觸類旁通Elasticsearch:原理一、邏輯設計 二、實體設計三、索引資料四、搜尋資料

圖8 仍然可用的分片将傳回部分結果

(3)命中統計資料

回複的最後一項組成元素是hits,這項相當長因為它包含了比對文檔的數組。數組之前包含了幾項統計資料:

"total" : 10,
"max_score" : 1.4880564           

複制

total表示比對文檔的總數,max_score是這些比對文檔的最高得分。文檔得分,是該文檔和給定搜尋條件的相關性衡量,得分預設是通過TF-IDF算法進行計算的。

比對文檔的總數和回複中的文檔數量可能并不相同。ES預設限制結果數為10,可使用size參數修改傳回的結果數量。檢視total字段的值,可以擷取比對搜尋條件的精确文檔數量。

(4)結果文檔

"hits" : [
  {
    "_index" : "get-together",
    "_type" : "_doc",
    "_id" : "2",
    "_score" : 1.4880564,
    "_source" : {
      "name" : "Elasticsearch Denver"
    }
  }
]           

複制

結果中包括每個比對文檔所屬的索引、類型、它的ID、得分,以及搜尋查詢中所指定的字段的值。查詢中使用了_source=name,location_event.name。如果結果中某個指定字段的值為空,預設沒有該字段的定義,就像結果中沒有location_event.name字段。這點和資料庫不同,資料庫是有schema的,字段值和表定義分開處理,即使某字段沒有值,結果中該字段也會有個NULL值。如果不指定需要哪些字段,會傳回“_source”中的所有字段。_source是一個特殊的字段,ES預設在其中存儲原始的JSON文檔。

3. 如何搜尋

(1)設定查詢的字元串選項

query_string提供了除字元串之外的更多選項。例如,如果搜尋“Elasticsearch san Francisco”,ES預設查詢所有字段。如果想在名稱和标題中查詢,需要指定:

"fields": ["name", "title"]

ES預設傳回比對了任一指定關鍵詞的文檔(預設的操作符是OR)。如果希望比對所有的關鍵詞,需要指定:

"default_operator": "AND"

修改後的查詢如下:

curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "query_string": {
      "query": "elasticsearch",
      "fields": ["name", "title"],
      "default_operator": "AND"
    }
  }
}'           

複制

查詢字元串是指定搜尋條件的強大工具。ES分析字元串并了解所查找的詞條和其它選項,如字段和操作符,然後執行查詢。這項功能是從Lucene繼承而來。

(2)選擇合适的查詢類型

除query_string外,ES還有很多其它類型的查詢。例如,如果在name字段中隻查找“elasticsearch”一個詞,term查詢更直接:

curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "term": {
      "name": "elasticsearch"
    }
  }
}'           

複制

(3)使用過濾器

如果不需要通過結果得分傳回結果,可以使用過濾器查詢替代。過濾器查詢隻關心一條結果是否比對搜尋條件,是以過濾器查詢更快,而且更容易緩存。例如:

curl "172.16.1.127:9200/get-together/_search?pretty" -H 'Content-Type: application/json' -d'
{
  "query": {
    "bool": {
      "filter": {
        "term": {
          "name": "elasticsearch"
        }
      }
    }
  }
}'           

複制

傳回的結果和同樣詞條的查詢相同,但結果沒有根據得分排序,因為所有的結果得分都是0。

(4)應用聚合

除了查詢和過濾,還可以通過聚合進行各種統計。例如實作SQL的簡單聚合:

select count(*), organizer from get-together group by organizer;           

複制

ES查詢指令如下:

curl 172.16.1.127:9200/get-together/_doc/_search?pretty -H 'Content-Type: application/json' -d '
{
  "aggregations": {
    "organizers": {
      "terms": {
        "field": "organizer"
      }
    }
  }
}'           

複制

當在get-together索引上執行此聚合查詢時,報以下錯誤:

"Fielddata is disabled on text fields by default. Set fielddata=true on [organizer] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead."

ES聚合使用一個叫Doc Values的資料結構。Doc Values使聚合更快、更高效且記憶體友好。Doc Values的存在是因為反向索引隻對某些操作是高效的。反向索引的優勢在于查找包含某個條目的文檔,而反過來确定哪些條目在單個文檔裡并不高效。

Doc Values結構類似如下:

Doc Terms

-----------------------------------------------------------------

Doc_1 | brown, dog, fox, jumped, lazy, over, quick, the

Doc_2 | brown, dogs, foxes, in, lazy, leap, over, quick, summer

Doc_3 | dog, dogs, fox, jumped, over, quick, the

Doc values在索引時生成,伴随反向索引建立。像反向索引一樣基于per-segment,且是不可變,被序列化存儲到磁盤。通過序列化持久化資料結構到磁盤,可以用作業系統的檔案緩存來代替JVM heap。但是當工作空間需要的記憶體很大時,Doc Values會被置換出記憶體,這樣會導緻通路速度降低,但是如果放在JVM heap,将直接導緻記憶體溢出錯誤。

Doc Values預設對除了分詞的所有字段起作用。因為分詞字段産生太多tokens且Doc Values對其并不是很有效。Doc Values預設開啟,如果不執行基于一個确定的子段聚合、排序或執行腳本(Script ),可以選擇關閉Doc Values,這可以節省磁盤空間,提高索引資料的速度。

text字段不支援doc_values,text使用fielddata,一種在查詢時期生成在緩存裡的資料結構。當字段在首次sort、aggregations或in a script時建立,讀取磁盤上所有segment的反向索引,反轉 term<->doc 的關系,加載到jvm heap,它将在segment的整個生命周期内一直存在。fielddata很耗記憶體,預設禁用fielddata。text字段是先分詞再索引的,是以,應該使用不分詞的keyword用來聚合。

organizer字段的mapping如下:

"organizer" : {
  "type" : "text"
}           

複制

正如錯誤提示中所指出的,要解決這個問題,可選擇兩種方式:一是設定fielddata=true,二是增加keyword字段。第一種方法可以即時生效,第二種方法需要重新索引資料才能生效。是以建議在建立index時,仔細定義mapping,以免以後修改結構産生問題。

第一種方式:

# 設定fielddata=true
curl -XPOST "172.16.1.127:9200/get-together/_mapping/_doc?pretty" -H 'Content-Type: application/json' -d'
{
  "properties": {
    "organizer": {
      "type": "text",
      "fielddata": "true"
    }
  }
}'

# 執行聚合查詢
curl 172.16.1.127:9200/get-together/_doc/_search?pretty -H 'Content-Type: application/json' -d '
{
  "aggregations": {
    "organizers": {
      "terms": {
        "field": "organizer"
      }
    }
  }
}'           

複制

第二種方式:

# 修改organizer字段的映射
curl -XPOST "172.16.1.127:9200/get-together/_mapping/_doc?pretty" -H 'Content-Type: application/json' -d'
{
  "properties": {
    "organizer": {
      "type": "text",
      "fields": {
        "keyword": {
          "type": "keyword",
          "ignore_above": 256
        }
      }
    }
  }
}'

# 重新索引資料

# 在organizer.keyword字段上執行聚合
curl 172.16.1.127:9200/get-together/_doc/_search?pretty -H 'Content-Type: application/json' -d '
{
  "aggregations": {
    "organizers": {
      "terms": {
        "field": "organizer.keyword"
      }
    }
  }
}'           

複制

傳回的聚合結果如下:

"aggregations" : {
    "organizers" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "Lee",
          "doc_count" : 2
        },
        {
          "key" : "Andy",
          "doc_count" : 1
        },
        {
          "key" : "Daniel",
          "doc_count" : 1
        },
        {
          "key" : "Mik",
          "doc_count" : 1
        },
        {
          "key" : "Tyler",
          "doc_count" : 1
        }
      ]
    }
  }           

複制

關于Doc Values和FieldData的更多說明,參見“Es官方文檔整理-3.Doc Values和FieldData”。

4. 通過ID擷取文檔

為了擷取一個具體的文檔,必須要知道它所屬的索引、類型和ID。然後就可以發送HTTP GET請求到這篇文檔的URI:

curl '172.16.1.127:9200/get-together/_doc/1?pretty'           

複制

回複包括所指定的索引、類型和ID。如果文檔存在,found字段的值是true,此外還有其版本和源。如果文檔不存在,found字段的值是false:

curl '172.16.1.127:9200/get-together/_doc/doesnt-exist?pretty'           

複制

傳回:

{
  "_index" : "get-together",
  "_type" : "_doc",
  "_id" : "doesnt-exist",
  "found" : false
}           

複制

通過ID獲得文檔要比搜尋更快,所消耗的資源成本也更低。這也是實時完成的:隻要索引操作完成了,新的文檔就可以通過GET API擷取。相比之下,搜尋是近實時的,因為它們需要等待預設情況下每秒進行一次的重新整理操作。這個思想和DB也類似,通過主鍵查詢通常是查詢資料最快的途徑。