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ì?
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ì?
Câu trả lời:
Dưới đây là một ví dụ về sự khác biệt, như một spark-shell
phiê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ờ, map
biế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 map
với split
chứ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ề None
và 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)
["a b c", "", "d"] => [["a","b","c"],[],["d"]]
?
split
qua danh sách các Chuỗi sẽ tạo ra Danh sách các mảng)
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 map
và flatMap
và 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 map
và flatMap
.
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ử.
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 đó flatMap
trên RDD wc
sẽ 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 map
và flatMap
là:
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ăngmap
trả 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.
.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.collect
và bạn sẽ thấy một mảng các mảng.
wc.collect()
chưa
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) )
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,
Sử dụng test.md
là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 map
phương thức, bạn sẽ nhận được các dòng test.md
, đối với flatMap
phương thức, bạn sẽ nhận được số lượng từ.
Các map
phương pháp tương tự như flatMap
, họ là tất cả trở lại một RDD mới. map
phương thức thường sử dụng trả về một RDD mới, flatMap
phương thức thường sử dụng các từ chia.
map
trả về RDD với số phần tử bằng nhau trong khi flatMap
có 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
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).
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.
map
Hà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.
Ví dụ về map
việ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 flatMap
là 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.
Ví dụ về flatMap
việ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)
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]]
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).
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)
Đố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 :)
map
: Nó trả về một cái mới RDD
bằ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 RDD
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.
Ngoài ra, hàm trong flatMap
có 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]
bản đồ :
là một phương thức bậc cao hơn lấy một hàm làm đầu vào và áp dụng nó cho từng phần tử trong RDD nguồn.
Bản đồ phẳng:
một phương thức bậc cao và hoạt động chuyển đổi có chức năng đầu vào.
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
những lời than vãn
RDD.map
vàRDD.flatMap
trong 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ữamap
vàflatMap
trong Scala, có thể hữu ích cho bạn.