Elasticsearch系列---簡單入門實戰

概要

本篇主要介紹一下Elasticsearch Document的數據格式,在Java應用程序、關係型數據庫建模的對比,介紹在Kibana平臺編寫Restful API完成基本的集羣狀態查詢,Document最基本CRUD操作示例以及bulk批處理示例。

Document數據格式

Java應用系統的數據模型都是面向對象的,有些對象比較複雜,傳統的業務系統,數據需要落地到關係型數據庫,在數據庫領域模型設計時,會把複雜的POJO對象設計成一對一或一對多的關係,進行扁平化處理,查詢的時候,需要多表查詢並還原回POJO對象的格式。
Elasticsearch是文檔數據庫,Document存儲的數據結構,可以和POJO保持一致,並且使用JSON格式,這樣查詢數據時比較方便。

Document文檔數據示例:

{
  "fullname" : "Three Zhang",
  "text" : "hello elasticsearch",
  "org": {
      "name": "development",
      "desc": "all member are lovely"
  }
}

Restful API讓請求更容易

前面文章有提及Elasticsearch與Kibana搭配使用,Kibana界面的Dev Tools菜單,可以發送Elasticsearch的Restful請求。後續的Restful API請求,如無例外,均是在Kibana平臺上執行的。

我們先拿幾個查詢集羣信息的請求來試試

  1. 檢查集羣的健康狀況

GET /_cat/health?v

epoch      timestamp cluster        status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1573626290 14:24:50  hy-application yellow          1         1     1  1    0    0       1             0                  -                 50.3%

從上面能看出node、shard的數量等,還有一個是集羣的狀態,上面顯示的是yellow,爲什麼是yellow?
集羣的狀態有green、yellow、red三種,定義如下:

  • green:每個索引的primary shard和replica shard都是active狀態的
  • yellow:每個索引的primary shard都是active狀態的,但是部分replica shard不是active狀態,處於不可用的狀態
  • red:不是所有索引的primary shard都是active狀態的,部分索引有數據丟失了

我們的示例只啓動了一個elasticsearch實例,只有一個node,由於索引默認會使用5個primary shard和5個replica shard,並且同一個node下面的primary shard和replica shard不能分配在一臺機器上(容錯機制),所有隻有1個primary shard被分配和啓動了,replica shard沒有第二臺node去啓動,因而是yellow狀態。如果想變成green判斷,另外啓一臺node即可。

  1. 查看集羣中有哪些索引

GET /_cat/indices?v

health status index                  uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   location               48G_CgE7TiWomlYsyQW1NQ   5   1          3            0       11kb           11kb
yellow open   company_mem            s9DKUeyWTdCj2J8BaFYXRQ   5   1          3            0       15kb           15kb
yellow open   %{[appname]}           ysT9_OibR5eSRu19olrq_w   5   1         32            0    386.5kb        386.5kb
yellow  open   .kibana                4yS67TTOQGOD7l-uMtICOg   1   0          2            0       12kb           12kb
yellow open   tvs                    EM-SvQdfSaGAXUADmDFHVg   5   1          8            0     16.3kb         16.3kb
yellow open   company_org            wIOqfx5hScavO13vvyucMg   5   1          3            0     14.6kb         14.6kb
yellow open   blog                   n5xmcGSbSamYphzI_LVSYQ   5   1          1            0      4.9kb          4.9kb
yellow open   website                5zZZB3cbRkywC-iTLCYUNg   5   1         12            0     18.2kb         18.2kb
yellow open   files                  _6E1d7BLQmy9-7gJptVp7A   5   1          2            0      7.3kb          7.3kb
yellow open   files-lock             XD7LFToWSKe_6f1EvLNoFw   5   1          1            0        8kb            8kb
yellow open   music                  i1RxpIdjRneNA7NfLjB32g   5   1          3            0     15.1kb         15.1kb
yellow open   book_shop              1CrHN1WmSnuvzkfbVCuOZQ   5   1          4            0     18.1kb         18.1kb
yellow open   avs                    BCS2qgfFT_GqO33gajcg_Q   5   1          0            0      1.2kb          1.2kb
  1. 查看node信息

GET /_cat/nodes?v

響應:

ip             heap.percent ram.percent cpu load_1m load_5m load_15m node.role master name
192.168.17.137           38          68   0    0.08    0.03     0.05 mdi       *      node-1

我們可以看到node的名稱。

  1. 創建索引命令

創建名稱爲"location"的索引

PUT /location?pretty

響應:

{
  "acknowledged": true,
  "shards_acknowledged": true
}

查看索引,能看到剛剛創建的索引location

health status index                  uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   location               48G_CgE7TiWomlYsyQW1NQ   5   1          3            0       11kb           11kb
yellow open   .kibana                4yS67TTOQGOD7l-uMtICOg   1   0          2            0       12kb           12kb
  1. 刪除索引命令

刪除名稱爲"location"的索引

DELETE /location?pretty

再查看索引,剛剛創建的索引location已經刪除掉了

health status index                  uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   .kibana                4yS67TTOQGOD7l-uMtICOg   1   0          2            0       12kb           12kb

是不是很簡單,交互界面挺友好吧?

入門CRUD操作

介紹document最基本的CRUD操作,以兒童英文歌曲爲背景

  1. 新增歌曲

我們設計的兒歌結構包含四個字段:歌名name,歌詞content,語言種類language,歌曲時間長length,單位是秒,放在JSON字符串裏。
PUT語法:
<REST Verb> /<Index>/<Type>/<ID>
REST Verbs可以是PUT、POST、DELETE,後斜槓後的內容分別是索引名、類型名、ID。

