MySQL搜索多个关键字并按最佳匹配顺序排列

时间:2013-06-20 20:21:45

标签: php mysql search

我目前为我的博客设置了一个标签系统。 每个博客都插入博客表中,标签插入到标签表中。 标记表有一列blog_id,用于将每个标记链接到博客项目。

所以让我们说:

Blog table:
id - name 
20 - a nice blog post about product x

Tag table:
id - blog_id - tag
12 - 20 - nice
13 - 20 - product x

我有一个搜索功能,可以根据搜索字符串搜索标签,并且工作正常。

但我想扩展查询以搜索多个标签,并按最佳匹配排序。搜索多个标签不会有问题,因为我可以爆炸搜索字符串并循环遍历它,但是通过最佳匹配排序是我无法弄清楚的。

所以,假设我有3篇博文,每篇都有以下标签:
1.阳光,入耳式,耳机,评论
2.梨,耳罩,耳机,评论
3.梨,入耳式,耳机,评论

用户搜索“梨入耳式耳机”,我希望结果的顺序为:
3.(因为3个标签匹配)
1.(因为2个标签匹配)
2.(因为1个标签匹配)

这是查询的样子:

SELECT `b`.* 
FROM (`blog` b) 
WHERE (
    b.name LIKE '%pear in-ear earphones%' 
    OR 
    b.id IN ( 
        SELECT bt.blog_id 
        FROM blog_tags bt 
        WHERE bt.tag LIKE '%pear in-ear earphones%' 
        AND bt.blog_id = b.id 
        ) 
    ) 
ORDER BY `b`.`date` desc


谁能救我?
我看过“全文搜索”,但这不是一个选项,因为我的表是InnoDB
提前谢谢!

2 个答案:

答案 0 :(得分:3)

我个人喜欢使用Solr进行文字匹配。您可以创建这些复杂的公式,这些公式将使名称中的匹配比标记中的匹配更高,反之亦然。它也匹配复数。因此,如果我搜索butterflies,它会找到butterfly匹配。

这是另一个可以帮助您按频率订购博客标签的查询。此查询将获取标签中至少有一个匹配项的所有博客项目。它将按匹配的标签数量排序

SELECT *
FROM blog b
JOIN (
    SELECT blog_id, COUNT(*) as matches 
    FROM tags 
    WHERE tag in ('pear', 'in-ear', 'earphones') 
    GROUP BY blog_id
) t
ON t.blog_id = b.blog_id
ORDER BY matches desc

您可以添加特定字符串的匹配数,如下所示:

SELECT *,
    t.matches + 
    COALESCE((LENGTH(b.`title`)-LENGTH(REPLACE(b.`title`,'pear','')))/LENGTH('pear'),0) + 
    COALESCE((LENGTH(b.`title`)-LENGTH(REPLACE(b.`title`,'in-ear','')))/LENGTH('in-ear'),0) + 
    COALESCE((LENGTH(b.`title`)-LENGTH(REPLACE(b.`title`,'earphones','')))/LENGTH('earphones'),0) AS total_matches,
FROM blog b
LEFT JOIN (
    SELECT blog_id, COUNT(*) as matches 
    FROM tags 
    WHERE tag in ('pear', 'in-ear', 'earphones') 
    GROUP BY blog_id
) t
ON t.blog_id = b.blog_id
ORDER BY total_matches desc
ORDER BY 

只是注意这个查询可能会很慢,所有这些匹配和事情。我仍然建议使用像Solr

这样的索引软件

答案 1 :(得分:2)

以下查询按匹配数计算与特定列表和订单匹配的标记数:

select b.*
from blog b join
     blog_tags bt
     on b.id = bt.blog_id
where bt.tag in ('pear', 'in-ear', 'earphones')
group by blog_id
order by COUNT(*) desc;

请注意,在原始查询中使用like不正确。所有标签都不包含字符串'pear in-ear earphones'

相关问题