快速的字符串搜索
Fast in string search
我有一个问题,我正在寻找一些指导来解决最有效的方法。我有2亿个字符串的数据,大小从3个字符到70个字符。字符串由字母、数字和一些特殊字符(如:破折号和下划线)组成。我需要能够快速搜索整个字符串或字符串内的任何子字符串(最小子字符串大小为3)。快速在这里定义为小于1秒。
作为我的第一个切口,我做了以下操作:
-
创建了38个索引文件。索引包含所有以特定字母开头的子字符串。前4mb包含100万个哈希桶(哈希链的开始)。索引的其余部分包含来自散列桶的链表链。哈希是均匀分布的。100万个哈希桶保存在RAM中,并镜像到磁盘。
-
当一个字符串被添加到索引时,它被分解成它的不重复的(在它自己内部)3-n个字符的子字符串(当n是字符串的长度-1时)。因此,例如,"苹果"在"A"索引中存储为苹果,苹果,ppl,pp(子字符串也存储在"L"answers"P"索引中)。
搜索/添加服务器作为守护进程运行(在c++中),并且像冠军一样工作。典型的搜索时间小于1/2秒。
问题在流程的前端。我通常一次添加30,000个键。这个过程会持续很长时间。通过基准测试,将时间加载到包含180,000个可变长度键的空索引中大约是3.5小时。
这个方案除了加载时间很长之外是有效的。
在我疯狂优化(或尝试)之前,我想知道是否有更好的方法来解决这个问题。对于这么大的数据集,前后通配符搜索(例如:在DBMS中像'%ppl%'这样的字符串)非常慢(例如在MySQL中以小时为数量级)。因此,DBMS解决方案似乎是不可能的。我不能使用全文搜索,因为我们处理的不是普通的单词,而是可能由也可能不是由真正的单词组成的字符串。
根据您的描述,加载数据需要花费所有时间,因为您正在处理I/O,将膨胀的字符串镜像到硬盘。这肯定会成为瓶颈,主要取决于您向磁盘读取和写入数据的方式。
使用mmap
和一些LRU策略可能会改善执行时间。我很确定复制数据的想法是为了使搜索更快,但是由于您使用的是—看起来是—只有一台机器,因此您的瓶颈将从内存搜索跳到I/O请求。
另一个您可能不感兴趣的解决方案(:——)是将数据拆分到多台机器上。考虑到您构建数据的方式,实现本身可能需要一些时间,但它将非常简单。你会有:
- 每台机器由一组桶负责,使用接近
hash_id(bucket) % num_machines
的东西选择; - 插入在本地执行,从每台机器;
- 搜索可以由一些类型的查询应用程序接口,或者简单地聚集到查询集中——如果应用程序不是交互式的;
- 搜索甚至可能具有分布式接口,考虑到您可能从一个节点发送启动请求,并将请求转发到另一个节点(也是集群请求,以避免过多的I/O开销)。
另一个优点是,正如你所说,数据是均匀分布的——已经o/;这通常是分布式实现中最挑剔的部分之一。此外,这将是高度可伸缩的,因为当数据大小增长时,您可以添加另一台机器。
与其一次解决所有问题,不如38次解决问题。
读取180,000个字符串中的每个字符串。在每个字符串中找到"A",并只将内容写入"A"哈希表。完成后,将"A"哈希表的整个完成结果写到磁盘上。(要有足够的内存将整个"A"哈希表存储在内存中——如果没有,就创建更小的哈希表。也就是说,有38^2个哈希表在字母对上,有1444个不同的表。你甚至可以动态地改变哈希表的键值,根据它们的前缀有多常见,所以它们的大小都是适度的。跟踪这些前缀的长度并不昂贵。)
然后读取180,000个字符串中的每一个,寻找"B"。等。
我的理论是,你的速度比你可以的慢,因为你的大数据表的缓存抖动。
下一件可能有帮助的事情是限制你做哈希的字符串的长度,以缩小你的表的大小。
如果将哈希值的长度限制为10个字符,则只有508个子字符串的长度为3到10,而不是处理长度为70的字符串的所有2278个子字符串的长度为3到70。在长度大于10的弦上可能不会有那么多碰撞。同样,您可以让哈希的长度是动态的——长度X哈希可能有一个标志,表示"如果字符串比X长,请尝试长度X+Y哈希,这太常见了",否则就直接终止哈希。这样可以减少表中的数据量,但在某些情况下会降低查找速度。
- 在对象数组中搜索字符串并返回相应值的函数
- 在 QTextEdit 中搜索字符串
- C++ 中用于搜索字符串模式的正则表达式
- 如何在文件中搜索字符串并打印包含该字符串的行
- 搜索字符串是否至少包含一次从 0 到 9 的所有数字的最有效方法
- 从文件中提取的数据中的C 搜索字符串失败
- 在数组中搜索字符串的所有术
- 在 main 中搜索字符串的结尾时出现分段错误,但不在函数C++中搜索
- 在字符串中搜索字符串序列
- c++搜索字符串列表中的特定字符串
- 从文件中读取一行,并在其中搜索字符串(c++)
- 在向量中搜索C++字符串s中的单词
- 在另一个进程的内存中搜索字符串的每个匹配项
- 当搜索字符串有空格时查找字符串
- 在结构向量中搜索字符串C++
- 搜索字符串中的第一个字符不同于"X"
- 搜索字符串(只查找完全匹配的字符串,不忽略大写或小写字符
- 如何在C++中搜索字符串数组
- 替换特定位置后出现的所有搜索字符串
- 搜索字符串以使用递归查找另一个字符串