Сравнение двух больших списков и выбор подходящих результатов - PullRequest
0 голосов
/ 25 марта 2020

Я много раз пытался его найти, но не смог найти подходящего решения. У меня есть два больших списка строк по 1,5 миллиона записей в каждом. Оба этих списка передаются в SQL Query внутри предложения where для разных столбцов. Например: Select * from TBL1 where FOO IN (Col1_List) and BAR IN (Col2_list);

Из-за некоторых ограничений lambda не поддерживающих более 16К значений внутри IN Clause в SQL, я хочу каждый раз передавать ограниченные значения для обработки, рассмотрим пример ниже :

Col1_list = ['1_a_title','2_title','3_b_title','4_c_title','5_title']  #  and so on ..
Col2_list = ['1_a','2','3_b','4_c','5']  # and so on..

Как видите, Col1_list содержит несколько дополнительных символов для каждого значения (скажем, _title) по сравнению с Col2_list. Оба списка начинаются с целого числа, и эти целые числа могут иметь некоторые другие присоединенные символы (как в случае 1_a, 3_b).

Цель : Я хочу передать значения 16K внутри предложения IN, поэтому необходимо, чтобы целочисленные части Col1_list и Col2_list должны были совпадать для получения правильных результатов sql. Я попробовал следующий код:

Подход 1: - Цикл по Col2_list и сопоставление его для создания нового списка совпадающих записей:

for i in range(0, len(Col2_list), 16000):
    chunk = Col2_list[i:i + 16000]
    new_kl = []
    for val_to_check in chunk:
      print(val_to_check)
      new_kl.append([item1 for item1 in Col1_list if val_to_check.split('_')[0] == item1.split('_')[0]])
      print(val_to_check + " - " + str(new_kl))
    <Do Processing for obtained 16K values>

Подход 2: Пробовал то же самое с Для понимания

for i in range(0, len(Col2_list), 16000):
    chunk = Col2_list[i:i + 16000]
    matched_list = [item for x in chunk for item in Col1_list if item.split('_')[0] == x.split('_')[0]]
    <Do Processing for obtained 16K values>

Оба эти подхода работают ужасно медленно. Может ли кто-нибудь, пожалуйста, подскажите мне, как можно сделать это быстрее.

Примечание: Пожалуйста, пока не принимайте во внимание платформу, я в порядке с запуском сценария на экземпляре EC2, если требуется, но все еще нужно решение вышеуказанной проблемы.

Ответы [ 2 ]

0 голосов
/ 27 марта 2020

Похоже, что вы уже решили эту проблему с помощью базы данных, но вы также можете значительно ускорить это в Python, используя более подходящие структуры данных.

По сути, вы сравниваете каждое значение в Col2 с каждым значением в Col1, чтобы увидеть, имеют ли они один и тот же первый элемент. Вместо этого вы можете просто сгруппировать элементы в Col1 по их первому элементу, сохранить их в словаре, а затем получить значения, соответствующие первому элементу значения из Col2 из этого указания.

import collections
col1_dict = collections.defaultdict(list)
for item1 in col1_list:
    col1_dict[item1.split('_')[0]].append(item1)

for i in range(0, len(col2_list), 16000):
    matched_list = [item for val_to_check in col2_list[i:i + 16000]
                         for item in col1_dict[val_to_check.split('_')[0]]]
    # more processing

This уменьшит сложность с O (# col1 x # col2) до O (# col1 + # col2). (Понимание списка все еще имеет два цикла for, но, поскольку каждый элемент из Col1 будет находиться в одной «корзине», внутренние циклы имеют объединенное время выполнения только # итераций Col1.)

0 голосов
/ 27 марта 2020

Согласно предложению @AnthonyOteri, я выполнял обработку в основном на стороне базы данных, и она работала нормально и за гораздо меньшее время.

...