8

我有一个搜索查询,它在数据库上执行全文搜索。

$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)";

当我搜索“Cardozo,Horacio”或“cardozo”或“horacio”时,我没有得到任何结果,但是我知道数据库中有一个艺术家有 2 条记录,艺术家_full_name = Cardozo,Horacio。

如果我删除所有 MATCH 字段并且只有al. artist_full_name我得到 2 个结果。如果我添加al. description我得到 1 个结果,因为描述中存在“Horacio Cardozo”。

如果在任何 MATCH 字段中满足任何条件(任何搜索查询词),是否有办法让搜索返回所有记录?我尝试删除 IN BOOLEAN MODE 但产生了相同的结果。

4

1 回答 1

24

似乎 InnoDB 表不允许在相同MATCH()条件下搜索多个全文索引。

在这里,您的字段并不都属于同一个表,因此它们被不同的索引覆盖。请注意,如果您有这样的表,则同样的限制适用:

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

看起来全文搜索可能只搜索它遇到的第一个全文索引,但这只是我从这个经验中推断出来的,请不要认为这是理所当然的。

底线是您应该拆分搜索,以便每个MATCH()子句使用一个全文索引:

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

如果您有两个不同的索引 onauction和一个 on ,这说明了可能的查询user。您需要使其适应您的实际结构(如果您需要更多指导,请发布表格的描述)。

请注意,这仅适用于 InnoDB 表。有趣的是,MyISAM 表似乎没有表现出同样的限制


更新:原来这是InnoDB 引擎中的一个错误,已在 5.6.13/5.7.2 中修复。上面的示例现在正确地失败,并出现“找不到与列列表匹配的 FULLTEXT 索引”。确实,没有索引 on (f1, f2),而是一个 on(f1)一个 on (f2)正如变更日志所建议的那样

与 MyISAM 不同,InnoDB 不支持对非索引列进行布尔全文搜索,但没有强制执行此限制,导致查询返回不正确的结果。

值得注意的是,虽然此类查询使用 MyISAM 返回正确的结果集,但它们的运行速度比预期的要慢,因为它们会默默地忽略现有的全文索引

于 2013-07-04T00:01:09.170 回答