1. 程式人生 > >優化Elasticsearch查詢效能

優化Elasticsearch查詢效能

給檔案系統快取提供記憶體

  Elasticsearch嚴重依賴於檔案系統快取,以便快速進行搜尋。 通常應該確保至少有一半的可用記憶體進入檔案系統快取,以便Elasticsearch可以將索引的熱區域保留在實體記憶體中。

使用更快的硬體

  如果搜尋受I / O限制,應該調查為檔案系統快取提供更多記憶體(參見上文)或購買更快的驅動器。 特別是已知SSD驅動器比旋轉磁碟效能更好。 始終使用本地儲存,應避免使用NFS或SMB等遠端檔案系統。 還要注意虛擬化儲存,例如亞馬遜的Elastic Block Storage。 虛擬化儲存與Elasticsearch配合得非常好,因為設定起來非常快速和簡單,所以它很有吸引力,但與專用本地儲存相比,它在本質上也很慢。 如果在EBS

上放置索引,請務必使用預配置IOPS,否則可能會快速限制操作。
  如果搜尋受CPU限制,您應該調查購買更快的CPU。

文件建資料模板

  應對文件進行建模,以使搜尋時間操作儘可能便宜。
  特別是,應該避免連線。 巢狀(nested )可以使查詢慢幾倍,父-子(parent-child)關係的資料可以使查詢慢幾百倍。 因此,如果可以通過非規範化文件來回答相同的問題,則可以預期顯著的加速。(強烈建議,因為我也是自己自定義模板的,後面我會出一篇專門說如何設計資料模板的文章)

搜尋儘可能少的欄位

  query_stringmulti_match查詢所針對的欄位越多,ES就越慢。 提高多個欄位的搜尋速度的常用技術是在索引時將其值複製到單個欄位中,然後在搜尋時使用此欄位。 這可以使用對映的

copy-to指令自動執行,而無需更改文件源。
  下面是一個包含電影的索引示例,這些電影通過將兩個值都索引到name_and_plot欄位中來優化搜尋電影名稱和圖表的查詢。

PUT movies
{
  "mappings": {
    "_doc": {
      "properties": {
        "name_and_plot": {
          "type": "text"
        },
        "name": {
          "type": "text",
          "copy_to": "name_and_plot"
        },
        "plot": {
          "type": "text",
          "copy_to": "name_and_plot"
        }
      }
    }
  }
}

預索引資料

  應該利用查詢中的模式來優化資料索引的方式。
  例如,如果所有文件都有一個price欄位,並且大多數查詢在固定的範圍列表上執行範圍聚合,則可以通過將範圍預先索引到索引中並使用術語聚合來加快此聚合。 例:建立一條文件:

PUT index/_doc/1
{
  "designation": "spoon",
  "price": 13
}

搜尋請求如下

GET index/_search
{
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 10 },
          { "from": 10, "to": 100 },
          { "from": 100 }
        ]
      }
    }
  }
}

然後可以通過索引時間範圍的price_range欄位來壓縮文件,該欄位應該對映為keyword

PUT index
{
  "mappings": {
    "_doc": {
      "properties": {
        "price_range": {
          "type": "keyword"
        }
      }
    }
  }
}

PUT index/_doc/1
{
  "designation": "spoon",
  "price": 13,
  "price_range": "10-100"
}

然後搜尋請求可以聚合此新欄位,而不是在price欄位上執行範圍聚合。

GET index/_search
{
  "aggs": {
    "price_ranges": {
      "terms": {
        "field": "price_range"
      }
    }
  }
}

Mappings

  某些資料雖然是數字並不意味著會對映為數字欄位。通常,儲存識別符號的欄位(例如ISBN或從另一個數據庫中識別記錄的任何數字)可以將其對映為keyword而不是integerlong

避免指令碼

  一般來說,應該避免使用指令碼。但如果是必要的,應該使用painless或者expressions指令碼引擎。

搜尋舍入日期

  使用now的日期欄位上的查詢通常不能快取,因為被匹配的範圍一直在變化。但是,從使用者體驗的角度來看,切換到一個完整的日期通常是可以接受的,並且可以更好地利用查詢快取。
  例如下面的查詢:

PUT index/_doc/1
{
  "my_date": "2016-05-11T16:30:55.328Z"
}

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "my_date": {
            "gte": "now-1h",
            "lte": "now"
          }
        }
      }
    }
  }
}

可以用以下查詢替換:

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "my_date": {
            "gte": "now-1h/m",
            "lte": "now/m"
          }
        }
      }
    }
  }
}

  在這種情況下,我們舍入到分鐘,因此如果當前時間是16:31:29,範圍查詢將匹配my_date欄位的值在15:31:0016:31:59之間的所有內容。 如果多個使用者在同一分鐘內執行包含此範圍的查詢,則查詢快取可以幫助加快速度。 用於舍入的間隔越長,查詢快取可以提供的幫助越多,但要注意過於激進的舍入也可能會損害使用者體驗。
