[英]Spark java.lang.StackOverflowError
我正在使用spark來計算用戶評論的pagerank,但是當我在一個大數據集上運行我的代碼時,我一直得到Spark java.lang.StackOverflowError
(40k條目)。 當在少量條目上運行代碼時,它工作正常。
輸入示例:
product/productId: B00004CK40 review/userId: A39IIHQF18YGZA review/profileName: C. A. M. Salas review/helpfulness: 0/0 review/score: 4.0 review/time: 1175817600 review/summary: Reliable comedy review/text: Nice script, well acted comedy, and a young Nicolette Sheridan. Cusak is in top form.
代碼:
public void calculatePageRank() {
sc.clearCallSite();
sc.clearJobGroup();
JavaRDD < String > rddFileData = sc.textFile(inputFileName).cache();
sc.setCheckpointDir("pagerankCheckpoint/");
JavaRDD < String > rddMovieData = rddFileData.map(new Function < String, String > () {
@Override
public String call(String arg0) throws Exception {
String[] data = arg0.split("\t");
String movieId = data[0].split(":")[1].trim();
String userId = data[1].split(":")[1].trim();
return movieId + "\t" + userId;
}
});
JavaPairRDD<String, Iterable<String>> rddPairReviewData = rddMovieData.mapToPair(new PairFunction < String, String, String > () {
@Override
public Tuple2 < String, String > call(String arg0) throws Exception {
String[] data = arg0.split("\t");
return new Tuple2 < String, String > (data[0], data[1]);
}
}).groupByKey().cache();
JavaRDD<Iterable<String>> cartUsers = rddPairReviewData.map(f -> f._2());
List<Iterable<String>> cartUsersList = cartUsers.collect();
JavaPairRDD<String,String> finalCartesian = null;
int iterCounter = 0;
for(Iterable<String> out : cartUsersList){
JavaRDD<String> currentUsersRDD = sc.parallelize(Lists.newArrayList(out));
if(finalCartesian==null){
finalCartesian = currentUsersRDD.cartesian(currentUsersRDD);
}
else{
finalCartesian = currentUsersRDD.cartesian(currentUsersRDD).union(finalCartesian);
if(iterCounter % 20 == 0) {
finalCartesian.checkpoint();
}
}
}
JavaRDD<Tuple2<String,String>> finalCartesianToTuple = finalCartesian.map(m -> new Tuple2<String,String>(m._1(),m._2()));
finalCartesianToTuple = finalCartesianToTuple.filter(x -> x._1().compareTo(x._2())!=0);
JavaPairRDD<String, String> userIdPairs = finalCartesianToTuple.mapToPair(m -> new Tuple2<String,String>(m._1(),m._2()));
JavaRDD<String> userIdPairsString = userIdPairs.map(new Function < Tuple2<String, String>, String > () {
//Tuple2<Tuple2<MovieId, userId>, Tuple2<movieId, userId>>
@Override
public String call (Tuple2<String, String> t) throws Exception {
return t._1 + " " + t._2;
}
});
try {
//calculate pagerank using this https://github.com/apache/spark/blob/master/examples/src/main/java/org/apache/spark/examples/JavaPageRank.java
JavaPageRank.calculatePageRank(userIdPairsString, 100);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sc.close();
}
當你的for循環變得非常大時,Spark無法再跟蹤血統。 在for循環中啟用檢查點,以便每10次迭代檢查一次rdd。 檢查點將解決問題。 不要忘記清理檢查點目錄。
http://spark.apache.org/docs/latest/streaming-programming-guide.html#checkpointing
我有多個建議可以幫助您大大提高問題代碼的性能。
一個例子是RDD。
count
- 告訴你文件中的行數,需要讀取文件。 所以,如果你寫RDD。count
,此時將讀取文件,計算行數,並返回計數。如果你打電話給RDD怎么辦? 再
count
一次? 同樣的事情:文件將被讀取並再次計數。 那么RDD是什么?cache
呢? 現在,如果你運行RDD。 第一次count
,文件將被加載,緩存和計數。 如果你打電話給RDD。count
第二次,操作將使用緩存。 它只會從緩存中獲取數據並計算行數,而不是重新計算。
閱讀更多有關緩存的信息 。
在您的代碼示例中,您不會重復使用已緩存的任何內容。 所以你可以從那里刪除.cache
。
rddFileData
, rddMovieData
和rddPairReviewData
步驟,以便一次性發生。 擺脫.collect
因為這會將結果帶回驅動程序,也許是錯誤的實際原因。
當您的DAG變大並且代碼中發生過多級別的轉換時,就會出現此問題。 在最終執行操作時,JVM將無法保持執行延遲執行的操作。
檢查點是一種選擇。 我建議為這種聚合實現spark-sql。 如果您的數據是結構化的,請嘗試將其加載到數據框中並執行分組和其他mysql函數來實現此目的。
不幸的是, 對我來說很容易的解決方案是在每幾次迭代后調用.collect()
。 嗯,事情至少起作用,作為一個快速解決方案。
匆忙,我無法建議使用檢查點工作的建議解決方案(也許它無論如何都不會工作?)
注意:似乎設置spark選項可能會起作用......但我現在沒時間,所以我沒有檢查如何從pyspark設置spark的java選項,如果可能的話。 更改配置的相關頁面:
如果有人通過更改最大遞歸限制來實現這一點,那么這里的評論對其他人來說會很好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.