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 上安裝
留言
張貼留言