Map vs mapValues ​​в Spark

В настоящее время я изучаю Spark и разрабатываю алгоритмы пользовательского машинного обучения. Мой вопрос в чем разница между .map() и .mapValues() и в каких случаях я должен использовать один вместо другого?

Ответ 1

mapValues применим только для PairRDD, что означает RDD формы RDD[(A, B)]. В этом случае mapValues работает только с этим значением (вторая часть кортежа), а map работает со всей записью (кортеж ключа и значения).

Другими словами, при заданных f: B => C и rdd: RDD[(A, B)] эти два идентичны (почти - см. комментарий внизу):

val result: RDD[(A, C)] = rdd.map { case (k, v) => (k, f(v)) }

val result: RDD[(A, C)] = rdd.mapValues(f)

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

С другой стороны, если вы тоже хотите преобразовать ключи (например, вы хотите применить f: (A, B) => C), вы просто не можете использовать mapValues, потому что он будет передавать значения только вашей функции.

Последнее различие относится к разделу: если вы применили какое-либо настраиваемое разделение к вашему RDD (например, используя partitionBy), использование map "забудет" этого парирования (результат вернется к умолчанию разделение), поскольку ключи могли быть изменены; mapValues, однако, сохраняет любой набор разделителей на RDD.

Ответ 2

map принимает функцию, которая преобразует каждый элемент коллекции:

 map(f: T => U)
RDD[T] => RDD[U]

Когда T является кортежем, мы можем действовать только на значения - не клавиши mapValues ​​принимает функцию, которая отображает значения на входах в значения на выходе: mapValues(f: V => W) Где RDD[ (K, V) ] => RDD[ (K, W) ]

Совет: используйте mapValues, когда вы можете избежать перестановки, когда данные разделяются клавишей

Ответ 3

Когда мы используем map() с Pair RDD, мы получаем доступ как к ключу, так и по значению. несколько раз нас интересует только доступ к значению (& not key). В этом случае мы можем использовать mapValues ​​() вместо map().

Пример mapValues ​​

val inputrdd = sc.parallelize(Seq(("maths", 50), ("maths", 60), ("english", 65)))
val mapped = inputrdd.mapValues(mark => (mark, 1));

//
val reduced = mapped.reduceByKey((x, y) => (x._1 + y._1, x._2 + y._2))

reduced.collect

Array [(String, (Int, Int))] = Array ((english, (65,1)), (maths, (110,2)))

val average = reduced.map { x =>
                           val temp = x._2
                           val total = temp._1
                           val count = temp._2
                           (x._1, total / count)
                           }

average.collect()

res1: Array [(String, Int)] = массив ((английский, 65), (математика, 55))