为了简化我的问题,假设我有一张包含大量书籍及其各自内容的表格。另一方面,我有一个关键字表。我想找到匹配的对。请参阅下面简单的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服务器上的单独表中。有什么建议?你会如何解决这个任务?你能指点一个好方向吗?
答案 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不是线程安全的。 (或至少,不一定)