Elasticsearch 基礎入門詳文

来源:https://www.cnblogs.com/88223100/archive/2023/01/17/Basic-Introduction-to-Elasticsearch.html
-Advertisement-
Play Games

Elasticsearch(簡稱:ES)功能強大,其背後有很多預設值,或者預設操作。這些操作優劣並存,優勢在於我們可以迅速上手使用 ES,劣勢在於,其實這些預設值的背後涉及到很多底層原理,怎麼做更合適,只有數據使用者知道。用 ES 的話來說,你比 ES 更懂你的數據,但一些配置信息、限制信息,還是需... ...


Elasticsearch(簡稱:ES)功能強大,其背後有很多預設值,或者預設操作。這些操作優劣並存,優勢在於我們可以迅速上手使用 ES,劣勢在於,其實這些預設值的背後涉及到很多底層原理,怎麼做更合適,只有數據使用者知道。用 ES 的話來說,你比 ES 更懂你的數據,但一些配置信息、限制信息,還是需要在瞭解了 ES 的功能之後進行人工限制。

你是否遇到:在使用了一段時間 ES 之後,期望使用 ES 的其他功能,例如聚合、排序,但因為欄位類型受限,無奈只能進行reindex等一系列問題?

題主在遇到一些問題後,發現用 ES 很簡單,但是會用 ES 很難。這讓我下定決心一定好好瞭解 ES,也就出現了本文。

 

前言

ES(全稱 Elastic Search)是一款開源、近實時、高性能的分散式搜索引擎。在近 3 年的熱門搜索引擎類數據統計中,ES 都霸居榜首(數據來源:DBRaking),可見的其深受大家的喜愛。

圖片

隨著 ES 的功能越來越強大,其和資料庫的邊界也越來越小,除了進行全文檢索,ES 也支持聚合/排序。ES 底層基於Lucene開發,針對Lucene的局限性,ES 提供了 RESTful API 風格的介面、支持分散式、可水平擴展,同時它可以被多種編程語言調用。

ES 很多基礎概念以及底層實現其本質是 Lucene 的概念。

ps:本文所有的 dsl 查詢、結果展示均基於 ES v7.7

 

歷史背景

Lucene 的歷史背景

下圖這個人叫Doug Cutting,他是 Hadoop 語言和 Lucene 工具包的創始人。Doug Cutting 畢業於斯坦福大學,在 Xerox 積累了一定的工作經驗後,從 1997 年開始,利用業餘時間開發出了 Lucene。Lucene 面世於 1999 年,並於 2005 年成為 Apache 頂級開源項目。

圖片

Lucene的特點:

  • Lucene是基於 java 編寫的,開源的全文檢索引擎工具包
  • Lucene具有高性能:在相同的硬體環境下,基於 Hadoop 的 webmap(Lucene 的第一個應用) 的反應速度是之前系統的 33 倍

Lucene的局限性:

  • 僅限於 java 開發。
  • 類庫的介面學習成本高:本質上Lucene就是一個編程庫,可以按原始介面來調用,但是如果在應用程式中直接使用Lucene,需要覆蓋大量的集成框架工作。
  • 原生並不支持水平擴展,若需實現海量數據的搜索引擎,需在此基礎上格外開發以支持分散式。

ES 的歷史背景

ElasticSearch創始人-Shay Banon
  • 2004 年,Shay Banon 基於 Lucene 開發了 Compass,在考慮 Compass 的第三個版本時,他意識到有必要重寫 Compass 的大部分內容,以“創建一個可擴展的搜索解決方案”。因此,他創建了“一個從頭構建的分散式解決方案”,並使用了一個公共介面,即 HTTP 上的 JSON,它也適用於 Java 以外的編程語言。
  • 2010 年,Shay Banon 在發佈了 Elasticsearch 的第一個版本。

ES 多個版本可能出現破壞性變更,例如,在 6.x,ES 不允許一個 Index 中出現多個Type。在 ES 的官網,每個版本都對應著一個使用文檔。

