Обработка больших наборов данных в Java / Clojure: данные littleBig

Я работал над графиком / приложение для обработки данных ( вы можете увидеть скриншот здесь ), использующее Clojure (хотя часто мне кажется, что я использую больше Java, чем Clojure), и начало тестировать мое приложение с большими наборами данных. У меня нет проблем с примерно 100 тысячами очков, но когда я начинаю подниматься выше этого уровня, я сталкиваюсь с проблемами пространства в куче.

Теперь, теоретически, около половины ГБ должно быть достаточно для хранения около 70 миллионов дублей. Конечно, я я делаю много вещей, которые требуют некоторых накладных расходов, и на самом деле я могу держать 2-3 копии данных в памяти одновременно, но я еще не много оптимизировал, и 500k или около того все еще порядков величина меньше, чем у меня должна быть возможность загрузить.


Я понимаю, что у Java есть искусственные ограничения (которые могут быть изменены) на размер кучи, и я понимаю, что они могут быть частично изменены с помощью параметров, которые вы можете указать при запуске JVM. Это приводит меня к моим первым вопросам :

  • Могу ли я изменить максимально допустимое пространство кучи, если я использую Swank-Clojure (через Leiningen), который JVM имеет при запуске?

  • Если я упакую это приложение (как я планирую) как Uberjar, смогу ли я убедиться, что у моей JVM есть какое-то минимальное пространство кучи?

Но я ' Я не доволен, просто полагаясь на кучу JVM для поддержки моего приложения. Я не знаю размера данных, с которыми я мог бы в конечном итоге работать, но он мог достигнуть миллионов пунктов, и, возможно, куча не могла вместить это. Поэтому мне интересно найти альтернативы тому, чтобы просто накапливать данные. Вот некоторые идеи, которые у меня были, и вопросы о них:

  • Можно ли было бы одновременно читать только части большого (текстового) файла, чтобы я мог импортировать и обрабатывать данные в виде «кусков» Например, n строк одновременно? Если так, то как?

  • Есть ли какой-нибудь более быстрый способ доступа к файлу, из которого я буду читать (потенциально быстро, в зависимости от реализации), кроме простого чтения из него поочередно? Думаю, я Я спрашиваю здесь о любых советах / хитростях, которые работали для вас в прошлом, если вы делали подобное.

  • Могу ли я «взять образец» из файла; например, читать только каждые z строк, эффективно уменьшая выборку моих данных?

Прямо сейчас я планирую, если будут ответы на вышеперечисленное (я буду продолжать поиск!), Или предложения, предлагаемые, которые приводят к эквивалентным решениям, считывать порцию данных за раз, отображать их на временной шкале ( см. Скриншот - шкала времени выделена зеленым) и позволяла пользователю взаимодействовать только с этим битом, пока он не щелкнет на следующем фрагменте (или что-то еще), а затем я сохраню изменения, внесенные в файл и загрузить следующий «кусок» данных и отобразить его.

В качестве альтернативы, я бы отобразил всю временную шкалу всех данных (с пониженной выборкой, чтобы я мог их загрузить), но разрешил бы доступ только к одной ». есть ли лучший способ ? Обратите внимание, что я не могу уменьшить выборку данных основного окна, так как мне нужно иметь возможность обрабатывать их и позволить пользователю взаимодействовать с ними (например, щелкните точку или рядом с ней, чтобы добавить «маркер» к этой точке: этот маркер отображается как вертикальное правило над этой точкой).

Буду признателен за любые идеи, ответы, предложения или исправления! Я также готов разъяснить есть ли лучший способ ? Обратите внимание, что я не могу уменьшить выборку данных основного окна, так как мне нужно иметь возможность обрабатывать их и позволить пользователю взаимодействовать с ними (например, щелкните точку или рядом с ней, чтобы добавить «маркер» к этой точке: этот маркер отображается как вертикальное правило над этой точкой).

Буду признателен за любые идеи, ответы, предложения или исправления! Я также готов разъяснить на мой вопрос любым способом, который вы хотели бы.

Это, мы надеемся, по крайней мере частично, будет с открытым исходным кодом; Мне нужен простой в использовании, но быстрый способ создания xy-графиков с большим количеством данных в мире Clojure.


РЕДАКТИРОВАТЬ Понижение частоты дискретизации возможно только при построении графика, а не всегда, в зависимости от графических элементов. Мне нужен доступ ко всем данным для анализа. (Просто проясните это!) Хотя я определенно должен рассмотреть вопрос о понижающей дискретизации, я не думаю, что это решит мои проблемы с памятью в меньшей мере, поскольку все, что я делаю для построения графиков, это рисование на BufferedImage.

10
задан Brian Tompsett - 汤莱恩 8 December 2015 в 18:26
поделиться

3 ответа

Могу ли я изменить максимально допустимую кучу пробел, если я использую Swank-Clojure (через Leiningen) JVM при запуске?

Вы можете изменить размер кучи Java, указав параметры -Xms (min heap) и -Xmx (max heap) при запуске, см. docs .

Таким образом, что-то вроде java -Xms256m -Xmx1024m ... даст начальную кучу 256 МБ с возможностью увеличения до 1 ГБ.

Я не использую Leiningen / Swank, но думаю, что это можно изменить. По крайней мере, должен быть сценарий запуска для Java где-нибудь, где вы можете изменить аргументы.

Если я упакую это приложение (например, я планирую) как Uberjar, я бы в состоянии гарантировать, что моя JVM имеет какой-то минимальное пространство кучи?

Управление памятью осуществляется не из файла jar, а из сценария запуска, обычно файла .sh или .bat, который вызывает java и предоставляет аргументы.

Могу ли я "сэмплировать" из файла; например читать только каждые z строк?

java.io.RandomAccessFile предоставляет произвольный доступ к файлу по байтовому индексу, который вы можете использовать для выборки содержимого.

Можно ли было читать только части большого (текстового) файла на время, чтобы я мог импортировать и обрабатывать данные в «кусках», т.е.g, n строк в время? Если да, то как?

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

В качестве альтернативы можно использовать механизмы Java в java.io - BufferedReader.readLine () или FileInputStream.read (byte [] buffer)

Есть ли какие-то более быстрый способ доступа файл, из которого я буду читать (потенциально быстро, в зависимости от реализация), кроме простого чтение из него понемногу?

В Java / Clojure есть BufferedReader, или вы можете поддерживать свой собственный байтовый буфер и читать более крупные фрагменты за раз.

Чтобы максимально использовать имеющуюся у вас память, сохраняйте данные как можно более примитивными.

Для некоторых фактических чисел предположим, что вы хотите построить график содержимого музыкального компакт-диска:

  • Компакт-диск имеет два канала, каждый с 44 100 выборками в секунду.
    • 60 мин. музыки тогда ~ 300 миллионов точек данных
  • Представлено как 16 бит (2 байта, короткое) на точку данных: 600 МБ
  • Представлено как примитивный массив int (4 байта на точку данных): 1,2 ГБ
  • Представлено как целое число массив (32 байта на точку данных): 10 ГБ

Используя числа из этого блога для размера объекта (16 байт служебных данных на объект, 4 байта для примитивного int, объекты выровнены по 8-байтовым границам, 8- байтовые указатели в массиве = 32 байта на целочисленную точку данных).

На «нормальном» компьютере даже 600 МБ данных - это непросто хранить в памяти одновременно, поскольку вы, вероятно, будете использовать много памяти и в другом месте.Но переход от простых чисел к числам в рамке сам по себе уменьшит количество точек данных, которые вы можете хранить в памяти, на порядок.

Если бы вы изобразили данные с 60-минутного компакт-диска на «обзорной» временной шкале шириной 1900 пикселей, у вас был бы один пиксель для отображения двух секунд музыки (~ 180 000 точек данных). Очевидно, что этого слишком мало, чтобы показать какой-либо уровень детализации, вам может понадобиться некоторая форма подвыборки или сводных данных.

Таким образом, описываемое вами решение - обрабатывать весь набор данных по частям для отображения сводки на временной шкале «обзора» и сохранять в памяти только небольшое подмножество для главного окна «подробностей» - звучит вполне разумно.

Обновление:

При быстром чтении файла: В этой статье умножена скорость чтения файла для 13 различных способов чтения файла размером 100 МБ на Java - результаты варьируются от 0,5 секунды до 10 минут (!). В общем, чтение происходит быстро с приличным размером буфера (от 4 до 8 кбайт) и (очень) медленно при чтении по одному байту за раз.

В статье также есть сравнение с C на случай, если кому-то интересно. (Спойлер: самые быстрые операции чтения Java находятся в пределах 2 раз по сравнению с файлом с отображением памяти в C.)

7
ответ дан 4 December 2019 в 00:59
поделиться

Выбросив пару идей из левого поля ...

Вы можете найти что-нибудь полезное в библиотеке Colt ... http://acs.lbl.gov/software/colt/

Или, возможно, ввод-вывод с отображением памяти.

2
ответ дан 4 December 2019 в 00:59
поделиться

Пара мыслей:

  • Лучший способ обрабатывать большие наборы данных в памяти в Java / Clojure - использовать большие массивы примитивов. Если вы это сделаете, вы в основном используете немного больше памяти, чем размер базовых данных. Вы прекрасно обрабатываете эти массивы в Clojure с функциональностью aget / aset

  • . Я бы хотел уменьшить выборку, но сохранил способ ленивого доступа к подробным точкам «по запросу», если вам это нужно, например в случае взаимодействия с пользователем. Это похоже на то, как карты Google позволяют видеть весь мир и загружают детали только при увеличении масштаба ....

  • Если вас интересует только изображение на выходе из графика xy, то вы можете построить его с помощью загрузка нескольких тысяч точек за раз (например, загрузка в ваши примитивные массивы), их построение и затем отбрасывание. Таким образом, вам не нужно будет хранить в памяти полный набор данных.

2
ответ дан 4 December 2019 в 00:59
поделиться
Другие вопросы по тегам:

Похожие вопросы: