Elasticsearch Bài học 21: Xử lý tiếng Việt chuẩn xác trong Elasticsearch với Vietnamese Analyzer
Trong tiếng Anh, các từ được phân tách rõ ràng bằng khoảng trắng (ví dụ: Sunscreen for face). Tokenizer standard có thể dễ dàng cắt chúng thành ["sunscreen", "for", "face"] cực kỳ chuẩn xác.
Tuy nhiên, tiếng Việt lại thuộc nhóm ngôn ngữ đơn âm tiết (Monosyllabic). Một từ có nghĩa có thể cấu tạo từ 2 hoặc 3 âm tiết đứng cách nhau bởi khoảng trắng. Ví dụ: "Sữa rửa mặt", "Kem chống nắng".
Nếu áp dụng standard tokenizer cho dữ liệu tại Hasaki, từ "Kem chống nắng" sẽ bị băm thành ["kem", "chống", "nắng"]. Hệ quả là khi khách hàng tìm kiếm "áo chống mưa", họ vẫn có thể nhìn thấy "kem chống nắng" nằm ở trang kết quả do hệ thống vô tình match trúng token "chống". Điểm số Ranking (Scoring) bị nhiễu loạn nghiêm trọng.
Để Elasticsearch thực sự "hiểu" tiếng Việt, chúng ta cần thay thế standard bằng một Tokenizer sử dụng từ điển NLP (Xử lý ngôn ngữ tự nhiên).
1. Cài đặt Plugin Vietnamese Analysis
Elasticsearch mặc định không tích hợp sẵn bộ phân giải tiếng Việt. Bạn bắt buộc phải cài thêm Plugin (phổ biến và chuẩn mực nhất hiện nay là elasticsearch-analysis-vietnamese dựa trên lõi Cốc Cốc Tokenizer).
Cách cài đặt: Bạn cần chui vào bên trong (bash/sh) của từng container/server đang chạy Elasticsearch và thực thi lệnh cài đặt plugin tương ứng với version đang dùng (ví dụ bản 8.x):
Bash
# Bên trong container Elasticsearch
./bin/elasticsearch-plugin install https://github.com/duydo/elasticsearch-analysis-vietnamese/releases/download/v8.10.2/elasticsearch-analysis-vietnamese-8.10.2.zip
Lưu ý vận hành: Sau khi cài plugin, bạn bắt buộc phải restart lại Node đó thì Elasticsearch mới nhận diện được Analyzer mới.
2. So sánh X-Quang: standard vs vi_analyzer
Ngay sau khi restart, cụm của bạn đã được trang bị thêm một bộ phân tích có tên là vi_analyzer. Hãy dùng API _analyze để soi thử sự khác biệt.
Thử nghiệm với standard:
JSON
POST _analyze
{
"analyzer": "standard",
"text": "kem chống nắng đi biển"
}
Kết quả:
["kem", "chống", "nắng", "đi", "biển"](5 tokens rời rạc).
Thử nghiệm với vi_analyzer:
JSON
POST _analyze
{
"analyzer": "vi_analyzer",
"text": "kem chống nắng đi biển"
}
Kết quả:
["kem_chống_nắng", "đi", "biển"](Chỉ còn 3 tokens).
Nhờ vào bộ từ điển NLP, Cốc Cốc Tokenizer đã nhận diện được "kem chống nắng" là một danh từ ghép và nối chúng lại bằng dấu gạch dưới (_). Giờ đây, từ khóa này trở thành một Token duy nhất, nguyên khối. Khách tìm "chống mưa" sẽ không bao giờ bị match nhầm vào "kem_chống_nắng" nữa. Độ chính xác (Precision) của hệ thống tăng lên đột phá.
3. Tích hợp vi_analyzer vào Custom Analyzer
Ở Bài 20, chúng ta đã build một Custom Analyzer giải quyết bài toán "H&M" và từ đồng nghĩa "kcn". Bây giờ, hãy "độ" lại cỗ máy đó, rút lõi standard ra và thay bằng lõi tiếng Việt.
JSON
PUT hasaki_products_v2
{
"settings": {
"analysis": {
"char_filter": {
"brand_mapper": {
"type": "mapping",
"mappings": ["H&M => hm_brand"]
}
},
"filter": {
"ecommerce_synonyms": {
"type": "synonym",
"synonyms": [
"kcn, kem_chống_nắng",
"srm, sữa_rửa_mặt"
]
}
},
"analyzer": {
"vietnamese_ecommerce_analyzer": {
"type": "custom",
"char_filter": ["brand_mapper"],
"tokenizer": "vi_tokenizer",
"filter": [
"lowercase",
"ecommerce_synonyms"
]
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "vietnamese_ecommerce_analyzer"
}
}
}
}
Một chi tiết sinh tử cần lưu ý trong file JSON trên: Trong mảng từ đồng nghĩa (synonyms), thay vì viết "kcn, kem chống nắng", chúng ta phải viết là "kcn, kem_chống_nắng" (có dấu gạch dưới). Lý do là vì synonym filter đứng sau vi_tokenizer trong Pipeline. Tại thời điểm chạy đến filter này, văn bản đã bị Tokenizer nối lại bằng dấu gạch dưới rồi. Nếu bạn viết khoảng trắng, từ đồng nghĩa sẽ không thể match được với token gốc.
4. Bài toán thực tế: Stopwords tiếng Việt
Tiếng Việt có rất nhiều từ nối làm câu thêm tự nhiên nhưng lại vô dụng trong tìm kiếm, ví dụ: các, những, của, là, thì, mà, ở, tại, bị, được. Những từ này (Stopwords) xuất hiện trong mọi Document, khiến file Inverted Index phình to và làm chậm quá trình Search.
Bạn có thể cấu hình loại bỏ chúng bằng cách thêm một filter stop kết hợp từ điển tiếng Việt:
JSON
"filter": {
"vietnamese_stop": {
"type": "stop",
"stopwords_path": "analyzers/vietnamese_stopwords.txt"
}
}
(File vietnamese_stopwords.txt là một file text chứa các từ vô nghĩa, mỗi từ 1 dòng, được bạn upload thủ công lên thư mục config/analyzers/ của máy chủ Elasticsearch). Sau đó, hãy gắn filter vietnamese_stop này vào cuối chuỗi Pipeline của Custom Analyzer.
Đến lúc này, cấu trúc Mapping và Analyzer của bạn đã quá hoàn hảo cho thị trường Việt Nam. Nhưng có một vấn đề rất lớn phát sinh:
Mọi thiết lập về Analyzer và Mapping chỉ có thể được khai báo lúc Khởi tạo Index. Vậy với Index hasaki_products cũ đang chứa 1 triệu bản ghi live trên Production (đang xài Analyzer cũ), làm sao chúng ta "bứng" toàn bộ dữ liệu đó sang Index mới hasaki_products_v2 một cách an toàn mà không làm sập hệ thống (Zero-downtime)?
All rights reserved