我之前从未尝试过MYSQL,但我需要实现搜索。我有三个表,'articles','articles_tags'和'tags'。
'文章'包含我想要搜索的第一件事,即“标题”字段。
'articles_tags'是一个数据透视表,它将'articles'和'tags'关联在一起。 'articles_tags'有两个字段:'articles_id'和'tag_id'。
'tags'包含我要搜索的第二件事,即'name'字段。
我的问题是,我需要一种方法来搜索“标题”字段,以及与该文章相关的每个标记(“tags.name”),并返回文章的相关性(或按相关性排序)。 / p>
实施此方法的好方法是什么?我很确定只能从一个查询中完成这两个查询,然后将相关性“混合”在一起就可以了。
感谢。
编辑:忘了说,如果我可以为匹配标签提供更多权重而不是匹配标题中的单词,那就太棒了。我并不是真的要求任何人写这个东西,而是给我一些方向。我是PHP和MySQL的新手。
答案 0 :(得分:2)
从@james.c.funk给出的答案开始,但做了一些更改。
SELECT a.id, a.title,
MATCH (a.title) AGAINST (?) AS relevance
FROM articles AS a
LEFT OUTER JOIN (articles_tags AS at
JOIN tags AS t ON (t.id = at.tag_id AND t.name = ?))
ON (a.id = at.article_id)
WHERE MATCH (a.title) AGAINST (? IN BOOLEAN MODE)
ORDER BY IF(t.name IS NOT NULL, 1.0, relevance) DESC;
我假设您希望标记匹配与完整字符串匹配,而不是使用全文搜索。
同样使用一个左外连接而不是两个,因为如果满足articles_tags
的连接,那么肯定会有一个标签。将标记名称比较放在连接条件内而不是WHERE
子句中。
布尔模式使得MATCH()
在匹配时返回1.0,这使得它无用作为相关性的度量。因此,在选择列表中进行额外比较以计算相关性。该值介于0.0和1.0之间。现在,我们可以通过将其标记为1.0的相关性来使标记匹配排序更高。
答案 1 :(得分:2)
此时是否值得,建议您将搜索工作卸载到实际为此目的编写的内容上?
在我们的产品中,我们使用MySQL来存储数据,但使用Lucene索引我们的所有数据(通过Solr - 但这无关紧要)。
值得一看,因为设置相对简单,它非常强大,比试图操纵数据库做你想要的更容易。
对不起,这不是问题的直接答案,我只是觉得这种情况在这种情况下总是值得一提:)
答案 2 :(得分:1)
以下是我过去的做法。它看起来很慢,但我认为你会发现它不是。
我添加了一点复杂性来展示其他可以轻松完成的工作。在此示例中,文章将获得1分的部分标题匹配,2分部分用于部分标记匹配,3分用于精确标记匹配,4分用于精确标题匹配。然后它按照分数添加和排序。
SELECT
a.*,
SUM(
CASE WHEN a.title LIKE '%keyword%' THEN 1 ELSE 0 END
+
CASE WHEN t.name LIKE '%keyword%' THEN 2 ELSE 0 END
+
CASE WHEN t.name = 'keyword' THEN 3 ELSE 0 END
+
CASE WHEN a.title = 'keyword' THEN 4 ELSE END
) AS score
FROM article a, articles_tags at, tags t
WHERE a.id = at.article_id
AND at.tag_id=t.id
AND (a.title LIKE '%keyword%' OR t.name LIKE '%keyword%')
GROUP BY a.id
ORDER BY score;
注意:这不会返回没有标签的文章。我使用简单连接来减少查询中的噪音,并突出显示正在进行评分的内容。要包含没有标签的文章,只需将连接保留为连接。
答案 3 :(得分:0)
答案 4 :(得分:0)
这个快速演示查询远未优化,但应该是一个很好的起点
SELECT * FROM
(SELECT a.id, a.title,
MATCH (a.title) AGAINST ('$s_search_term') AS title_score,
SUM(MATCH (t.name) AGAINST ('$s_search_term')
) AS tag_score
FROM articles AS a
LEFT JOIN articles_tags AS at
ON a.id = at.article_id
LEFT JOIN tags AS t
ON t.id = at.tag_id
WHERE MATCH (a.title) AGAINST ('$s_search_term')
OR MATCH (t.name) AGAINST ('$s_search_term')
GROUP BY a.id) AS table1
ORDER BY 2*tag_score + title_score DESC
您可能希望将tag_score除以COUNT(t.id)来规范化。抱歉,提供查询比解释如何制作更容易。
答案 5 :(得分:0)
您可能需要查看sphinx,http://www.sphinxsearch.com/