在使用 ES 之前,最好先瞭解 ES 的版本歷史。下麵列出一些比較重大的更新版本,可以在瞭解了基本概念之後再看。

  • 初始版本 0.7.0 2010 年 5 月 14 日

    • Zen Discovery 自動發現模塊 - Groovy Client 支持 - 簡單的插件管理機制 - 更好支持 ICU 分詞器
  • 1.0.0 2014 年 2 月 14 日

    • 支持聚合分析 Aggregations
    • CAT API 支持
    • Doc values 引入
    • 支持聯盟查詢
    • 斷路器支持
  • 2.0.0 2015 年 10 月 28 日

    • query/filter 查詢合併,都合併到 query 中,根據不同的 context 執行不同的查詢
    • 增加了 pipleline Aggregations 在 ES 中,有 Query 和 Filter 兩種 Context - Query Context :相關性算分
    • Filter Context :不需要算分(YES OR NO), 可以利用 Cache 獲得更好的性能
    • 存儲壓縮可配置
    • Rivers 模塊被移除
    • Multicast 組播發現成為組件
  • 5.0.0 2016 年 10 月 26 日

    • Lucene 6.x 的支持,磁碟空間少一半;索引時間少一半;查詢性能提升 25%;支持 IPV6。
    • Internal engine 級別移除了用於避免同一文檔併發更新的競爭鎖,帶來 15%-20%的性能提升
    • Shrink API ,它可將分片數進行收縮成它的因數,如之前你是 15 個分片,你可以收縮成 5 個或者 3 個又或者 1 個,那麼我們就可以想象成這樣一種場景,在寫入壓力非常大的收集階段,設置足夠多的索引,充分利用 shard 的並行寫能力,索引寫完之後收縮成更少的 shard,提高查詢性能
    • 引入新的欄位類型 Text/Keyword 來替換 String
    • 提供了 Painless 腳本,代替 Groovy 腳本
    • 新增 Sliced Scroll 類型,現在 Scroll 介面可以併發來進行數據遍歷了。每個 Scroll 請求,可以分成多個 Slice 請求,可以理解為切片,各 Slice 獨立並行,利用 Scroll 重建或者遍歷要快很多倍。- 限制索引請求大小,避免大量併發請求壓垮 ES
    • 限制單個請求的 shards 數量,預設 1000 個
  • 6.0.0 2017 年 8 月 31 日

    • Index sorting,即索引階段的排序。
    • 順序號的支持,每個 es 的操作都有一個順序編號(類似增量設計)
    • 無縫滾動升級
    • 逐步廢棄 type,在 6.0 裡面,開始不支持一個 index 裡面存在多個 type
    • Index-template inheritance,索引版本的繼承,目前索引模板是所有匹配的都會合併,這樣會造成索引模板有一些衝突問題, 6.0 將會只匹配一個,索引創建時也會進行驗證 - Load aware shard routing, 基於負載的請求路由,目前的搜索請求是全節點輪詢,那麼性能最慢的節點往往會造成整體的延遲增加,新的實現方式將基於隊列的耗費時間自動調節隊列長度,負載高的節點的隊列長度將減少,讓其他節點分攤更多的壓力,搜索和索引都將基於這種機制。- 已經關閉的索引將也支持 replica 的自動處理,確保數據可靠。
  • 7.0.0 2019 年 4 月 10 日

    • 集群連接變化:TransportClient 被廢棄 以至於,es7 的 java 代碼,只能使用 restclient
    • 重大改進-正式廢除單個索引下多 Type 的支持
    • es6 時,官方就提到了 es7 會刪除 type,並且 es6 時已經規定每一個 index 只能有一個 type。在 es7 中使用預設的_doc 作為 type,官方說在 8.x 版本會徹底移除 type。api 請求方式也發送變化,如獲得某索引的某 ID 的文檔:GET index/_doc/id 其中 index 和 id 為具體的值
    • Lucene9.0 - 引入了真正的記憶體斷路器,它可以更精準地檢測出無法處理的請求,並防止它們使單個節點不穩定 - Zen2 是 Elasticsearch 的全新集群協調層,提高了可靠性、性能和用戶體驗,變得更快、更安全,並更易於使用 - 新功能 - New Cluster coordination - Feature - Complete High Level REST Client - Script Score Query - 性能優化 - Weak-AND 演算法提高查詢性能
    • 預設的 Primary Shared 數從 5 改為 1,避免 Over Sharding
      shard 也是一種資源,shard 過多會影響集群的穩定性。因為 shard 過多,元信息會變多,這些元信息會占用堆記憶體。shard 過多也會影響讀寫性能,因為每個讀寫請求都需要一個線程。所以如果 index 沒有很大的數據量,不需要設置很多 shard。
    • 更快的前 k 個查詢
    • 間隔查詢(Intervals queries) 某些搜索用例(例如,法律和專利搜索)引入了查找單詞或短語彼此相距一定距離的記錄的需要。Elasticsearch 7.0 中的間隔查詢引入了一種構建此類查詢的全新方式,與之前的方法(跨度查詢 span queries)相比,使用和定義更加簡單。與跨度查詢相比,間隔查詢對邊緣情況的適應性更強。

 

