快速入門ElasticSearch(上)

寫在前面

ElasticSearch是一個分佈式、可擴展、實時的搜索與數據分析引擎,它能從項目一開始就賦予你的數據以搜索、分析和探索的能力,在日常工作和學習中扮演著非常重要的角色,鑑於此本篇將從ElasticSearch的安裝、基礎概念、基本用法、高級查詢等角度來進行介紹。

ElasticSearch簡介

ElasticSearch是一款基於Apache Lucene構建的開源搜索引擎,採用Java編寫,提供簡單易用的RESTful API,開發者可以通過它輕鬆實現簡單明瞭的搜索功能。ElasticSearch輕鬆的橫向擴展能力,支持PB級別的結構化和非結構化數據處理。其實就是說當機器的磁盤容量不滿足需求的時候,可以通過不斷的橫向添加節點(機器)來解決容量問題,通過這種方式可以使我們的存儲容量從GB到TB甚至PB級別的轉化。

接下來學習ElasticSearch的應用場景: (1)海量數據分析引擎。當你需要對應用日誌、系統日誌等進行分析時,可以使用ElasticSearch的聚合搜索功能來實現; (2)站內搜索引擎。當你需要快速搭建一個站內搜索的時候,使用ElasticSearch就能完成這個任務; (3)數據倉庫。開發者可以使用ElasticSearch強大的分佈式搜索能力,直接將其作為數據倉庫產品來使用,可以存儲PB級別的結構化或者非結構化數據,這樣可以為上層應用提供強大的數據存儲能力。

當然上面介紹的應用場景只是一些較為通用的場景,而實際上一些大型公司會將ElasticSearch用在其他的地方,如英國衛報公司則使用ElasticSearch來實時蒐集用戶日誌和社交網絡數據以便於實時分析公眾對文章的響應程度。而維基百科和GitHub儘管都使用ElasticSearch進行站內實時的數據搜索,但是維基百科則使用ElasticSearch提供全文搜索,並高亮關鍵字;GitHub則使用ElasticSearch來解鎖1000多億代碼;百度則使用ElasticSearch搭建其實時日誌監控平臺。

ElasticSearch安裝

ElasticSearch的版本非常特殊,它的迭代順序是這樣的:1.x-->2.x-->5.x-->6.x-->7.x。為什麼會出現這個問題呢?那是因為ElasticSearch屬於Elastic技術棧,但是Elastic技術棧中其他中間件的版本更新迭代不同,版本號也出現了混亂,舉個例子ElasticSearch用2.x版本,而要求Kibana使用4.x版本,這勢必會提高小白的學習門檻,要知道在學習任何軟件的第一部分就是選擇合適版本,鑑於此Elastic在16年就正式統一了所有Elastic技術棧中所有產品的版本號。綜合考慮目前情況,筆者選擇使用ElasticSearch6.x版本,當然在後續文章中則會使用最新版的7.x系列來進行學習。

ElasticSearch單實例安裝

第一步,下載安裝java8及以上版本,之後進行環境變量的設置: (1)JAVA_HOME值為G:\Application\java1.8;(2)在系統變量的Path處設置兩個值,分別是:%JAVA_HOME%\bin和%JAVA_HOME%\jre\bin。(3)使用java -version命令來檢驗是否安裝成功,輸出版本信息則表明Java安裝成功:

快速入門ElasticSearch(上)

第二步,新建ElasticSearch文件,並將後續下載的文件存放與此,同時便於後續管理。

第三步,下載ElasticSearch安裝包,點擊 ElasticSearch鏡像地址,選擇合適的64位版本後進行下載。

第四步,啟動ElasticSearch。開發者可以進入到ElasticSearch的bin目錄,然後直接執行start /min elasticsearch命令即可在後臺啟動ElasticSearch。之後直接打開瀏覽器,輸入http://127.0.0.1:9200後顯示下圖所示信息,也表明elasticsearch已成功啟動:

快速入門ElasticSearch(上)

這樣關於ElasticSearch單實例的安裝就完成了,但是由於ElasticSearch返回的是JSON格式信息,對開發者並不是非常友好,因此需要安裝Head插件,因為它提供了Web界面,幫我們解決了無界面這一問題,同時也可以提供基本信息查看,REST請求模擬,以及基本數據的檢索等功能。點擊 這裡 獲取插件,然後download,選擇下載ZIp文件即可:

快速入門ElasticSearch(上)

