https://unsplash.com/photos/_DyUcJalGAc
準備好 ElasticSearch 的環境後,我們就能開始學習操作。本文整理出一些 REST API,除了資料基本的 CRUD 操作,也包含排序與分頁。讀者在練習時,可以透過 Postman 這項工具發出請求。或者使用 GUI 工具(如 Elasticvue),將會更便利。
一、ElasticSearch 的索引(index)
ES 的索引並不是一般資料庫中,用來加快查詢速度的索引,而是一種類似「資料表」(table)或「集合」(collection)的存在。所以裡面會存放資料。
(一)建立 index
以下範例是建立一個叫做「student」的 index。
PUT /student
(二)刪除 index
以下範例是刪除一個叫做「student」的 index。
DELETE /student
若想同時刪除多個 index,可用「,」將 index 名稱隔開,例如:
DELETE /student,course
當 index 被刪除,裡面的資料也會隨之刪除。
二、新增資料
ES 是以 JSON 格式來儲存資料,我們稱之為「文件」(document),與 NoSQL 相似。
以下範例是在一個叫做 student 的 index 新增一筆 document。若 index 不存在,ES 會自動建立。
POST /student/_doc { "name": "Vincent Zheng", "grade": 2, "conductScore": 86, "introduction": "I have a blog used to record what I learn in my career.", "job": { "name": "衛生股長", "isPrimary": true } }
每個 document 在 index 中都有自己的 id。由於我們在新增時沒有特別指定,因此 ES 會自動產生。
以下範例是新增另一筆 document,並且指定 id 為「104」。
POST /student/_doc/104 { "name": "Winnie Kuo", "grade": 1, "conductScore": 71, "introduction": "To lead a team in company in career, learn to lead students in university first.", "job": { "name": "班長", "isPrimary": false } }
只要在 API 路徑加上想要的 id 即可。雖然此處的 id 都是數字,但 ES 固定將 document 的 id 存為字串。
三、查詢資料
在前一節的範例中,新增了兩筆 document,接下來讓我們試著查詢看看。
(一)無條件
以下範例是查詢所有資料,也就是沒有條件。其實 HTTP 方法使用 GET 也可以,但 GUI 工具可能會提示說不能在 GET 請求攜帶 request body。
POST /student/_search { "query": { "match_all": {} } }
基本上就是將條件寫在 query 欄位中,其中「match_all」是全部的意思。
(二)包含關鍵字
以下範例是查詢 introduction 欄位中包含「company」或「career」字眼的資料。
POST /student/_search { "query": { "match": { "introduction": "company career" } } }
其中「match」是包含指定關鍵字的意思。關於更多查詢語法,筆者將在「使用 DSL 撰寫查詢條件」文章中介紹。
(三)閱讀查詢結果
以前面包含關鍵字的條件為例,以下是得到的 response body 之部份內容。附帶一提,ES 預設取最前面 10 筆資料。
{ "hits": { "total": { "value": 2, "relation": "eq" }, "max_score": 0.8506131, "hits": [ { "_index": "student", "_id": "10445000", "_score": 0.8506131, "_source": { "name": "Winnie Kuo", "grade": 1, "conductScore": 71, "introduction": "To lead a team in company in career, learn to lead students in university first.", "job": { "name": "班長", "isPrimary": false } } }, { "_index": "student", "_id": "eOL6zoEByNeVQnvbc4ea", "_score": 0.1878095, "_source": { "name": "Vincent Zheng", "grade": 2, "conductScore": 86, "introduction": "I have a blog used to record what I learn in my career.", "job": { "name": "衛生股長", "isPrimary": true } } } ] } }
接著筆者針對幾個欄位做說明。
- hits.total.value:查詢到的 document 筆數
- hits.max_score:查詢結果中最高的分數
- hits.hits:一個包含查詢結果的陣列
- hits.hits._id:document 的 id
- hits.hits._score:document 的 分數
- hits.hits._source:document 的實際內容
讀者可以發現,id 為「104」的 document 擁有的關鍵字較多,因此分數更高。此外,由於我們沒有指定排序方式,因此 ES 預設是以分數來排序。
四、更新資料
(一)更新部份欄位
以下範例是更新指定 id 的 document 之特定欄位。若原先不存在該欄位,ES 會視為新增欄位。
POST /student/_update/104 { "doc": { "grade": 2, "job": { "isPrimary": true }, "majority": "企業管理" } }
這個請求會將 grade 欄位值設為 2;job 物件的 isPrimary 欄位設為 true;並新增 majority 欄位。
(二)覆蓋整筆資料
以下範例是覆蓋指定 id 的 document 之內容,原先的資料將會被完全取代。
POST /student/_doc/104 { "doc": { "name": "Winnie Pooh", "majority": [ "經營管理" ] } }
以上兩個 API,都是將要用於更新 document 的欄位值放於 request body 的 doc 欄位中。
五、刪除資料
(一)透過 id 刪除
以下範例是刪除 id 為 104 的 document:
DELETE /student/_doc/104
(二)透過條件刪除
以下範例是刪除符合條件的資料。此處刪除 name 欄位包含「Vincent」字眼的 document。
POST /student/_delete_by_query { "query": { "match": { "name": "Vincent" } } }
其實完成刪除操作後,ES 是先將 document 標記為「已刪除」。到了特定的時機才會在背景執行物理上的刪除,釋放出空間。
六、排序與分頁
本節使用以下範例資料示範排序與分頁。讀者練習前不妨將前面使用的 student 的 index 刪除,再逐一新增這 3 筆 document。
{ "name": "Vincent", "grade": 2, "conductScore": 86, "courses": [ { "name": "計算機概論", "point": 3 }, { "name": "程式設計", "point": 4 }, { "name": "投資學", "point": 3 } ], "introduction": "company career" } { "name": "Winnie", "grade": 1, "conductScore": 71, "courses": [ { "name": "會計學", "point": 3 }, { "name": "商業概論", "point": 2 } ], "introduction": "company" } { "name": "Mario", "grade": 3, "conductScore": 86, "courses": [ { "name": "會計學", "point": 5 }, { "name": "審計學", "point": 3 }, { "name": "企業資源規劃", "point": 3 } ], "introduction": "career" }
在學生資料的 document 中,除了名字(name)、年級(grade),還多了操行成績(conductScore)與修習課程(courses)。而課程中又包含學分(point)欄位。
(一)單一欄位排序
以下範例是根據年級遞增排序。
POST /student/_search { "query": { "match_all": {} }, "sort": [ { "grade": "asc" } ] }
在 request body 中,加入了一個 sort 陣列欄位。而陣列元素則描述用來排序的欄位與方向,其中方向不區分大小寫。
此例的查詢結果依序為:Winnie、Vincent、Mario。
除了 document 本身的欄位,我們還能使用 ES 給予 document 的分數來排序。以下範例使用了 match 的查詢條件產生分數差異,並根據分數遞增排序。
POST /student/_search { "query": { "match": { "introduction": "company career" } }, "sort": [ { "_score": "asc" } ] }
(二)多欄位排序
以下範例是先使用操行成績遞減排序,再使用年級遞增排序。
POST /student/_search { "query": { "match_all": {} }, "sort": [ { "conductScore": "desc" }, { "grade": "asc" } ] }
只要將先排序的欄位放在陣列中的前面即可。此例的查詢結果依序為:Vincent、Mario、Winnie。
(三)使用陣列排序
ES 支援使用陣列元素進行排序。由於一個陣列中會有多個元素,因此我們得選擇一種「取值」方式,才能用來排序 document,比方說取最大、最小、總和等。
以下範例是依照修習學分數的總和來遞增排序:
POST /student/_search { "query": { "match_all": {} }, "sort": [ { "courses.point": { "order": "asc", "mode": "sum" } } ] }
此例的查詢結果依序為:Mario、Vincent、Winnie。
在 request body 中,變成是 document 欄位名稱配上一個物件,裡面除了包含方向,還包含取值的模式(mode)。下面筆者列出 ES 支援的取值模式,同樣不區分大小寫。
- min:最小值
- max:最大值
- sum:總和
- avg:平均
- median:中位數
其中 sum、avg 與 median 只能用在數值欄位;而 min 與 max 除了數值欄位,亦可用於字串與日期。雖說我們可選擇一種取值模式,但 ES 仍會在未選擇時採取預設值。例如使用陣列元素遞增排序時,預設為 min;遞減排序時,預設為 max。
(四)分頁
ES 的分頁,採取的是「skip」與「limit」的概念。也就是先跳過一定數量的資料,再取接下來的幾筆作為結果。
以下範例是依照年級欄位遞增排序後,從第 3 筆資料開始取 1 筆。
POST /student/_search { "query": { "match_all": {} }, "sort": [ { "grade": "asc" } ], "from": 2, "size": 1 }
此例的查詢結果為:Mario。
進行分頁時會使用兩個參數。「from」代表起始的 document 位置;「size」代表要擷取的數量。要注意 document 的位置是從 0 開始算。再舉一個例子,若 from 為 0,size 為 2,則查詢結果依序為:Winnie、Vincent。
上一篇:【ElasticSearch 8】用途介紹與在 Windows 上安裝
留言
張貼留言