基礎概念介紹

下圖簡單概述了 index、type、document 之間的關係,type 在新版本中廢棄,所以畫圖時特殊標識了一下。

index

Index 翻譯過來是索引的意思。在 ES 里,索引有兩個含義:

  • 名詞:一個索引相當於關係型資料庫中的一個表(在 6.x 以前,一個 index 可以被認為是一個資料庫)
  • 動詞:將一份 document 保存在一個 index 里,這個過程也可以稱為索引。

type

在 6.x 之前, index 可以被理解為關係型資料庫中的【資料庫】,而 type 則可以被認為是【資料庫中的表】。使用 type 允許我們在一個 index 里存儲多種類型的數據,數據篩選時可以指定 type 。type 的存在從某種程度上可以減少 index 的數量,但是 type 存在以下限制:

  • 不同 type 里的欄位需要保持一致。例如,一個 index 下的不同 type 里有兩個名字相同的欄位,他們的類型(string, date 等等)和配置也必須相同。
  • 只在某個 type 里存在的欄位,在其他沒有該欄位的 type 中也會消耗資源。
  • 得分是由 index 內的統計數據來決定的。也就是說,一個 type 中的文檔會影響另一個 type 中的文檔的得分。

以上限制要求我們,只有同一個 index 的中的 type 都有類似的映射 (mapping) 時,才勉強適用 type 。否則,使用多個 type 可能比使用多個 index 消耗的資源更多。

這大概也是為什麼 ES 決定廢棄 type 這個概念,個人感覺 type 的存在,就像是一個語法糖,但是並未帶來太大的收益,反而增加了複雜度。

document

index 中的單條記錄稱為 document (文檔),可以理解為表中的一行數據。多條 document 組成了一個 index 。

"hits" : {
    "total" : {
      "value" : 3563,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "test",
        "_type" : "_doc",
        "_id" : "3073",
        "_score" : 1.0,
        "_source" : {
   ...
   }
  }
]

上圖為 ES 一條文檔數據,其中:

  • _index :文檔所屬索引名稱。
  • _type :文檔所屬類型名(此處已預設為_doc)。
  • _id :Doc 的主鍵。在寫入的時候,可以指定該 Doc 的 ID 值,如果不指定,則系統自動生成一個唯一的 UUID 值。
  • _score :顧名思義,得分,也可稱之為相關性,在查詢是 ES 會 根據一些規則計算得分,並根據得分進行倒排。除此之外,ES 支持通過 Function score query 在查詢時自定義 score 的計算規則。
  • _source :文檔的原始 JSON 數據。

field

一個 document 會由一個或多個 field 組成,field 是 ES 中數據索引的最小定義單位,下麵僅列舉部分常用的類型。

⚠️ 在 ES 中,沒有數組類型,任何欄位都可以變成數組。

string
text
  • 索引全文值的欄位,例如電子郵件正文產品描述
  • 如果您需要索引結構化內容,例如電子郵件地址、主機名、狀態代碼或標簽,您可能應該使用 keyword 欄位。
  • 出於不同目的,我們期望以不同方式索引同一欄位,這就是 multi-fields 。例如,可以將 string 欄位映射為用於全文搜索的 text 欄位,並映射為用於排序或聚合的 keyword 欄位:
PUT my_index
{
  "mappings": {
    "properties": {
      "city": {
        "type": "text",
        "fields": {
          "raw": {
            "type":  "keyword"
          }
        }
      }
    }
  }
}
  • ⚠️純 text 欄位預設無法進行排序或聚合
  • ⚠️ 使用text欄位一定要使用合理的分詞器
keyword
  • 用於索引結構化內容的欄位,例如 ID、電子郵件地址、主機名、狀態代碼、郵政編碼或標簽。如果您需要索引全文內容,例如電子郵件正文或產品描述,你應該使用 text 欄位。
  • 它們通常用於過濾(查找所有發佈狀態的博客文章)、排序和聚合keyword 欄位只能精確匹配
numeric

long, integer, short, byte, double, float, half_float, scaled_float...

  • 就整數類型( byte 、 short 、 integer 和 long )而言,應該選擇足以滿足用例的最小類型。
  • 對於浮點類型,使用縮放因數將浮點數據存儲到整數中通常更有效,這就是 scaled_float 類型的實現。
  • 下麵這個 case, scaling_factor 縮放因數設置為 100,對於所有的 API 來說, price 看起來都像是一個雙精度浮點數。但是對於 ES 內部,他其實是一個整數 long 。
