MySQL结合FULLTEXT和LIKE后退

时间:2015-06-29 23:43:40

标签: php mysql

我正在构建我的应用,使用单个搜索表搜索所有不同的对象类型,即:帖子,页面,产品等,基于this article.

我的表格布局如下:

CREATE TABLE IF NOT EXISTS myapp_search_index (
  id int(11) unsigned NOT NULL,
  language_id int(11) unsigned NOT NULL,
  `type` varchar(24) COLLATE utf8_unicode_ci NOT NULL,
  object_id int(11) unsigned NOT NULL,
  `text` text COLLATE utf8_unicode_ci NOT NULL
  PRIMARY KEY (id,language_id),
  FULLTEXT KEY `text.fdx` (`text`),
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;

我的搜索查询如下:

$items = $db->escape($query);

$query = $db->query("
    SELECT *, 
    SUM(MATCH(text) AGAINST('+{$items}' IN BOOLEAN MODE)) as score 
    FROM {$db->prefix}search_index 
    WHERE MATCH(text) AGAINST('+{$items}' IN BOOLEAN MODE) 
    GROUP BY language_id, type, object_id 
    ORDER BY score DESC 
    LIMIT " . (int)$start . ", " . (int)$limit . "
");

除非我们遇到诸如停用词和最小字长等全文限制,否则这种方法很有用。

例如,我在About Us页面的表格中有两个条目,一个包含页面标题,另一个包含页面内容。

运行查询about us不会返回任何结果,因为about是一个停用词,us小于最少4个字母。

所以,我的想法是使用传统的LIKE参数创建一个条件回退查询:

if (!$query->num_rows):
    $query = $db->query("
        SELECT * 
        FROM {$db->prefix}search_index 
        WHERE text LIKE '%{$items}%' 
        GROUP BY language_id, type, object_id 
        ORDER BY id DESC 
        LIMIT " . (int)$start . ", " . (int)$limit . "
    ");
endif;

再一次这很好用。我的About Us页现在结果很好。

但我想要的是在一个查询中运行这一切并以某种方式保持得分。

这可能吗?

编辑:

好的,回应迈克尔的回答和评论,我已经改变了我的疑问:

SELECT *, 
SUM(MATCH(text) AGAINST('{$search}' IN BOOLEAN MODE)) as score 
FROM {$db->prefix}test_index 
WHERE (
    MATCH(text) AGAINST('{$search}' IN BOOLEAN MODE) 
    AND text LIKE '%{$search}%') 
OR text LIKE '%{$search}%' 
GROUP BY language_id, type, object_id 
ORDER BY score DESC

我设置了一个包含100K行的测试表,其中50K包含我的lorem ipsum搜索字词。

查询整个表并以0.6379微秒的速度返回结果,但尚未进行任何查询缓存。

有人能告诉我这是否是一个公平的妥协?

2 个答案:

答案 0 :(得分:0)

使用多字词来玩自然语言模式:

SELECT id,prod_name, match( prod_name )
AGAINST ( '+harpoon +article' IN NATURAL LANGUAGE MODE) AS relevance
FROM testproduct 
ORDER BY relevance DESC

我们经常只使用solr集成,在其上投放json csv和文本文件。

答案 1 :(得分:0)

没有办法优雅地将全文搜索与LIKE结合起来以获得更多结果。

这是因为两个谓词必须与OR组合,这反过来意味着需要进行全表扫描(或者如果存在合适的BTREE则进行全索引扫描)以进行测试LIKE表达式。必须评估所有行,这将删除您从全文搜索中获得的任何优化。

在相反的情况下,将MATCHLIKE结合使用AND而不是OR - 在全文匹配返回不够精确匹配的情况下 - 效果很好,因为优化程序使用全文索引查找所有可能匹配的行,然后根据LIKE表达式筛选标识的行。 (当存在其他可能的查询计划时,优化器几乎总是首选全文索引。)不幸的是,这与您需要的相反。