ID(整数)|タイトル(テキスト)|テキスト(テキスト)|タグ(テキスト)の4つのフィールドを含む6M行のデータベース(sqlite)があります。
ここで、たとえばタイトルに表示される各単語の出現回数をカウントし、word|count や tag|word|count などの他のテーブルにインポートする必要があります。
私のコードは Python 2.7 では次のようになります。
from nltk.tokenize import wordpunct_tokenize
from collections import Counter
import sqlite3
word_count = Counter()
pair_count = Counter()
conn = sqlite3.connect('database')
c = conn.cursor()
for query in c.execute('SELECT Tags, Title FROM data'):
tags = query[0].strip().split()
title = wordpunct_tokenize(query[1])
for word in title:
word_count[word] += 1
for tag in tags:
pair_count[(tag, word)] += 1
...
問題は、カウンターが大きくなりすぎて、1M 行でメモリ エラーが発生したことです。100K 行ごとにカウンターを再初期化し、カウントを db ファイルに追加しようとしましたが、タグと単語のペアの数が膨大なため、このアプローチは非常に遅いようです。
...
for query in c.execute('SELECT Tags, Title FROM data'):
i += 1
if i % 100000 == 0:
conn1 = sqlite3.connect('counts.db')
c1 = conn1.cursor()
# update word count
for word in word_count:
c1.execute('SELECT Count FROM word_count WHERE Word=?', (word,))
count = c1.fetchone()
# add to existing count and update
if count:
count = word_count[word] + count[0]
c1.execute('UPDATE word_count SET Count=? WHERE Word=?', (count, word))
# insert new row
else:
c1.execute('INSERT INTO title_word_count VALUES (?,?)', (word, word_count[word]))
# update pair count
for pair in pair_count:
c1.execute('SELECT Count FROM pair_count WHERE Tag=? AND Word=?', pair)
count = c1.fetchone()
if count:
count = pair_count[pair] + count[0]
c1.execute('UPDATE pair_count SET Count=? WHERE Tag=? AND Word=?', (count, pair[0], pair[1]))
else:
c1.execute('INSERT INTO pair_count VALUES (?,?,?)', (pair[0], pair[1], pair_count[pair]))
conn1.commit()
conn1.close()
# reinitiate counters
word_count = Counter()
pair_count = Counter()
...
複数のマシンにアクセスせずにこの問題を解決する方法はありますか? また、コードに関する提案をいただければ幸いです。
編集:
インデックスを作成してcounts.db
各バッチを更新しようとしましたが、それでも遅すぎます。それぞれ 200000 行の 7 つのバッチを処理するのに 10 時間かかりました。
私は最初のアイデアに従うことで終わりました。ただし、100K 行ごとにカウントを更新する代わりに、ペアsubcounts
が重複している可能性があるにもかかわらず、それらをテーブルに挿入するだけです。Tag, Word
その後INSERT INTO pair_count SELECT Tag, Word, SUM(Count) FROM subcounts GROUP BY Tag, Word;
、最終結果を教えてくれました。合計で約3時間かかりました。
@abernert の提案に従って取得した一時テーブルを誤って削除しましたが、実行可能だと思います。
アドバイスをくれた @Steve と @abernert に感謝します!