請求如下:

PUT /music/children/1
{
    "name": "gymbo",
    "content": "I hava a friend who loves smile, gymbo is his name",
    "language": "english",
    "length": "75"
}

響應內容包含索引名、類型名、ID值,version版本號(樂觀鎖控制),結果類型(created/updated/deleted三種),shard信息等,如果新增時該索引不存在,會自動創建索引,索引名即請求時指定的那個,document裏面的field類型,就根據elasticsearch定義的自動映射類型,並且每個field都會建立倒排索引,讓其可以被搜索到。

total和successful爲什麼數據不相等?
新增document時,會往primary shard和replica shard分別寫入document,但由於只有一個node,replica未啓動,所以總共寫入2次,primary shard成功,數量是1。failed只記錄primary shard寫入失敗的情況。

響應如下:

{
  "_index": "music",
  "_type": "children",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}
  1. 修改歌曲
    修改document有兩種方式,一種是增量修改,只修改指定的field,另一種是全量替換文檔,原有的信息全部被替換掉
  • 增量修改length的值,注意是POST請求,並且尾部有_update,doc是固定寫法,請求如下:
POST /music/children/1/_update
{
  "doc": {
    "length": "76"
  }
}

響應:

{
  "_index": "music",
  "_type": "children",
  "_id": "1",
  "_version": 2,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 1,
  "_primary_term": 1
}
  • 全量替換文檔,請求如下:
PUT /music/children/1
{
    "name": "gymbo",
    "content": "I hava a friend who loves smile, gymbo is his name",
    "language": "english",
    "length": "77"
}

響應:

{
  "_index": "music",
  "_type": "children",
  "_id": "1",
  "_version": 3,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 2,
  "_primary_term": 1
}

細心的童鞋可以,全量替換文檔的語法和創建索引是一樣的,對!就是同一個語法 ,是創建還是更新取決於上面的ID存不存在,不存在做創建,存在做更新,更新成功version+1,但這種全量替換有個不好的地方,必須帶上完整的屬性,否則未聲明屬性就沒有了。

想想要使用這個語法的場景:先GET所有的屬性,然後把要更新的屬性更新上,再調用全量替換的更新語法。實際上這種做法不多,原因不外乎兩個:操作複雜,要先查詢後更新;報文過大(相對於增量更新)。所以企業研發一般使用增量方式做document更新。

  1. 查詢歌曲

查詢語句:GET /music/children/1

_source即爲JSON的內容,查詢結果:

{
  "_index": "music",
  "_type": "children",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "name": "gymbo",
    "content": "I hava a friend who loves smile, gymbo is his name",
    "language": "english",
    "length": "75"
  }
}
  1. 刪除歌曲

刪除語句:DELETE /music/children/1

響應結果:

{
  "_index": "music",
  "_type": "children",
  "_id": "1",
  "_version": 4,
  "result": "deleted",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 3,
  "_primary_term": 1
}

bulk批處理

上一節提及的增刪改操作,是針對單個document的,Elasticsearch還有一個批處理命令,可以批量執行這些操作。

  1. bulk的基本語法示例
    還是以上面的兒歌爲案例背景
POST /music/children/_bulk
{"index":{"_id":"1"}}
{"name": "gymbo", "content": "I hava a friend who loves smile, gymbo is his name", "language": "english", "length": "75"}
{"create":{"_id":"2"}}
{"name": "wake me, shark me", "content": "don't let me sleep too late", "language": "english", "length": "55"}
{ "update": {"_id": "2", "retry_on_conflict" : 3} }
{ "doc" : {"content" : "don't let me sleep too late, gonna get up brightly early in the morning"} }
{ "delete": {"_id": "3" }}

可以把多條命令放在一起執行,如果一個bulk請求內有不同的index和type,可以把index和type也可以寫在body json裏,每一個操作要兩個json串:

{"action": {"metadata"}}
{"data"}

delete例外,它只需要1個json串就可以了

action的類型有以下幾種:

  • index:普通的PUT操作,ID不存在時創建document,ID存在時做全量替換
  • create:強制創建,等同於PUT /index/type/id/_create命令
  • update:執行的增量修改操作
  • delete:刪除document操作
  1. bulk注意事項
    bulk api有嚴格的語法要求,每個json串內不能換行,同時每個json串之間必須要有一個換行,否則會報語法錯誤。
    bulk既然是多條命令批量執行,遇到錯誤怎麼辦?會中斷嗎?
    如果bulk請求內有命令執行錯誤,會直接跳過,繼續執行下一條,同時在響應報文裏會對每條命令的結果分別展示,正確的就展示正確的結果,錯誤的會相應提示錯誤日誌。

  2. bulk的性能問題
    bulk既然是批處理,那bulk size與最佳性能肯定存在一定的聯繫,bulk請求的內存會先加載到內存裏,bulk的請求取決於命令的條數和每個命令內容的多少,與性能的關係示例圖(表達概念,數據不具備參考性)如下:
    bulk的性能變化圖

bulk性能優化的目標就是找到這個拐點,需要反覆嘗試一個最佳的size,跟具體的業務數據特性,併發量有關,常見的設置範圍一般是1000-5000之間,bulk請求的大小控制在5-15MB之間(僅供參考)。

小結

本篇簡單介紹了一下document的數據格式,並順帶講解了一下Elasticsearch集羣紅黃綠三種狀態的判定標準,重點是在kibana平臺演示的CRUD小案例和bulk批處理示例,最爲基礎,可以多花一些時間熟悉熟悉。

專注Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區
Java架構社區

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章