标签排列的高效查询生成

时间:2012-03-11 22:23:02

标签: sql performance algorithm

这是我在工作中遇到的问题的简化版本。细节已经改变并且更加通用化,因此我可以更容易地解释它。

假设您有一个博客引擎,可以在创建博客帖子时为其分配标签。所以我可以写一篇标题为“我在意大利度假”的帖子,我决定在其中添加以下标签:has-photosvacationfamily。作为我的博客引擎的一部分,我可以基于标签组创建自定义操作。所以我在写之前就确定任何带有has-photosfamily标签的帖子都会在Facebook上自动共享。当第一次创建该帖子时,我必须自动交叉引用其所有标签以及可以对这些标签的组合执行的所有操作。

当保存“意大利假期”帖子后,我需要查找以下标签组的所有操作:

  • has-photos
  • vacation
  • family
  • has-photos& vacation
  • has-photos& family
  • vacation& family
  • has-photos& vacation& family

生成该查询是微不足道的,我只是从帖子的原始标记集中获得任何长度的所有排列。它是2^N - 1标签组合的可能性。

当你对大型数据集提出这个问题时,我遇到的问题就出现了。我们正在处理的是以下内容:

  • 每天抵达的10,000多个“帖子”
  • 每个“帖子”20+“标签”
  • 当博客帖子到达时已存在1,000个“操作”,其中触发的标记数量不同

当一个帖子到达时有20个标签,这个标签出现了一百多万个排列,我会生成一个查询。即使我的数据库允许我向它发送大的查询字符串(提示:它没有),它仍然需要永远运行。

我有没有想到的聪明的解决方案?就在我看来,我有一种可能性:

操作使用OR而不是AND

我可以改变它,这样当你创建一个预定义的动作时,它所作用的标记是隐式OR,而不是AND。然后,代码组合从2^N - 1降至N。不幸的是,这会严重限制“标记操作”功能的有用性。

编辑:我不一定在SQL中寻找答案。解决这个问题只是一种不同的方法,即使它只是一个高级别的描述。

3 个答案:

答案 0 :(得分:1)

您可以解决此问题:对于您有操作的所有可能匹配(仅在您的示例中为has-photos and family),计算帖子是否与此操作匹配。如果你只有一些只有少量触发器的动作,这将很快。

答案 1 :(得分:1)

这看起来像http://en.wikipedia.org/wiki/Rete_algorithm这样的规则引擎算法。我想这样做的第一步就是在内存中保留1000个动作的列表,并在保存新帖子时比SQL检查更快的内容。

答案 2 :(得分:0)

您可以合并GROUP BYCOUNTHAVING:将每个操作的代码数量存储在操作行中,现在您可以轻松获得匹配的操作&# 39; IDS:

数据库结构:

tag
  id
  name

action
  id
  tag_count
  // = SELECT COUNT(*) FROM action_tag WHERE action_tag.action_id=action.id

action_tag
  action_id
  tag_id

示例行:

tag
id name
1  has-photos
2  vacation
3  family

action
id tag_count
1  1
2  3

action_tag
action_id tag_id
1         3
2         1
2         2
2         3

选择:

SELECT     action.id
FROM       action
INNER JOIN tag         ON tag.name IN (<tag_1>,<tag_2>,....)
INNER JOIN action_tag  ON action_tag.action_id = action.id
                      AND action_tag.tag_id = tag.id
GROUP BY action.id
HAVING COUNT( action_tag ) = action.tag_count