如何匹配两个数据库表中的相关值?

时间:2015-02-24 20:28:17

标签: mysql regex performance perl

为了简化我的问题,假设我有一张包含大量书籍及其各自内容的表格。另一方面,我有一个关键字表。我想找到匹配的对。请参阅下面简单的Perl脚本,它可以很好地说明问题。

#title => content
%books = (
    "Foodworld" => "Cheesburgers and Hamburgers are the best you can ...",
    "Marvelous Salad" => "Russian dressing is superb when ...",
    "Delicious Steaks" => "Only BBQ RipEye"
);

#id => keyword
%keywords = (
    "1234" => "Cheeseburgers",
    "2345" => "dressing",
    "9789" => "Hamburgers"
);

while ( my ($title,$content) = each %books ) {
  while ( my ($keywordID, $keyword) = each %keywords ) {
    if ( $content =~ /$keyword/ ) {
      print "$title \t $keywordID \n";
    }
  }
}

输出将是:

Marvelous Salad  2345
Foodworld        1234
Foodworld        9789

我的问题是,书籍集合包含约70,000个标题和关键词列表~30,000个单词。两者都在MySQL服务器上的单独表中。有什么建议?你会如何解决这个任务?你能指点一个好方向吗?

2 个答案:

答案 0 :(得分:2)

乍一看,这听起来像是要创建一个与key_words相关的junction table书籍。实际上,您可能想要创建两个联结表 - 一个将标题与key_words相关联,另一个将内容与key_words相关联。

简单的联结表由一对列组成,每列都有“REFERENCES FOREIGN KEY”...一个用于“book”ID,另一个用于“key_word”ID。

您仍然需要执行嵌套循环来创建这些联结密钥引用,并且该表可能很大(key_word和title / contents的每个组合都有一行)。但查询可能会非常快。

通过这些联结表中的任何一个,您都有大约三种类型的简单查询。一个人发现所有包含给定key_word的书籍,另一个找到与给定书籍相关联的所有key_words,最后一个会告诉您是否存在给定的key_word / book组合。

(其他更复杂的查询可以找到交叉点之类的东西,并设置书籍和关键词的差异 - 所有包含“海豚”和“宠物”的书籍。还需要考虑进一步的考虑因素。词干,你可能想用一个库将词汇标准化为词干。)

连接表通常在它们的两列上都有一个复合键(通常没有自己的代理键)。这隐式地创建了一个索引,同时还对该组合强加了UNIQUE约束。 “REFERENCES FOREIGN KEY”子句还确保关联的引用完整性 - 并且暗示您必须在之前创建book / title和key_word条目,您可以创建任何关联。 (进一步删除这些实体将需要删除所有联结条目或在DDL上使用CASCADE选项。)

答案 1 :(得分:0)

从算法上讲,我无法看到任何快捷方式 - 您必须检查每个关键字的每个标题,因此您获得的两个循环是唯一的方法。

我提供的加速过程的方法是,您可以编译正则表达式 - 并且值得做您已经拥有的场景。

Perl通常编译一个静态正则表达式,但如果它包含一个变量,它就不能。但是,您可以使用:

Is there a way to precompile a regex in Perl?

这会改善一些事情。您可能会找到类似的内容:

my $regex = join ( "|", keys %keywords );
$regex = qr/$regex/; 

可能更有效地编制30,000个单词编译RE,而不是单独测试每个。您需要自己测试才能检查。 (Devel::NYTProf可能有帮助)

我还建议 - 它看起来像你的代码的方式,书的完整内容被加载到$content。您希望避免一次使用多个 - 这看起来像你一样。但我建议你需要谨慎从大部分数据库中取出所有书籍 - 一次取一个,然后检查它,假设$content相当大。

我想补充一点 - 这个问题会很好地扩展,因为你没有数据依赖性。您可以在Perl中使用线程或分叉来进行并行化。但要小心,因为DBI不是线程安全的。 (或至少,不一定)