LINUX.ORG.RU

Экономия ресурсов на записи в файл

 ,


0

1

Есть микросервис на java, он экспортирует данные из базы в файл. Файл на выходе должен быть XLSX. На определенном количестве строк зашкаливает либо оперативная память, либо размер файла. Я с такими задачами работал давно и не в курсе как сейчас лучше делать. Навскидку можно через стримы или POI. Гугл выдает много разного, но без учета вопроса нагрузки, а мне нужно выбрать самый экономичный вариант. Про CSV в курсе, но это на крайний случай. Что подскажете?

★★★★★

Вопрос не очень понятен. Да, в POI есть потоковое API. Да, для больших файлов его надо использовать, чтобы не было неограниченного расхода памяти. Судя по всему ты это не хуже меня знаешь.

Что значит «зашкаливает размер файла» - ещё менее понятно. Если зашкаливает размер файла, значит надо покупать диск побольше.

Если у тебя файл в сотни GB, эксель его не откроет. Зачем тебе тогда XLSX?

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)

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

Вообще, в Больших Данных обычно не работают с экселем, а используют как раз либо CSV, либо специализированные форматы: Parquet, AVRO, ORC. Если ты перегонишь данные в Паркет и будешь пользоваться соответствующими инструментами (типа Спарка), то есть вероятность бесплатно получить много перформанса на больших объемах. Вообще, возможно, даже на любых объемах - сложно представить себе что-то более неэффективное, чем работать с данными, выуживая их из глубин DOM-а, где они лежат в формате, предназначенном для удобства визуального рендеринга

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от Legioner

Ну сотни GB это пока рано, а вот сотни MB уже реально. И мне часто приходит ошибка 413. Я еще не решил ее, но если буду знать, что процесс записи файла нельзя сделать принипиально экономичнее/оптимальнее, то наверное буду просто для большого числа строк делать CSV файл.

Lordwind ★★★★★
() автор топика

Плюсую предыдущих комментаторов - очень может быть, что записать то файл получится, если подкрутить POI, но вот Excel его потом не факт, что откроет.

Если критично важно чтобы был именно XLSX, возможно, решением будет разбить на части.

BattleCoder ★★★★★
()

Надо написать нормальный экспорт. Я писал на php потому, что всё готовое было ужасным в плане потребления памяти.

Psilocybe ★★★★
()
Ответ на: комментарий от Legioner

в POI есть потоковое API

А вот интересно, я как-то не сталкивался, можно ли вообще xlsx записывать потоком? С csv как бы нет проблемы дописывать строки в конец, но xls таки предполагает некий «целиковый» документ. Или таки дизайн xlsx предусматривает такой вариант?

no-such-file ★★★★★
()
Ответ на: комментарий от stevejobs

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

Можно использовать вразумительное подмножество для XLSX.

Psilocybe ★★★★
()
Ответ на: комментарий от Psilocybe

писал на php потому, что всё готовое было ужасным в плане потребления памяти

Ну вот, а я хотел потроллить ТСа, предложив переписать на пыхе.

no-such-file ★★★★★
()
Ответ на: комментарий от Psilocybe

Ну т.е. оно пишет что-то типа <row><cell>...</cell>...</row> и потом ещё при закрытии xls дописывает в конец бороду закрывающую документ. Так?

no-such-file ★★★★★
()

Попробуй другие либы, не поей единой.

'лсо, уверен, что нужен именно майковский формат? Современные офисные пакеты сносно понимают разного рода ODF.

izzholtik ★★★
()
Последнее исправление: izzholtik (всего исправлений: 1)
Ответ на: комментарий от Lordwind

Всё возможно. В сокет отдавай поток и всё. Просто не надо буферизовывать нигде.

Legioner ★★★★★
()
Ответ на: комментарий от no-such-file

Apache POI - HSSF and XSSF Limitations

There are some inherent limits in the Excel file formats. These are defined in class SpreadsheetVersion. As long as you have enough main-memory, you should be able to handle files up to these limits. For huge files using the default POI classes you will likely need a very large amount of memory.

There are ways to overcome the main-memory limitations if needed: For writing very huge files, there is SXSSFWorkbook which allows to do a streaming write of data out to files (with certain limitations on what you can do as only parts of the file are held in memory).

Legioner ★★★★★
()

Если нет необходимости в картинках, формулах и стилях - экспортируй в CSV. Всякие эксели вполне способны его импортировать без особых проблем.

Stanson ★★★★★
()
Последнее исправление: Stanson (всего исправлений: 1)
Ответ на: комментарий от Legioner

Изучил этот вопрос подробней. Этот класс в любом случае использует диск. Т.е. сначала файл будет сохранён на диск, а потом уже отправлен клиенту. Не совсем честный стриминг. Но видимо с экселем лучше нельзя.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)

Про CSV в курсе, но это на крайний случай.

Если «крайний случай» из-за того, что хочется отдать клиетну иммено XLSX, а не из-за нехватки возможностей, то можно сгенерить CSV и сконвертировать его внешним процессом, например ssconvert (gnumeric)

annulen ★★★★★
()
Ответ на: комментарий от annulen

сконвертировать его внешним процессом

я об этом и думал как о возможной крайней мере, но если потом фронту отдавать ответ с адресом файла, этот внешний процесс должен api поддерживать, иначе и смысла нет

