2015-07-15 3 views
3

Я пытаюсь использовать пакет Dedupe, чтобы объединить небольшие беспорядочные данные в каноническую таблицу. Поскольку каноническая таблица очень большая (122 миллиона строк), я не могу загрузить ее все в память.Как эффективно привязывать записи к большой таблице с помощью python Dedupe?

В настоящее время подхода, который я использую на основе от this занимает целый день на тестовых данных: таблицы 300k строк из запутанных данных, хранящихся в Словаре и таблицу 600k строк канонических данных, хранящихся в 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) 
0

Это, вероятно, будет быстрее, но если вы выразили запрос в качестве соединения:

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» в вашей первоначальной попытке редко оптимизируется, а также правильное соединение.