寻找更快的方式来执行字符串搜索

时间:2011-04-13 07:36:47

标签: java perl optimization search

我必须认识到大量的URL(几百万行)属于特定类别。我有另一个列表,其中包含子字符串,如果URL中存在属于该类别。比如,A类。

要检查的子字符串列表包含大约10k个这样的子字符串。我所做的只是在子字符串文件中一行一行地查找匹配项,如果发现该URL属于A类,我在测试中发现这相当耗时。

我不是计算机科学专业的学生,​​因此对优化算法知之甚少。但有没有办法让这更快?只是简单的想法。编程语言不是一个大问题,但Java或Perl会更受欢迎。

要匹配的子字符串列表不会有太大变化。但是我会收到不同的URL列表,所以每次我都要运行它。瓶颈似乎是URL,因为它们可以变得很长。

9 个答案:

答案 0 :(得分:8)

是的,我在java中为你提出的问题实现了Aho-Corasick algorithm算法,并且在幼稚实现(你正在做的事情)上显示出大约x180的持续改进。 有几种在线实现,但我会调整它们以获得更好的性能。 请注意,解决方案的复杂性受到单词长度(在您的情况下为URL)的限制,而不是子字符串的数量。此外,它只需要平均一次通过匹配。

P.S - 我们曾经在求职面试中向人们提出这个问题,因此有很多方法可以解决这个问题。我提供的那个是我们在生产代码中使用的那个(现在)胜过所有其他解决方案。

编辑:之前写错了算法名,修复了......

答案 1 :(得分:4)

Perl非常擅长在正则表达式中优化备用字符串的长列表(最多可达到某个整体编译的正则表达式长度,它会恢复到效率较低的机制)。 您应该能够构建一个正则表达式来匹配某个类别,如:

$catAre = join( '|', map quotemeta, @catAstrings );
$catAre = qr/$catAre/;

答案 2 :(得分:3)

当然可以采用不同的方法来优化这一点。关于你的背景,我会给你一个简单的草图。假设子字符串列表不会经常变化。

  1. 从所有子字符串生成一个巨大的正则表达式。
  2. 编译正则表达式,请参阅。例如,Java中的类Pattern。将引用存储到已编译的正则表达式。
  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。)