Уведомления

Группа в Telegram: @pythonsu

#1 Окт. 31, 2012 13:40:32

hulygun
Зарегистрирован: 2012-08-25
Сообщения: 74
Репутация: +  2  -
Профиль   Отправить e-mail  

Обработка csv большого размера

Ув. сообщество, я только начинаю знакомство с django и python в целом.
Как лучше всего обрабатывать csv файлы большого размера?
На данном этапе работает следующий код:

class Distr(models.Model):
    name          = models.CharField(max_length=20, verbose_name="Название")
    mail          = models.EmailField()
    file          = models.FileField(upload_to="csv", blank=True, verbose_name="Файл CSV")
    def save(self):
        super(Distr, self).save()
        csv_file   = self.file.path
        dataReader = csv.reader(open(csv_file), delimiter=',', lineterminator='\n')
        for row in dataReader:
            tovar  = Item()
            if row[0] != 'Бла-бла-бла':
                filter  = Item.objects.filter(distr = self, artikul = row[0])
                if filter:
                    exist = filter.get()
                    exist.price = row[2]
                    exist.count = row[3]
                    exist.save()
                else:
                    tovar.artikul = row[0]
                    tovar.name  = row[1]
                    tovar.distr = self
                    tovar.price = row[2]
                    tovar.count = row[3]
                    tovar.save()
Он хоть и рабочий, но скорее всего кривой в силу моего слабого скилла в django. Для csv небольшого размера разница производительности, думаю, будет весьма не значительная, но если, скажем, в файле будет около 8к позиций, то это не будет гуд.
Подскажите, как лучше будет поступить?
Была идея разбивать csv, скажем, по 1 метру и выполнять импорт по кускам, но я пока не смог нагуглить как это делается… Логика мне то понятна: взять файл, считать первые 1мб данных + n данных до переноса строки, обработать, запомнить сколько точно байт обработал, потом проделал бы тоже самое со следующего байта

Отредактировано hulygun (Окт. 31, 2012 13:40:55)

Офлайн

#2 Окт. 31, 2012 15:54:35

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Обработка csv большого размера

Вот это

dataReader = csv.reader(open(csv_file), delimiter=',', lineterminator='\n')
лучше заменить на
with open(csv_file, 'rb') as f:
    dataReader = csv.reader(f, delimiter=',', lineterminator='\n')

Что касается больших размеров, то все зависит от железа.
По-умолчанию для чтения файлов используется системная настройка размера буфера.
Буфер будет выделен под весь файл. Эффективно при достаточном количестве памяти.

Если хотите сами управлять размером буфера, используйте третий параметр функции open.
Правда, он не на всех ОС работает.

Самый быстрый способ - загрузить весь файл в память.
На больших размерах файлов - чем больше буфер, тем быстрее.
Само собой, все за счет ресурсов. В данном случае, за счет памяти.



Офлайн

#3 Окт. 31, 2012 15:57:56

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Обработка csv большого размера

Если ключевая строка

if row[0] != 'Бла-бла-бла':
встречается часто, можно сделать свой генератор, в который и включить это условие.



Офлайн

#4 Окт. 31, 2012 19:11:36

hulygun
Зарегистрирован: 2012-08-25
Сообщения: 74
Репутация: +  2  -
Профиль   Отправить e-mail  

Обработка csv большого размера

За генератор отдельное спасибо. Но вот только всё равно за раз 8к запросов к базе не сильно ли много?

Офлайн

#5 Окт. 31, 2012 21:18:20

Lexander
От:
Зарегистрирован: 2008-09-19
Сообщения: 1139
Репутация: +  33  -
Профиль   Отправить e-mail  

Обработка csv большого размера

Опять же, зависит от ресурсов и мощности железа.
Но, в любом случае, вам лучше явно управлять транзакциями. Сейчас, судя по коду, у вас каждое изменение - отдельная транзакция - это создает ненужную нагрузку на БД в данном случае.

Для вашей конфигурации сервера опытным путем установите размер пакета записей, сохраняемых в одной транзакции.
Если у вас хостинг, начните с 100 штук и двигайтесь в сторону увеличения, пока не получите наивысшую производительность.
Если VDS, начните с 500 штук.
Если свой сервер,- с 1000.



Офлайн

#6 Окт. 31, 2012 22:58:28

hulygun
Зарегистрирован: 2012-08-25
Сообщения: 74
Репутация: +  2  -
Профиль   Отправить e-mail  

Обработка csv большого размера

Смысл в следующем:
Есть сущность Дистрибьютер(Distr), которая заполняется вручную админом, у каждого дистрибьютора есть csv с товарами. Тоесть админ заполняет поля этой сущности, загружает csv и создаются автоматом товары. Как делать

Lexander
установите размер пакета записей, сохраняемых в одной транзакции
я понятия не имею (скилл слишком мал). Но и на том спасибо. Завтра буду пробовать копать в этом направлении. Правда я даже понятия не имею, как поставить вопрос гуглу((( Пока проект на локале, но думаю в будущем будет vds.

Офлайн

#7 Ноя. 1, 2012 06:37:01

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Обработка csv большого размера

hulygun
Правда я даже понятия не имею, как поставить вопрос гуглу
Что-то вроде “django manual commit”

db.transaction.commit_manually

Псевдокод:
from django.db import transaction
 
BULK_SAVE_COUNT = 500
 
class Distr(models.Model):
    ...
    @transaction.commit_manually
    def save(self):
        ...
        added_items = 0
        for row in dataReader:
            ...
            something.save()
            added_items += 1
            if not added_items % BULK_SAVE_COUNT:
                transaction.commit()
        transaction.commit()
Считаем количество сохраненных объектов и через каждые BULK_SAVE_COUNT штук комитим транзакцию.

Еще в 1.4 появилась bulk_create()

Отредактировано reclosedev (Ноя. 1, 2012 06:47:10)

Офлайн

#8 Ноя. 1, 2012 07:20:42

hulygun
Зарегистрирован: 2012-08-25
Сообщения: 74
Репутация: +  2  -
Профиль   Отправить e-mail  

Обработка csv большого размера

О…. благодарю великодушно… ушёл копать

Офлайн

#9 Ноя. 5, 2012 12:49:08

lomach
От:
Зарегистрирован: 2012-01-28
Сообщения: 43
Репутация: +  0  -
Профиль   Отправить e-mail  

Обработка csv большого размера

Я в джанго тоже не очень опытный, но по опыту PHP и Perl могу сказать, что разницу в производительности вы не очень почувствуете при размере файла в 8к строк, если, конечно, это не будут делать одновременно постоянно десяток человек. Загрузить такой файл несколько раз в сутки нормально с точки зрения нагрузки на железо и БД. Только с оговоркой, что добрые соседи по железу на VDS в этот момент не уматывают ресурсы общего железного сервера в хлам.




Django 1.8, БД MySQL 6
Debian Linux 7.0

Офлайн

#10 Ноя. 5, 2012 13:45:56

fashust
От:
Зарегистрирован: 2011-07-17
Сообщения: 30
Репутация: +  3  -
Профиль   Отправить e-mail  

Обработка csv большого размера

если у вас действительно большие файлы, то мне кажется лучше вынести логику его обработки куда-то вне основного потока, повесьте celery task на post_save, а в самом task уже делайте импорт файла, иначе у вас могут возникнуть проблемы, например, с request timeout



import this

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version