Sự khác biệt giữa bản đồ và bản đồ phẳng và trường hợp sử dụng tốt cho mỗi bản đồ là gì?


249

Ai đó có thể giải thích cho tôi sự khác biệt giữa map và FlatMap và trường hợp sử dụng tốt cho mỗi cái là gì không?

"Làm phẳng kết quả" nghĩa là gì? Nó tốt cho cái gì?


4
Vì bạn đã thêm thẻ Spark, tôi sẽ cho rằng bạn đang hỏi về RDD.mapRDD.flatMaptrong Apache Spark . Nói chung, các hoạt động RDD của Spark được mô hình hóa sau các hoạt động thu thập Scala tương ứng của chúng. Các câu trả lời trong stackoverflow.com/q/1059776/590203 , thảo luận về sự khác biệt giữa mapflatMaptrong Scala, có thể hữu ích cho bạn.
Josh Rosen

1
Hầu hết các ví dụ ở đây dường như cho rằng FlatMap chỉ hoạt động trên bộ sưu tập, đây không phải là trường hợp.
Boon

Câu trả lời:


195

Dưới đây là một ví dụ về sự khác biệt, như một spark-shellphiên:

Đầu tiên, một số dữ liệu - hai dòng văn bản:

val rdd = sc.parallelize(Seq("Roses are red", "Violets are blue"))  // lines

rdd.collect

    res0: Array[String] = Array("Roses are red", "Violets are blue")

Bây giờ, mapbiến đổi một RDD có độ dài N thành một RDD khác có độ dài N.

Ví dụ: nó ánh xạ từ hai dòng thành hai độ dài dòng:

rdd.map(_.length).collect

    res1: Array[Int] = Array(13, 16)

Nhưng flatMap(nói một cách lỏng lẻo) biến đổi một RDD có độ dài N thành một tập hợp các bộ sưu tập N, sau đó làm phẳng chúng thành một RDD kết quả duy nhất.

rdd.flatMap(_.split(" ")).collect

    res2: Array[String] = Array("Roses", "are", "red", "Violets", "are", "blue")

Chúng tôi có nhiều từ trên mỗi dòng và nhiều dòng, nhưng chúng tôi kết thúc với một mảng đầu ra của các từ

Chỉ để minh họa điều đó, FlatMapping từ một tập hợp các dòng đến một tập hợp các từ trông giống như:

["aa bb cc", "", "dd"] => [["aa","bb","cc"],[],["dd"]] => ["aa","bb","cc","dd"]

Do đó, RDD đầu vào và đầu ra thường sẽ có các kích cỡ khác nhau cho flatMap.

Nếu chúng tôi đã cố gắng sử dụng mapvới splitchức năng của mình, chúng tôi đã kết thúc với các cấu trúc lồng nhau (RDD gồm các mảng từ, với loại RDD[Array[String]]) vì chúng tôi phải có chính xác một kết quả cho mỗi đầu vào:

rdd.map(_.split(" ")).collect

    res3: Array[Array[String]] = Array(
                                     Array(Roses, are, red), 
                                     Array(Violets, are, blue)
                                 )

Cuối cùng, một trường hợp đặc biệt hữu ích là ánh xạ với một hàm có thể không trả về câu trả lời và do đó trả về một Option. Chúng ta có thể sử dụng flatMapđể lọc ra các phần tử trả về Nonevà trích xuất các giá trị từ các phần tử trả về a Some:

val rdd = sc.parallelize(Seq(1,2,3,4))

def myfn(x: Int): Option[Int] = if (x <= 2) Some(x * 10) else None

rdd.flatMap(myfn).collect

    res3: Array[Int] = Array(10,20)

(lưu ý ở đây rằng Tùy chọn hoạt động giống như một danh sách có một phần tử hoặc phần tử 0)


1
Sẽ gọi phân chia trong bản đồ cung cấp ["a b c", "", "d"] => [["a","b","c"],[],["d"]]?
dùng2635088

1
Có - (nhưng lưu ý rằng ký hiệu không chính thức của tôi chỉ nhằm chỉ ra một bộ sưu tập thuộc loại nào đó - thực tế là ánh xạ splitqua danh sách các Chuỗi sẽ tạo ra Danh sách các mảng)
DNA

