Как мне эффективно связать записи с большой таблицей, используя 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" в исходной попытке редко оптимизируется так же, как и правильное соединение.

Другие вопросы по тегам