Как мне эффективно связать записи с большой таблицей, используя python Dedupe?
Я пытаюсь использовать Dedupe
пакет для объединения небольших беспорядочных данных в каноническую таблицу. Поскольку каноническая таблица очень большая (122 миллиона строк), я не могу загрузить все это в память.
Текущий подход, который я использую, основанный на этом, занимает целый день на тестовых данных: таблица строк из 300 КБ беспорядочных данных, сохраненных в dict, и таблица строк из 600 КБ канонических данных, хранящихся в MySQL. Если я сделаю все это в памяти (прочитайте каноническую таблицу как диктат), это займет всего полчаса.
Есть ли способ сделать это более эффективным?
blocked_pairs = block_data(messy_data, canonical_db_cursor, gazetteer)
clustered_dupes = gazetteer.matchBlocks(blocked_pairs, 0)
def block_data(messy_data, c, gazetteer):
block_groups = itertools.groupby(gazetteer.blocker(messy_data.viewitems()),
lambda x: x[1])
for (record_id, block_keys) in block_groups:
a = [(record_id, messy_data[record_id], set())]
c.execute("""SELECT *
FROM canonical_table
WHERE record_id IN
(SELECT DISTINCT record_id
FROM blocking_map
WHERE block_key IN %s)""",
(tuple(block_key for block_key, _ in block_keys),))
b = [(row[self.key], row, set()) for row in c]
if b:
yield (a, b)
2 ответа
Ускорьте его, разделив запрос на два запроса. я использую mysql
и все столбцы, используемые в примере, проиндексированы...
def block_data(messy_data, c, gazetteer):
block_groups = itertools.groupby(gazetteer.blocker(messy_data.viewitems()),
lambda x: x[1])
for (record_id, block_keys) in block_groups:
a = [(record_id, messy_data[record_id], set())]
c.execute("""SELECT DISTINCT record_id
FROM blocking_map
WHERE block_key IN %s""",
(tuple(block_key for block_key, _ in block_keys),))
values = tuple(row['record_id'] for row in c)
if values:
c.execute("""SELECT *
FROM canonical_table
WHERE record_id IN %s""",
(values,))
b = [(row['record_id'], row, set())
for row in c]
if b:
yield (a, b)
Вероятно, было бы еще быстрее, если бы вы выразили запрос как JOIN:
SELECT canonical_table.*
FROM canonical_table
JOIN blocking_map
ON (canonical_table.record_id = blocking_map.record_id)
WHERE blocking_map IN %s
Ваше решение в основном заключается в объединении в Python, поэтому, вероятно, база данных сделает это лучше. Синтаксис "IN" в исходной попытке редко оптимизируется так же, как и правильное соединение.