Задать вопрос

Как организовать обработку больших объемов данных?

Существует поле целых чисел от 0 до 15 000 000.
По этому полю раз в три дня рассчитываются последовательности из 500 000 значений(алгоритмы расчета последовательностей меняются, можно считать случайными). Таких последовательностей 15 000 000, каждая последовательность отсортирована по возрастанию. Далее необходимо выбрать N последовательностей с максимальным охватом поля. Соответственно уложить расчеты в 3 часа и занять минимум вычислительных ресурсов.

Пример:
$sequence1 = array(n1=>1, n2=>5, n3=>100.....n500000 => 14900999) //1-я последовательность
$sequence2 = array(n1=>4, n2=>5, n3=>99.....n500000 => 14900999) //2-я последовательность
Последовательностей $sequence1, $sequence2......$sequence15000000 // 15 000 000 последовательностей по 500 000 значений
Считаем суммы уникальных значений поля для N последовательностей.
Выбираем последовательность с максимальной суммой.

Вопросы по задаче:
|. Подскажите, как лучше организовать систему хранения, или может быть решение не предусматривающее хранение всех данных?
||. Какие инструменты выбрать для расчетов?
|||. Подскажите быстрые алгоритмы сравнения больших объемов данных, ведь надо сравнивать 500 000 с 500 000 записей
|V. Разрешима ли данная задача в домашних условиях?

Мои мысли:
|. Расчеты одной последовательности идут долго порядка 3-х минут, поэтому предполагаю хранить последовательности
Идеи которые отлетели
sql- индексированная таблица для быстрых сравнений (одна таблица >10mb, 15 000 000 таблиц это 150ТБ, такой объем никто не даст)
txt - файл через запятую ( один файл >4мб, весь расчет уложится в 60ТБ, что тоже много)
zip- один файл >1mb, весь расчет уложится в 15ТБ, ближе к теме, но все равно много.
Может есть другие идеи хранения данных?

||. Взял php, sql, так как с ними знаком, возможно использование других инструментов

|||.Пробовал сравнение индексных таблиц join-м, скорость приемлемая, но надо иметь 15 000 000 индексных таблиц, что много по памяти
Сравнение в php count(array_diff($arr1, $arr2)), не получилось в два массива запихать по 500 000 значений, ошибка памяти, пробовал REDIS, он помогает, но пока запихаешь туда два массива времени уйдет много
Бегать перебором по массивам в цикле и проверять есть ли уже значение, вариант в лоб, дольше всего.

|V. Возможно ли используя 16гб оперативки, Core i7, 2TB HDD, уложиться в 3 часа расчетов? И вообще реально ли произвести подобного рода расчеты в разумное время?
  • Вопрос задан
  • 901 просмотр
Подписаться 8 Сложный 28 комментариев
Ответ пользователя Юрий К ответам на вопрос (5)
riky
@riky
Laravel
Сравнение в php count(array_diff($arr1, $arr2)), не получилось в два массива запихать по 500 000 значений, ошибка памяти


сам недавно пересечениями баловался, были массивы более 10М чисел, даже не сортированные.

1) в php 500к запихнуть легко, просто юзай ini_set memory_limit.

2) конечно же нельзя исопльзовать array_diff , исопльзуй array_diff_key это будет просто на порядок быстрее, тк по ключам там есть индекс. ну и массивы конечно надо перевернуть предварительно array_flip. по времени даже вместе со флипом оно будет на порядок быстрее.

3) в конце концов сделал на GO, точно не помню но по скорости получилось раз в 3-5 наверное быстрее. точно сравнивать сложно тк в php загрузка данных тоже была довольно медленной, да и памяти он расходует гораздо больше. если нужно посчитать пересечение в сортированных списках - нужно сделать цикл пробегаясь по обоим массивам одновременно за один проход.

примерно так:
func intersectCount(ids1, ids2 []uint32) int {
	j := 0
	cnt := 0
	for i := 0; i < len(ids1); i++ {
		for ;(j < len(ids2)) && (ids2[j] < ids1[i]); j++ {}
		if (j < len(ids2)) && (ids2[j] == ids1[i]) {
			cnt++
		}
	}
	return cnt
}


на php конечно так делать бессмысленно, тк array_diff_key на С и будет на порядок быстрее.

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

у меня было 1000 списков чисел, в списках от 1 до 15 млн uint32 чисел. нужно было посчитать пересечением каждое с каждым. в один поток на не очень мощном компе это заняло около 3-4 часов.

очень много времени уходит на чтение с диска, поэтому загружал списки в память по 200 штук и высчитывал пересечение каждое с каждым, потом загружалась следующая партия и тд.

посчитать пересечение 15 млн списков каждое с каждым в лоб за 3 часа выглядит нереально. нужен дешевый способ за один раунд выбрать небольшое количество подходящих и искать уже оптимальное среди них.
Ответ написан