【问题标题】:Select rows with similar tags (many-to-many relation) from SQL database从 SQL 数据库中选择具有相似标签(多对多关系)的行
【发布时间】:2014-03-18 04:28:52
【问题描述】:

我的实体表和标签通过另一个表绑定到它(多对多关系)。

我选择了一个实体,我的目标是找到一组具有尽可能多相似标签的实体。该集合必须按“相似性”排序——每个实体与所选实体共享的标签数量。如果标签具有相同的 id,则它们是相似的。

我想知道是否有一种优雅而快速的方法可以通过单个查询来做到这一点。

我现在看到的唯一解决方案是在我的应用程序中获取所有标签-实体关系并计算它们的相似性,然后进行另一个数据库查询来选择我计算的内容,但它看起来不太优雅。

数据库结构:

实体 ID ...

标签 ID 名字

entity_tag entity_id tag_id

更新:MySQL 的最终解决方案。

所以我有绘画、标签和绘画标签关系的表格。此查询为先前选择的绘画获取相似的绘画及其“相似性指数”。

SELECT site_painting.*, Count(tr.tag_id) as similarity
From site_painting_tag_relation as tr
Inner Join site_painting_tag_relation as tr2 ON ( tr2.tag_id = tr.tag_id and tr2.painting_id = :id )
Left join site_painting on site_painting.id=tr.painting_id
Where tr.painting_id <> :id
Group By  tr.painting_id
Having Count(*) > 0
Order By  Count(*) DESC, tr.painting_id limit 1

【问题讨论】:

  • 相对于任何 tblEntity 行,每个 tblTAG 行都有一个可计算的相似度,从 100% 到 0%。 Similarity% 可以与 tblMany2Many 和在该 % 上创建的二级索引一起存储。然后让一个循环从 100% 开始沿着 %-s 向下走,到 99% 到 95% 到 90% 到 80%(以某种步进方式),直到它检索到所需数量的行。
  • @donPablo 抱歉,但这不是我想要的;可能是我没有正确描述这个问题。标签本身不需要比较。如果它们具有相同的 ID,则它们被认为是相似的。所以我想选择与我的主记录绑定到相同标签ID的记录。
  • 我认为您需要更多地解释应该以相似度百分比返回什么?因此,如果实体 A 有标签 X 和 Y,而实体 B 有标签 Y 和 Z,你会期望看到 B 从 A 返回,因为它至少有一个匹配的标签?
  • @ChrisMoutray 完全正确。此外,如果我们有带有标签 X 和 Y(也可能还有 Z)的实体 C,则应该以比记录 B 更高的优先级选择它。
  • 好的,所以选择返回所有具有 1 个或多个匹配项的实体,匹配项从高到低排序..

标签: sql database


【解决方案1】:

好的,关于 db 结构的信息很有帮助 --

entity id ...

entity_tag entity_id tag_id

tag id name

让我们看一些示例值--

entity
  id=100
  id=...
  id=199

entity_tag
  100, 3
  100, 5
  101, 1
  102, 7
  ...
  199, 3
  199, 7

tag
  id=1
  id=...
  id=10

因此,如果我们对我们拥有的 entity_tag 进行非规范化

  100   3,5
  101  1
  102       7
  199   3   7

与其他人的相似度指数为 199,范围为 0 到 10

  100   1 in common
  101   0 in common
  102   1 in common
  199 self, no comparison

如果我没记错的话,我们希望显示 100 和 102 是最高的, 努??

这是对 SQL 的一个尝试—— 可能是这样的——

SELECT  TOP 10
FROM
(SELECT
   allET.EID,
   Count(*) as Similarity


 From entity_tag as allET

 Left Join 
      (Select * From  entity_tag  Where EID = myEID ) as myET
 On allET.TID = myET.TID

 Where allET.EID <> myEID

 Group By  allET.EID

 Having Count(*) > 0

 Order By  Count(*) DESC, allET.EID
)

【讨论】:

  • 好的。克里斯,你会写 SQL 吗?
  • 谢谢,它工作正常。嗯,差不多。由于某种原因,它在每条记录上将“相似性”增加 1,因此我的结果包含完全不相关的记录,相似性 = 1。我不太明白它为什么会这样的确切原因,但我通过用内连接替换左连接和子选择来解决它。像这样: >Inner Join entity_tag as allET2 ON ( allET2.tag_id = allET.tag_id AND allET2.entity_id = myEID ) 改变条件 'count(*)>1' 也可以。
  • 我已经用适合 mysql 的最终查询更新了我的问题。
猜你喜欢
  • 1970-01-01
  • 2012-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多