Lordwind ★★★★★
() автор топика
Ответ на: комментарий от Lordwind

ssconvert может читать stdin и писать в stdout, не нужны никакие файлы

annulen ★★★★★
()
Ответ на: комментарий от Lordwind

С другой стороны, можно записать в файл и вернуть его путь в заголовке X-Accel-Redirect (если фронт такое умеет). api никакие не нужны, желаемое имя файла или даже полный путь (хоть в /tmp/XXXXX.xlsx) ты сам передаешь

annulen ★★★★★
()

XLSX

Там содержимое вроде в zip запаковано. Очень неудобно, когда хочешь генерировать и отсылать кусочками большие объемы данных.

Может все-таки CSV? Пользователь откроет его в Excel, а потом может сохранить в своем любимом формате.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Там содержимое вроде в zip запаковано.

Кстати, коллега-джавист говорил, что нативные реализации gzip в java медленные, а обертку для сишной zlib использовать у них некошерно, так как нативный код и все такое

Очень неудобно, когда хочешь генерировать и отсылать кусочками большие объемы данных.

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

annulen ★★★★★
()

Если хочешь отдавать клиенту поток, то можно отдавать xml excel

https://docs.microsoft.com/en-us/previous-versions/technet-magazine/cc161037(v=msdn.10)?redirectedfrom=MSDN


<?xml version="1.0"?>
<ss:Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
    <ss:Worksheet ss:Name="Sheet1">
        <ss:Table>
            <ss:Row>
                <ss:Cell>
                    <ss:Data ss:Type="String">First Name</ss:Data>
                </ss:Cell>
                <ss:Cell>
                    <ss:Data ss:Type="String">Last Name</ss:Data>
                </ss:Cell>
                <ss:Cell><ss:Data ss:Type="String">Phone Number</ss:Data>
                </ss:Cell>
            </ss:Row>
        </ss:Table>
    </ss:Worksheet>
</ss:Workbook>

Это тоже открывается экселем.

xlsx это zip он не может в полный полноценный поток by design.

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 3)
Ответ на: комментарий от Lordwind

Какая либа и формат дадут больше экономии по памяти+цпу?

в зависимости от того, как именно используется память и цпу ))) Например, у тебя там OLAP или OLTP

вот тут про Паркет есть мини-лекция:

https://databricks.com/session_eu19/the-parquet-format-and-performance-optimization-opportunities

stevejobs ★★★★☆
()
Ответ на: комментарий от vtVitus

xlsx это zip он не может в полный полноценный поток by design.

С чего бы это? Насколько мне известно, однофайловый zip от gzip отличается форматом заголовка и алгоритмом контрольной суммы, а gzip вполне себе потоковый

annulen ★★★★★
()

когда ты экономишь, сын соседки просто покупает многотерабайтный массив SRAM с парой дизель-генераторов

anonymous
()
Ответ на: комментарий от annulen

Насколько мне известно, однофайловый zip от gzip отличается форматом заголовка

Нэт. Zip это контейнер и от gzip от отличается существенно. Позиция и размер центрального каталога находится в самом конца zip. Т.е. чтоб начать раскодировать нужен самый конец. Само понятие заголовка (т.е. того что в начале) в zip отсутствует. Zip поддерживает несколько различных алгоритмов сжатия, а не один Deflate. Ну и xlsx это контейнер далеко не одного файла.

vtVitus ★★★★★
()
Последнее исправление: vtVitus (всего исправлений: 1)
Ответ на: комментарий от vtVitus

Позиция и размер центрального каталога находится в самом конца zip. Т.е. чтоб начать раскодировать нужен самый конец.

Но кодировать же это не должно мешать? Пишем поток deflate’ом, а потом центральный каталог.

Zip поддерживает несколько различных алгоритмов сжатия, а не один Deflate.

Для сжатия таких xml-файлов другой алгоритм и не нужен) zstd там все равно нет

Ну и xlsx это контейнер далеко не одного файла.

Т.е. если xml из примера позипать, то это не будет валидным xlsx?

annulen ★★★★★
()
Ответ на: комментарий от annulen

Т.е. если xml из примера позипать, то это не будет валидным xlsx?

Нет это будет сжатым xml файлом, который эксель не откроет. Сжимать одиночный xml в принципе нет смысла - от сожмётся при передаче сервером и разожмётся клиентом.

Но кодировать же это не должно мешать?

при кодировании, если все файлы уже сгенерированы, то формирование zip будет потоковый. Но для xlsx я не уверен, что файлы генерятся по очереди, поэтому придётся всю файловую байду сначала сгенерировать, а уж потом сжимать.

Для сжатия таких xml-файлов другой алгоритм и не нужен) zstd там все равно нет

Я про то что в zip и gzip больше отличий чем общего.

vtVitus ★★★★★
()
Ответ на: комментарий от Lordwind

413 это же лимит на сервере, скорее всего проксирующем. И отдавать надо чанками, вычитывая из файлового потока. Дисковое пространство дешевле, его можно докупить. Насчёт ОЗУ не ясно - надо смотреть, как работает либа для xlsx, без веб сервера.

Мне нравится предложенный здесь вариант с xml, его можно генерировать в потоке и много памяти не потребуется. А вот с лимитом и отдачей всё равно придётся разбиратся.

InterVi ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.