內容概述

本文內容主要集中在應用層,通過下面幾個部分介紹當前最流行的搜尋工具:Elasticsearch,瞭解這些內容後,可以快速開始使用它。

  • 什麼是Elasticsearch,為什麼要使用它?
  • 基礎概念:節點,索引,型別對映和文件
  • 本地環境搭建,建立第一個index
  • 常用RESTful Api示例

什麼是Elasticsearch,為什麼要使用它?

Elasticsearch 是一個分散式、RESTful 風格的搜尋和資料分析引擎。

它基於Lunece實現,使用java語言編寫。Lunece是一個優秀的搜尋引擎庫,但它使用起來非常複雜。

Elasticsearch通過對 Lunece的封裝,隱藏了複雜性,提供了使用簡單的RESTful Api。

同時也實現了分散式叢集特性,具有儲存資料大,查詢效能好,擴充套件方便等特點。

為什麼要使用它

在業務開發中,基於ES的特性,通常有下面這些場景需要使用它:

  • 儲存大量資料。通過在使用mysql儲存的時候,資料的單位是G。使用ES的時候,資料的單位是T。由此可以看出ES使用於大資料量的儲存場景,基於分散式特性,它也支援備份和容災,並且可以很容易水平擴充套件容量。
  • 分詞搜尋引擎。ES具有強大的分詞能力,可以支援高效能的實時搜尋。
  • 高效資料分析。ES提供的聚合分析功能,可實現對儲存的大量資料的近實時統計分析。

基礎概念簡介

要使用ES,需要了解幾個最基本的概念,節點(node),索引(index),型別對映(mapping)和文件(doc)。

節點(node)

節點是組成ES叢集的基本單位,每個節點是一個執行的ES例項。每個物理機器上可以有多個節點,使用不同的埠和節點名稱。

節點按主要功能可以分為三種:主節點(Master Node),協調節點(Coordianting Node)和資料節點(Data Node)。下面簡單介紹下:

  • 主節點:處理建立,刪除索引等請求,維護叢集狀態資訊。可以設定一個節點不承擔主節點角色
  • 協調節點:負責處理請求。預設情況下,每個節點都可以是協調節點。
  • 資料節點:用來儲存資料。可以設定一個節點不承擔資料節點角色

索引(index)

索引是ES中的邏輯概念,是文件的容器。對ES的操作,基本都是對索引操作,一個ES叢集中,可以建立多個索引。

索引定義了一組文件的資料模型和處理方法。每個索引可以有多個主分片和副本分片,分別儲存在不同的節點。

  • 主分片的作用是對索引的擴容,使一個索引的容量可以突破單機的限制。
  • 副本分片是對資料的保護,每個主分片對應一個或多個副本分片,當主分片所在節點宕機時,副本分片會被提升為對應的主分片使用。
  • 一個主分片和它的副本分片,不會分配到同一個節點上。
  • 一個索引的分片數在建立時指定,如果要修改需要重建索引,代價很高。

型別對映(mapping)

mapping定義了一個索引中,文件儲存的每個欄位的資料型別。根據資料型別的不同,在新增文件時對每個欄位的處理也不同。

例如,對text型別的欄位,會先使用分詞器分詞,生成倒排索引,用於之後的搜尋。對keyword型別的欄位,不會分詞,搜尋時只能精確查詢。

一個簡單的mapping示例如下:

{
"javalogs": { //索引名稱
"mappings": {
"properties": {
"log_content": { //text型別,分詞,用於之後的分詞索引
"type": "text"
},
"date": {//時間型別
"type": "date"
},
"log_level": { //keyword型別,不分詞
"type": "keyword"
},
"ip": {
"type": "keyword"
}
}
}
}
}

在6.x版本中,每個索引中還可以有多個type,區分不同的mapping。在7.x中,type被取消,每個索引只有一個type:_doc

文件(doc)

  • 文件是Elasticsearch中的最小單位,每個索引都是有數量眾多的文件組成的。

  • 文件中包含多個欄位,每個欄位的型別由mapping定義。

  • 在一個索引中每個文件都有一個唯一id,可以在新增時指定,也可以自動生成。

下面通過一張圖來描述,節點(node),索引(index)和文件(doc)之間的關係。

本地環境搭建,建立第一個index

一切知識都要通過實踐掌握,所以在瞭解基本的概念和邏輯後,下面就進入實踐環節。

這裡推薦使用docker來搭建本地開發環境,docker對應windows和mac系統都有桌面版本,使用非常方便。因為網路限制,直接使用docker官方倉庫拉取映象會很慢,所以在安裝完成後,需要在設定中將倉庫的地址替換為國內源,這裡推薦https://docker.mirrors.ustc.edu.cn,速度很快,設定如下:

{
"registry-mirrors": [
"https://docker.mirrors.ustc.edu.cn"
]
}

下面我們使用docker安裝Elasticsearchkibana映象,kibana是es官方配套的視覺化分析工具,使用它的頁面dev tools可以很方便的通過api操作es。

因為要同時部署兩個docker映象,這裡推薦使用docker-composer,桌面版安裝完成後就帶有該命令,需要的配置如下:

