Обработка больших текстовых файлов в Python - PullRequest
0 голосов
/ 15 марта 2019

Я работаю над 2 большими файлами.В основном файле есть 2 поля, в которых указано имя клиента, а во втором - идентификатор клиента.У меня есть второй файл, который является подмножеством первого файла и имеет только имена клиентов.Я хочу найти идентификатор клиента из имен, которые существуют в моем файле подмножества.

Первый файл содержит 30 миллионов строк, а второй - 5 миллионов строк.

Я пытаюсь сделать это, используя словарь, но это занимает огромное время.

Можетпожалуйста, предложите мне лучший способ сделать это.

Вот фрагмент из моего кода и несколько строк из моих файлов.

Основной файл

#

Джон 2343245

Карим 126754

Роб 6543289

Виджей 2247861

Сэм 2649860

....

Подмножество второго файла

Сэм

Роб

Джон

def extract_info(sub_file,master_file):
    sub_fh = open(sub_file,'r',16777216)
    sub_inst_list = []
    for line in sub_fh:
        if line.startswith('#'):
            continue
        else:
            name = line.rstrip()
            sub_inst_list.append(name)
    sub_fh.close()


out_file = "results.rpt"
outf = open(out_file,'w')
bunchsize = 10000
bunch = []
master_fh = open(master_file,'r',16777216)
for line in master_fh:
    if line.startswith('#'):
        continue
    else:
        data = line.split()
        name = data[0]
        if str(data[1]) == "n/a":
            continue
        else:
            if name in sub_inst_list:
                id = str(data[1])
                line = "%-80s %-15s\n" % (name, id)
                bunch.append(line)
                if len(bunch) == bunchsize: 
                    outf.writelines(bunch)
                    bunch= []
                outf.writelines(bunch)
  master_fh.close()
  outf.close()

Ответы [ 2 ]

1 голос
/ 15 марта 2019

Лучший способ - поместить все данные из мастер-файла в базу данных, а затем найти значения на основе ключей из второго файла:

import sqlite3

conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute("CREATE TABLE data (Name VARCHAR(255), ID INT)")

# fill the DB
with open("master.txt") as f:
    for line in f:
        c.execute("INSERT INTO data VALUES (?, ?)", line.split())
conn.commit()

# search for data
with open("slave.txt") as f:
    for line in f:
        print(c.execute("SELECT ID FROM data WHERE Name=:search_name", {"search_name": line.strip()}).fetchall())

conn.close()
0 голосов
/ 15 марта 2019

Другое потенциальное решение (вероятно, медленнее, чем у ForceBru, но эй, это было забавно - кодировать XD) - это использовать потоки для резкого сокращения времени:

from queue import Queue
from threading import Thread

q = Queue()
number_of_threads = 3


def get_customer_id():
    while True:
        customer_name = q.get()
        with open('Master.txt', 'r') as f:
            for line in f.readlines():
                if customer_name.strip() in line:
                    print(line.strip())
                    break
        q.task_done()


with open('Slave.txt', 'r') as f:
    for line in f.readlines():
        q.put(line)

for i in range(number_of_threads):
    new_thread = Thread(target=get_customer_id)
    new_thread.setDaemon(True)
    new_thread.start()


print('main thread waiting')
q.join()
print('done')

Вы можете увеличить количество потоков, скажем до 100-200 может быть и пусть они проворачиваются!Это будет очень дорогостоящим в вычислительном отношении, хотя, поскольку у вас есть максимальное количество итераций почти 125 000 000 000 000 в худшем случае.Это довольно преувеличено, потому что оператор break должен сократить значительное количество этих итераций.И если он работает в 100 потоках, то вы можете разделить число на 100 после того, как уже уменьшите его до break (при условии, что вы еще не максимально используете процессор, в этом случае многопроцессорность будет лучше).Тем не менее, несмотря на то, что LOOOOTS вычислений с этим методом.

Это, по сути, делает то же самое, что и ваш первоначальный скрипт, но выполняет его во много раз быстрее, разделяя и завоевывая!

...