(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.