아파치 스파크 : map vs mapPartitions?


133

RDD mapmapPartitions방법 차이점은 무엇입니까 ? 그리고 flatMap좋아 map하거나 좋아 mapPartitions합니까? 감사.

(편집) 즉, 의미 적으로 또는 실행 측면에서 차이점은 무엇입니까?

  def map[A, B](rdd: RDD[A], fn: (A => B))
               (implicit a: Manifest[A], b: Manifest[B]): RDD[B] = {
    rdd.mapPartitions({ iter: Iterator[A] => for (i <- iter) yield fn(i) },
      preservesPartitioning = true)
  }

과:

  def map[A, B](rdd: RDD[A], fn: (A => B))
               (implicit a: Manifest[A], b: Manifest[B]): RDD[B] = {
    rdd.map(fn)
  }

3
아래 답변을 읽은 후 실제로 사용한 사람이 공유 한 [이 경험]을 살펴볼 수 있습니다. ( bzhangusc.wordpress.com/2014/06/19/… ) bzhangusc.wordpress.com/2014/06/19
Abhidemon

답변:


121

RDD의 map과 mapPartitions 메소드의 차이점은 무엇입니까?

메소드 은 함수를 적용하여 소스 RDD의 각 요소 를 결과 RDD의 단일 요소로 변환 합니다. mapPartitions 는 소스 RDD의 각 파티션 을 결과의 여러 요소 (아마도 없음)로 변환합니다.

그리고 flatMap은 map 또는 mapPartitions처럼 동작합니까?

flatMap 은 단일 요소 (as map) 에서 작동 하지 않으며 결과의 여러 요소 (as )를 생성합니다 mapPartitions.


3
감사합니다-맵이 셔플을 유발합니까 (아니면 파티션 수를 변경합니까)? 노드간에 데이터를 이동합니까? 노드 간 데이터 이동을 피하기 위해 mapPartitions를 사용했지만 flapMap이 그렇게 할 것인지 확실하지 않았습니다.
Nicholas White

- 당신은 소스를 보면 github.com/apache/incubator-spark/blob/...github.com/apache/incubator-spark/blob/... - 모두 mapflatMap부모와 똑같은 파티션을 가지고있다.
Alexey Romanov

13
참고로 2013 샌프란시스코 스파크 서밋 (goo.gl/JZXDCR)에서 발표자가 발표 한 프레젠테이션은 레코드 당 오버 헤드가 높은 작업이 맵 변환보다 mapPartition에서 더 잘 수행된다는 점을 강조합니다. 프레젠테이션에 따르면 새로운 작업을 설정하는 데 많은 비용이 듭니다.
Mikel Urkia

1
아주 작은 작업에서도 mapPartition을 호출하는 것이 빠르며 호출 맵보다 반복하는 것이 반대입니다. 나는 이것이지도 작업을 처리 할 언어 엔진을 시작하는 오버 헤드 일뿐이라고 가정합니다. (나는 R에있어 시작 오버 헤드가 더 클 수 있습니다.) 여러 작업을 수행하는 경우 mapPartitions가 약간 더 빠릅니다 .RDD를 한 번만 읽기 때문에 이것이 가정합니다. RDD가 RAM에 캐시되어 있어도 유형 변환으로 인한 많은 오버 헤드가 줄어 듭니다.
Bob

3
map기본적으로 함수를 가져 와서 f전달합니다 iter.map(f). 기본적으로 편리한 방법입니다 mapPartitions. 순수한 맵 스타일 변환 작업 (즉, 함수가 동일한 위치)에 성능 이점이 있거나 처리를 위해 일부 객체를 만들어야하는 경우 이러한 객체를 공유 mapPartitions할 수 있다면 유리 할 것입니다.
NightWolf

129

꼬마 도깨비. 팁 :

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?

예. flatmap.. 자체 설명 의 예 2를 참조하십시오 .

Q1. RDD의 차이 무엇 mapmapPartitions

