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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...