В настоящее время я изучаю Spark и разрабатываю алгоритмы пользовательского машинного обучения. Мой вопрос в чем разница между .map()
и .mapValues()
и в каких случаях я должен использовать один вместо другого?
Map vs mapValues в Spark
Ответ 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))