在7.11版本後ES推出了runtime這個新功能,在以往都是
Schema on Write:寫入時就已經定義好資料的數據結構
現在新增Runtime後,導入了
Schema on Read:在讀取時才決定要怎麼解析資料
Runtime field也就是在執行query的當下,才對資料進行解析
優點:
缺點:
mapping設定:
例如原本的欄位只有存身分證字號,但是我們想透過runtime來整合出哪幾個縣市的人有多少
PUT /test-runtime
{
"mappings": {
"runtime": {
"city": {
"type": "keyword",
"script": {
"source": "emit(doc['TW-id'].value.substring(0, 1))"
}
}
},
"properties": {
"TW-id": {
"type": "keyword"
}
}
}
}
接著輸入我們的資料,使用bulk API
雖然之前沒提過,但是我覺得都能到這天的可以直接看官方文檔了,我就不額外補充了
https://www.elastic.co/guide/en/elasticsearch/reference/8.9/docs-bulk.html
POST /_bulk
{"index": {"_index": "test-runtime", "_id": 1}}
{"TW-id": "R123456789"}
{"index": {"_index": "test-runtime", "_id": 2}}
{"TW-id": "B123456789"}
{"index": {"_index": "test-runtime", "_id": 3}}
{"TW-id": "A123456789"}
{"index": {"_index": "test-runtime", "_id": 4}}
{"TW-id": "A123456769"}
{"index": {"_index": "test-runtime", "_id": 5}}
{"TW-id": "A123456719"}
接著我們直接看結果:
GET /test-runtime/_search
{
"query": {
"match_all": {}
}
}
結果中沒有我們的runtime field
還記得我們一開始說的嗎~ runtime field出來的欄位不索引,那_source當然沒東西
我們使用fields API
GET /test-runtime/_search
{
"fields": ["*"],
"query": {
"match_all": {}
}
}
就能找到資料了
那如果要刪除也很簡單:
PUT /test-runtime/_mapping
{
"runtime": {
"city": null
}
}
另外在前面的Dynamic也提過可以設定成runtime
此時產出的欄位type有稍微不同,所以要注意:
偵測類型 | dynamic: true | dynamic: runtime |
---|---|---|
float | float | double |
json | object | 不會產生 |
string(但內容都是數字) | float或long | double或long |
接下來我們說一下search的runtime,這邊因為還沒提過search
所以不會用太難的語法,並且因為runtime的核心就是在執行query時才執行
所以避不開search,而search那邊內容也很多,再拉一個runtime比較難統整
畢竟他還是跟我們前一天的內容還是有很高關聯性的
此時我們先把剛剛的索引刪掉,然後創一個新的
PUT /test-runtime
{
"mappings": {
"properties": {
"TW-id": {
"type": "keyword"
}
}
}
}
並且再次輸入資料(跟上面一模一樣)
接著輸入查詢語與聚合
GET /test-runtime/_search
{
"runtime_mappings": {
"city": {
"type": "keyword",
"script": {
"source": "emit(doc['TW-id'].value.substring(0, 1))"
}
}
},
"aggs": {
"city": {
"terms": {
"field": "city"
}
}
}
}
我們就能看到,針對這個runtime欄位所做的聚合
而這也是使用runtime field相比於script的優勢,能對欄位再作進一步的處理
接著來說明與runtime同時推出的Async search
Async search:
async API可以用非同步的方式送出搜尋請求,並且可以監控它的進程並在部分結果能夠取得時獲取
使用方式如下,並且請求體跟一般_search沒什麼差別
POST /index_name/_async_search
送出請求後會返回以下範例:
{
"id" : "FmRldE8zREVEUzA2ZVpUeGs2ejJFUFEaMkZ5QTVrSTZSaVN3WlNFVmtlWHJsdzoxMDc=",
"is_partial" : true,
"is_running" : true,
"start_time_in_millis" : 1583945890986,
"expiration_time_in_millis" : 1584377890986,
"response" : {
"took" : 1122,
"timed_out" : false,
"num_reduce_phases" : 0,
"_shards" : {
"total" : 562,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 157483,
"relation" : "gte"
},
"max_score" : null,
"hits" : [ ]
}
}
}
// 獲取
GET /_async_search/id
// 刪除
DELETE /_async_search/id
可以設置的參數:
今天介紹了runtime field,這個可以在開發初期多加利用的好工具
並且如果搜尋量大,可以使用async API在背景執行,不影響其他排程使用
但是如果開發方向已經確定了,還是制定好mapping或是reindex等操作才是最佳解
參考資料
runtime field:
https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-mapping-fields.html
https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-search-request.html
async API:
https://www.elastic.co/guide/en/elasticsearch/reference/current/async-search.html#async-search