我必须认识到大量的URL(几百万行)属于特定类别。我有另一个列表,其中包含子字符串,如果URL中存在属于该类别。比如,A类。
要检查的子字符串列表包含大约10k个这样的子字符串。我所做的只是在子字符串文件中一行一行地查找匹配项,如果发现该URL属于A类,我在测试中发现这相当耗时。
我不是计算机科学专业的学生,因此对优化算法知之甚少。但有没有办法让这更快?只是简单的想法。编程语言不是一个大问题,但Java或Perl会更受欢迎。
要匹配的子字符串列表不会有太大变化。但是我会收到不同的URL列表,所以每次我都要运行它。瓶颈似乎是URL,因为它们可以变得很长。
答案 0 :(得分:8)
是的,我在java中为你提出的问题实现了Aho-Corasick algorithm算法,并且在幼稚实现(你正在做的事情)上显示出大约x180的持续改进。 有几种在线实现,但我会调整它们以获得更好的性能。 请注意,解决方案的复杂性受到单词长度(在您的情况下为URL)的限制,而不是子字符串的数量。此外,它只需要平均一次通过匹配。
P.S - 我们曾经在求职面试中向人们提出这个问题,因此有很多方法可以解决这个问题。我提供的那个是我们在生产代码中使用的那个(现在)胜过所有其他解决方案。编辑:之前写错了算法名,修复了......
答案 1 :(得分:4)
Perl非常擅长在正则表达式中优化备用字符串的长列表(最多可达到某个整体编译的正则表达式长度,它会恢复到效率较低的机制)。 您应该能够构建一个正则表达式来匹配某个类别,如:
$catAre = join( '|', map quotemeta, @catAstrings );
$catAre = qr/$catAre/;
答案 2 :(得分:3)
当然可以采用不同的方法来优化这一点。关于你的背景,我会给你一个简单的草图。假设子字符串列表不会经常变化。
答案 3 :(得分:2)
我建议使用古老的Grep而不是使用编程语言来执行此任务。它使用快速Boyer-Moore string searching algorithm,这应该足以容纳几百万行。
答案 4 :(得分:2)
我之前在Perl中做过这样的事情,将~13k关键字列表与来自Twitter的传入数据流进行比较,找出所有与这些关键字匹配的推文(以及每个匹配的关键字)。粗略地说,代码如下:
use Regexp::Assemble;
my $ra = Regexp::Assemble->new;
$ra->add(@keywords);
my $regex = $ra->re;
for my $tweet (@tweets) {
my @matches = $tweet =~ /$regex/g;
# do whatever with @matches...
}
请注意,这使用Regexp::Assemble来构建正则表达式,这不是核心Perl发行版的一部分,因此如果您想要修改此代码,则需要从CPAN安装。
如果您使用的是perl 5.10或更高版本,那么还有“智能匹配”运算符(~~
)可以执行类似操作而无需任何其他模块。
答案 5 :(得分:1)
您可以将子字符串压缩为共享相同前缀的类。这应该会大大减少时间。
如果您通过每次迭代将字符串移动1来查找匹配项,则可以使用更好的算法(与正则表达式一样)来提高速度。
答案 6 :(得分:1)
对于实现常见字符串搜索算法的Java库,请参阅https://stackoverflow.com/questions/5564610/fast-alernative-for-stringindexofstring-str的答案。结合并行化,您应该能够相当快地解析数百万个URL。这很容易做到;你应该尝试一下,看看时间是否可以接受,然后再进一步研究优化。
答案 7 :(得分:1)
我首先把它写成评论,但后来我意识到,我认为它更适合作为答案
您可以使用一些信息检索系统(如Java中的Apache Lucene)并使用它将URL索引为文档。
然后,在索引之后 - 您可以迭代查询,并搜索每个查询,结果将是匹配的URL。
的优点:强>
*搜索不需要针对每个查询迭代所有URl。
*如果您以后需要子串/查询的交集或联合 - 库会为您提供此功能
的 CONS:强>
*索引需要一段时间......
*您可能需要在RAM /磁盘上为索引留出一些额外空间。
我认为这是一种值得探索的方法,也许在索引时消耗的时间值得搜索。
答案 8 :(得分:0)
我目前正在研究这个问题。我得出了这个结论:
Aho-corasick在制作树时会消耗更多内存。如果没有内存问题而不是它的优点。 但是看看HAT Trie一次。它是hash和trie(tree)的组合。它将在某个级别创建一个树,其余的字符将形成一个哈希值,应该在哈希表中标记。
抱歉更多技术语言。但是,如果您从URL列表中搜索特定的URL,我认为HAT特里是更好的选择。 (我已经形成了一个HAT trie,它将消耗12MB用于存储6个URL。)