重溫Elasticsearch

什麼是 Elasticsearch ?

Elasticsearch (ES) 是一個基於 Lucene 構建的開源、分佈式、RESTful 接口全文搜索引擎。仍是一個分佈式文檔數據庫,其中每一個字段均是被索引的數據且可被搜索,它可以擴展至數以百計的服務器存儲以及處理PB級的數據。它能夠在很短的時間內在儲、搜索和分析大量的數據。它一般做爲具備複雜搜索場景狀況下的核心發動機。css

官網:https://www.elastic.co/downloads/elasticsearch
中文社區:https://es.xiaoleilu.com/
什麼是PB級別:https://baike.baidu.com/item/PetaByte/5910820html

爲何要用 Elasticsearch ?

一、提升搜索效率

若是使用數據庫進行模糊查詢,好比 like 語句,他會遍歷整張表,同時進行字符串匹配,若是數據庫數據量很是龐大的話,會很是消耗資源和時間。java

在換用 Elasticsearch 後,TB級別數據也能在毫秒級就能返回檢索結果。node

緣由:Elasticsearch是基於倒排索引的web

二、自動分詞

在使用數據庫的前提下,組合詞檢索是很是困難的,好比,當用戶在搜索框輸入"四川火鍋」時,數據庫一般只能把這四個字去進行所有匹配。但是在文本中,可能會出現「推薦四川好吃的火鍋」,這時候就沒有結果了。數據庫

緣由:數據庫並不支持分詞。若是人工去開發分詞功能,費時費精力。json

若是換用 Elasticsearch,使用雲搜索服務後,就不用太過於關注分詞了,由於 Elasticsearch 支持中文分詞插件,很好地解決了問題。當用戶使用Elasticsearch時進行搜索時,Elasticsearch 就自動幫他分好詞了。服務器

例如當輸入「四川火鍋」時,Elasticsearch會自動作下面兩件事 :微信

  1. 將「四川火鍋」分詞成「四川」和「火鍋」
  2. 查找包含這兩個詞的文檔
3. 相關性

在用數據庫作搜索時,結果常常會出現一系列文檔。可是數據庫並不支持相關性搜索。 數據結構

例如,當用戶搜索「咖啡廳」的時候,他極可能更想知道附近哪裏能夠喝咖啡,而不是怎麼開咖啡廳。

  • 到底什麼文檔是用戶真正想要的呢?
  • 怎麼才能把用戶想看的文檔放在搜索列表最前面呢?

當使用了雲搜索服務後,發現 Elasticsearch 能很好地支持相關性評分。經過合理的優化,雲搜索服務可以返回精準的結果,知足用戶的需求。

緣由: Elasticsearch 支持全文搜索和相關度評分。這樣在返回結果就會根據分數由高到低排列。分數越高,意味着和查詢語句越相關。

因此,當用戶搜索「星巴克咖啡」,帶有「星巴克咖啡」的信息就要比只包含「咖啡」的信息靠前。

四、海量存儲

Elasticsearch 是爲高可用和可擴展而生的。能夠經過購置性能更強的服務器來完成。

橫向可擴展性:只須要增長臺服務器,作一點兒配置,啓動一下 Elasticsearch 就能夠併入集羣。

分片機制提供更好的分佈性:同一個索引分紅多個分片(sharding), 這點相似於HDFS的塊機制;分而治之的方式可提高處理效率。

高可用:提供複製( replica) 機制,一個分片能夠設置多個複製,使得某臺服務器在宕機的狀況下,集羣仍舊能夠照常運行,並會把服務器宕機丟失的數據信息複製恢復到其餘可用節點上。

五、可視化界面

在使用數據庫進行查詢數據時,不少時候都是經過工程代碼或者命令端完成。其實在分析結果時並不太方便,缺乏一個可視化界面來提升效率。

緣由: 數據庫自身一般不帶可視化界面。而在完成搜索相關的任務時,經常須要根據搜索結果來進行分析。

而 Kibana 可視化工具則完美支持 Elasticsearch。研發人員可以在上面快速地進行概念驗證,分析結果,提升開發效率。

Elasticsearch基本概念

Elasticsearch是面向文檔型數據庫的,一條數據即一個文檔,用 JSON 做爲文檔序列化的格式,好比下面這條用戶數據:

