我必须搜索一个25 GB的维基百科语料库以获得一个单词。我用grep但需要很多时间。是否有一个高效,简单的表示,可以快速搜索。另外,我想找到完全匹配。
谢谢。
答案 0 :(得分:3)
您可能希望对从字到列的位置(字节码偏移)的映射做索引。单词列表将按字母顺序排序。然后,您可以在这个大的单词列表中找到某些字母开头的二级索引。
Lazy hash | Word index | Corpus
aaa starts at X | aaa | lorem ipsum dolor
aab starts at Y | ... | sit amet .....
aac ... | and 486, 549, 684, ... | ...
... ... | |
zzz ... | |
这是我所在部门的自然语言教授倡导的方式(我们在算法课程中将此练习作为实验室)。
答案 1 :(得分:3)
您是否尝试过使用索引引擎...说,Lucene和Nutch一起使用? Lucene是索引引擎。 Nutch是网络爬虫。结合力量!
我忘了提及...... CouchDB(http://couchdb.apache.org/)
答案 2 :(得分:2)
我使用Boyer-Moore算法及其simplified version取得了成功。网络上有各种语言的实现。
答案 3 :(得分:0)
@aloobe的答案是使用将单词映射到位置的索引文件。我只想阐述一下,虽然我认为OP正在寻找的答案可能只是Boyer-Moore。
索引文件看起来像这样(简化为使用人类可读的2位数字):
53 17 89 03
77 79 29 39
88 01 05 15
...
上面的每个条目都是您认为足够重要的单词或字母的字节偏移量。在实践中,你不会使用字母索引,因为你的索引文件比你的语料库大!
诀窍是,如果你要用位置替换那些位置的单词,你的索引文件将是按字母顺序排序的语料库版本:
and and are as
ate bad bat bay
bear best bin binge
这使您可以通过索引文件对语料库执行Binary Search。如果您正在搜索上面的“最佳”一词,您将获取索引文件中的中间条目,79。然后您将转到语料库中的位置/字节79并查看其中的单词。它是bad
。我们按字母顺序best > bad
知道,因此位置必须位于索引文件的后半部分。
所以我们抓住79(第6)和第15(第12)之间的中间索引,在我的例子中是01。然后我们查看语料库中的位置/字节88(第9个)以查找bear
。 best > bear
所以我们再试一次 - 中间索引现在是01(第10)或05(第11),取决于你如何回合。但显然我们会在1或2次搜索中找到best
。如果我们有12个单词就像这个例子,在最坏的情况下最多需要4次搜索。对于 25GB文件,其平均字长为5个字母和空格,即大约40亿字。但是,在最坏的情况下,您只会搜索~32次。那时,你的程序的更多时间花在旋转磁盘和缓冲输入上,而不是实际搜索!
此方法也适用于重复的单词。如果要查找单词the
的所有位置,则可以在the
上进行二进制搜索,直到找到索引为止。然后,您将重复从索引文件中的位置减去1,每次使用该值查看语料库。如果该位置的字词仍为the
,请继续。当您最终停止时,索引文件中的最早索引将映射到the
。
创建索引文件是唯一棘手的部分。您需要浏览语料库中的每个单词,构建单词及其索引的数据结构。在此过程中,跳过过于常见或短而无法列出的单词,如“a”,“I”,“the”,“and”,“is”等。完成后,您可以采用该数据结构并将其转换为索引文件。对于25GB的文件,您的索引必须是>不幸的是,32位,因此使用long
(在Java中)或long long
(在C中)来保存它。没有理由它对你来说是人类可读的,所以把索引写成64位值,而不是字符串。
我建议的结构是self-balancing binary search tree。每个节点都是一个字符串值(单词)和索引。但是,树仅根据字符串比较节点。如果你这样做,那么按顺序遍历(左,节点,右)将准确地给你索引文件。
希望这有帮助!我多年前开发手机词典时使用的一个例子是Jim Breen's EDICT。由于EUC编码和日文字符可能很难拿起,但目的是相同的。