2
Cảm ơn bạn đã viết nó lên, đây là lời giải thích tốt nhất mà tôi đã đọc để phân biệt sự khác biệt giữa cùng
Rajiv

97

Nói chung, chúng tôi sử dụng ví dụ đếm từ trong hadoop. Tôi sẽ đưa các trường hợp sử dụng cùng và sẽ sử dụng mapflatMapvà chúng ta sẽ thấy sự khác biệt như thế nào nó được xử lý dữ liệu.

Dưới đây là tệp dữ liệu mẫu.

hadoop is fast
hive is sql on hdfs
spark is superfast
spark is awesome

Các tập tin trên sẽ được phân tích cú pháp bằng cách sử dụng mapflatMap.

Sử dụng map

>>> wc = data.map(lambda line:line.split(" "));
>>> wc.collect()
[u'hadoop is fast', u'hive is sql on hdfs', u'spark is superfast', u'spark is awesome']

Đầu vào có 4 dòng và kích thước đầu ra cũng là 4, tức là N phần tử ==> N phần tử.

Sử dụng flatMap

>>> fm = data.flatMap(lambda line:line.split(" "));
>>> fm.collect()
[u'hadoop', u'is', u'fast', u'hive', u'is', u'sql', u'on', u'hdfs', u'spark', u'is', u'superfast', u'spark', u'is', u'awesome']

Đầu ra khác với bản đồ.


Hãy gán 1 làm giá trị cho mỗi khóa để lấy số từ.

  • fm: RDD được tạo bằng cách sử dụng flatMap
  • wc: RDD được tạo bằng cách sử dụng map
>>> fm.map(lambda word : (word,1)).collect()
[(u'hadoop', 1), (u'is', 1), (u'fast', 1), (u'hive', 1), (u'is', 1), (u'sql', 1), (u'on', 1), (u'hdfs', 1), (u'spark', 1), (u'is', 1), (u'superfast', 1), (u'spark', 1), (u'is', 1), (u'awesome', 1)]

Trong khi đó flatMaptrên RDD wcsẽ cung cấp đầu ra không mong muốn dưới đây:

>>> wc.flatMap(lambda word : (word,1)).collect()
[[u'hadoop', u'is', u'fast'], 1, [u'hive', u'is', u'sql', u'on', u'hdfs'], 1, [u'spark', u'is', u'superfast'], 1, [u'spark', u'is', u'awesome'], 1]

Bạn không thể có được số từ nếu mapđược sử dụng thay vì flatMap.

Theo định nghĩa, sự khác biệt giữa mapflatMaplà:

map: Nó trả về một RDD mới bằng cách áp dụng hàm đã cho cho từng phần tử của RDD. Chức năng maptrả về chỉ một mục.

flatMap: Tương tự map, nó trả về một RDD mới bằng cách áp dụng một hàm cho từng phần tử của RDD, nhưng đầu ra bị làm phẳng.


14
tôi cảm thấy câu trả lời này tốt hơn câu trả lời được chấp nhận.
Krishna

15
Tại sao trên trái đất bạn sẽ tạo ảnh chụp màn hình không thể đọc được, khi bạn chỉ có thể sao chép dán văn bản đầu ra?
nbubis

Vì vậy, FlatMap () là map () + "flatten" và tôi biết nó không có ý nghĩa gì nhiều nhưng có loại hàm "flatten" nào mà chúng ta có thể sử dụng sau map () không?
burakongun

2
Mã của bạn có một lỗi đánh máy sai. Kết quả của .map(lambda line:line.split(" "))không phải là một chuỗi các chuỗi. Bạn nên thay đổi data.collect() thành wc.collectvà bạn sẽ thấy một mảng các mảng.
swdev

1
yeah, nhưng kết quả của lệnh vẫn sai. bạn đã chạy wc.collect()chưa
swdev

18

Nếu bạn đang hỏi sự khác biệt giữa RDD.map và RDD.flatMap trong Spark, bản đồ sẽ biến đổi RDD có kích thước N thành một kích thước N khác. ví dụ.

myRDD.map(x => x*2)

ví dụ: nếu myRDD bao gồm Đôi.

