(MySQL&PHP)
Rắc rối sẽ diễn ra khi có quá nhiều thông tin và chính ta cũng không biết chính xác phải tìm cái gì.
Sau đây mình sẽ giới thiệu tới cách bạn 2 cách để có thể tìm kiếm gần đúng trong SQL.
Cách 1: MATCH, AGAINST
Đây là một kiểu tìm kiếm Full text mà nếu các bạn vào google search một phát với từ khóa:"tìm kiếm toàn văn"sẽ ra một đống bài giống nhau hoàn toàn, không hiểu ăn cắp từ web nào ra mà cuối cùng bài nào cũng giống như bài nào.
Mấy bài nó nó rất nhiều và rất kỹ lưỡng, đến mức đọc không hiểu nỗi.
Mình chỉ hiểu sơ sơ đến mức đủ xài.
Ví dụ ta có một bảng rất đơn giản tên là topic gồm 2 cột : id_topic và subject, ý tưởng để tìm kiếm tựa bài đơn giản chỉ với một câu lệnh:
Mã nguồn[chọn]:
SELECT * FROM topic WHERE $subject=subject
Với biến $subject là những gì người dùng nhập vào(tất nhiên là đả qua xử lý như loại bỏ các ký tự đặc biệt...) Vấn đề nảy sinh ra với cậu lệnh SQL trên là nếu người dùng nhập vào chuỗi :"con gà con"thì những chỉ những hàng chứa chuỗi chính xác như thế mới được trả về.
Điều này sẽ không thích hợp cho việc tiềm kiếm.
Giải quyết vấn đề trên với MATCH, AGAINST
Vấn đề sẽ được giải quyết khá là đơn giản với MATCH, AGAINST, câu lệnh lúc này ta dùng đơn giản chỉ là:
Mã nguồn[chọn]:
SELECT *FROM topic
WHERE MATCH(subject) AGAINST('$subject')
Viết rời ra cho các bạn dễ nhìn cấu trúc thôi, chứ chả có gì đặc biệt cả. giá trị bên trong MATCH() là tên cột chứa nội dung cần tìm, còn giá trị chứa bên trong AGAINST() chính là những gì cần tìm.
Mọi việc lúc sau ta cứ để cho hệ CSDL tự mầng.
Chú ý:Để có thể dùng MATCH, AGAINST, cột nào chứa thông tin cần tìm phải được khai báo chỉ mục FULL TEXT.
Ví dụ bảng topic trên phải được tạo ra như thế này: Mã nguồn[chọn]:
CREATE TABLE IF NOT EXISTS topic (
id_topic int(10) unsigned NOT NULL,
subject tinytext NOT NULL,
PRIMARY KEY (id_topic),
FULLTEXT KEY subject (subject)
)ENGINE=MyISAM DEFAULT
CHARSET=utf8 AUTO_INCREMENT=0";
Sử dụng LIKE
Nhiều bạn có kinh nghiệm sẽ ngay lập tức dừng lại ở bước này vì thực chất chỉ khi LIKE đã không thể dùng được người ta mới dùng tới MATCH, AGAINS.
Nhưng sau đây mình có một thuật giải của vấn đề này dành cho các bạn:
B 1: Xử lý chuỗi nhập vào, cho nó thành chữ thường hết, bỏ mấy cái gì không phải chữ cái ra, tốt nhất là bỏ luôn dấu.
B 2: biến chuỗi đó thành mảng, mọi phần tử của mảng là một từ trong chuỗi.
B 3: Chọn ngẩu nhiên vài trăm dòng có chứa một phần tử (chọn đại hay mặt định là phần tử đầu tiên).
Đây là bước duy nhất có dùng LIKE
Mã nguồn[chọn]:
SELECT * FROM topic WHERE subject LIKE'%array[1]%' B 4: từ vài trăm dòng đã chọn ra, lấy cái tiêu đề (nội dung chứ cần so sánh), xử lý tương tự như chuỗi nhập vào( đừng chuyễn nó thành mảng nhé).
B 5: với các pần tử còn lại của mảng, tìm xem nó có xuất hiện bên trong mấy trăm chuỗi trả lời đả pick ra không(chạy 2 vòng lặp kép), nếu có thì gán một biến mảng kết hợp với key là id của dòng đã pick ra, mỗi lần như thế thì giá trị tăng lên 1
B 6: tuỳ theo muốn trả ra kết lấy ra 3 phần tử của mảng có giá trị cao nhất, thay đổi kháo thành giá trị, giá trị thành khoá, sau đó chạy câu lệnh truy vấn lấy ra thông tin còn lại của topic có Id tương ứng, còn nếu link bài viết dạng index?id=$id thì quá khoẻ.
Với thuật toán trên đây có lẽ vẫn chưa phải là thuật toán tối ưu nhất bởi lẽ nó vẫn chưa xác định được từ khoá cần có, cũng như có thể là rất lâu nếu tìm kiếm các từ trong tất cả các hàng, cũng như khi chọn ngẩu nhiên có thể ta đả bỏ qua các hàng chứa thông tin chính xác hơn.