什么是获得相关项目的最佳SQL查询?

时间:2009-06-27 16:01:54

标签: sql linq sql-server-2005 tsql

我有一个小网站,我希望在标签的基础上获得相关视频...什么可能是最好的MS SQL 2005查询,以获得基于标签的相关视频。如果你能给出很棒的LINQ查询。

这是数据库架构:

CREATE TABLE Videos
    (VideoID bigint not null , 
    Title varchar(100) NULL, 
    Tags varchar(MAX) NULL, 
    isActive bit NULL  )

INSERT INTO Videos VALUES ( 1,'Beyonce Shakira - Beautiful Liar','shakira, beyonce, music, video',1)
INSERT INTO Videos VALUES ( 2,'Beyonce Ego Remix','beyonce, music, video',1)
INSERT INTO Videos VALUES ( 3,'Beyonce Ego','beyonce, music, video',1)

在观看ID为1的视频时,我想要的是它应该根据标签显示相关视频,大多数匹配的术语应该排在最前面。

先谢谢

4 个答案:

答案 0 :(得分:6)

您显示的模式,使用填充到Tags字符串中的每个视频的所有标记进行非规范化,都是为您的目的设计的 - 在TSQL中没有合理的方法来计算这种格式的两个字符串之间有意义的“共性”,因此没有合理的方法来检查哪些项目具有相对较高的共性,因此可能被视为“相关”。如果模式是不可触及的,那么你必须为此目的实现一个用户定义的函数(用C#或其他.NET语言),即使这样你也会或多或少地扫描整个表,因为没有合理的方法在这样的基础上索引。

如果您可以重新设计架构(还有两个表:一个用于存放标签,另一个用于表示标签和视频之间的多对多关系),可能会有更好的前景;在这种情况下,大概有多少(数量级)视频的预期,总体上有多少(同上)不同的标签,以及视频预期会有多少标签,这可能会让设计和有效方式得以实现追求你的目的。

编辑:根据评论,显然可以重新设计架构,但仍然没有给出关于我问的数字的指示,因此适当的指数和c将仍然是一个完全神秘的东西。无论如何,假设模式是这样的(每个表可以根据需要包含其他列,只需将它们添加到查询中;并且VARCHAR长度也无关紧要):

CREATE TABLE Videos (VideoID INT PRIMARY KEY,
                     VideoTitle VARCHAR(80));

CREATE TABLE Tags (TagID INT PRIMARY KEY,
                   TagText VARCHAR(20));

CREATE TABLE VideosTags (VideoID FOREIGN KEY REFERENCES Videos,
                         TagID FOREIGN KEY REFERENCES Tags,
                         PRIMARY KEY (VideoId, TagId));

即。只是经典的“多多关系”教科书的例子。

现在给出视频的标题,比如@MyTitle,可以很容易地查询与其最“相关”的5个视频的标题,例如:

WITH MyTags(TagId) AS
(
  SELECT VT1.TagID
  FROM Videos V1
  JOIN VideosTags VT1 ON (V1.VideoID=VT1.VideoID)
  WHERE V1.VideoTitle=@MyTitle
)
SELECT TOP(5) V2.VideoTitle, COUNT(*) AS CommonTags
FROM Videos V2
JOIN VideosTags VT2 ON (V2.VideoID=VT2.VideoID)
JOIN MyTags ON (VT2.TagId=MyTags.TagId)
GROUP BY V2.VideoId
ORDER BY CommonTags DESC;

答案 1 :(得分:0)

您最好分割模式,以便标签位于单独的表中,然后使用中间表链接到视频,这可能是...

select v.*
from Video v
  inner join VideoTag vt 
    inner join Tag t on vt.TagID = t.TagID
  on v.VideoID = vt.VideoID 
where t.Description = @tagText

修改后的架构看起来像

视频

VideoID
Title
Description

标签

TagID
Description

VideoTag

VideoID
TagID

或者,您可以尝试使用更简单的查询,例如

select VideoID, Title, Description
from Video
where Tags like '%' + @tag + '%'

但这会匹配包含其他标签的标签(例如'art'和'martial art'),这就是为什么我认为将模式拆分为更好的解决方案。

答案 2 :(得分:0)

如果您使用的是代码,那么您只需要WHERE tag = 'thistag'条件(如果同一个表中有一个代码),或者WHERE tag in (SELECT tag FROM tags_table WHERE video_id = this_video_id)如果您将代码标准化为你的视频表,虽然任何一个解决方案可能会返回很多视频,所以你必须以某种方式修剪它。

这就是它变得有趣(而且很难)的地方;您不仅需要为每个视频存储一组标记,还需要为每个标记到视频关系存储一个关联分数。这会变得混乱和主观。

另一方面,如果你真的想要“最匹配的术语”(请在你的编辑中提到),我真正认为你需要的是数据挖掘查询Basket analysis是一种常用于显示“相关项目”的技术,当人们有兴趣查看其他对项目感兴趣的人也感兴趣的内容时。这有点超出SQL查询,但如果你有SQL Server 2005,它是Analysis Services包的一部分。值得一看!

编辑:既然您已发布架构,我强烈建议您将Tags字段规范化为另一个表格。围绕包含多个分隔项的字段进行编码非常困难,并由1st form normalisation解决。

答案 3 :(得分:0)

如果我已正确理解您的问题,因为您有一个视频表格,并且在该表格中有一列“标记”,其中一系列标记用逗号分隔;那么这里是LINQ查询...

dbDataContext db = new dbDataContext();

var movies =
    from v in db.Videos
    where v.Tags.Contains("Thriller")
    select v;

我用VideoId,Name和Tags制作了一个快速表。我添加了一部电影'黑客帝国'并放置标签'惊悚片;动作片;戏剧片' - 该查询找到了黑客唱片。

作为旁注,有一个标签表,然后是一个包含VideoId的表格以及属于它们的标签,这不是更好吗?

只是一个想法。希望有所帮助。