Tại sao cần cập nhật bổ sung?
Thay vì sử dụng PUT để thay thế toàn bộ tài liệu (tốn kém hiệu năng do phải đọc, sửa, ghi lại), Elasticsearch cung cấp cơ chế _update cho phép chỉnh sửa từng trường cụ thể. Phương pháp này tránh được các bước trung gian như:
- Truy vấn shard chứa tài liệu → Trả về bộ nhớ → Chỉnh sửa → Gửi lại shard → Ghi chỉ mục
- Giảm thiểu xung đột đồng thời nhờ thực hiện tất cả thao tác trong cùng shard
Cách triển khai cơ bản
Thay vì sử dụng POST index/type/id (gây mất dữ liệu), dùng _update để cập nhật từng trường:
// Tạo mẫu dữ liệu
PUT company/employee/1001
{
"user_name": "Tran Van A",
"current_age": 28,
"salary": 12000
}
// Cập nhật bổ sung trường tuổi
POST company/employee/1001/_update
{
"doc": {
"current_age": 29
}
}
Quan trọng: Nếu dùng POST company/employee/1001 thay vì _update, toàn bộ tài liệu sẽ bị ghi đè → trường salary sẽ mất đi.
Xử lý phức tạp với script
Painless script tích hợp (ưu tiên)
// Tăng lương 10% bằng script
POST company/employee/1001/_update
{
"script": {
"source": "ctx._source.salary *= params.raise_factor",
"params": {
"raise_factor": 1.1
}
}
}
Script Groovy (đã lỗi thời)
(Chỉ hỗ trợ trên ES 5.x, ES 6+ không còn hỗ trợ)
// Lưu script vào ${ES_HOME}/config/scripts/increase_salary.groovy
// Nội dung: ctx._source.salary *= bonus
POST company/employee/1001/_update
{
"script": {
"lang": "groovy",
"file": "increase_salary",
"params": {
"bonus": 1.1
}
}
}
Lưu ý: Hệ thống báo Deprecation: [groovy] scripts are deprecated. Nên sử dụng painless thay thế.
Chế độ upsert khi tài liệu không tồn tại
// Nếu tài liệu id=1001 không tồn tại, tự tạo mới với trường level
POST company/employee/1001/_update
{
"script": "ctx._source.level = params.new_level",
"upsert": {
"user_name": "New Employee",
"level": 0
},
"params": {
"new_level": 3
}
}
Kết quả: "result": "created" nếu tài liệu chưa tồn tại.
Điều khiển xung đột đồng thời
Tham số retry_on_conflict xác định số lần thử lại khi xung đột:
POST company/employee/1001/_update?retry_on_conflict=3
Cơ chế hoạt động:
- Client A và B cùng đọc tài liệu với
_version=1 - Client A cập nhật thành công →
_version=2 - Client B cập nhật → phát hiện
_version=1 ≠ 2→ xung đột - Client B tự động thử lại
retry_on_conflictlần (mặc định 0)