【问题标题】:MySQL fulltext search over multiple columns: result confusionMySQL全文搜索多列:结果混淆
【发布时间】:2013-07-03 22:45:43
【问题描述】:

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

$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' 时,我没有得到任何结果,但我知道有一位艺术家在 db 中有 2 条记录,artist_full_name = Cardozo, Horacio。

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

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

【问题讨论】:

  • 代替IN BOOLEAN MODE,试试IN NATURAL LANGUAGE MODE
  • IN NATURAL LANGUAGE MODE 是默认模式(即未指定模式时)
  • 搜索时仍然产生 0 个结果。我检查了数据库中的所有字段都是全文但仍然没有。

标签: mysql full-text-search


【解决方案1】:

似乎 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

看起来全文搜索可能只搜索它遇到的第一个全文索引但这只是我扣除from this experience的东西,请不要把它当作授予。

底线是您应该拆分搜索,以便每个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...

如果您在auction 上有两个不同的索引,在user 上有一个不同的索引,这说明了可能的查询。您需要根据您的实际结构调整它(如果您需要更多指导,请发布表格说明)。

请注意,这仅适用于 InnoDB 表。有趣的是,MyISAM 表 do not seem to show the same limitation.


更新:原来这是a bug in the InnoDB engine,已在 5.6.13/5.7.2 中修复。上面的示例现在正确地失败,并出现“找不到与列列表匹配的 FULLTEXT 索引”。实际上,(f1, f2) 上没有索引,但(f1) 上有一个索引,(f2) 上有另一个索引。 As the changelog advises:

与 MyISAM 不同,InnoDB 不支持在 非索引列,但未强制执行此限制,导致 在返回错误结果的查询中。

值得注意的是,虽然此类查询使用 MyISAM 返回正确的结果集,但它们的运行速度比预期的要慢,如 they silently ignore existing fulltext indexes

【讨论】:

  • 我可以使用 * 来获取该单词之后的任何内容,但是有没有办法获取搜索查询可能从单词中间开始的单词?例如:query=pple 返回结果 'apple'
  • 您可以使用如下搜索条件:... WHERE field LIKE '%pple'% 是通配符)但此类查询不能使用全文索引(也不能使用常规索引)。 "MySQL cannot use an index if the columns do not form a leftmost prefix of the index" (这个语句最初是为了描述多列索引,但对于部分索引来说实际上是一样的想法)。
  • 您在where 子句中使用多个match ... or match ... 部分的建议似乎也阻止了myisam 使用索引。带有union 的独立查询效果更好。例如,select * from rsspodcastitems where match title against ("vegetables") or match subtitle against ("vegetables") --&gt; 16 rows in set (2.46 sec)select * from rsspodcastitems where match title against ("vegetables") union select * from rsspodcastitems where match subtitle against ("vegetables") --&gt; 16 rows in set (0.02 sec)
猜你喜欢
  • 2012-04-20
  • 1970-01-01
  • 2023-01-13
  • 2021-09-10
  • 1970-01-01
  • 2013-03-30
  • 2016-04-30
  • 2014-02-18
  • 1970-01-01
相关资源
最近更新 更多