Imp. TIỀN BOA :
Bất cứ khi nào bạn có khởi tạo hạng nặng nên được thực hiện một lần cho nhiều RDD
phần tử thay vì một lần cho mỗi RDD
phần tử và nếu việc khởi tạo này, chẳng hạn như tạo đối tượng từ thư viện bên thứ ba, không thể được tuần tự hóa (để Spark có thể truyền nó qua cụm các nút worker), sử dụng mapPartitions()
thay cho
map()
. mapPartitions()
cung cấp cho việc khởi tạo được thực hiện một lần trên mỗi tác vụ / luồng / phân vùng worker thay vì một lần cho mỗi RDD
phần tử dữ liệu : xem bên dưới.
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
})
Quý 2 không flatMap
hành xử như bản đồ hay như thế mapPartitions
nào?
Đúng. vui lòng xem ví dụ 2 của flatmap
.. nó tự giải thích.
Q1. Sự khác biệt giữa RDD map
vàmapPartitions
map
hoạt động chức năng đang được sử dụng ở cấp độ phần tử trong khi
mapPartitions
thực hiện chức năng ở cấp độ phân vùng.
Kịch bản ví dụ : nếu chúng ta có 100K phần tử trong mộtRDD
phân vùngcụ thểthì chúng ta sẽ tắt chức năng đang được sử dụng bởi phép chuyển đổi ánh xạ 100K lần khi chúng ta sử dụngmap
.
Ngược lại, nếu chúng ta sử dụng mapPartitions
thì chúng ta sẽ chỉ gọi hàm cụ thể một lần, nhưng chúng ta sẽ chuyển trong tất cả các bản ghi 100K và nhận lại tất cả các phản hồi trong một lệnh gọi hàm.
Sẽ có hiệu suất tăng do map
hoạt động trên một chức năng cụ thể rất nhiều lần, đặc biệt là nếu chức năng đó đang làm một việc đắt tiền mỗi lần mà nó sẽ không cần phải làm nếu chúng ta chuyển tất cả các yếu tố cùng một lúc (trong trường hợp mappartitions
).
bản đồ
Áp dụng một hàm biến đổi trên mỗi mục của RDD và trả về kết quả dưới dạng RDD mới.
Các biến thể liệt kê
bản đồ def [U: ClassTag] (f: T => U): RDD [U]
Thí dụ :
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
Đây là một bản đồ chuyên dụng chỉ được gọi một lần cho mỗi phân vùng. Toàn bộ nội dung của các phân vùng tương ứng có sẵn dưới dạng luồng giá trị tuần tự thông qua đối số đầu vào (Iterarator [T]). Hàm tùy chỉnh phải trả về một Iterator khác [U]. Các trình lặp kết quả kết hợp được tự động chuyển đổi thành RDD mới. Xin lưu ý rằng các bộ dữ liệu (3,4) và (6,7) bị thiếu trong kết quả sau do phân vùng chúng tôi đã chọn.
preservesPartitioning
cho biết liệu hàm đầu vào có bảo vệ bộ phân vùng hay không, false
trừ khi đây là một cặp RDD và hàm đầu vào không sửa đổi các khóa.
Các biến thể liệt kê
def mapPartitions [U: ClassTag] (f: Iterator [T] => Iterator [U], keepesPartitioning: Boolean = false): RDD [U]
ví dụ 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))
Ví dụ 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)
Chương trình trên cũng có thể được viết bằng cách sử dụng FlatMap như sau.
Ví dụ 2 sử dụng sơ đồ phẳng
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)
Phần kết luận :
mapPartitions
chuyển đổi nhanh hơn map
vì nó gọi hàm của bạn một lần / phân vùng, không phải một lần / phần tử ..
Đọc thêm: foreach Vs foreachPartitions Khi nào nên sử dụng Cái gì?