end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

SQLite FTS5 Extension による全文検索

参考url

python script

上記の参考urlからの写経です

import re
import unicodedata
import sqlite3

def main():
    db_conn = sqlite3.connect('sqlite_fts_3.db')
    # db_conn = sqlite3.connect(':memory:') # for debug

    db_cur  = db_conn.cursor()

    # FTS5全文検索仮想テーブル作成。
    # 「UNINDEXED」は全文検索の対象外column指定。
    # ftsが自動生成する為、primary keyの指定は不要。
    sql_create_tbl = '''
    CREATE VIRTUAL TABLE IF NOT EXISTS fts USING fts5(
    file UNINDEXED,
    date UNINDEXED,
    text)
'''
    db_cur.execute( sql_create_tbl )
    
    add_texts(db_cur)

    full_text_search(db_cur)
    
    db_cur.close()
    db_conn.close()


def add_texts( db_cur ):
    src_datas = [
        ['file1.txt', '2021-01-15', 'あいうえお、うえお。( A 1 )①'],
        ['file2.txt', '2021-01-16', 'かきくけこ、くけこ。( B 2 )㈱'],
        ['file3.txt', '2021-01-17', 'さしすせそ、すせそ。( C 3 )㍿'],
        ['file4.txt', '2021-01-18', 'たちつてと、つてと。( D 4 )㈲'],
        ['file5.txt', '2021-01-19', 'なにぬねの、ぬねの。( E 5 )㌫'],
        ['file6.txt', '2021-01-20', 'た ちつて と、つて と。(X 6)㈹'],
    ]

    sql_insert = 'INSERT INTO fts(file,date,text) VALUES (?,?,?)'
    i = 0
    for src_data in src_datas:
        # python 側で、N-gramにして登録
        src_data[2] = bigram( src_data[2] )
        db_cur.execute(sql_insert,src_data)
    db_cur.connection.commit()
    return

def bigram(text):
    if len(text) >= 2:
        return ' '.join((text[i:i+2] for i in range(0, len(text)-1, 1)))
    return text

def bigram2text(text):
    if len(text) > 2:
        texts = [text[i] for i in range(0, len(text), 3)]
        texts.append(text[-1])
        return ''.join(texts)
    return text


def full_text_search(db_cur):
    # 検索keyword
    keywords = ['たち', 'つてと']

    bigram_keywords = []
    for keyword in keywords:
        bigram_keywords.append(f'"{bigram(keyword)}"')
    bigram_keywords = ' '.join(bigram_keywords)
    print(f'bigram_keywords: {bigram_keywords}')

    sql = 'SELECT * FROM fts WHERE text MATCH ? LIMIT 100'
    db_cur.execute(sql, (bigram_keywords,))

    results = db_cur.fetchall()
    for result in results:
        found_txt = bigram2text(result[2])
        print(  found_txt )

if __name__ == '__main__':
    main()