{
    "name" :     "John",
    "sex" :      "Male",
    "age" :      25,
    "birthDate""1990/05/01",
    "about" :    "I love to go rock climbing",
    "interests": [ "sports""music" ]
}

關於Elasticsearch以及Kibana的安裝請參考以前的一篇文章:<瞭解一下Elasticsearch的基本概念>

Elasticsearch是如何作到快速索引的?

首先 Elasticsearch 使用的是倒排索引,何爲倒排索引?

如上圖,當用戶搜索「手機」時,Elasticsearch 就會當即返回文檔 F,G,H。這樣就不用花多餘的時間在其餘文檔上了,所以檢索速度獲得了數量級的提高。

也許你還不太瞭解倒排索引,甚至是正向索引也不瞭解?

什麼是正向索引

正向索引是文檔與關鍵詞一一對應的數據結構。

其以文檔的ID爲關鍵字,表中記錄文檔中每一個字的位置信息,查找時掃描表中每一個文檔中字的信息直到找出全部包含查詢關鍵字的文檔。

這種組織方法在創建索引的時候結構比較簡單,創建比較方便且易於維護;由於索引是基於文檔創建的,如果有新的文檔加入,直接爲該文檔創建一個新的索引塊,掛接在原來索引文件的後面。如果有文檔刪除,則直接找到該文檔號文檔對應的索引信息,將其直接刪除。可是在查詢的時候需對全部的文檔進行掃描以確保沒有遺漏,這樣就使得檢索時間大大延長,檢索效率低下。

儘管正向索引的工做原理很是的簡單,可是因爲其檢索效率過低,除非在特定狀況下,不然實用性價值不大。

爲了進一步理解,在這舉個例子:

咱們假設有網頁1和網頁2:

網頁1中僅包含一句話:廈門SEO顧問瀟湘馭文爲您提供廈門SEO培訓服務。

網頁2中也僅包含一句話:SEO是一門藝術。

通過搜索引擎初步分詞以後,網頁1和2的正向索引以下圖所示:

假設使用正向索引,那麼當你搜索SEO的時候,搜索引擎必須檢索網頁中的每個關鍵詞,假設一個網頁中包含成千上百個關鍵詞,可想而知,會形成大量的資源浪費。因而倒排索引應運而生。

什麼是倒排索引

正向索引是關鍵詞與文檔一一對應的數據結構。

其以字或詞爲關鍵字進行索引,表中關鍵字所對應的記錄表項記錄了出現這個字或詞的全部文檔,一個表項就是一個字表段,它記錄該文檔的ID和字符在該文檔中出現的位置狀況。

因爲每一個字或詞對應的文檔數量在動態變化,因此倒排表的創建和維護都較爲複雜,可是在查詢的時候因爲能夠一次獲得查詢關鍵字所對應的全部文檔,因此效率高於正排表。

在全文檢索中,檢索的快速響應是一個最爲關鍵的性能,而索引創建因爲在後臺進行,儘管效率相對低一些,但不會影響整個搜索引擎的效率。

歸納:正排索引是從文檔到關鍵字的映射(已知文檔求關鍵字),倒排索引是從關鍵字到文檔的映射(已知關鍵字求文檔)。

咱們再來看一下上邊的例子用倒排索引是什麼樣的。

從上圖能夠一目瞭然,倒排索引能夠直接參與排名。

好比你搜索「SEO」,搜索引擎能夠快速檢索出包含「SEO」搜索詞的網頁1和網頁2,爲後續的相關度和權重計算奠基基礎,從而大大加快了返回搜索結果的速度。

再看一個例子:

倒排索引會對以上文檔內容進行關鍵詞分詞,可使用關鍵詞直接定位到文檔內容。

當你搜索[科技公司]後,會當即返回序號id爲[1,2,4,5]的文檔,而不是去進行全文關鍵字匹配。

DSL語言查詢與過濾

什麼是DSL語言?

ES 中的查詢請求有兩種方式,一種是簡易版的查詢,另一種是使用JSON完整的請求體,叫作結構化查詢(DSL)。

因爲DSL查詢更爲直觀也更爲簡易,因此大都使用這種方式。

DSL查詢是POST過去一個JSON,因爲POST的請求是JSON格式的,因此存在不少靈活性,也有不少形式。

舉個例子,詳細的可自行查詢瞭解:

根據名稱精準查詢姓名:

GET ttyy/user/_search
{
  "query": {
    "term": {
      "name""奶茶"
    }
  }
}

其中 term 是表明徹底匹配,即不進行分詞器分析,文檔中必須包含整個搜索的詞彙;相似的還有 Match;

分詞器

什麼是分詞器

由於 Elasticsearch 中默認的標準分詞器分詞器對中文分詞不是很友好,會將中文詞語拆分紅一個一箇中文的漢字,所以引入中文分詞器 ik 插件。

演示傳統分詞器

{
  "analyzer""standard",
  "text""奧迪a4l"
}

{
    "tokens": [
        {
            "token""奧",
            "start_offset"0,
            "end_offset"1,
            "type""<IDEOGRAPHIC>",
            "position"0
        },
        {
            "token""迪",
            "start_offset"1,
            "end_offset"2,
            "type""<IDEOGRAPHIC>",
            "position"1
        },
        {
            "token""a4l",
            "start_offset"2,
            "end_offset"5,
            "type""<ALPHANUM>",
            "position"2
        }
    ]
}

採用 ik 分詞器後:

{
  "analyzer""ik_smart",
  "text""奧迪"
}

{
    "tokens": [
        {
            "token""奧迪",
            "start_offset"0,
            "end_offset"2,
            "type""CN_WORD",
            "position"0
        },
        {
            "token""a4l",
            "start_offset"2,
            "end_offset"5,
            "type""LETTER",
            "position"1
        }
    ]
}

ES集羣環境搭建

ES爲何要實現集羣

在搭建集羣以前先了解一下es爲何要實現集羣。

ES集羣中索引可能由多個分片構成,而且每一個分片能夠擁有多個副本。經過將一個單獨的索引分爲多個分片,咱們能夠處理不能在一個單一的服務器上面運行的大型索引,簡單的說就是索引的大小過大,致使效率問題。不能運行的緣由多是內存也多是存儲。

因爲每一個分片能夠有多個副本,經過將副本分配到多個服務器,能夠提升查詢的負載能力。

簡而言之就是提升查詢的負載能力。

ES集羣核心原理分析:

數據存儲。

一、每一個索引會被分紅多個分片shards進行存儲,默認建立索引是分配5個分片進行存儲。
每一個分片都會分佈式部署在多個不一樣的節點上進行部署,該分片成爲primary shards。
注意:索引的主分片primary shards定義好後,後面不能作修改。

二、爲了實現高可用數據的高可用,主分片能夠有對應的備分片replics shards,replic shards分片承載了負責容錯、以及請求的負載均衡。
**注意: **每個主分片爲了實現高可用,都會有本身對應的備分片,主分片對應的備分片不能存放同一臺服務器上。,主分片primary shards能夠和其餘replics shards存放在同一個node節點上。

補充1:單臺ES服務器中是沒有備份分片的
補充2:主分片對應的備份分片不能存放在同一臺服務器上。

以下圖所示:

Node表示服務器,P表示主分片,R表示備份分片

服務器環境

準備三臺服務器

服務器名稱 IP地址
node-1 192.168.212.182
node-2 192.168.212.183
node-3 192.168.212.184

服務集羣配置

vi elasticsearch.yml
cluster.namemyes  ###保證三臺服務器節點集羣名稱相同
node.namenode-1 #### 每一個節點名稱不同 其餘兩臺爲 node-1 ,node-2
network.host: 192.168.212.180 #### 實際服務器ip地址
discovery.zen.ping.unicast.hosts["192.168.212.184", "192.168.212.185","192.168.212.186"]##多個服務集羣ip
discovery.zen.minimum_master_nodes: 1

關閉防火牆 systemctl stop firewalld.service

默認底層開啓9300 集羣

驗證集羣效果:

http://192.168.212.185:9200/_cat/nodes?pretty

參考文章:
https://blog.csdn.net/weixin_39819880/article/details/82083034
https://www.cnblogs.com/dreamroute/p/8484457.html

我建立了一個java相關的公衆號,用來記錄本身的學習之路,感興趣的小夥伴能夠關注一下微信公衆號哈:niceyoo

相關文章
相關標籤/搜索