Trong khi FlatMap có thể biến đổi RDD thành bao phấn có kích thước khác: vd.:

myRDD.flatMap(x =>new Seq(2*x,3*x))

sẽ trả về RDD có kích thước 2 * N hoặc

myRDD.flatMap(x =>if x<10 new Seq(2*x,3*x) else new Seq(x) )

17

Nó hiểu rõ câu hỏi ban đầu của bạn: ý của bạn là gì?

Khi bạn sử dụng FlatMap, bộ sưu tập "đa chiều" sẽ trở thành bộ sưu tập "một chiều" .

val array1d = Array ("1,2,3", "4,5,6", "7,8,9")  
//array1d is an array of strings

val array2d = array1d.map(x => x.split(","))
//array2d will be : Array( Array(1,2,3), Array(4,5,6), Array(7,8,9) )

val flatArray = array1d.flatMap(x => x.split(","))
//flatArray will be : Array (1,2,3,4,5,6,7,8,9)

Bạn muốn sử dụng FlatMap khi,

  • chức năng bản đồ của bạn dẫn đến việc tạo các cấu trúc nhiều lớp
  • nhưng tất cả những gì bạn muốn là một cấu trúc đơn giản - phẳng - một chiều, bằng cách loại bỏ TẤT CẢ các nhóm bên trong

15

Sử dụng test.mdlàm ví dụ:

➜  spark-1.6.1 cat test.md
This is the first line;
This is the second line;
This is the last line.

scala> val textFile = sc.textFile("test.md")
scala> textFile.map(line => line.split(" ")).count()
res2: Long = 3

scala> textFile.flatMap(line => line.split(" ")).count()
res3: Long = 15

scala> textFile.map(line => line.split(" ")).collect()
res0: Array[Array[String]] = Array(Array(This, is, the, first, line;), Array(This, is, the, second, line;), Array(This, is, the, last, line.))

scala> textFile.flatMap(line => line.split(" ")).collect()
res1: Array[String] = Array(This, is, the, first, line;, This, is, the, second, line;, This, is, the, last, line.)

Nếu bạn sử dụng mapphương thức, bạn sẽ nhận được các dòng test.md, đối với flatMapphương thức, bạn sẽ nhận được số lượng từ.

Các mapphương pháp tương tự như flatMap, họ là tất cả trở lại một RDD mới. mapphương thức thường sử dụng trả về một RDD mới, flatMapphương thức thường sử dụng các từ chia.


9

maptrả về RDD với số phần tử bằng nhau trong khi flatMapcó thể không.

Một trường hợp sử dụng ví dụ đểflatMap Lọc ra dữ liệu bị thiếu hoặc không chính xác.

Một trường hợp sử dụng ví dụ chomap Sử dụng trong nhiều trường hợp trong đó số lượng phần tử đầu vào và đầu ra là như nhau.

số.csv

1
2
3
-
4
-
5

map.py thêm tất cả các số trong add.csv.

from operator import *

def f(row):
  try:
    return float(row)
  except Exception:
    return 0

rdd = sc.textFile('a.csv').map(f)

print(rdd.count())      # 7
print(rdd.reduce(add))  # 15.0

FlatMap.py sử dụng flatMapđể lọc ra dữ liệu bị thiếu trước khi bổ sung. Số lượng ít hơn được thêm vào so với phiên bản trước.

from operator import *

def f(row):
  try:
    return [float(row)]
  except Exception:
    return []

rdd = sc.textFile('a.csv').flatMap(f)

print(rdd.count())      # 5
print(rdd.reduce(add))  # 15.0

8

map và FlatMap tương tự nhau, theo nghĩa là chúng lấy một dòng từ RDD đầu vào và áp dụng một hàm trên nó. Cách chúng khác nhau là hàm trong bản đồ chỉ trả về một phần tử, trong khi hàm trong FlatMap có thể trả về danh sách các phần tử (0 trở lên) dưới dạng iterator.

Ngoài ra, đầu ra của FlatMap được làm phẳng. Mặc dù hàm trong FlatMap trả về một danh sách các phần tử, FlatMap trả về một RDD có tất cả các phần tử từ danh sách theo cách phẳng (không phải là danh sách).


