【问题标题】:Whats the best SQL Query to get Related Items?获取相关项目的最佳 SQL 查询是什么?
【发布时间】:2009-06-27 16:01:54
【问题描述】:

我有一个小网站,我想根据标签获取相关视频...根据标签获取相关视频的最佳 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 的视频时,它应该根据其标签显示相关视频,并且最匹配的字词应该排在最前面。

提前致谢

【问题讨论】:

  • 您至少可以提供您的架构来提供查询吗?
  • 如果你能给出一个很棒的表结构。
  • 请发布您的表结构的 DDL,以及示例数据的 INSERT 语句。请准确说明您的意思:视频与其他视频相关、标签相同、全部相同、部分相同等?
  • @MarcV:那不是模式。请参阅 stackoverflow.com/questions/1048381/… 以获取良好 SQL 问题的示例。

标签: sql linq sql-server-2005 tsql


【解决方案1】:

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

如果您可以重新设计架构(多使用两张表:一张用于保存标签,一张用于提供标签和视频之间的多对多关系)可能会有更好的前景;在这种情况下,一些关于您预计有多少(数量级)视频、总共有多少(同上)不同标签以及视频预计有多少标签的一些指示可能允许设计和有效的方法追求你的目的。

编辑:每个 cmets,显然可以重新设计架构,尽管仍然没有说明我问的数字,所以适当的索引 &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;

【讨论】:

  • 假设我可以重新设计架构,那么 SQL 查询会是什么?
  • 如果你可以重新设计架构,那么请看我上面的回答。
【解决方案2】:

如果您要基于标签,您只需要一个WHERE tag = 'thistag' 条件(如果同一个表中有一个标签),或者如果您将标签从视频表中规范化,则需要WHERE tag in (SELECT tag FROM tags_table WHERE video_id = this_video_id),尽管这两种解决方案都可能会返回大量视频,因此您必须以某种方式对其进行修剪。

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

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

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

【讨论】:

  • 你的意思是如果我使用这个结构表视频 - VideoID - Title - isActive Tags Table - TagID - Tag VideoTags Table - VideoID - TagID 那么查询会是什么?
【解决方案3】:

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

dbDataContext db = new dbDataContext();

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

我用 VideoId、Name 和 Tags 制作了一个快速表格。我添加了一部电影“The Matrix”并添加了标签“Thriller;Action;Drama”——该查询找到了 The Matrix 记录。

附带说明一下,有一个标签表,然后是一个包含 VideoId 以及哪些标签属于它们的表,不是更好吗?

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

【讨论】:

  • 如何从源视频中读取所有标签并根据所有标签找到所有视频?大多数匹配的字词排在首位。
【解决方案4】:

您最好拆分架构,以便标签位于单独的表中,然后使用中间表链接到视频,例如......

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

视频标签

VideoID
TagID

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

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

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

【讨论】:

  • 如果 VideoTag 表中有一个TagAffinity 列会更好,这样可以更轻松地选择最适合给定查询的视频(假设 OP 仅限于 SQL 语句并且不能使用篮子分析)
  • 其中标签 = @tag 或标签如 '%,' + @tag 或标签如@tag + ',%' 或标签如'%,' + @tag + ',%'跨度>
猜你喜欢
  • 1970-01-01
  • 2012-04-23
  • 1970-01-01
  • 2020-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多