Elasticsearch Bài học 20: Tự build Custom Analyzer để phục vụ bài toán nghiệp vụ đặc thù
Ở Bài 19, chúng ta đã hiểu rõ cơ chế 3 bước của một Analyzer: Character Filters -> Tokenizer -> Token Filters. Bộ standard analyzer mặc định hoạt động khá ổn cho văn bản tiếng Anh thông thường, nhưng khi áp dụng vào E-commerce (nơi đầy rẫy mã SKU, tên thương hiệu viết tắt, và từ lóng), nó sẽ tạo ra những kết quả tìm kiếm cực kỳ thảm họa.
Khi đó, bạn bắt buộc phải tự tay "lắp ráp" một Custom Analyzer (Bộ phân tích tùy chỉnh) của riêng mình.
1. Khai báo Custom Analyzer ở đâu?
Khác với Mapping (định nghĩa cấu trúc dữ liệu), Analyzer thuộc về phần Settings (Cấu hình luồng hoạt động) của Index.
Bạn phải định nghĩa Custom Analyzer ngay lúc khởi tạo Index bằng lệnh PUT. Cấu trúc khai báo luôn tuân theo nguyên tắc: Định nghĩa các thành phần lẻ (char_filter, filter) trước, rồi mới "lắp ráp" chúng lại trong block analyzer.
2. Kịch bản E-commerce: Bài toán "H&M" và "KCN"
Giả sử hệ thống Hasaki của bạn gặp 2 bài toán tìm kiếm từ khách hàng:
-
Lỗi ký tự đặc biệt: Khách tìm chữ
"H&M". Analyzer mặc định xóa dấu&và tách thành 2 chữ"h"và"m", khiến kết quả search ra toàn các từ chứa chữ H hoặc M (rất rác). Chúng ta muốn giữ nguyên hoặc biến nó thành một từ liền mạch. -
Từ đồng nghĩa & Viết tắt: Khách hàng lười gõ, họ tìm
"kcn", nhưng tên sản phẩm trên database lại ghi là"Kem chống nắng". Hoặc tìm"srm"thay cho"Sữa rửa mặt".
Chúng ta sẽ giải quyết cả 2 bài toán này trong cùng 1 Custom Analyzer.
3. Thực hành: Khởi tạo Index với Custom Analyzer
Hãy mở Kibana Dev Tools và chạy lệnh khởi tạo Index hasaki_products sau:
JSON
PUT hasaki_products
{
"settings": {
"analysis": {
"char_filter": {
"brand_mapper": {
"type": "mapping",
"mappings": [
"H&M => hm_brand",
"M.A.C => mac_brand"
]
}
},
"filter": {
"ecommerce_synonyms": {
"type": "synonym",
"synonyms": [
"kcn, kem chống nắng",
"srm, sữa rửa mặt",
"laptop, máy tính xách tay, macbook"
]
}
},
"analyzer": {
"hasaki_custom_analyzer": {
"type": "custom",
"char_filter": [
"brand_mapper"
],
"tokenizer": "standard",
"filter": [
"lowercase",
"ecommerce_synonyms"
]
}
}
}
},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "hasaki_custom_analyzer"
}
}
}
}
Phân tích cấu trúc lắp ráp trên:
-
Block
char_filter: Chúng ta tự chế ra một bộ lọc ký tự tên làbrand_mapper. Nếu thấy chữH&M, nó sẽ lập tức thay thế thành chuỗihm_brand(để bảo vệ chữ này không bị Tokenizer băm nát ở bước sau). -
Block
filter: Chúng ta chế ra bộ lọc token tên làecommerce_synonymsdùng kiểusynonym. Ở đây quy định rõ các cụm từ đồng nghĩa cách nhau bằng dấu phẩy. -
Block
analyzer: Đây là nơi lắp ráp thành phẩm mang tênhasaki_custom_analyzer. Chúng ta khai báo type làcustomvà nạp các phụ kiện vào theo đúng thứ tự luồng chảy: Đi quabrand_mapper-> Băm bằngstandardtokenizer -> Đưa tất cả về chữ thường (lowercase) -> Cuối cùng nhân bản các từ đồng nghĩa quaecommerce_synonyms. -
Block
mappings: Cuối cùng, chúng ta áp dụng thẳng chiếc máy tự chế này cho trườngnamecủa dữ liệu.
4. X-Quang thành quả bằng API _analyze
Để kiểm chứng xem chiếc máy của chúng ta hoạt động có đúng logic không, hãy gọi API kiểm tra:
JSON
POST hasaki_products/_analyze
{
"analyzer": "hasaki_custom_analyzer",
"text": "Sữa rửa mặt nam H&M"
}
Kết quả Token sinh ra trong Inverted Index sẽ là:
["sữa", "rửa", "mặt", "srm", "nam", "hm_brand"]
Hãy chú ý phép màu vừa xảy ra:
-
Cụm "H&M" không bị băm nát thành "h" và "m" nữa, nó đã được map thành token
hm_brand. -
Cụm "Sữa rửa mặt" không chỉ sinh ra các token rời rạc
sữa,rửa,mặt, mà nhờ có bộ lọc synonym, nó tự động nội suy và đẻ thêm một tokensrmnhét vào Index (dù trong câu gốc không hề có chữ srm). -
Giờ đây, khách hàng lên ô tìm kiếm gõ
"srm nam hm"chắc chắn sẽ ra đúng sản phẩm này.
5. Quy tắc vận hành (Production Rule)
Với tư cách là Backend Engineer, bạn phải nằm lòng quy tắc sinh tử này: Bạn KHÔNG THỂ thay đổi Settings Analyzer của một Index đang mở (Open).
Nếu ngày mai Hasaki có thêm từ đồng nghĩa mới "tt" -> "tẩy trang", bạn không thể gửi lệnh PUT sửa thẳng vào Index đang chạy live. Bạn bắt buộc phải thực hiện 3 bước:
-
Đóng Index tạm thời:
POST hasaki_products/_close(Lúc này API search sẽ báo lỗi). -
Cập nhật Settings thêm từ đồng nghĩa:
PUT hasaki_products/_settings { ... } -
Mở lại Index:
POST hasaki_products/_open
(Cách tối ưu hơn để cập nhật từ đồng nghĩa mà không gây downtime là đưa danh sách synonym ra một file .txt độc lập trên server và dùng API Reload Search Analyzers - nhưng đó là một bài toán nâng cao dành cho vận hành cụm lớn).
Đến đây, bạn đã biết cách build một Analyzer cho riêng mình. Tuy nhiên, nếu bạn thử nhập một câu tiếng Việt có dấu phức tạp như "Chống nắng đi biển", standard tokenizer vẫn băm nó theo khoảng trắng thành ["chống", "nắng", "đi", "biển"]. Trong tiếng Việt, "chống nắng" là một từ ghép có nghĩa, nếu tách rời nó sẽ làm giảm độ chính xác của điểm Ranking (Scoring).
Để giải quyết triệt để tìm kiếm tiếng Việt, chúng ta cần một Tokenizer thông minh hơn, dựa trên từ điển NLP.
All Rights Reserved