7

tất cả các ví dụ đều tốt .... Dưới đây là hình ảnh minh họa đẹp mắt ... nguồn lịch sự: DataFlair đào tạo tia lửa

Bản đồ: Bản đồ là một hoạt động chuyển đổi trong Apache Spark. Nó áp dụng cho từng phần tử của RDD và nó trả về kết quả là RDD mới. Trong Bản đồ, nhà phát triển hoạt động có thể xác định logic nghiệp vụ tùy chỉnh của riêng mình. Logic tương tự sẽ được áp dụng cho tất cả các yếu tố của RDD.

mapHàm Spark RDD lấy một phần tử làm quy trình đầu vào theo mã tùy chỉnh (được chỉ định bởi nhà phát triển) và trả về một phần tử tại một thời điểm. Bản đồ biến đổi một RDD có độ dài N thành một RDD khác có độ dài N. Các RDD đầu vào và đầu ra thường sẽ có cùng số lượng bản ghi.

nhập mô tả hình ảnh ở đây

Ví dụ về mapviệc sử dụng scala:

val x = spark.sparkContext.parallelize(List("spark", "map", "example",  "sample", "example"), 3)
val y = x.map(x => (x, 1))
y.collect
// res0: Array[(String, Int)] = 
//    Array((spark,1), (map,1), (example,1), (sample,1), (example,1))

// rdd y can be re writen with shorter syntax in scala as 
val y = x.map((_, 1))
y.collect
// res1: Array[(String, Int)] = 
//    Array((spark,1), (map,1), (example,1), (sample,1), (example,1))

// Another example of making tuple with string and it's length
val y = x.map(x => (x, x.length))
y.collect
// res3: Array[(String, Int)] = 
//    Array((spark,5), (map,3), (example,7), (sample,6), (example,7))

Bản đồ phẳng :

A flatMaplà một hoạt động chuyển đổi. Nó áp dụng cho từng phần tử của RDD và nó trả về kết quả như mới RDD. Nó tương tự như Map, nhưng FlatMap cho phép trả về 0, 1 hoặc nhiều phần tử từ chức năng bản đồ. Trong hoạt động FlatMap, nhà phát triển có thể xác định logic nghiệp vụ tùy chỉnh của riêng mình. Logic tương tự sẽ được áp dụng cho tất cả các yếu tố của RDD.

"Làm phẳng kết quả" nghĩa là gì?

Hàm FlatMap lấy một phần tử làm quy trình nhập theo mã tùy chỉnh (được chỉ định bởi nhà phát triển) và trả về 0 hoặc nhiều phần tử tại một thời điểm. flatMap() biến đổi một RDD có độ dài N thành một RDD khác có độ dài M.

nhập mô tả hình ảnh ở đây

Ví dụ về flatMapviệc sử dụng scala:

val x = spark.sparkContext.parallelize(List("spark flatmap example",  "sample example"), 2)

// map operation will return Array of Arrays in following case : check type of res0
val y = x.map(x => x.split(" ")) // split(" ") returns an array of words
y.collect
// res0: Array[Array[String]] = 
//  Array(Array(spark, flatmap, example), Array(sample, example))

// flatMap operation will return Array of words in following case : Check type of res1
val y = x.flatMap(x => x.split(" "))
y.collect
//res1: Array[String] = 
//  Array(spark, flatmap, example, sample, example)

// RDD y can be re written with shorter syntax in scala as 
val y = x.flatMap(_.split(" "))
y.collect
//res2: Array[String] = 
//  Array(spark, flatmap, example, sample, example)

5

Sự khác biệt có thể được nhìn thấy từ bên dưới mã pyspark mẫu:

rdd = sc.parallelize([2, 3, 4])
rdd.flatMap(lambda x: range(1, x)).collect()
Output:
[1, 1, 2, 1, 2, 3]


rdd.map(lambda x: range(1, x)).collect()
Output:
[[1], [1, 2], [1, 2, 3]]

3

Flatmap và Map đều biến đổi bộ sưu tập.

Sự khác biệt:

map (func)
Trả về một tập dữ liệu phân tán mới được hình thành bằng cách chuyển từng phần tử của nguồn thông qua hàm func.

