Python中的大规模拼写检查
让我来分享一下我的情况,虽然我没找到其他人在做类似的事情,但肯定有人在做。我现在正在做一个Python项目,需要检查大约16000个单词的拼写。这个单词的数量还会继续增加,真是让人头疼。目前,我是从Mongo数据库中提取单词,然后逐个检查拼写,使用的是pyenchant库。我已经先把所有单词从Mongo中提取出来,这样就不会因为数据库的速度而拖慢我的进度。现在,我大约需要20分钟来处理这16000个单词,显然这个时间太长了。我有几个想法和问题:
显然,我可以利用多线程或者某种并行处理的方法。即使我把这些单词分成4份,假设性能达到最佳,我也大约需要5分钟。
有没有办法知道pyenchant底层使用的是哪个拼写库?Enchant的官网似乎暗示它在拼写检查时会使用所有可用的拼写库和字典。如果是这样的话,那我可能每个单词都要经过三到四个拼写字典的检查。这可能就是我遇到的问题,但我很难证明这一点。即使真是这样,我的选择真的就是卸载其他库吗?这听起来不太好。
所以,有没有什么办法让我在这个过程中提高一点性能?我可以把任务分成并行处理,但我还是希望在这样做之前,能让核心部分的速度快一点。
补充:抱歉,没喝咖啡就发帖了……如果一个单词拼写错误,Enchant会给我生成一个建议列表。看起来我在这个处理过程中花费了大部分时间就是在这里。
3 个回答
也许有个更好的办法就是先压缩文档,因为这样可以去掉重复的单词,实际上你只需要检查这些单词一次。我之所以建议这样做,是因为这可能比自己写一个独特的单词查找工具要快。
压缩后的版本应该在文件中有对独特单词的引用,你可能需要查一下这些引用是怎么结构的。
然后你可以检查所有的独特单词。我希望你不是用单独的SQL查询来检查它们,应该把字典以树的形式加载到内存中,然后用这个字典来检查单词。
完成这些后,只需解压缩一下,嘿,搞定了,所有的单词都检查过了。这应该是个相对快速的解决方案。
或者,如果检查拼写真的像评论里说的那么快,那你可能根本不需要经过整个压缩过程,这说明可能是实现上有问题。
我会使用一种叫做彼得·诺维格风格的拼写检查器。我已经写了一篇完整的文章来介绍这个。
http://blog.mattalcock.com/2012/12/5/python-spell-checker/
这里有一段代码,它会查看要检查的单词可能的修改。
def edits1(word):
s = [(word[:i], word[i:]) for i in range(len(word) + 1)]
deletes = [a + b[1:] for a, b in s if b]
transposes = [a + b[1] + b[0] + b[2:] for a, b in s if len(b)>1]
replaces = [a + c + b[1:] for a, b in s for c in alphabet if b]
inserts = [a + c + b for a, b in s for c in alphabet]
return set(deletes + transposes + replaces + inserts)
你应该用这段代码快速遍历你不断增长的单词数据文件,以进行检查。想了解更多信息,可以查看完整的文章:
我想大家都同意,这里性能瓶颈在于 Enchant;对于这个大小的数据集,检查一个单词是否拼写正确几乎是瞬间完成的。那么,为什么不这样做呢:
在内存中建立一个正确拼写单词的集合,可以使用 Enchant 的字典,或者自己找一些(比如 OpenOffice 的字典)。
可选地,可以把文档中的单词去重,比如放进一个
set
里。这样做可能不会节省太多时间。检查每个单词是否在这个集合里。这一步很快,因为只是查找集合中的内容。(大概是
O(log N)
,其中 N 是单词的数量?假设set
是通过哈希分桶并进行二分查找的……有 Python 大牛可以纠正我。)如果不在集合里,那么再请 Enchant 推荐一个单词。这一步必然会比较慢。
这个方法假设你大部分单词都是拼写正确的;如果不是,你就得想点别的办法了。