字符串与Python + Sqlite的相似性(Levenshtein距离/编辑距离)

时间:2018-04-11 15:41:25

标签: python sqlite string-comparison similarity

Python + Sqlite中是否有字符串相似性度量,例如sqlite3模块?

用例示例:

import sqlite3
conn = sqlite3.connect(':memory:')
c = conn.cursor()
c.execute('CREATE TABLE mytable (id integer, description text)')
c.execute('INSERT INTO mytable VALUES (1, "hello world, guys")')
c.execute('INSERT INTO mytable VALUES (2, "hello there everybody")')

此查询应与ID为1的行匹配,但不应与ID为2的行匹配:

c.execute('SELECT * FROM mytable WHERE dist(description, "He lo wrold gyus") < 6')

如何在Sqlite + Python中执行此操作?

关于到目前为止我发现的内容的注释:

  • Levenshtein distance,即将一个单词更改为另一个单词所需的最小单字符编辑数(插入,删除或替换)可能很有用,但我不确定是否Sqlite中存在官方实现(我见过一些自定义实现,如this one

  • Damerau-Levenshtein是相同的,除了它还允许在2个相邻字符之间进行转置;它也被称为Edit distance

  • 我知道自己可以define a function,但实现这样的距离将是非常重要的(对数据库进行超级高效的自然语言处理比较实际上并非无关紧要),这就是我想要的原因看看Python / Sqlite是否已经具备了这样的工具

  • Sqlite具有FTS(全文搜索)功能:FTS3FTS4FTS5

    CREATE VIRTUAL TABLE enrondata1 USING fts3(content TEXT);     /* FTS3 table */
    CREATE TABLE enrondata2(content TEXT);                        /* Ordinary table */
    SELECT count(*) FROM enrondata1 WHERE content MATCH 'linux';  /* 0.03 seconds */
    SELECT count(*) FROM enrondata2 WHERE content LIKE '%linux%'; /* 22.5 seconds */
    

    但我没有找到与这种“相似距离”的字符串比较,FTS的功能MATCHNEAR似乎没有字母变化等的相似性度量。

  • 此外this answer显示:

      

    SQLite的FTS引擎基于令牌 - 搜索引擎试图匹配的关键词   有各种各样的标记器,但它们相对简单。 “简单”的标记器简单地将每个单词拆分并对其进行小写:例如,在字符串“快速的棕色狐狸跳过懒狗”中,单词“jumps”会匹配,但不会“跳”。 “porter”标记器有点高级,剥离了单词的结合,因此“跳跃”和“跳跃”匹配,但是像“jmups”这样的拼写错误不会。

    后者(“jmups”无法与“跳跃”类似的事实)使得我的用例难以实现,遗憾的是。

2 个答案:

答案 0 :(得分:3)

以下是一个现成的示例test.py

import sqlite3
db = sqlite3.connect(':memory:')
db.enable_load_extension(True)
db.load_extension('./spellfix')                 # for Linux
#db.load_extension('./spellfix.dll')            # <-- UNCOMMENT HERE FOR WINDOWS
db.enable_load_extension(False)
c = db.cursor()
c.execute('CREATE TABLE mytable (id integer, description text)')
c.execute('INSERT INTO mytable VALUES (1, "hello world, guys")')
c.execute('INSERT INTO mytable VALUES (2, "hello there everybody")')
c.execute('SELECT * FROM mytable WHERE editdist3(description, "hel o wrold guy") < 600')
print c.fetchall()
# Output: [(1, u'hello world, guys')]

重要提示:距离editdist3已标准化,以便

  

值100用于插入和删除,150用于替换

以下是在Windows上首先要做的事情:

  1. 下载https://sqlite.org/2016/sqlite-src-3110100.ziphttps://sqlite.org/2016/sqlite-amalgamation-3110100.zip并解压缩

  2. C:\Python27\DLLs\sqlite3.dll替换为sqlite3.dll的新here。如果跳过此内容,您将获得sqlite3.OperationalError: The specified procedure could not be found以后的

  3. 执行命令

    call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat"  
    

    call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" x64
    cl /I sqlite-amalgamation-3110100/ sqlite-src-3110100/ext/misc/spellfix.c /link /DLL /OUT:spellfix.dll
    python test.py
    

    (使用MinGW,它将是:gcc -g -shared spellfix.c -I ~/sqlite-amalgation-3230100/ -o spellfix.dll

  4. 以下是如何在Linux Debian上执行此操作:

    (基于this answer

    apt-get -y install unzip build-essential libsqlite3-dev
    wget https://sqlite.org/2016/sqlite-src-3110100.zip
    unzip sqlite-src-3110100.zip
    gcc -shared -fPIC -Wall -Isqlite-src-3110100 sqlite-src-3110100/ext/misc/spellfix.c -o spellfix.so
    python test.py
    

    以下是使用较旧的Python版本在Linux Debian上执行此操作的方法:

    如果您的发行版的Python有点旧,则需要另一种方法。由于sqlite3模块是内置于Python的,因此升级它似乎not straightforwardpip install --upgrade pysqlite只会升级pysqlite模块,而不是升级基础SQLite库)。因此this method例如import sqlite3; print sqlite3.sqlite_version是3.8.2:

    wget https://www.sqlite.org/src/tarball/27392118/SQLite-27392118.tar.gz
    tar xvfz SQLite-27392118.tar.gz
    cd SQLite-27392118 ; sh configure ; make sqlite3.c ; cd ..
    gcc -g -fPIC -shared SQLite-27392118/ext/misc/spellfix.c -I SQLite-27392118/src/ -o spellfix.so
    python test.py   # [(1, u'hello world, guys')]
    

答案 1 :(得分:1)

我实现了与距离相关的函数(Damerau-Levenshtein、Jaro-Winkler、最长公共子串和子序列)作为 SQLite 运行时可加载扩展。支持任何 UTF-8 字符串。

https://github.com/schiffma/distlib