Обработка огромного объема данных с использованием Java - PullRequest
2 голосов
/ 12 июня 2009

В рамках требования нам нужно обработать около 3 миллионов записей и связать их с корзиной. Эта связь определяется набором правил (состоящих из 5-15 атрибутов, с одним или диапазоном значений и приоритетом), которые получают блок для записи. Последовательная обработка такого большого числа явно выходит за рамки. Может ли кто-нибудь направить нас к подходу, чтобы эффективно разработать решение?

Ответы [ 10 ]

6 голосов
/ 12 июня 2009

3 миллиона записей на самом деле не так уж много с точки зрения объема данных (очевидно, в зависимости от размера записи), поэтому я хотел бы предложить, что проще всего попробовать распараллелить обработку между несколькими потоками ( используя фреймворк java.util.concurrent.Executor). Пока у вас есть несколько доступных процессорных ядер, вы сможете добиться почти линейного увеличения производительности.

3 голосов
/ 12 июня 2009

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

Если у вас многоядерный компьютер, разделенные данные могут обрабатываться параллельно. Если вы определили назначение группы записей, вы можете записать информацию обратно в базу данных, используя пакетную возможность PreparedStatement.

Если у вас только одноядерный компьютер, вы все равно можете достичь некоторых улучшений производительности, разработав разделение поиска данных - обработка данных - пакетной обратной записи, чтобы использовать время паузы операций ввода / вывода.

1 голос
/ 12 июня 2009

В качестве бессмысленного теста у нас есть система с внутренним кешем. В настоящее время мы загружаем 500К строк. Для каждой строки мы генерируем статистику, размещаем ключи в разных кэшах и т. Д. В настоящее время для обработки требуется менее 20 секунд.

Это бессмысленный тест, но это пример того, что в зависимости от обстоятельств 3M строк не так много строк на современном оборудовании.

Это сказал.

Как предлагали другие, разбейте работу на части и распараллелите прогоны, по 1-2 потока на ядро. Каждый поток поддерживает свои собственные локальные структуры данных и состояние, и в конце мастер-процесс объединяет результаты. Это грубый алгоритм «карта / уменьшение». Ключевым моментом здесь является обеспечение того, чтобы потоки не боролись за глобальные ресурсы, такие как глобальные счетчики и т. Д. Пусть окончательная обработка результатов потока обрабатывает их последовательно.

Вы можете использовать более одного потока на ядро, если каждый поток выполняет ввод-вывод в БД, поскольку ни один поток не будет чисто привязан к ЦП. Просто запустите процесс несколько раз с различным количеством потоков, пока он не выйдет быстрее всего.

Мы наблюдаем увеличение скорости на 50%, даже когда мы запускаем пакеты через постоянную систему очередей, такую ​​как JMS, для распределения работы по сравнению с линейной обработкой, и я видел эти преимущества на 2-ядерных портативных компьютерах, поэтому есть определенное место прогресс здесь.

Еще одна вещь, если это возможно, не делайте ЛЮБОГО дискового ввода-вывода (сохраняйте чтение данных из БД) до самого конца. В этот момент у вас появляется гораздо больше возможностей для пакетирования любых обновлений, которые необходимо сделать, чтобы вы могли, по крайней мере, сократить время прохождения сигнала в сети. Даже если вам пришлось обновлять каждую строку, большие пакеты SQL все равно будут показывать чистый прирост производительности. Очевидно, что это может быть интенсивное использование памяти. К счастью, большинство современных систем имеют много памяти.

1 голос
0 голосов
/ 13 июня 2009

Я бы попытался отодвинуться назад с автором спецификации, чтобы больше сосредоточиться на том, «что» нужно сделать, а не как. Я не могу себе представить, почему спецификация подтолкнула бы 'java' к операции с интенсивным использованием данных. Если это связано с данными, сделайте это с SQL. Если вы используете Oracle, есть функция nTile. Таким образом, создание фиксированного набора сегментов так же тривиально, как:

выберите Ntile (4) более (упорядочить по empno) GRP, EMPNO, ENAME от emp

Что приводит к:

GRP EMPNO ENAME
--- ----- ---------
1  7369 SMITH
1  7499 ALLEN
1  7521 WARD
1  7566 JONES
2  7654 MARTIN
2  7698 BLAKE
2  7782 CLARK
2  7788 SCOTT
3  7839 KING
3  7844 TURNER
3  7876 ADAMS
4  7900 JAMES
4  7902 FORD
4  7934 MILLER

Как минимум, вы можете, по крайней мере, установить свои «сегменты» в SQL, тогда ваш Java-код должен будет просто обработать данный сегмент.

Worker worker = new Worker(bucketID);
worker.doWork();

Если вас не интересует количество сегментов (в приведенном выше примере запрашивалось 4 сегмента), а точнее фиксированный размер каждого сегмента (5 записей на блок), тогда SQL будет:

select ceil(row_number()over(order by empno)/5.0) grp,
  empno,
  ename
from emp

Выход:

GRP      EMPNO ENAME
    --- ---------- -------
1       7369 SMITH
1       7499 ALLEN
1       7521 WARD
1       7566 JONES
1       7654 MARTIN
2       7698 BLAKE
2       7782 CLARK
2       7788 SCOTT
2       7839 KING
2       7844 TURNER
3       7876 ADAMS
3       7900 JAMES
3       7902 FORD
3       7934 MILLER

Оба приведенных выше примера взяты из потрясающей книги: Поваренная книга SQL, 1-е издание Энтони Молинаро

0 голосов
/ 12 июня 2009

Основываясь на пересмотренном описании, я думаю, что попробую взглянуть на сортировку данных.

Сортировка может быть процессом n log (n); и если большинство сравнений для прямого равенства в сортируемых полях, это должно привести к общей сложности ~ O (n log (n)). Теоретически. Если после назначения элемента в корзину он больше не нужен, просто удалите его из списка данных.

Даже если для различных этапов логики необходимо несколько раз восстановить данные, это все равно должно быть немного быстрее, чем при подходе n ^ 2.

По сути, это потребует предварительной обработки данных, чтобы упростить их фактическую обработку.

Это делает определенные предположения о логике назначения сегментов (nameley, что это не слишком далеко от предоставленного кода псевдо); и будет недействительным, если вам нужно извлечь данные из каждой пары A, B.

Надеюсь, это поможет.

Редактировать: Я бы прокомментировал, если бы мог; но, увы, я слишком новый. Предварительная обработка применяется как к данным, так и к отдельным категориям. В конечном счете, все, что вам нужно сделать, чтобы перейти от 15-минутного времени вычисления к 5-минутному времени, - это уметь программно определять 2/3 с + категорий, которые не могут и никогда не будут совпадать ... менее чем за O (n) амортизированных время. Признаюсь, что может быть неприменимо к вашей конкретной ситуации.

0 голосов
/ 12 июня 2009

Последовательная обработка такого большого номер явно выходит за рамки.

Не думаю, что ты это знаешь. Сколько времени занимает обработка 1000 записей таким образом? 10000? 100000? 1000000? Если ответ действительно «слишком длинный», тогда хорошо: начните искать оптимизации. Но вы можете найти ответ «незначительный», и тогда вы закончите.

Другие ответы ссылались на это, но это весь мой ответ. Докажите, что у вас есть проблемы, прежде чем начать оптимизацию. Тогда, по крайней мере, у вас есть простая, правильная система для профилирования и сравнения с оптимизированными ответами.

0 голосов
/ 12 июня 2009

Эффективные этапы проектирования для этого сценария состоят в том, чтобы сначала определить все и все места, где вы можете разделить записи, которые нужно обработать, чтобы обеспечить распараллеливание с полным движком (то есть четыре устройства, работающие с записями по 750 тыс. Каждый, сравнительно дешевы). Затем, в зависимости от стоимости правил, которые суммируют вашу запись (я рассматриваю назначение сегмента как операцию суммирования), определите, будет ли ваша операция привязана к процессору или к поиску записи.

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

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

0 голосов
/ 12 июня 2009

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

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

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

http://www.ibm.com/developerworks/library/j-thread.html
http://www.ibm.com/developerworks/java/library/j-threads1.html http://www.devarticles.com/c/a/Java/Multithreading-in-Java/

0 голосов
/ 12 июня 2009

Есть ли причина, по которой вам приходится использовать Java для обработки данных? Не могли бы вы использовать SQL-запросы для записи в промежуточные поля? Вы можете использовать каждое поле - атрибуты - до тех пор, пока у вас не будет все, что вам нужно.

Или вы могли бы использовать гибрид SQL и Java ... Используйте разные процедуры, чтобы получить разные "корзины" информации, а затем отправить его по одному пути потока для более подробной обработки и другому запросу, чтобы получить другой набор данных и отправить что по другому пути потока ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...