3.1 Tiền xử lý văn bản: từ chuỗi ký tự thành term
Trước khi có index, phải quyết định term là gì. Đây là quyết định đắt nhất trong cả hệ thống lexical: đổi tokenizer, giữ nguyên thuật toán ranking, lớp A đã nhảy +20.8% (Tầng 0).
Chuỗi xử lý chuẩn, theo đúng thứ tự:
| Bước | Việc | Ví dụ | Cần cho tiếng Việt? |
|---|---|---|---|
| 1. Chuẩn hoá Unicode | NFC/NFD — ế có thể là 1 code point hoặc e+dấu | xóa (NFC) ≠ xóa (NFD) dù trông giống | Bắt buộc. Bỏ bước này thì hai chuỗi giống nhau không khớp nhau |
| 2. Hạ chữ | case folding | POST → post | Có |
| 3. Cắt token | biên từ | AES-256 → aes-256? aes+256? | Có, và đây là chỗ hay chết |
| 4. Bỏ dấu | diacritic folding | mật khẩu → mat khau | Tuỳ — có công thức hoà vốn, xem 3.10 |
| 5. Bỏ stopword | loại từ quá phổ biến | bỏ của, và, là | Không. Với BM25, idf tự lo. Đo thực: bỏ stopword làm lớp B tụt −11% |
| 6. Rút gốc từ | stemming / lemmatization | running → run | Không có nghĩa với tiếng Việt — tiếng Việt không biến hình |
Hai cái bẫy của bước 3
Phần tiêu đề “Hai cái bẫy của bước 3”Bẫy 1 — tokenizer “làm sạch” ăn mất định danh. Một regex kiểu [^\W\d_]+
(chỉ giữ chữ cái) làm thế này:
'E2003' -> [] ← mã lỗi bốc hơi'POST /v1/transactions' -> ['post', 'transactions'] ← mất /v1'uptime 99,9%' -> ['uptime'] ← mất con số'AES-256' -> ['aes'] ← mất 256Không exception, không log. Hệ thống chỉ đơn giản không bao giờ tìm ra những tài liệu đó. Đây là lỗi tệ nhất của cả lớp lexical.
Bẫy 2 — âm tiết ≠ từ. Tiếng Việt viết rời từng âm tiết: cài đặt là một từ,
hai âm tiết. Cắt theo dấu cách (syllable tokenization) cho bạn cài, đặt —
hai term độc lập, nên đặt cài và cài đặt khớp bằng nhau.
Hai hướng xử lý:
| Cách | Cách làm | Đánh đổi |
|---|---|---|
| Âm tiết + n-gram từ | index cả cài, đặt, và bigram cài_đặt | Đơn giản, không cần model, index to hơn ~2× |
| Word segmentation | dùng bộ tách từ (VnCoreNLP, underthesea) | Đúng hơn về ngôn ngữ, nhưng thêm một phụ thuộc và một nguồn lỗi khi từ mới xuất hiện |
Trong thực tế, âm tiết + bigram thắng về tỉ lệ lợi/chi phí cho phần lớn hệ tìm kiếm sản phẩm: cụm từ vẫn được ghi nhận qua bigram, và không có model nào tách sai.
Quy tắc sống còn
Phần tiêu đề “Quy tắc sống còn”Tokenizer của index và tokenizer của query phải là cùng một hàm.
Không phải “giống nhau” — là cùng một hàm, gọi từ cùng một chỗ. Mọi lệch nhau giữa hai đường này đều biểu hiện thành “tìm không ra” mà không có lỗi nào được ném.