2013-07-03 29 views
7

Tôi có một truy vấn tìm kiếm thực hiện tìm kiếm toàn văn bản trên DB.Tìm kiếm toàn văn MySQL trên nhiều cột: sự nhầm lẫn kết quả

$sql = "SELECT 
* 
FROM 
`tbl_auction_listing` AS `al` 
JOIN 
`tbl_user` AS `u` ON `al`.`user_id` = `u`.`user_id` 
LEFT JOIN 
`tbl_gallery_details` AS `gd` ON `al`.`user_id` = `gd`.`user_id` 
LEFT JOIN 
`tbl_self_represented_details` AS `sr` ON `u`.`user_id` = `sr`.`user_id` 
WHERE 
`al`.`status` = '" . ACTIVE . "' 
AND 
`al`.`start_date` < NOW() 
AND 
`al`.`end_date` > NOW() 
AND 
MATCH(`al`.`listing_title`, 
`al`.`description`, 
`al`.`provenance`, 
`al`.`title`, 
`al`.`artist_full_name`, 
`al`.`artist_first_name`, 
`al`.`artist_last_name`, 
`sr`.`artist_name`, 
`gd`.`gallery_name`, 
`u`.`username`) AGAINST('$search_query' IN BOOLEAN MODE)"; 

Khi tôi tìm kiếm cho 'Cardozo, Horacio' hoặc 'Cardozo' hoặc 'Horacio' Tôi không nhận được kết quả tuy nhiên tôi biết có một nghệ sĩ với 2 bản ghi trong db với artist_full_name = Cardozo, Horacio.

Nếu tôi xóa tất cả các trường MATCH và chỉ có al. artist_full_name Tôi nhận được 2 kết quả. Nếu tôi thêm vào al. description Tôi nhận được 1 kết quả vì 'Horacio Cardozo' tồn tại trong phần mô tả.

Có cách nào để tìm kiếm trả về tất cả hồ sơ nếu có bất kỳ điều kiện nào (bất kỳ từ truy vấn tìm kiếm nào) được đáp ứng trong bất kỳ trường MATCH nào không? Tôi đã cố gắng loại bỏ IN BOOLEAN MODE nhưng đã tạo ra kết quả tương tự.

+0

Thay vì 'IN BOOLEAN MODE', hãy thử' IN NATURAL LANGUAGE MODE' –

+0

'IN NATURAL LANGUAGE MODE' là chế độ mặc định (nghĩa là khi không có chế độ nào được chỉ định) – RandomSeed

+0

Vẫn tạo ra 0 kết quả khi tìm kiếm.Tôi đã kiểm tra rằng tất cả các trường trong DB là toàn văn nhưng vẫn không có gì. – puks1978

Trả lời

15

Dường như các bảng InnoDB không cho phép tìm kiếm trên một số chỉ mục toàn văn trong cùng điều kiện MATCH().

Ở đây các trường của bạn không thuộc cùng một bảng, do đó chúng được bao phủ bởi các chỉ mục khác nhau. Chú ý hạn chế cũng áp dụng nếu bạn đã có một bảng như thế này:

CREATE TABLE t (
    f1 VARCHAR(20), 
    f2 VARCHAR(20), 
    FULLTEXT(f1), FULLTEXT(f2) 
) ENGINE=InnoDB; 

SELECT * FROM t 
WHERE MATCH(f1, f2) AGAINST ('something in f2'); -- likely to return no row 

trông giống như một tìm kiếm toàn văn chỉ có thể tìm kiếm trên các chỉ số toàn văn đầu tiên nó gặp nhưng đây chỉ là một cái gì đó tôi trích from this experience, xin vui lòng không chấp nhận điều này.

Các bottomline là bạn nên chia tìm kiếm của bạn để sử dụng một chỉ mục toàn văn duy nhất cho mỗi MATCH() khoản:

SELECT * FROM auction, user, gallery, ... 
WHERE 
    MATCH(auction.field1, auction.field2) AGAINST ('search query' IN BOOLEAN MODE) OR 
    MATCH(auction.field3) AGAINST ('search query' IN BOOLEAN MODE) OR 
    MATCH(user.field1, user.field2, user.field3) AGAINST... 

Đây là một minh hoạ của một truy vấn có thể nếu bạn có hai chỉ số riêng biệt trên auction và một một trên user. Bạn cần phải thích ứng với cấu trúc thực tế của bạn (vui lòng đăng mô tả bảng của bạn nếu bạn cần thêm hướng dẫn).

Lưu ý rằng điều này chỉ áp dụng cho các bảng InnoDB. Điều thú vị là các bảng MyISAM do not seem to show the same limitation.


Cập nhật: nó chỉ ra đây là a bug in the InnoDB engine, cố định trong 5.6.13/5.7.2. Ví dụ trên bây giờ thất bại đúng với "Không thể tìm thấy chỉ mục FULLTEXT khớp với danh sách cột". Thật vậy, không có chỉ mục trên (f1, f2), nhưng một trên (f1) và một số khác trên (f2). As the changelog advises:

Không giống như MyISAM, InnoDB không hỗ trợ tìm kiếm toàn văn boolean trên cột nonindexed, nhưng hạn chế này đã không được thực thi, kết quả trong các truy vấn trả lại kết quả không chính xác.

Đáng chú ý là mặc dù các truy vấn như vậy trả lại kết quả chính xác được đặt với MyISAM, chúng chạy chậm hơn một kết quả có thể mong đợi, là they silently ignore existing fulltext indexes.

+0

Tôi có thể sử dụng * để nhận bất kỳ thứ gì sau từ đó nhưng có cách nào để nhận các từ mà truy vấn tìm kiếm có thể bắt đầu ở giữa từ không? Ví dụ: truy vấn = pple trả về kết quả 'táo' – puks1978

+0

Bạn có thể sử dụng điều kiện tìm kiếm như: '... WHERE trường LIKE '% pple'' ('% 'là ký tự đại diện) nhưng truy vấn đó không thể sử dụng chỉ mục toàn văn (cũng không phải chỉ mục thông thường). "[MySQL không thể sử dụng chỉ mục nếu các cột không tạo thành tiền tố tận cùng bên trái của chỉ mục] (http://dev.mysql.com/doc/refman/5.6/en/mysql-indexes.html)" (câu lệnh này là ban đầu có ý định mô tả các chỉ mục đa cột, nhưng nó thực sự là ý tưởng tương tự cho một chỉ mục từng phần). – RandomSeed

+0

Đề xuất của bạn để sử dụng nhiều phần 'kết hợp ... hoặc kết hợp ...' trong mệnh đề 'where' dường như ngăn không cho myisam sử dụng chỉ mục. Các truy vấn độc lập với 'union' hoạt động tốt hơn. E, g, 'select * từ rsspodcastitems trong đó trùng khớp với tiêu đề (" rau ") hoặc khớp với phụ đề (" rau ") -> 16 hàng trong bộ (2,46 giây)' trong khi 'chọn * từ rsspodcastitems trong đó tiêu đề trùng khớp với ("rau") union select * from rsspodcastitems nơi phụ đề trùng khớp với ("rau") -> 16 hàng trong tập hợp (0,02 giây) '. – Jules

Các vấn đề liên quan