ES 27 - Elasticsearch的腳本使用實踐


本文以 ES 6.6.0 版本為例進行演示.

1 關於腳本

ES提供了腳本支持 —— 可以通過Groovy外置腳本(已過時)、內置painless腳本實現各種復雜操作.

—— painless有輕便之意, 使用時直接在語法中調用即可, 無需外置, 也就是不支持通過外部文件存儲painless腳本並調用的方法.

// 向ES中插入一條數據:
PUT employee/developer/1
{
    "name": "shou feng", 
    "age": 20,
    "salary": 10000
}
  
// 通過GET發送腳本, 允許為每個匹配的文檔返回腳本評估(script evaluation)內容: 
GET employee/_search
{
    "script_fields": {
        "change_age_field": {	// 該字段不存在 - script fields可以處理未存儲的字段
            "script": {
                "lang":   "expression",
                "source": "doc['age'] * multiplier",  // 獲取age字段的值進行計算
                "params": {
                    "multiplier": 2
                }
            }
        }
    }
}

// 響應結果為: 
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 1,
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "employee",
        "_type" : "developer",
        "_id" : "1",
        "_score" : 1.0,
        "fields" : {
          "change_age_field" : [
            40.0
          ]
        }
      }
    ]
  }
}

2 腳本使用的最佳實踐

Elasticsearch第一次加載一個新腳本時, 會將新腳本編譯並存儲在緩存中.

編譯可能是一個繁重的過程, 如果需要將變量傳遞給腳本, 建議: 將它們作為命名參數傳遞給腳本本身(方式①), 而不是硬編碼在腳本中(方式②).

(1) 方式① 參數傳遞:

"source": "doc['age'] * multiplier",
"params": {
    "multiplier": 2
}

(2) 方式② 硬編碼:

"source": "doc['age'] * 2"

(3) 優劣對比:

  • 每次乘數改變時都必須重新編譯第②個版本, 而第①個版本只編譯一次.

  • 如果短時間內編譯過多的腳本, ES將拒絕帶有circuit_breaking_exception錯誤的新腳本.

  • Elasticsearch默認情況下, 每分鍾最多編譯15個內聯腳本, 可以通過修改 script.max_compilations_rate 的值來更改此設置.

2.1 創建腳本並存儲

可以使用_scripts API 將腳本存儲在集群狀態中, 並從集群狀態中檢索腳本.

使用_scripts/{id}的方式操作腳本, 具體步驟如下:

(1) 首先在集群狀態中創建名為calculate-score的腳本:

POST _scripts/calculate-score
{
    "script": {
        "lang": "painless",
        "source": "Math.log(_score * 2) + params.my_modifier"
    }
}

(2) 檢索存儲的腳本:

GET _scripts/calculate-score

(3) 通過腳本id使用已創建的腳本:

GET _search
{
    "query": {
        "script": {
            "script": {
                "id": "calculate-score",
                "params": {
                    "my_modifier": 2	// 傳遞腳本所需的參數
                }
            }
        }
    }
}

(4) 刪除腳本:

DELETE _scripts/calculate-score

2.2 腳本的緩存

默認情況下, 所有的腳本都會被緩存到ES集群中, 因此只有當腳本被更新之后, ES才會重新編譯它們.

同樣, 腳本沒有過期時間的說法, 但可以使用script.cache.expire設置更改過期時間.

也可以使用script.cache.max_size配置此腳本緩存的大小, 默認緩存大小為100.

存儲腳本的大小限制為65535字節, 可以通過 script.max_size_in_bytes來更改, 但是如果腳本非常大, 就應該考慮相關腳本的實現引擎是否足夠優秀.

2.3 Script Field - 腳本字段

腳本字段還可以通過訪問_source字段來提取文檔的其他字段 —— 使用params ['_source']提取要從中獲取的內容.

比如訪問_source元字段中message字段的內容, 可以用: "script": "params['_source']['message']"訪問.

另外: 理解doc['my_field'].valueparams['_source']['my_field']之間的區別非常重要:

① 使用doc關鍵字: 將導致該字段的術語加載到內存(緩存)中, 這樣腳本的執行速度會更快, 但也會帶來更多的內存消耗. 另外, doc […]符號只允許簡單的值字段(不能從中返回JSON對象), 並且它只對非分析或基於單個術語的字段有意義.

② 使用params關鍵字: 每次使用時都必須加載和解析_source, 這是非常緩慢的.

建議: 使用doc關鍵字, 從文檔中訪問相關字段的值, 這種方式更加高效.


參考資料

ES 6.6 官方文檔 - How to use scripts

版權聲明

作者: 馬瘦風(https://healchow.com)

出處: 博客園 馬瘦風的博客(https://www.cnblogs.com/shoufeng)

感謝閱讀, 如果文章有幫助或啟發到你, 點個[好文要頂👆] 或 [推薦👍] 吧😜

本文版權歸博主所有, 歡迎轉載, 但 [必須在文章頁面明顯位置標明原文鏈接], 否則博主保留追究相關人員法律責任的權利.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM