Сравнение массивов 5М+ значений?

Столкнулся с проблемой «нехватки» памяти при попытке выполнить array_diff для двух многомиллонных массивов. Кушается порядка 1200Мб при такой операции. Про время выполнения вообще молчу.
Один массив набирается из БД, второй массив приходит с удаленного сервера.
Подскажите кто как решил бы данный вопрос.
Запись в файл получается крайне громоздкая и затем достаточно геморно получить обратно разницу в нужном формате.

UPD 14/01/2017
В общем пока что решил вопрос редисом.
Если приходящий массив новый, записываю его сразу же листом в редиску, без сортировки.
Он будет являться эталонным.
При обновлении создаю еще один ключ с постпфиксом "_new".
Сравниваю поочередно два ключа через sDiff. В итоге в пых возвращаются два массива Delete, New.
Соответственно значения массива New добавляю в эталонный список, значения Delete удаляю из этого же списка.
Дропаю ключ "_new", в мускул произвожу те же самые записи, только в разные таблицы, для вывода юзеру.
Теперь осталось выяснить нагрузку на HDD от редиски :) Но пока что все летает.
Как появится возможность, буду переписывать нафиг все на пайтон.
Всем спасибо за помощь.
  • Вопрос задан
  • 796 просмотров
Решения вопроса 1
@Nc_Soft
Запишите оба массива в бд и сделайте joinом
Ответ написан
Пригласить эксперта
Ответы на вопрос 6
Sanasol
@Sanasol Куратор тега PHP
нельзя просто так взять и загуглить ошибку
Для этого есть всякие распределнные вычисления типа mapreduce на hadoop или аналогичных платформах.

Но 5млн строк это всё-таки не бигдата .
Делайте нормальный скрипт для проверки постепенной, а не 5 милионов сразу в функцию зах*уячить и ждать что всё будет прекрасно.
Можно еще очередь(amqp) поставить и воркеров запустить, и вкидывать туда задания. Но тоже это все аккуратно и постепенно.
Ответ написан
@private_tm
JAVA dev
На линуксе в терминале
diff 1.txt 2.txt > diff.txt
Ответ написан
Вообще это не для php задача, если перепишете на том же питоне с тем же самым алгоритмом, памяти уйдет раз в 10 примерно меньше (https://habrahabr.ru/post/141093/#comment_4719302 - почти пруф. Сам одно время интересовался, нужно было сравнивать массивы пользователей из вк, сейчас бы попробовал go наверное, с ним потребление памяти не изучал, но оно будет явно меньше, чем у php). Также как вариант записать данные со стороннего сервера себе и брать порциями, используя генераторы (yield), они как раз и созданы, чтобы экономить память, но лучше мне кажется все-таки использовать другой язык программирования на такие объемы.
Ответ написан
@pudovMaxim
web-developer
Если сортируется быстро, то можно отсортировать массивы, затем пройтись по одному и найти все вхождения в другом, ограничивая перебор брейком, т.е. что-то в духе:
sort($arr1);
sort($arr2);
$lv = 0;
$m = count($arr2);
foreach ($arr1 as $k1) {
    for ($i=$lv ;$i < $m; $i++) {
        if($k1 == $arr2[$i]) {
            // do smth
            $lv = i;
            break;
       }
       if ($k1 < $arr2[$i]) {
           break;
       }
   }
}

но это не готовое решение
Ответ написан
zoonman
@zoonman
⋆⋆⋆⋆⋆
Сложите данные во вторую таблицу и потом через SQL все сделайте.
Ответ написан
Комментировать
@ReenExe
А что если попробовать через разницу ключей?
$start = microtime(true);

$exists = array_fill(2e7, 7e7, true);
$stored = array_fill(3e7, 8e7, true);
shuffle($exists);
shuffle($stored);

echo microtime(true) - $start;
echo PHP_EOL;

$start = microtime(true);;

$diff = array_diff($stored, $exists);

echo microtime(true) - $start;
echo PHP_EOL;

$start = microtime(true);

$diff = array_keys(array_diff_key(array_fill_keys($stored, true), array_fill_keys($exists, true)));

echo microtime(true) - $start;
echo PHP_EOL;

// initialize:      11.500846147537
// array_diff:      4.1464519500732
// array_diff_key:  3.2659499645233

Решение с Redis возможно более правильное
Но вместо Python - PHP мигрируют на Golang
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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