指數和型別之間的差異

很容易看到 types 像 SQL 資料庫中的表,其中 index 是 SQL 資料庫。然而,這不是接近 types 的好方法。

關於型別

實際上,型別實際上只是 Elasticsearch 新增到每個文件的後設資料欄位:_type。上面的例子建立了兩種型別:my_typemy_other_type。這意味著與型別相關聯的每個文件都有一個自動定義的額外欄位,如 "_type": "my_type"; 這是使用文件編制索引,從而使其成為可搜尋或可過濾的欄位,但它不會影響原始文件本身,因此你的應用程式無需擔心它。

所有型別都存在於同一索引中,因此位於索引的相同集合分片中。即使在磁碟級別,它們也存在於相同的檔案中。建立第二種型別提供的唯一分離是合乎邏輯的。每種型別,無論它是否唯一,都需要存在於對映中,並且所有這些對映必須存在於叢集狀態中。這會佔用記憶體,如果每種型別都是動態更新的,它會隨著對映的變化而降低效能。

因此,最佳實踐是僅定義單個型別,除非你確實需要其他型別。通常會看到需要多種型別的場景。例如,假設你有汽車索引。你可以使用多種型別對其進行細分:

  • 寶馬
  • 煩擾
  • 本田
  • 馬自達
  • 賓士
  • 日產
  • rangerover
  • 豐田

這樣,你可以搜尋所有汽車或按製造商按需限制。這兩次搜尋之間的區別很簡單:

GET /cars/_search

GET /cars/bmw/_search

對 Elasticsearch 的新使用者來說,不明顯的是第二種形式是第一種形式的特化。它實際上被重寫為:

GET /cars/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term" : {
            "_type": "bmw"
          }
        }
      ]
    }
  }
}

它只是過濾掉任何未使用 _type 欄位索引的文件,其值為 bmw。由於每個文件都以其型別為 _type 欄位編制索引,因此這是一個非常簡單的過濾器。如果在任一示例中都提供了實際搜尋,則過濾器將根據需要新增到完整搜尋中。

因此,如果型別相同,則提供單一型別(例如,在此示例中為 manufacturer)並且有效地忽略它會好得多。然後,在每個文件中,明確提供一個名為 make 的欄位或你喜歡的任何名稱,並在你想要限制它時手動過濾它。這將減少對映到 1/n 的大小,其中 n 是單獨型別的數量。它確實為每個文件新增了另一個欄位,這是為了簡化對映。

在 Elasticsearch 1.x 和 2.x 中,這樣的欄位應該定義為

PUT /cars
{
  "manufacturer": { <1>
    "properties": {
      "make": { <2>
        "type": "string",
        "index": "not_analyzed"
      }
    }
  }
}
  1. 這個名字是任意的。
  2. 該名稱是任意的*,如果你也想要它,*它可以匹配型別名稱。

在 Elasticsearch 5.x 中,上面的程式碼仍然可以使用(它已被棄用),但更好的方法是使用:

PUT /cars
{
  "manufacturer": { <1>
    "properties": {
      "make": { <2>
        "type": "keyword"
      }
    }
  }
}
  1. 這個名字是任意的。
  2. 該名稱是任意的*,如果你也想要它,*它可以匹配型別名稱。

應該在索引中謹慎使用型別,因為它會使索引對映膨脹,通常沒有太大的好處。你必須至少有一個,但沒有任何東西說你必須有一個以上。

常見問題

  • 如果我有兩個(或更多)型別大多相同但每個型別有一些唯一欄位會怎麼樣?

在索引級別,存在正在與被稀疏地使用的幾個領域中使用的一種型別之間沒有差別多種型別的,與幾個不共享(意味著其它型別甚至從未共享一束非稀疏欄位之間採用現場(一個或多個))。

換句話說: *無論型別如何,*稀疏使用的欄位在索引上都是稀疏的。稀疏性不會因為它是以單獨的型別定義而對索引有益 - 或者真正受到傷害。

你應該只組合這些型別並新增單獨的型別欄位。

  • 為什麼單獨的型別需要以完全相同的方式定義欄位?

因為每個欄位實際上只在 Lucene 級別定義一次,無論有多少型別。型別存在的事實是 Elasticsearch 的一個特徵,它只是一個邏輯分離。

  • 我可以定義具有不同定義的相同欄位的單獨型別嗎?

不。如果你設法在 ES 2.x 或更高版本中找到這樣做的方法,那麼你應該開啟一個錯誤報告 。如前一個問題所述,Lucene 將它們視為單個欄位,因此無法使其正常工作。

ES 1.x 將此作為隱式要求,允許使用者建立條件,其中索引中的一個分片對映實際上與同一索引中的另一個分片不同。這實際上是一種競爭條件,可能會導致意想不到的問題。

規則的例外情況

  • 父/子文件需要在同一索引中使用單獨的型別。
    • 父母住在一種型別。
    • 孩子生活在一個單獨的型別中(但每個孩子與其父母住在同一個碎片中)。
  • 非常小眾的使用案例,其中建立大量的指數是不可取的,稀疏領域的影響優於替代方案。
    • 例如,Elasticsearch 監控外掛 Marvel(1.x 和 2.x)或 X-Pack 監控(5.x +)監控 Elasticsearch 本身的叢集,節點,索引,特定索引(索引級別)的變化,甚至是碎片。它可以每天建立 5 個以上的索引來隔離那些具有唯一對映的文件,或者它可能違反最佳實踐以通過共享索引來減少叢集負載(注意:已定義對映的數量實際上是相同的,但是建立的索引的數量從 n 減少到 1)。
    • 這是一種高階方案,但你必須考慮跨型別的共享欄位定義!