services:
kibana:
image: kibana:7.2.0
container_name: kibana-simple
environment:
- TIMELION_ENABLED=true
ports:
- "5601:5601"
networks:
- mynetwork
elasticsearch:
image: elasticsearch:7.2.0
container_name: es-simple
environment:
- cluster.name=mytestes #這裡就是ES叢集的名稱
- node.name=es-simple #節點名稱
- bootstrap.memory_lock=true
- network.publish_host=elasticsearch #節點發布的網路名稱
- discovery.seed_hosts=es-simple #設定叢集中的主機地址
- cluster.initial_master_nodes=es-simple #手動設定可以成為master的節點集合
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- esdata1:/usr/local/elasticsearch/simpledata
ports:
- 9200:9200
networks:
- mynetwork volumes:
esdata1:
driver: local networks:
mynetwork:
driver: bridge

建立一個名稱為docker-compose.yaml檔案,複製下面的配置到檔案中,然後再檔案所在目錄執行docker-compose up,之後會啟動兩個docker例項,分別是elasticsearchkibana

在本地瀏覽器中,訪問http://127.0.0.1:5601/,可以看到kibana的介面如下:

建立好的kibana已經預設添加了Elasticsearch的配置,通過管理工具可以很方便的檢視ES叢集的狀態,索引情況,刪除索引等。

下面通過dev tools建立索引,dev tools提供的命令提示很方便,並且可以把已寫好的請求儲存在瀏覽器快取中,非常適合用來學習Elasticsearch

這裡通過ES提供的RESTful Api建立了第一個索引, 並且設定了該索引中的mapping,ES的地址已經設定過,這裡可以不寫完整的域名,對應的curl完整請求如下:

curl --location --request PUT 'http://127.0.0.1:9200/javalogs' \
--header 'Content-Type: application/json' \
--data-raw '{
"mappings": {
"properties": {
"log_content": {
"type": "text"
},
"date": {
"type": "date"
},
"log_level": {
"type": "keyword"
},
"ip": {
"type": "keyword"
}
}
}
}'

常用RESTful Api示例

下面介紹下Elasticsearch中常用的api,這些例子都是直接在kibanadev tools中執行的,如果想用curl訪問,可參考前一節中的轉換例子。

新增文件

//自動生成_id
POST javalogs/_doc
{
"log_content" : "get user_id 123456",
"date" : "2020-04-15T11:09:08",
"log_level": "info",
"ip": "10.223.32.67"
}
//指定_id
POST javalogs/_doc/111
{
"log_content" : "api response in 55ms",
"date" : "2020-04-15T11:09:07",
"log_level": "info",
"ip": "10.223.32.67"
}

查詢文件-不分詞型別

ES在文件查詢時,對於不分詞的查詢,直接按值查詢即可,例如下面這樣:

//不分詞型別查詢
POST javalogs/_search
{
"query": {
"match": {
"ip": "10.223.32.67"
}
}
}

查詢文件-分詞型別

這裡主要說下分詞型別的查詢,對於分析型別的field在查詢時,也會預設把查詢的語句分詞。假設有兩個文件如下:

//文件1
{
"log_content" : "call aaa service error",
"date" : "2020-04-15T11:09:07",
"log_level": "error",
"ip": "10.223.32.67"
} //文件2
{
"log_content" : "call bbb service error",
"date" : "2020-04-15T11:09:08",
"log_level": "error",
"ip": "10.223.32.67"
}

當搜尋條件為call aaa service時,實際上會把兩個文件都搜尋出來。

這是因為在搜尋時,條件call aaa service會被分詞為callaaaservice,所有包含這三個詞的文件都會被搜尋出來,例如下面:

//普通搜尋,兩個文件都會返回
POST javalogs/_search
{
"query": {
"match": {
"log_content": "call aaa service"
}
}
}

那如果想要只搜尋包含call aaa service的文件,應該如何做呢?

按照上面的分析,需要同時包含這三個詞,並且按照給定的順序,才返回對應的文件,那麼這個可以使用match_phrase實現,示例如下:

//文件必須同時包含三個詞,並且順序與搜尋條件一致才會返回。這裡只會返回-文件1
POST javalogs/_search
{
"profile": "true",
"query": {
"match_phrase": {
"log_content": "call aaa service"
}
}
}

那如果條件是包含callaaaservice,但是不一定是連著的,該如何搜尋呢?可以使用operator操作符實現。

例如有第三個文件如下:

//文件3
{
"log_content" : "call inner aaa service error",
"date" : "2020-04-15T11:09:08",
"log_level": "error",
"ip": "10.223.32.67"
}

要想把文件1文件2都搜尋出來,查詢的示例如下:

//文件中同時包含call,aaa和service就會返回,不按順序。會返回-文件1和文件2
POST javalogs/_search
{
"query": {
"match": {
"log_content":
{
"query": "call aaa service",
"operator": "and"
}
}
}
}

上面就是對Elasticsearch的簡單介紹和實戰操作示例,希望能幫助大家快速入門使用ES。

以上內容屬個人學習總結,如有不當之處,歡迎在評論中指正