2015-12-20 8 views
2

(EDIT: посмотрев, где этот вопрос начался, он действительно оказался в гораздо лучшем месте. Он оказался хорошим ресурсом на границах размеров RDD в Spark при настройке через SparkContext.parallelize() по сравнению с фактическим размером лимиты RDD, а также раскрыты некоторые аргументы для распараллеливания(), которые не найдены в пользовательских документах. Особенно обратите внимание на комментарии нуль323 и его принятый ответ.)Настройка искровых RDD-размеров: Кастинг длинный до Double внутри 10^9 + для цикла, действительно плохая идея?

Ничего нового под солнцем, но я не могу найти этот вопрос уже задан .. . Вопрос заключается в том, как неправильно/нецелесообразно/нецелесообразно запускать листинг внутри большого цикла for в Java.

Я хочу запустить цикл for для инициализации Arraylist, прежде чем передать его методу SparkContext.parallelize(). Я нашел передачу неинициализированного массива, чтобы Spark мог вызвать пустую ошибку коллекции.

Я видел много сообщений о том, как плавают и удваиваются плохие идеи, как счетчики, я получаю это, просто кажется, что это тоже плохая идея? Как должен быть лучший способ?

numListLen будет 10^6 * 10^3 на данный момент, возможно, как большой на 10^12 в какой-то момент.

List<Double> numList = new ArrayList<Double>(numListLen); 
    for (long i = 0; i < numListLen; i++) { 
     numList.add((double) i); 
    } 

Мне бы хотелось услышать, где именно этот код падает и может быть улучшен. Я студент-младший студент CS, поэтому я еще не видел всех углов хаха. Here's a CMU page seemingly approving this approach in C с использованием неявного литья.


Только для фона, numList собирается передать Спарк, чтобы сказать ему, сколько раз, чтобы запустить моделирование и создать RDD с результатами, как это:

JavaRDD DataSet = jsc.parallelize (numList, SLICES_AKA_PARTITIONS);

// the function will be applied to each member of dataSet 
    Double count = dataSet.map(new Function<Double, Double>() {... 

(На самом деле я хотел бы, чтобы запустить этот ArrayList создание через Спарк, но это, кажется, не принимают достаточно времени, чтобы гарантировать, что 5 секунд на моем i5 двухъядерных, но если увеличить до 10^12, то ... дольше)

+1

_ Мне бы очень хотелось услышать, где именно этот код падает. - для начала вы не можете выделить 'ArrayList' больше, чем' Integer.MAX_VALUE'. – zero323

+0

О, да, он перевернулся и пытается назначить отрицательную длину ArrayList ... очень полезная обратная связь, я знал, что если бы я привел Искра на картинке, я мог бы получить от вас ответ. Спасибо, и если вы хотите ответить на этот вопрос и решить основной вопрос о том, есть ли более эффективный способ бросить, я бы принял ответ. – JimLohse

+0

И, я полагаю, в этом ключе максимальная «длина» RDD - это максимальная длина коллекции scala? Per Spark Java docs для parallelize() aka makeRDD() - public RDD makeRDD (scala.collection.Seq seq ... Я думаю, что это отдельный вопрос, который будет искать это и спросить, не могу ли я его найти : max length of spark RDD – JimLohse

ответ

2

davidstenberg и Konstantinos Chalkias уже охвачены проблемы, связанные с использованием Doubles как счетчики и radiodef отметил проблему, связанную с созданием объектов в цикле, но в конце дня вы просто не можете выделить ArrayListInteger.MAX_VALUE больше. Кроме того, даже с элементами 2 это довольно большой объект, а сериализация и сетевой трафик могут добавить существенные накладные расходы на вашу работу.

Там несколько способов, вы можете справиться с этим:

  • используя SparkContext.range метод:

    range(start: Long, end: Long, 
        step: Long = 1, numSlices: Int = defaultParallelism) 
    
  • инициализацией RDD с помощью объекта диапазона. В PySpark вы можете использовать или range (xrange в Python 2), в Scala Range:

    val rdd = sc.parallelize(1L to Long.MaxValue) 
    

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

    В Java 8 LongStream.range может работать одинаково, но похоже, что JavaSparkContext не предоставляет требуемые конструкторы. Если вы достаточно храбры, чтобы иметь дело со всеми синглтонами и implicits, вы можете напрямую использовать Scala Range, и если нет, вы можете просто написать дружественную Java-оболочку.

  • инициализировать RDD используя emptyRDD метод/небольшое количество семян и заполнить его с помощью mapPartitions(WithIndex)/flatMap.См., Например, Creating array per Executor in Spark and combine into RDD

    С небольшим количеством творчества вы можете создать бесконечное количество элементов таким образом (Spark FlatMap function for huge lists).

  • данный конкретный вариант использования вы также должны посмотреть на mllib.random.RandomRDDs. Он предоставляет количество полезных генераторов из разных распределений.

2

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

Одна проблема с двойным или поплавком в качестве счетчика циклов заключается в том, что точность с плавающей запятой оставит пробелы в представленной последовательности чисел. Можно добраться до места в пределах допустимого диапазона числа с плавающей запятой, где добавление одного падает ниже точности отображаемого числа (требуется 16 цифр, если формат с плавающей запятой поддерживает только 15 цифр). Если бы ваш цикл прошел через такую ​​точку при нормальном выполнении, он не увеличивался бы и не продолжался бы в бесконечном цикле.

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

Ни одна из этих проблем не возникает с вашим длинным, как счетчик циклов. Так что наслаждайтесь тем, что сделали это правильно.

+0

за комментарий к zero323 выше Я пропустил что-то LOL Я ценю ответ, хотя, полезная информация – JimLohse

2

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

Тем не менее, двойные номера из 2^52..2^53 представляют целую часть правильно, но после того, как 2^53, не всегда можно достичь целое частей точности.

На практике и потому, что ваш шаг петли , вы бы не испытывать каких-либо проблем до 9,007,199,254,740,992 если вы использовали double в качестве счетчика и, таким образом, избегая литья (вы не можете избежать бокс, хотя от double до Double).

Выполнение простого приращения теста; вы увидите, что 9 007 199 254 740 995 является первым ложным положительным!

FYI: для float номеров, вы безопасны инкрементацию до 2^24 = 16777216article вы предоставили, она использует номер 100000001.0f> 16777216 представить проблему).

+0

Спасибо за анализ, нуль323 на самом деле попал в гвоздь на голове – JimLohse