FlatMap (func)
Tương tự như bản đồ, nhưng mỗi mục đầu vào có thể được ánh xạ thành 0 hoặc nhiều mục đầu ra (vì vậy func nên trả về Seq thay vì một mục duy nhất).

Hàm biến đổi:
map : Một phần tử trong -> một phần tử ra.
FlatMap : Một phần tử trong -> 0 hoặc nhiều phần tử ra (một bộ sưu tập).


3

RDD.map trả về tất cả các phần tử trong mảng đơn

RDD.flatMap trả về các phần tử trong Mảng của mảng

giả sử chúng ta có văn bản trong tệp text.txt như

Spark is an expressive framework
This text is to understand map and faltMap functions of Spark RDD

Sử dụng bản đồ

val text=sc.textFile("text.txt").map(_.split(" ")).collect

đầu ra:

text: **Array[Array[String]]** = Array(Array(Spark, is, an, expressive, framework), Array(This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD))

Sử dụng bản đồ phẳng

val text=sc.textFile("text.txt").flatMap(_.split(" ")).collect

đầu ra:

 text: **Array[String]** = Array(Spark, is, an, expressive, framework, This, text, is, to, understand, map, and, faltMap, functions, of, Spark, RDD)

2

Đối với tất cả những người đã muốn liên quan đến PySpark:

Chuyển đổi ví dụ: FlatMap

>>> a="hello what are you doing"
>>> a.split()

['xin chào bạn đang làm gì đó']

>>> b=["hello what are you doing","this is rak"]
>>> b.split()

TracBack (cuộc gọi gần đây nhất vừa qua): Tệp "", dòng 1, trong AttributionError: đối tượng 'list' không có thuộc tính 'split'

>>> rline=sc.parallelize(b)
>>> type(rline)

>>> def fwords(x):
...     return x.split()


>>> rword=rline.map(fwords)
>>> rword.collect()

[['xin chào', 'cái gì', 'là', 'bạn', 'đang làm'], ['này', 'là', 'rak']]

>>> rwordflat=rline.flatMap(fwords)
>>> rwordflat.collect()

['xin chào', 'cái gì', 'là', 'bạn', 'đang làm', 'cái này', 'là', 'rak']

Hy vọng nó giúp :)


2

map: Nó trả về một cái mới RDDbằng cách áp dụng một hàm cho mỗi phần tử của RDD. Hàm trong .map chỉ có thể trả về một mục.

flatMap: Tương tự như bản đồ, nó trả về một cái mới RDDbằng cách áp dụng một hàm cho từng phần tử của RDD, nhưng đầu ra bị làm phẳng.

Ngoài ra, hàm trong flatMapcó thể trả về danh sách các phần tử (0 trở lên)

Ví dụ:

sc.parallelize([3,4,5]).map(lambda x: range(1,x)).collect()

Đầu ra: [[1, 2], [1, 2, 3], [1, 2, 3, 4]]

sc.parallelize([3,4,5]).flatMap(lambda x: range(1,x)).collect()

Đầu ra: thông báo o / p được làm phẳng trong một danh sách duy nhất [1, 2, 1, 2, 3, 1, 2, 3, 4]

Nguồn: https://www.linkedin.com/pulse/difference-b between-map-flmapmap-transformations-spark-pyspark-pandey/



-1

Sự khác biệt về đầu ra của bản đồ và bản đồ phẳng:

1.flatMap

val a = sc.parallelize(1 to 10, 5)

a.flatMap(1 to _).collect()

Đầu ra:

 1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 7, 1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

2 . map:

val a = sc.parallelize(List("dog", "salmon", "salmon", "rat", "elephant"), 3)

val b = a.map(_.length).collect()

Đầu ra:

3 6 6 3 8

-1
  • map (func) Trả về một tập dữ liệu phân tán mới được hình thành bằng cách chuyển từng phần tử của nguồn thông qua hàm func kê khai.so map () là một số hạng

những lời than vãn

  • FlatMap (func) Tương tự như bản đồ, nhưng mỗi mục đầu vào có thể được ánh xạ thành 0 hoặc nhiều mục đầu ra để func nên trả về một Chuỗi thay vì một mục duy nhất.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.