Learning Spark筆記3-傳遞函數給Spark
傳遞函數給Spark
大多數的Spark轉換和一些動作都依賴傳遞函數計算數據。
1.Python
在Python中我們使用3種形式傳遞函數到Spark。對於較短的函數,我們可以傳lambda表達式、通過頂層函數傳遞或定義本地函數。
Example 3-18. Passing functions in Python
word = rdd.filter(lambda s: "error" in s)
def containsError(s):
return "error" in s
word = rdd.filter(containsError)
有一件事需要注意的是,它會序列化函數中的對象。當你傳遞一個函數時,如果該函數是一個對象的成員或包含屬性的引用(例如,self.field),Spark會將整個對象發送給工作節點,這樣的對象肯定要比你需要信息大的多。有些時候,這也可以能會引起你的程序失敗,
Example 3-19. Passing a function with field references (don’t do this!)
class SearchFunctions(object):
def __init__(self, query):
elf.query = query
def isMatch(self, s):
return self.query in s
def getMatchesFunctionReference(self, rdd):
# Problem: references all of "self" in "self.isMatch"
return rdd.filter(self.isMatch)
def getMatchesMemberReference(self, rdd):
# Problem: references all of "self" in "self.query"
return rdd.filter(lambda x: self.query in x)
相反的,只需將您需要的字段從您的對象中提取到一個局部變量中,並將其傳入,就像我們所做的那樣。
class WordFunctions(object):
...
def getMatchesNoReference(self, rdd):
# Safe: extract only the field we need into a local variable
query = self.query
return rdd.filter(lambda x: query in x)
2.Scala
在Scala中,我們可以傳遞定義的內聯函數,引用方法或static。
Example 3-21. Scala function passing
class SearchFunctions(val query: String) {
def isMatch(s: String): Boolean = {
s.contains(query)
}
def getMatchesFunctionReference(rdd: RDD[String]): RDD[String] = {
// Problem: "isMatch" means "this.isMatch", so we pass all of "this"
rdd.map(isMatch)
}
def getMatchesFieldReference(rdd: RDD[String]): RDD[String] = {
// Problem: "query" means "this.query", so we pass all of "this"
rdd.map(x => x.split(query))
}
def getMatchesNoReference(rdd: RDD[String]): RDD[String] = {
// Safe: extract just the field we need into a local variable
val query_ = this.query
rdd.map(x => x.split(query_))
}
}
在Scala中如果出現NotSerializableException,通常都是由一個非序列化類中的方法或屬性引用導致的。請注意,傳遞本地可序列化變量或頂層對象的成員函數是安全的。
3.Java
Example 3-22. Java function passing with anonymous inner class
RDD<String> errors = lines.filter(new Function<String, Boolean>() {
public Boolean call(String x) {
return x.contains("error");
}
});
Example 3-23. Java function passing with named class
class ContainsError implements Function<String, Boolean>() {
public Boolean call(String x) {
return x.contains("error");
}
}
RDD<String> errors = lines.filter(new ContainsError());
編程風格是個人偏好,但是我們發現,頂層命名函數用於組織大型程序通常比較簡單,頂級函數的另一個優點是可以給它們構造函數參數
Example 3-24. Java function class with parameters
class Contains implements Function<String, Boolean>() {
private String query;
public Contains(String query) { this.query = query; }
public Boolean call(String x) { return x.contains(query); }
}
RDD<String> errors = lines.filter(new Contains("error"));
在Java 8中,你也可以使用lambda表達式
Example 3-25. Java function passing with lambda expression in Java 8
RDD<String> errors = lines.filter(s -> s.contains("error"));
大多數的Spark轉換和一些動作都依賴傳遞函數計算數據。
1.Python
在Python中我們使用3種形式傳遞函數到Spark。對於較短的函數,我們可以傳lambda表達式、通過頂層函數傳遞或定義本地函數。
Example 3-18. Passing functions in Python
word = rdd.filter(lambda s: "error" in s)
def containsError(s):
return "error" in s
word = rdd.filter(containsError)
有一件事需要注意的是,它會序列化函數中的對象。當你傳遞一個函數時,如果該函數是一個對象的成員或包含屬性的引用(例如,self.field),Spark會將整個對象發送給工作節點,這樣的對象肯定要比你需要信息大的多。有些時候,這也可以能會引起你的程序失敗,
Example 3-19. Passing a function with field references (don’t do this!)
class SearchFunctions(object):
def __init__(self, query):
elf.query = query
def isMatch(self, s):
return self.query in s
def getMatchesFunctionReference(self, rdd):
# Problem: references all of "self" in "self.isMatch"
return rdd.filter(self.isMatch)
def getMatchesMemberReference(self, rdd):
# Problem: references all of "self" in "self.query"
return rdd.filter(lambda x: self.query in x)
相反的,只需將您需要的字段從您的對象中提取到一個局部變量中,並將其傳入,就像我們所做的那樣。
class WordFunctions(object):
...
def getMatchesNoReference(self, rdd):
# Safe: extract only the field we need into a local variable
query = self.query
return rdd.filter(lambda x: query in x)
2.Scala
在Scala中,我們可以傳遞定義的內聯函數,引用方法或static。
Example 3-21. Scala function passing
class SearchFunctions(val query: String) {
def isMatch(s: String): Boolean = {
s.contains(query)
}
def getMatchesFunctionReference(rdd: RDD[String]): RDD[String] = {
// Problem: "isMatch" means "this.isMatch", so we pass all of "this"
rdd.map(isMatch)
}
def getMatchesFieldReference(rdd: RDD[String]): RDD[String] = {
// Problem: "query" means "this.query", so we pass all of "this"
rdd.map(x => x.split(query))
}
def getMatchesNoReference(rdd: RDD[String]): RDD[String] = {
// Safe: extract just the field we need into a local variable
val query_ = this.query
rdd.map(x => x.split(query_))
}
}
在Scala中如果出現NotSerializableException,通常都是由一個非序列化類中的方法或屬性引用導致的。請注意,傳遞本地可序列化變量或頂層對象的成員函數是安全的。
3.Java
Example 3-22. Java function passing with anonymous inner class
RDD<String> errors = lines.filter(new Function<String, Boolean>() {
public Boolean call(String x) {
return x.contains("error");
}
});
Example 3-23. Java function passing with named class
class ContainsError implements Function<String, Boolean>() {
public Boolean call(String x) {
return x.contains("error");
}
}
RDD<String> errors = lines.filter(new ContainsError());
編程風格是個人偏好,但是我們發現,頂層命名函數用於組織大型程序通常比較簡單,頂級函數的另一個優點是可以給它們構造函數參數
Example 3-24. Java function class with parameters
class Contains implements Function<String, Boolean>() {
private String query;
public Contains(String query) { this.query = query; }
public Boolean call(String x) { return x.contains(query); }
}
RDD<String> errors = lines.filter(new Contains("error"));
在Java 8中,你也可以使用lambda表達式
Example 3-25. Java function passing with lambda expression in Java 8
RDD<String> errors = lines.filter(s -> s.contains("error"));
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.