没有繁重的数据库怎么做模糊字符串搜索?

时间:2009-05-07 13:11:31

标签: python database full-text-search fuzzy-search

我有目录号到产品名的映射:

35  cozy comforter
35  warm blanket
67  pillow

需要搜索能够找到拼写错误的混合名称,例如“warm cmfrter”

我们使用edit-distance(difflib)编写代码,但它可能无法扩展到18000个名称。

我实现了与Lucene类似的东西,但是PyLucene只包装了Java,这会使部署复杂化到最终用户。

SQLite通常没有编译的全文或评分。

Xapian bindings就像C ++一样,有一些学习曲线。

Whoosh尚未有详细记录,但包括可滥用的拼写检查程序。

还有什么?

6 个答案:

答案 0 :(得分:4)

显然,快速进行模糊比较的唯一方法是减少它们;)

不是编写另一个n-gram搜索或改进Whoosh中的那个,我们现在保留一个单词索引,检索所有与查询共有至少一个(正确拼写)单词的条目,并使用difflib对这些单词进行排名。在这种情况下运作良好。

答案 1 :(得分:2)

Nucular 有全文搜索,但它不支持拼写错误的匹配 盒子外面。您可以尝试为每个条目添加其他字段 哪个索引 SOUNDEX翻译术语,然后使用soundex翻译进行搜索 用户输入。我真的不知道这有多好用......

看一下advas http://advas.sourceforge.net/news.php,它有一个很好的演示,比较各种类似soundex的方法:

advas/examples Aaron$ python phonetic_algorithms.py 
                    soundex       metaphone           nyiis      caverphone 
====================================================================================================
 schmidt :             S253           sxmtt          sssnad      SKMT111111
  schmid :             S253            sxmt          sssnad      SKMT111111
 schmitt :             S253            sxmt         sssnatt      SKMT111111
   smith :             S530            sm0h           snatt      SMT1111111
  smythe :             S530           smy0h           snatt      SMT1111111
 schmied :             S253            sxmt         sssnaad      SKMT111111
   mayer :             M600             myr           naaar      MA11111111
   meier :             M600              mr           naaar      MA11111111
....

我不知道他们中的任何一个是否适合你的未命名语言......

答案 2 :(得分:2)

SOUNDEX实施会产生太多误报。只有26,000(最多)可能的SOUNDEX代码。

虽然Metaphone算法是为英文姓氏设计的,但它对拼写错误非常有效;我在分支定位器中使用过一次它非常成功。

添加带有Metaphone翻译的字段,如果找不到完全匹配,则匹配该字段。你仍会得到误报,但与其他算法相比更少。

答案 3 :(得分:1)

计算两个字符串之间的编辑距离的常用方法是一种相当昂贵的算法(如果我没记错的话,它的时间复杂度是二次的)。也许如果您使用不同的字符串相似性度量标准,那么您的问题就会消失。

我最喜欢的模糊字符串匹配方法之一是trigrams matching。使用此方法比较两个字符串具有线性时间复杂度,这比上述编辑距离要好得多。您可以在Github上找到我的Python实现。完全有一个PostgreSQL contrib module。使它适应SQLite3应该不会太困难。

答案 4 :(得分:1)

Sybase SQL Anywhere有一个免费的网络版/开发人员版,附带全文索引/搜索和FUZZY运算符(以及一些实现约束)。

引用文档:

Specifying 'FUZZY "500 main street"' is equivalent to 
'500 OR mai OR ain OR str OR tre OR ree OR eet'. 

另一种方法是在全文搜索中使用评分。

答案 5 :(得分:1)

sqlite3支持python回调函数。 Matthew Barnett的正则表达式(http://code.google.com/p/mrab-regex-hg/)现在支持近似匹配。

所以,就像这样:

try:
    import regex
except ImportError:
    sys.stderr.write("Can't import mrab-regex; see http://pypi.python.org/pypi/regex\n")
    sys.exit(1)

def _sqlite3_regex(expr, item):
    return (not (not regex.search(expr, item)))

def main():
    ...
    database = sqlite3.connect(dbfile)
    database.create_function("regexp", 2, _sqlite3_regex)
    pattern = '(?:%s){e<=%d}' % (queriedname, distance)
    print [x for x in database.cursor().execute(
         "SELECT * FROM products WHERE (productname regexp '%s')" % pattern)]