Giải pháp cho bài toán tìm kiếm tiếng Việt trong cơ sở dữ liệu MySQL là một giải pháp chẳng đơn giản tí nào bởi tiếng Việt rất phức tạp. Nếu bạn có một server đủ mạnh thì nên áp dụng thuật toán tìm kiếm ngữ nghĩa tiếng Việt mà Google hay Xalo, Socbay áp dụng, còn không thì chúng ta cùng nghiên cứu nhé :)
Bạn nào đã từng lập trình chắc cũng biết là để tìm kiếm tiếng Việt cũng chẳng đơn giản tí nào và là vấn đề đau đầu.
Phụ mục
Giải pháp tìm kiếm thông thường – tìm kiếm khớp
Khi lập trình, để thực hiện một câu lệnh tìm kiếm chúng ta thường áp dụng 2 phương pháp sau:
Giải pháp 1:
SELECT * FROM table_name WHERE column_name = '%keyword%' |
Giải pháp 2:
SELECT * FROM table_name WHERE column_name LIKE '%keyword%' |
Hai giải pháp này được áp dụng khá nhiều khi chúng ta cần tìm những kết quả tìm kiếm với nội dung chính xác với từ khóa cần tìm. Tuy nhiên, tiếng Việt không đơn giản như vậy :(
Tìm kiếm Fulltex
Giải pháp này thường được áp dụng với cơ sở dữ liệu lớn, số lượng record nhiều. Theo mình biết thì với giải pháp này số lượng record càng nhiều thì dữ liệu càng chính xác. Điều bất tiện là tìm kiếm Fulltext chỉ áp dụng cho các field đã được fulltext. Giải pháp này có cái nay là không những tìm kiếm với từ khóa chính xác, nó còn tìm được các từ khóa gần giống và các record có liên quan đến dữ liệu trong keyword chúng ta đưa vào.
SELECT * from table_name WHERE match('column_1', 'column_2', 'column_3', '.....') against('keyword'); |
Khi câu lệnh MATCH được sử dụng trong mệnh đề SELECT nó sẽ trả lại một thứ tự sắp xếp theo mức độ thích hợp, được xác định bằng một con số thập phân dương. Số này càng gần với 0 thì bản ghi càng kém thích hợp. Giá trị thích hợp này được xác định dựa trên biểu thức tìm kiếm, số từ có trong các trường được đánh chỉ mục cũng như tổng số bản ghi được tìm kiếm.
Câu lệnh AGAINST chỉ chấp nhận một tham số. Đó là chuỗi mà chúng ta cần tìm.
Bạn hãy thực hiện câu lệnh trên với tìm kiếm khớp đã nói ở trên để xem chúng có trả về cùng một tập kết quả không? Câu trả lời có thể là: có và không. Chính sự can thiệp của thứ tự sắp xếp theo mức độ thích hợp đã làm cho tập kết quả này có sự sai khác.
Đặc biệt, mình thích tìm kiếm Fulltext bởi nó hỗ trợ tìm kiếm với các toán tử.
Tìm kiếm toàn văn với toán tử boolean
Bằng cách kết hợp nhiều toán tử bên trong chuỗi tìm kiếm, bạn có thể đưa vào hay loại trừ các từ khác, thay đổi các tổ hợp từ để thay đổi giá trị thích hợp… Sau đây là một số toán tử boolean thường dùng trong MySQL:
- + Dấu cộng ở đầu chỉ ra rằng từ này phải xuất hiện ở tất cả các hàng trả lại.
- – Dấu trừ ở đầu chỉ ra rằng từ này không được có mặt trong tất cả các hàng trả lại.
- Mặc định (khi không có dấu trừ hoặc dấu cộng) từ tìm kiếm là tùy chọn, nhưng hàng nào chứa từ đó sẽ được đánh giá cao hơn.
- < > Hai toán tử này được sử dụng để thay đổi phần đóng góp của từ vào giá trị thích hợp của một hàng. Toán tử < làm giảm, còn toán tử > làm tăng phần đóng góp.
- ( ) Các dấu ngoặc đơn được sử dụng để nhóm các từ vào một biểu thức con.
- ~ Dấu ngã nằm ở đầu có chức năng toán tử phủ định, làm cho phần đóng góp của từ vào giá trị thích hợp của hàng bị phủ định. Kí hiệu này có ích khi dùng để đánh giá các từ gây nhiễu. Một hàng có chứa một từ như vậy sẽ bị đánh giá thấp hơn các hàng khác, nhưng không có nghĩa là nó bị loại trừ, như trường hợp dùng toán tử – .
- * Một dấu hoa thị là toán tử cắt bỏ. Không giống như các toán tử khác, nó được nối vào từ chứ không phải đặt nó ở trước từ.
- “Mệnh đề được đặt trong dấu nháy kép”, sẽ chỉ so khớp với các hàng có chứa mệnh đề đó.
Hiện nay mình sử dụng thuật toán tìm kiếm này khá nhiều trong các project đang làm :)
Tìm kiếm với REGEXP BINARY
Giải pháp tìm kiếm này mình học được lúc làm việc với anh Thanh quản lý bên VINEXT :D
Hiện mình chưa có thời gian và điều kiện để nghiên cứu về giải pháp này nhưng tạm thời cứ post lên đã cho các bạn test thử:
SELECT * FROM table_name WHERE column_name REGEXP BINARY '^keyword'; |
Giải pháp này trả về kết quả là tất cả các record có xuất hiện từ khóa keyword.
Doan Thich says
Cám ơn bài viết rất hay của bạn.
Pikachu says
ai nói với bạn SELECT * FROM table_name WHERE column_name = ‘%keyword%’ thì ko thể tìm kiếm tiếng việt, bạn thử dùng SELECT * FROM table_name WHERE column_name like N’%keyword%’ . Cần j phải làm phức tạp lên vậy
Nguyễn Duy Nhân says
Bạn có thể phân tích lợi và hại của câu SQL của bạn được ko ?