mapmapPartitions파티션 레벨에서 기능 을 수행하는 동안 요소 별 레벨에서 사용되는 기능을 작동시킵니다 .

시나리오 예 : 특정RDD파티션에 100K 요소가있는경우 사용할 때 매핑 변환에 사용되는 함수를 100K 회 실행합니다map.

반대로 사용 mapPartitions하면 특정 함수를 한 번만 호출하지만 모든 100K 레코드를 전달하고 한 번의 함수 호출로 모든 응답을 다시 가져옵니다.

이후 성능 향상이있을 것입니다 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])를 통해 순차적 인 값 스트림으로 제공됩니다. 사용자 정의 함수는 또 다른 Iterator [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) 

결론 :

mapPartitionsmap한 번 / 요소가 아닌 한 번 / 파티션으로 함수를 호출하기 때문에 변환이 더 빠릅니다 .

추가 자료 : foreach 대 foreachPartitions 언제 사용 하는가?


4
동일한 결과를 사용 map하거나 mapPartitions달성 할 수 있음을 알고 있습니다 (질문의 두 가지 예 참조). 이 질문은 왜 당신이 다른 방법을 선택했는지에 관한 것입니다. 다른 답변의 의견은 정말 유용합니다! 또한, 당신은 언급하지 않았다 mapflatMap통과 falsepreservesPartitioning, 그리고 의미는 무엇인가.
Nicholas White

2
매번 실행 된 함수 대 함수를 한 번만 실행하면 패리티에 대한 링크가 누락되었습니다. mapPartition으로 한 번에 여러 데이터 레코드에 액세스하는 것은 매우 중요합니다. 답변을 주셔서 감사합니다
세미콜론과 덕트 테이프

1
map보다 나은 시나리오 가 mapPartitions있습니까? 경우에 mapPartitions좋은, 그래서이다, 왜 기본 맵 구현하지?
ruhong

1
@oneleggedmule : 위의 예와 같이 db 연결과 같은 리소스를 인스턴스화하는 경우 비용이 많이 드는 맵 요구 사항은 파티션 당 하나의 연결이므로 올바른 접근 방식입니다. 또한 saveAsTextFile 내부적으로 사용되는 mappartitions 참조
Ram Ghadiyaram

@oneleggedmule 필자의 관점에서 map ()은 이해하고 배우기가 더 쉬우 며 여러 언어의 일반적인 방법이기도합니다. 처음에이 Spark 특정 메소드에 익숙하지 않은 사용자는 mapPartitions ()보다 사용하기가 더 쉬울 수 있습니다. 성능 차이가 없다면 map ()을 사용하는 것을 선호합니다.
Raymond Chen

15

지도 :

  1. MapReduce의 map () 메소드와 매우 유사한 한 번에 하나의 행을 처리합니다.
  2. 매 행마다 변환에서 돌아옵니다.

맵 파티션

  1. 한 번에 전체 파티션을 처리합니다.
  2. 전체 파티션을 처리 한 후 함수에서 한 번만 리턴 할 수 있습니다.
  3. 전체 파티션을 처리 할 때까지 모든 중간 결과를 메모리에 보관해야합니다.
  4. MapReduce의 setup () map () 및 cleanup () 함수를 제공합니다

Map Vs mapPartitions http://bytepadding.com/big-data/spark/spark-map-vs-mappartitions/

Spark Map http://bytepadding.com/big-data/spark/spark-map/

Spark mapPartitions http://bytepadding.com/big-data/spark/spark-mappartitions/


2에 대해-반복자에서 반복자 변환을 수행하고 반복자를 일종의 컬렉션으로 구체화하지 않는 경우 실제로 전체 파티션을 메모리에 보유 할 필요가 없습니다. 실제로 스파크는 파티션의 일부를 디스크에 흘립니다.
ilcord

4
전체 파티션을 메모리에 보관할 필요는 없지만 결과는 나타납니다. 전체 파티션을 처리 할 때까지 결과를 반환 할 수 없습니다.
KrazyGautam
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.