注意:為了能夠利用查詢快取,可能很容易將範圍分割成一個大的可快取部分和一個小的不可快取部分,如下所示:

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "should": [
            {
              "range": {
                "my_date": {
                  "gte": "now-1h",
                  "lte": "now-1h/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gt": "now-1h/m",
                  "lt": "now/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gte": "now/m",
                  "lte": "now"
                }
              }
            }
          ]
        }
      }
    }
  }
}

但是,這種做法可能會使查詢在某些情況下執行得更慢,因為bool查詢引入的開銷可能會破壞更好地利用查詢快取的節省。

Force-merge只讀索引

  只讀索引將從合併到單個段中獲益。基於時間的索引通常是這樣的:只有當前時間框架的索引獲得新文件,而舊索引是隻讀的。
注意:不要強制將合併索引寫入到後臺合併過程中。

全域性序數預載入

  全域性序數是一個數據結構,用於在keyword 欄位上執行術語聚合。它們被延遲地載入到記憶體中,因為ES不知道哪些欄位將用於術語聚合,哪些欄位不會。可以通過mapping對映(如下)在重新整理時告訴Elasticsearch載入全域性序數:

PUT index
{
  "mappings": {
    "_doc": {
      "properties": {
        "foo": {
          "type": "keyword",
          "eager_global_ordinals": true
        }
      }
    }
  }
}

檔案系統快取預載入

  如果重新啟動執行Elasticsearch的計算機,則檔案系統快取將為空,因此在作業系統將索引的熱區域載入到記憶體之前需要一些時間,以便搜尋操作很快。 根據使用index.store.preload設定的副檔名,可以顯式地告訴作業系統應該將哪些檔案載入到記憶體中。預載入設定。
注意:如果檔案系統快取不夠大,無法儲存所有資料,那麼在太多索引或太多檔案上急切地將資料載入到檔案系統快取中會使搜尋速度變慢。謹慎使用。

將識別符號對映為keyword

  如果文件中有數字識別符號,則很容易將它們對映為數字,這與它們的json型別一致.但是,Elasticsearch索引數字的方式會優化範圍查詢,而keyword欄位在術語查詢時更好。 由於識別符號從未在範圍查詢中使用,因此應將它們對映為關鍵字。

使用索引排序來加速連線

  索引排序可以很有用,以便以稍微慢點的索引為代價使連線更快。在索引分類文件中閱讀更多資訊

使用preference來優化快取利用率

  有多個快取可以幫助搜尋效能,例如檔案系統快取請求快取查詢快取。然而,所有這些快取都是在節點級別上維護的,這意味著,如果您在一行中執行相同的請求兩次,擁有一個或多個副本,並使用預設的路由演算法round robin,那麼這兩個請求將進入不同的碎片副本,從而節點級快取發揮不起作用。
  由於搜尋應用程式的使用者通常會一個接一個地執行類似的請求,例如為了分析較窄索引子集,使用標識當前使用者或會話的偏好值可以幫助優化快取記憶體的使用。

副本可能有助於提高吞吐量,但並非總是如此

  除了提高彈性外,副本還可以幫助提高吞吐量。例如,如果您有單個分片索引和三個節點,則需要將副本數設定為2,以便總共擁有3個分片副本,以便使用所有節點。
  現在假設你有一個2分片索引和兩個節點。在一種情況下,副本的數量是0,這意味著每個節點擁有一個分片。在第二種情況下,副本的數量是1,這意味著每個節點具有兩個分片。哪種設定在搜尋效能方面表現最佳?通常,每個節點總共具有較少分片的設定將表現得更好。原因是它為每個分片提供了更大的可用檔案系統快取份額,而檔案系統快取可能是Elasticsearch的第一效能因子。同時,請注意,在單節點發生故障的情況下,沒有副本的設定會出現故障,因此在吞吐量和可用性之間需要進行權衡。
  那麼正確的副本資料是多少?如果您的群集具有num_nodes節點,則總共有num_primaries主分片,如果您希望最多能夠同時處理max_failures節點故障,那麼適合您的副本數量為max(max_failures,ceil(num_nodes /) num_primaries) - 1)

開啟自適應副本選擇

  當存在多個數據副本時,elasticsearch可以使用一組稱為adaptive replica selection的標準,根據包含每個碎片副本的節點的響應時間、服務時間和佇列大小,選擇資料的最佳副本。這可以提高查詢吞吐量並減少搜尋量大的應用程式的延遲。