簡體   English   中英

Spark java.lang.StackOverflowError

[英]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

我有多個建議可以幫助您大大提高問題代碼的性能。

  1. 緩存:緩存應該用於那些您需要一次又一次地引用相同/不同操作的數據集(迭代算法)。

一個例子是RDD。 count - 告訴你文件中的行數,需要讀取文件。 所以,如果你寫RDD。 count ,此時將讀取文件,計算行數,並返回計數。

如果你打電話給RDD怎么辦? count一次? 同樣的事情:文件將被讀取並再次計數。 那么RDD是什么? cache呢? 現在,如果你運行RDD。 第一次count ,文件將被加載,緩存和計數。 如果你打電話給RDD。 count第二次,操作將使用緩存。 它只會從緩存中獲取數據並計算行數,而不是重新計算。

閱讀更多有關緩存的信息

在您的代碼示例中,您不會重復使用已緩存的任何內容。 所以你可以從那里刪除.cache

  1. 並行化:在代碼示例中,您已經並行化了RDD中已經是分布式集合的每個元素。 我建議你合並rddFileDatarddMovieDatarddPairReviewData步驟,以便一次性發生。

擺脫.collect因為這會將結果帶回驅動程序,也許是錯誤的實際原因。

當您的DAG變大並且代碼中發生過多級別的轉換時,就會出現此問題。 在最終執行操作時,JVM將無法保持執行延遲執行的操作。

檢查點是一種選擇。 我建議為這種聚合實現spark-sql。 如果您的數據是結構化的,請嘗試將其加載到數據框中並執行分組和其他mysql函數來實現此目的。

不幸的是, 對我來說很容易的解決方案是在每幾次迭代后調用.collect() 嗯,事情至少起作用,作為一個快速解決方案。

匆忙,我無法建議使用檢查點工作的建議解決方案(也許它無論如何都不會工作?)


注意:似乎設置spark選項可能會起作用......但我現在沒時間,所以我沒有檢查如何從pyspark設置spark的java選項,如果可能的話。 更改配置的相關頁面:

如果有人通過更改最大遞歸限制來實現這一點,那么這里的評論對其他人來說會很好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM