2009-06-12 2 views
2

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

+2

Не могли бы вы объяснить, что вы ищете? Я не вижу, как вы можете обрабатывать записи, не перебирая их каким-либо образом. Или вы ищете несколько многопоточных решений? –

+1

Вы говорите об обработке 3 миллионов записей один раз или ежедневно/неделю/месяц? –

ответ

6

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

+1

+1 для «записей 3M не большое число». 3M обратный отсчет занимает 0,1 секунды на современном процессоре. –

+1

Это не совсем то, что я имел в виду .... – skaffman

+1

Я понимаю, что вы делаете в своем ответе - я также твердо верю, что позиция OP, что записи 3M слишком велики для линейной обработки, когда вам нужно суммировать каждая запись в любом случае слишком ошибочна для слов. –

1
+2

Hadoop, скорее всего, перехитрит для этого. Идея Hadoop о «огромном» довольно отличается от нескольких миллионов - ее предназначено для терабайт данных. Offort настройки Hadoop не следует недооценивать, столь же впечатляет, как и он. – skaffman

+0

Вы правы. Я также понял, что связан с неправильным постом.Теперь он изменился на тот, который не упоминает Map/Reduce, но представляет собой интересную небольшую историю о том, когда Hadoop можно использовать. Однако набор инструментов Map/Reduce, упомянутый в другом сообщении, по-видимому, делает Hadoop более простым в использовании и может использоваться без него. Это может быть актуально здесь, но опять же, вероятно, нет. Во всяком случае, вот этот пост: http://open.blogs.nytimes.com/2009/05/11/announcing-the-mapreduce-toolkit/ –

3

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

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

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

0

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

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

0

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

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

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

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

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

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

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

0

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

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

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

1

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

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

указано.

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

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

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

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

0

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

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

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

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

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

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

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

+0

Сортировка может быть n * log (n) > процесс; и если большинство сравнений для прямого равенства на > сортируемых полях, это должно дать > полную сложность O (n * log (n) + n). > Теоретически. Если после назначения в ковке элемента > его больше не нужно >, просто удалите его из списка > данных Нет, мы не можем удалить элементы после назначения его в ведро. Его реальные данные и должны быть сохранены в базе данных после обработки. Кроме того, мы не можем сортировать данные по некоторому параметру bcoz, оба из них представляют собой два разных объекта. Просто, что мы пытаемся связать их с некоторыми параметрами –

0

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

выберите NTILE (4) по (порядка по Empno) GRP, Empno, Ename от эми

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

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 ведра) tbut, а фиксированный размер каждого сегмента (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 Cookbook, 1-е издание Энтони Молинаро

Смежные вопросы