В настоящее время я изучаю 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))