- Giới thiệu về Script ======
Elasticsearch cung cấp hỗ trợ script - cho phép thực hiện các thao tác phức tạp thông qua script Groovy (đã lỗi thời) hoặc script painless tích hợp.
Painless có nghĩa là "nhẹ nhàng", khi sử dụng có thể gọi trực tiếp trong cú pháp mà không cần lưu ở bên ngoài. Điều này có nghĩa là không hỗ trợ phương pháp lưu và gọi script painless từ file bên ngoài.
// Chèn dữ liệu vào ES:
PUT employee/developer/1
{
"name": "shou feng",
"age": 20,
"salary": 10000
}
// Gửi script qua GET, cho phép trả về nội dung đánh giá script cho mỗi tài liệu khớp:
GET employee/_search
{
"script_fields": {
"change_age_field": { // Trường này không tồn tại - script fields có thể xử lý các trường chưa được lưu
"script": {
"lang": "expression",
"source": "doc['age'] * multiplier", // Lấy giá trị trường age để tính toán
"params": {
"multiplier": 2
}
}
}
}
}
// Kết quả phản hồi:
{
"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
]
}
}
]
}
}
- Thực hành tốt nhất khi sử dụng Script ===========
Khi Elasticsearch lần đầu tiên tải một script mới, nó sẽ biên dịch và lưu script đó vào bộ nhớ cache.
Quá trình biên dịch có thể tốn kém, nếu cần truyền biến cho script, nên: truyền chúng dưới dạng tham số đặt tên cho script chính (cách①), thay vì mã cứng trong script (cách②).
(1) Cách① Truyền tham số:
"source": "doc['age'] * multiplier",
"params": {
"multiplier": 2
}
(2) Cách② Mã cứng:
"source": "doc['age'] * 2"
(3) So sánh ưu nhược điểm:
- Mỗi khi hệ số nhân thay đổi, phiên bản② phải biên dịch lại, trong khi phiên bản① chỉ biên dịch một lần.
- Nếu biên dịch quá nhiều script trong thời gian ngắn, ES sẽ từ chối các script mới với lỗi
circuit_breaking_exception. - Mặc định, Elasticsearch chỉ biên dịch tối đa 15 script nội tuyến mỗi phút, có thể thay đổi cài đặt này bằng cách sửa giá trị
script.max_compilations_rate.
2.1 Tạo và lưu Script
Sử dụng API _scripts để lưu script trong trạng thái cluster và truy xuất từ trạng thái cluster.
Sử dụng _scripts/{id} để thao tác với script, các bước cụ thể như sau:
(1) Đầu tiên tạo script tên là calculate-score trong trạng thái cluster:
POST _scripts/calculate-score
{
"script": {
"lang": "painless",
"source": "Math.log(_score * 2) + params.my_modifier"
}
}
(2) Truy xuất script đã lưu:
GET _scripts/calculate-score
(3) Sử dụng script đã tạo qua id:
GET _search
{
"query": {
"script": {
"script": {
"id": "calculate-score",
"params": {
"my_modifier": 2 // Truyền tham số cần thiết cho script
}
}
}
}
}
(4) Xóa script:
DELETE _scripts/calculate-score
2.2 Cache Script
Mặc định, tất cả các script đều được cache trong cluster ES, chỉ khi script được cập nhật, ES mới biên dịch lại chúng.
Tương tự, script không có khái niệm thời gian hết hạn, nhưng có thể sử dụng cài đặt script.cache.expire để thay đổi thời gian hết hạn.
Có thể sử dụng script.cache.max_size để cấu hình kích thước cache script, kích thước cache mặc định là 100.
Giới hạn kích thước script lưu là 65535 byte, có thể thay đổi bằng script.max_size_in_bytes, nhưng nếu script rất lớn, nên xem xét xem engine thực hiện script có đủ tốt không.
2.3 Script Field - Trường Script
Script field còn có thể truy cập trường _source để trích xuất các trường khác của tài liệu - sử dụng params['_source'] để trích xuất nội dung cần lấy.
Ví dụ để truy cập nội dung trường
messagetrong trường siêu dữ liệu_source, có thể dùng:"script": "params['_source']['message']".
Ngoài ra: Hiểu rõ sự khác biệt giữa doc['my_field'].value và params['_source']['my_field'] rất quan trọng:
① Sử dụng từ khóa doc: sẽ dẫn đến việc tải các thuật ngữ của trường vào bộ nhớ (cache), giúp script thực thi nhanh hơn nhưng cũng tiêu tốn nhiều bộ nhớ hơn. Ngoài ra, ký hiệu
doc[...]chỉ cho phép các trường giá trị đơn giản (không thể trả về đối tượng JSON từ đó) và chỉ có ý nghĩa với các trường không được phân tích hoặc dựa trên thuật ngữ đơn lẻ.② Sử dụng từ khóa params: mỗi lần sử dụng đều phải tải và phân tích
_source, điều này rất chậm.Khuyến nghị: Sử dụng từ khóa
docđể truy cập giá trị của các trường liên quan từ tài liệu, cách này hiệu quả hơn.