Імп. ПОРАДА :
Кожен раз, коли у вас є ініціалізація важкої ваги, яку слід робити один раз для багатьох RDDелементів, а не один раз на RDDелемент, і якщо ця ініціалізація, наприклад створення об'єктів із сторонньої бібліотеки, не може бути серіалізована (щоб Spark міг передати її через кластер до робочі вузли), використовувати mapPartitions()замість
map(). mapPartitions()передбачає, що ініціалізація повинна бути виконана один раз для кожного робочого завдання / потоку / розділу замість одного разу на RDDелемент даних, наприклад: див. нижче.
val newRd = myRdd.mapPartitions(partition => {
val connection = new DbConnection /*creates a db connection per partition*/
val newPartition = partition.map(record => {
readMatchingFromDB(record, connection)
}).toList // consumes the iterator, thus calls readMatchingFromDB
connection.close() // close dbconnection here
newPartition.iterator // create a new iterator
})
Q2. чи flatMapповодиться як карта чи як mapPartitions?
Так. дивіться, будь ласка, приклад 2 flatmap.. її пояснення.
Q1. Яка різниця між RDD mapтаmapPartitions
mapпрацює функція, що використовується на рівні елемента, в той час як
mapPartitionsвиконує функцію на рівні розділу.
Приклад Сценарій : якщо в конкретномуRDDрозділіу нас є 100K елементів,тоді ми знімемо функцію, яку використовує трансформація відображення 100K разів, коли ми використовуємоmap.
І навпаки, якщо ми використовуємо, mapPartitionsто ми будемо викликати певну функцію лише один раз, але ми передамо всі записи в 100 К і отримаємо всі відповіді за один виклик функції.
Збільшується продуктивність, оскільки mapпрацює над певною функцією стільки разів, особливо якщо функція робить що-небудь дороге, що не потрібно було б робити, якщо ми передамо всі елементи одразу (у випадку mappartitions).
карта
Застосовує функцію перетворення до кожного елемента RDD і повертає результат як новий RDD.
Варіанти лістингу
визначити карту [U: ClassTag] (f: T => U): RDD [U]
Приклад:
val a = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3)
val b = a.map(_.length)
val c = a.zip(b)
c.collect
res0: Array[(String, Int)] = Array((dog,3), (salmon,6), (salmon,6), (rat,3), (elephant,8))
mapPartitions
Це спеціалізована карта, яка викликається лише один раз для кожного розділу. Весь вміст відповідних розділів доступний у вигляді послідовного потоку значень через вхідний аргумент (Iterarator [T]). Спеціальна функція повинна повертати ще один ітератор [U]. Об'єднані ітератори результатів автоматично перетворюються на новий RDD. Зверніть увагу, що кортежі (3,4) та (6,7) відсутні в наступному результаті через обраний нами розділ.
preservesPartitioningвказує, чи зберігає функція введення частку, яка повинна бути, falseякщо це не пара RDD і функція введення не змінює клавіші.
Варіанти лістингу
def mapPartitions [U: ClassTag] (f: Ітератор [T] => Ітератор [U], зберігаєПереділення: Булева = хибна): RDD [U]
Приклад 1
val a = sc.parallelize(1 to 9, 3)
def myfunc[T](iter: Iterator[T]) : Iterator[(T, T)] = {
var res = List[(T, T)]()
var pre = iter.next
while (iter.hasNext)
{
val cur = iter.next;
res .::= (pre, cur)
pre = cur;
}
res.iterator
}
a.mapPartitions(myfunc).collect
res0: Array[(Int, Int)] = Array((2,3), (1,2), (5,6), (4,5), (8,9), (7,8))
Приклад 2
val x = sc.parallelize(List(1, 2, 3, 4, 5, 6, 7, 8, 9,10), 3)
def myfunc(iter: Iterator[Int]) : Iterator[Int] = {
var res = List[Int]()
while (iter.hasNext) {
val cur = iter.next;
res = res ::: List.fill(scala.util.Random.nextInt(10))(cur)
}
res.iterator
}
x.mapPartitions(myfunc).collect
// some of the number are not outputted at all. This is because the random number generated for it is zero.
res8: Array[Int] = Array(1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 5, 7, 7, 7, 9, 9, 10)
Вищеописану програму також можна записати за допомогою flatMap наступним чином.
Приклад 2 з використанням плоскої карти
val x = sc.parallelize(1 to 10, 3)
x.flatMap(List.fill(scala.util.Random.nextInt(10))(_)).collect
res1: Array[Int] = Array(1, 2, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10)
Висновок:
mapPartitionsперетворення відбувається швидше, ніж mapоскільки воно викликає вашу функцію один раз / розділ, а не один раз / елемент ..
Подальше читання: foreach Vs foreachPartitions Коли користуватися Що?