Недавно в этом тикете сообщалось, что при настройке модели ALS с использованием Spark MLlib может возникнуть исключение ArrayIndexOutOfBoundsException. Это трудно воспроизвести, и кажется, что решить эту проблему можно только при подгонке модели ALS к большому количеству рейтинговых данных.

Так уж получилось, что такое же исключение было замечено в нашей работе Spark. Я потратил много времени на изучение деталей реализации ALS в Spark MLlib. Единственный способ столкнуться с этой проблемой ArrayIndexOutOfBoundsException в коде Spark ALS — это то, что код создает неправильную маршрутизацию оценок между пользователями и элементами в рейтинге обучения. После изучения деталей в течение нескольких дней я не вижу в этом ничего плохого.

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

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

Почему эта проблема затрагивает ALS в Spark MLlib? Это связано с тем, как ALS реализован в Spark MLlib. Код Spark ALS вычисляет информацию о маршрутизации между пользователями и элементами среди рейтинговых данных. Похоже, что пользователь 100 оценивает элемент 20, 25, 50, 60, а элемент 60 оценивается пользователем 5, 20, 100, 200. Таким образом, факторы пользователя и элемента могут быть разделены на соответствующие разделы для подгонки.

Информация о маршрутизации для пользователей и элементов рассчитывается на основе входного рейтинга RDD по отдельности. Таким образом, когда происходит сбой выборки и необходимо перезапустить некоторые задачи во входном RDD, это изменяет часть информации о маршрутизации. Когда код ALS запускается для сопоставления идентификатора пользователя или элемента с факторами, вероятно, происходит несоответствие и возникает исключение ArrayIndexOutOfBoundsException.

Чтобы решить эту проблему, нам нужно сделать ввод RDD для ALS детерминированным. Очень простой способ сделать это — поставить контрольную точку на RDD. Поскольку контрольная точка сохраняет RDD в надежном хранилище, таком как HDFS, повторный запуск RDD с контрольной точкой просто считывает необходимые разделы с диска.