"price": {
        "type": "scaled_float",
        "scaling_factor": 100
      }
  • 如果 scaled_float 無法滿足精度要求,可以使用 double 、 float 、 half_float 。
  • 不是所有的欄位都適合存儲為 numberic ,numberic 類型更擅長 range 類查詢,精確查詢可以嘗試使用 keyword 。

mapping

mapping 是一個定義 document 結構的過程, mapping 中定義了一個文檔所包含的所有 field 信息。

定義欄位索引過多會導致爆炸的映射,這可能會導致記憶體不足錯誤和難以恢復的情況, mapping 提供了一些配置對 field 進行限制,下麵列舉幾個可能會比較常見的:

  • index.mapping.total_fields.limit 限制 field 的最大數量,預設值是 1000(field 和 object 內的所有欄位,都會加入計數)。
  • index.mapping.depth.limit 限制 object 的最大深度,預設值是 20。
  • index.mapping.field_name_length.limit 限制中欄位名的長度,預設是沒有限制。
dynamic mapping

在索引 document 時,ES 的動態 mapping 會將新增內容中不存在的欄位,自動的加入到映射關係中。ES 會自動檢測新增欄位的邏輯,並賦予其預設值。

  • One of the most important features of Elasticsearch is that it tries to get out of your way and let you start exploring your data as quickly as possible.
  • You know more about your data than Elasticsearch can guess, so while dynamic mapping can be useful to get started, at some point you will want to specify your own explicit mappings.

截取了部分 ES 官方文檔中的話術,ES 認為一些自動化的操作會讓新手上手更容易。但是同時,又提出,你肯定比 ES 更瞭解你的數據,可能剛開始使用起來覺得比較方便,但是最好還是自己明確定義映射關係。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Go語言上手(一) 這是我參與「第五屆青訓營 -後端場」筆記創作活動的的第一篇筆記。 先上代碼倉庫: WenTesla/GoLang-Study: 一個學習Go的倉庫 (github.com) 這個倉庫下放下我目前學習GO的所有筆記以及代碼,還未整理,最後會將倉庫進行整理。 基礎語法 一:類型 GO ...
  • 1. 生成6位數字隨機驗證碼 import random import string def num_code(length=6): """ 生成長度為length的數字隨機驗證碼 :param length: 驗證碼長度 :return: 驗證碼 """ return ''.join(random ...
  • 本篇主要介紹Java NIO的基本原理和主要組件 Netty是由JBOSS提供的Java開源網路應用程式框架,其底層是基於Java提供的NIO能力實現的。因此為了掌握Netty的底層原理,需要首先瞭解Java NIO的原理。 NIO簡介 電腦主要由CPU、記憶體、外存、IO設備等硬體組成,電腦執行 ...
  • keytool 是 Java 自帶的一個安全相關的工具,用於管理密鑰和證書;本文主要介紹其基本使用;文中所使用到的軟體版本:Java 1.8.0_321。 1、簡介 keytool 命令是一個密鑰和證書管理的工具。它允許用戶使用數字簽名管理自己的公鑰/私鑰對和相關證書,用於自我身份驗證(向其他用戶和 ...
  • 1 簡介 如果要選擇GCP為雲平臺,則經常需要創建GCE(Google Compute Engine),有以下幾種方式: (1) 在瀏覽器創建 (2) 命令 gcloud (3) Terraform 在開始之前,可以查看:《初始化一個GCP項目並用gcloud訪問操作》。 2 GCP Console ...
  • 前言 眾所周知記憶體緩存(MemoryCache)數據是從記憶體中獲取,性能表現上是最優的,但是記憶體緩存有一個缺點就是不支持分散式,數據在各個部署節點上各存一份,每份緩存的過期時間不一致,會導致幻讀等各種問題,所以我們實現分散式緩存通常會用上Redis 但如果在高併發的情況下讀取Redis的緩存,會進行 ...
  • 前言 上一篇文章我們講了怎麼使用 NET.AutoApi 這個組件來動態生成webapi介面,讓我們不需要創建控制器去轉發業務層代碼。這篇文章主要是講解NET.AutoApi 底層是怎麼實現動態生成webapi介面 我們回顧下- NET.AutoApi 最終的效果 NET.AutoApi內部原理 其 ...
  • ● 什麼是廠商和軟體商: 廠商:一般是指Centos、紅帽、ubantu、suse等等,各linux發行版操作系統的發行廠家,廠家會維護系統的軟體,做相應的測試、補丁發佈、安全更新等 軟體商:一般指各軟體發行商,例如openssh、docker、nginx、tomcat等等,他們是將自己的軟體產品進 ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...