請注意該插件要求nodejs版本大於6,可以使用node -v命令來查看當前系統nodejs版本的信息,可以看到筆者為v12.13.1,滿足要求,其實這就是一個node項目,因此需要進入到elasticsearch-head-master包內,然後執行npm install命令來安裝相關依賴包,之後執行npm run start,當然也可以使用cnpm命令來代替之前的npm命令,結果如下所示:

快速入門ElasticSearch(上)

可以看到它的Web服務運行在http://localhost:9100,因此可以打開瀏覽器去訪問這個地址:

快速入門ElasticSearch(上)

但是目前Web頁面顯示集群未連接,但是此時ElasticSearch和Head插件都已經啟動了,所以問題在於兩者還未完成通信(存在跨域問題),因此需要停掉正在運行的ElasticSearch,同時進入到其config包內,修改其elasticsearch.yml配置文件,在其末尾添加如下兩行代碼:

<code>http.cors.enabled: true
http.cors.allow-origin: "*"
/<code>

最後保存退出,重啟ElasticSearch和Head插件,注意順序不能搞錯,然後再去瀏覽器訪問http://localhost:9100地址,此時頁面如下所示:

快速入門ElasticSearch(上)

ElasticSearch多實例安裝

接下來將搭建一個包含3個節點的集群,其中一個master,兩個slave節點,為了便於操作將之前搭建的單節點實例作為master節點。首先進入到之前搭建的單節點實例中,修改其elasticsearch.yml配置文件,如下所示:

<code>cluster.name: envythink
node.name: master
node.master: true
network.host: 127.0.0.1
http.port: 9200
/<code>

注意各個配置信息所在的位置:

快速入門ElasticSearch(上)

快速入門ElasticSearch(上)

之後重啟ElasticSearch這一master節點,然後訪問瀏覽器確認集群名稱和當前節點修改都已生效:

快速入門ElasticSearch(上)

由於ElasticSearch默認啟動使用的是elasticsearch.yml配置文件,且無法以其他名稱文件啟動,因此要想實現一臺機器部署多個實例,就必須直接複製多個安裝程序。

在ElasticSearch目錄下新建slave-node目錄,然後複製兩份安裝文件進入並修改名字為slave1和slave2,其中slave1中config目錄下的elasticsearch.yml配置文件修改如下信息:

快速入門ElasticSearch(上)

快速入門ElasticSearch(上)

可以看到這裡我們修改了節點的名稱和端口號,以及配置發現集群的IP地址。同時將此的elasticsearch.yml配置文件複製一份到slave2中config目錄下,替換之前的elasticsearch.yml配置文件,並將節點名稱和端口號依次修改為slave2和9202,之後啟動這兩個salve節點,並重啟Head插件,之後再去瀏覽器中訪問Head頁面,如下所示:(注意這個順序可能會隨著節點的順序而發生變動)

快速入門ElasticSearch(上)

如果出現下面的錯誤:

<code> failed to send join request to master [{master}{4f6DA5uJQ8iJokZ3T18gjg}{2dOtfXXbTrynhShWrzt3xQ}{127.0.0.1}{127.0.0.1:9300}{ml.machine_memory=8374956032, ml.max_open_jobs=20, xpack.installed=true, ml.enabled=true}], reason [RemoteTransportException[[master][127.0.0.1:9300]
/<code> 

那是因為之前複製ElasticSearch文件時,將其data目錄下的文件也一同複製了,因此需要清空data文件夾,然後再進行重試即可。

ElasticSearch基礎概念

首先是集群和節點的概念,我們知道集群是由一個或多個節點組成的,如前面我們搭建的具有三個節點的集群,其默認名稱為ElasticSearch,但是前面我們通過cluster.name參數將其修改為envythink。請注意對於任意一個節點來說,其集群的名字只能有一個,實際上所有的節點都是靠這個集群的名稱來加入集群的。此外每個節點都有自己的名字,可以通過node.name來自定義,同時節點都是可以存儲數據,參與集群索引數據,以及搜索數據的獨立服務。其次是索引,你可以將其理解為是含有相同屬性的文檔集合。接著是類型,一般來說索引可以定義一個或者多個類型,但是文檔必須是屬於一個類型。那麼問題來了,文檔又是什麼呢?文檔就是可以被索引的基本數據單位,如用戶的個人信息,它是ElasticSearch中最基本的存儲單位。索引在ElasticSearch中是通過名字來識別的,且它必須是英文字母小寫,且不含中劃線,我們都是通過名字來對文檔數據進行增刪改查等操作。

關於索引、類型和文檔這三者之間的關係,可以借鑑數據庫的相關知識,將索引類比為數據庫;類型類比為數據表;而文檔就是一行SQL記錄。再來舉一個較為詳細的系統,假設我們這裡有一個信息查詢系統,此處使用ElasticSearch來作存儲,那麼裡面的數據就可以分為各種各樣的索引,如圖書索引,服裝索引,電器索引等,而對於圖書索引又可以細分為文學類、工具類、技術類等類型,而具體到每一本書籍則就是文檔,也就是最小的存儲單位。

和索引相關還有兩個比較重要的概念就是分片和備份。每個索引都有多個分片,每個分片就是一個Lucene索引。而拷貝一份分片就完成了分片的備份。使用分片可以將索引進行拆分,可以分擔每一個索引上的壓力,同時分片還允許用戶進行水平擴展和拆分,以及分佈式的操作,可以提高搜索以及其他操作的效率。使用備份的好處就是當一個主分片出現問題時,備份的分片就可以代替工作,從而提高了ElasticSearch的可用性,同時備份的分片也支持搜索操作,可以減輕搜索的壓力。ElasticSearch默認在創建索引時,會創建5個分片,一個用於備份,當然這個數據也是可以修改的。此外分片的數量只能在創建索引的時候指定,而不能在後期進行修改,但是備份卻是可以動態修改的。

ElasticSearch基本用法

由於ElasticSearch使用的是RESTful風格的API,因此在學習ElasticSearch的基本用法之前,需要了解ElasticSearch中API的基本格式:http://:///,注意上面的索引、類型和文檔都是名詞,而動作則使用HTTP對應的GET/POST/PUT/DELETE。

創建索引

接下來可以結合之前的Head插件來顯式創建索引,點擊左上角的索引-->創建索引-->填入數據-->點擊確定(注意這裡的movie是索引名稱,必須是英文小寫,且不能使用中劃線):

快速入門ElasticSearch(上)

之後回到首頁,可以看到頁面出現了10個綠底黑字的方框,這些都是ElasticSearch的分片,如下所示:

快速入門ElasticSearch(上)

其實你還可以發現這些方框有的邊框顏色粗,有的淺,那是因為粗的是主分片,淺的是分片的備份。其實上面這種是非結構化的創建,其實還有結構化的創建。那麼如何確定某個索引是結構化還是非結構化的呢?可以藉助於Head插件來完成,點擊索引的信息按鈕,然後點擊索引信息按鈕,如下所示:

快速入門ElasticSearch(上)

然後會彈出一個頁面,注意這裡面的"mappings"字段,它是結構化的關鍵詞,如果後面的內容是空的,則表示它是非結構化的索引。也就是說上面我們創建的movie其實是一個非結構化的索引:

快速入門ElasticSearch(上)

那麼問題來了,如何創建結構化的索引呢?同樣可以藉助於head插件,點擊右上角的“複合查詢”按鈕,然後選擇POST方式:

快速入門ElasticSearch(上)

並修改接口為movie/action/_mappings,然後在裡面新增如下代碼:

<code>{
  "action": {
    "properties": {
      "title": {
        "type": "text"
        }
    }
}
/<code>
快速入門ElasticSearch(上)

之後查看一下首頁,可以發現之前的“mappings”字段裡面已經顯示了剛才添加的信息:

快速入門ElasticSearch(上)

儘管使用Head插件可以結構化創建,但是對於JOSN的書寫並不太友好,此時我們可以使用Postman這一工具來進行創建,但是需要開發者自己書寫一些基礎配置信息,如"settings"等,之後才能編寫“mappings”關鍵字等信息,如下所示:

<code>{
 "settings": {
  "number_of_shards": 3,
  "number_of_replicas": 1
 },
 "mappings": {
  "novel": {
   "properties": {
    "name": {
     "type": "text"
    },
    "isbn": {
     "type": "keyword"
    },
    "price": {
     "type": "integer"
    },
    "published": {
     "type": "date",
     "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
    }
   }
  }
 }
}
/<code>

之後點擊提交即可,結果如下所示,注意使用PUT方法用於新增數據(ES6.x系列要求一個index只能存儲一種type):

快速入門ElasticSearch(上)

之後刷新首頁,可以看到右側多出了一個book的索引,然後查看該索引的信息可以發現該索引中的"mappings"關鍵字中的信息就是之前我們通過Postman創建的:

快速入門ElasticSearch(上)

數據插入

在學完了如何創建索引之後,接下來開始學習如何插入數據,在ElasticSearch中,插入分為兩種:“指定文檔id插入”和“自動產生文檔id插入”。這裡的文檔id它是一個唯一索引值,指向文檔數據。接下來學習如何使用Postman工具來插入數據,選擇PUT方法,並輸入接口為http://127.0.0.1:9200/book/novel/1,請注意這裡的book為索引,novel為類型,1是文檔的id,這個文檔id用於唯一標識文檔,然後書寫如下JSON信息:

快速入門ElasticSearch(上)

然後點擊確定,刷新首頁並點擊上方的數據預覽,可以看到我們之前的數據就已經成功插入了:

快速入門ElasticSearch(上)

同時可以看到對於book這一索引來說,其docs的數量為1,它表示book索引下所有的文檔的數量:

快速入門ElasticSearch(上)

在前面文檔的id都是開發者自己來指定的,其實還可以讓ES自己來生成,不過此時需要使用的是POST方法,相應的代碼如下所示:

<code>{
 "name": "《彷徨》",
 "isbn": "978-7-134-34663-7",
 "price": 69,
 "published": "2019-09-01 10:01:01"
}
/<code>

其中Postman對應的操作如下所示:

快速入門ElasticSearch(上)

可以看到此時的文檔id就是ES自動為我們所生成的字符串,這樣關於數據的插入就先學習到這。

數據修改

在簡單學完如何插入數據之後,接下來開始學習如何對數據進行修改。對數據修改有兩種方式:直接修改文檔和腳本修改文檔。首先學習直接修改文檔這種方式,在前面我們已經成功的往book這一索引中添加了兩條記錄,接下來就嘗試將之前文檔id為1的記錄的《朝花夕拾》修改為《吶喊》,繼續使用Postman測試工具同時使用POST方法,注意此時的API接口為http://127.0.0.1:9200/book/novel/1/_update,後面必須添加_update參數:

快速入門ElasticSearch(上)

此時開發者填入的JSON信息必須包裹在doc字段中,這個doc字段用於表明這是直接修改文檔方式:

<code>{
 "doc": {
  "name": "《吶喊》"
 }
}
/<code>

之後點擊確認,可以發現name屬性的值的確發生了變化:

快速入門ElasticSearch(上)

快速入門ElasticSearch(上)

除了上面介紹的直接修改文檔方式外,開發者還可以使用腳本修改文檔這一方式。ES支持多種腳本語言,這裡以內置的腳本語言painless為例進行說明,注意無論是直接修改文檔還是通過腳本來修改文檔,其對應的API接口是不變的,依舊為http://127.0.0.1:9200/book/novel/1/_update,但是前面的doc需要修改為script:

<code>{
 "script": {
  "lang": "painless",
  "inline": "ctx._source.price +=20"
 }
}
/<code>
快速入門ElasticSearch(上)

請注意其中的ctx表示上下文,_scorce則是獲取資源,而後面則是得到了文檔的屬性。不過這樣有一個問題:直接將參數寫進了語句中,而無法動態注入,其實上面的寫法可以採用動態屬性注入的方式:

<code>{
 "script": {
  "lang": "painless",
  "inline": "ctx._source.price=params.price",
  "params": {
   "price": 100
  }
 }
}
/<code>

這樣就可以實現屬性的動態賦值,那麼關於數據的簡單修改就學習到這裡。

數據刪除

接下來開始學習如何刪除數據,這裡主要學習如何刪除文檔和索引。首先學習如何刪除文檔,可以藉助於Postman測試工具,選擇使用DELETE方法,然後輸入API接口為http://127.0.0.1:9200/book/novel/1,注意這裡需要添加文檔id,然後點擊提交即可刪除文檔。

接下來是刪除索引,注意索引除非是必要刪除,否則不要輕易刪除,因為刪除它會刪除它所包含的所有數據。同樣刪除索引也可以藉助於Postman測試工具。選擇使用DELETE方法,然後輸入API接口為http://127.0.0.1:9200/book,注意這裡僅僅是需要添加索引名稱,然後點擊提交即可刪除索引。其實刪除索引還可以藉助於Head插件來完成,點擊movie索引的“動作”按鈕,然後選擇“刪除”,之後彈出輸入框,開發者輸入“刪除”後,點擊確定即可完成刪除:

快速入門ElasticSearch(上)

快速入門ElasticSearch(上)

然後首頁會自動刷新,可以看到索引名稱為movie的索引已經被刪除了:

快速入門ElasticSearch(上)

這樣關於數據的刪除就先學習到這裡,後續開始學習如何查詢數據。

數據查詢

接下來開始學習較為重要的數據查詢,數據查詢包括簡單查詢、條件查詢和聚合查詢這三種,下面將仔細學習這三種查詢方式。考慮到後續的需要,這裡就新創建了一個book索引,其對應的JSON信息為:

<code>{
 "settings": {
  "number_of_shards": 3,
  "number_of_replicas": 1
 },
 "mappings": {
  "novel": {
   "properties": {
    "word_count": {
     "type": "integer"
    },
    "author": {
     "type": "keyword"
    },
    "title": {
     "type": "text"
    },
    "publish_date": {
     "type": "date",
     "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
    }
   }
  }
 }
}
/<code>

之後查看一下首頁發現book索引已經創建成功,如下所示:

快速入門ElasticSearch(上)

接下來就是為這個book索引添加文檔,這裡提前準備了一些數據,如下所示:

快速入門ElasticSearch(上)

首先來學習簡單查詢,使用Postman測試工具,選擇GET方法,使用的接口為http://127.0.0.1:9200/book/novel/文檔id,然後查看結果:

快速入門ElasticSearch(上)

接著再來學習條件查詢,注意條件查詢使用POST方法,使用的接口為http://127.0.0.1:9200/book/_search,然後構建一個查詢的JOSN信息,注意所有的信息都必須包含在query這個關鍵詞內,match_all表示查詢所有的結果信息:

<code>{
 "query": {
  "match_all": {}
 }
}
/<code>
快速入門ElasticSearch(上)

請注意這裡面的took表示查詢所花費的時間,單位為毫秒;hits表示查詢的全部結果數,可以看到有12條信息,但是此處只會顯示10條,我們可以自己來指定返回的數量以及從從何處返回,只需在上述JSON格式信息中添加過濾條件即可,from表示從查詢的第一個數據開始返回,size表示只返回一個:

<code>{
 "query": {
  "match_all": {}
 },
 "from": 1,
 "size": 1
}
/<code>

運行結果如下所示:

快速入門ElasticSearch(上)

上面的條件查詢沒設置過濾條件,接下來嘗試查詢所有title中包含Java的文檔,此時對應的JSON格式信息如下:

<code>{
 "query": {
  "match": {
   "title": "Java"
  }
 }
}
/<code>

然後點擊查詢,可以發現居然只查詢到兩條,而title中包含JavaScript的卻沒有查詢到:

快速入門ElasticSearch(上)

查詢結果默認是根據_score倒序排列的,開發者可以自定義排序字段,如使用出版時間publish_date,然後將其默認的升序排序修改為倒序:

<code>{
 "query": {
  "match": {
   "title": "Java"
  }
 },
 "sort": {
  "publish_date": {
   "order": "desc"
  }
 }
}
/<code>

最後再來學習聚合查詢,所謂的聚合查詢就是指將多個相同的數據進行統計查詢,如根據字數對書籍進行聚合查詢,相應的JSON格式信息為:

<code>{
 "aggs": {
  "group_by_word_count": {
   "terms": {
    "field": "word_count"
   }
  }
 }
}
/<code>

請注意這裡的aggs表示聚合查詢,group_by_word_count是自定義的聚合名稱,terms表示聚合條件,field表示聚合字段為word_count。聚合結果如下所示:

快速入門ElasticSearch(上)

前面都是查詢的信息,後面則是聚合的結果,當然還可以多個聚合查詢,如:

<code>{
 "aggs": {
  "group_by_word_count": {
   "terms": {
    "field": "word_count"
   }
  },
  "group_by_publish_date": {
   "terms": {
    "field": "publish_date"
   }
  }
 }
}
/<code>

這樣在查詢結果的最後面會顯示出兩個聚合結果。其實還可以指定對某個值進行計算,如對字數word_count進行計算:

<code>{
 "aggs": {
  "grades_word_count": {
   "stats": {
    "field": "word_count"
   }
  }
 }
}/<code>

然後點擊運行,運算結果如下所示,裡面包含了最大值、最小值、平均值和總和:

快速入門ElasticSearch(上)

stats表示對指定字段進行計算,裡面包含5個值,如果只是需要單純的某個值,可以將stats修改為min、max、avg、sum和count。


快速入門ElasticSearch(上)


分享到:


相關文章: