Spark ML Transformer中的NullPointerException

时间:2016-11-03 21:32:50

标签: java apache-spark apache-spark-mllib apache-spark-ml

我没有长时间使用spark,所以这可能是一个新手的错误,但我知道如何修复NullPointerException。但是,以下错误让我感到困惑。

设置:我有关于HDFS的数据,我使用Spark阅读。数据存储为HIVE表,因此我将使用HiveContext。我使用的是Spark 1.6.0和MLLib_2.10。 Java是1.7。

目标:我正在阅读我想要的表格中的文字"分类"。我已经离线创建了一组(n-gram,weight)对,我计划在分类过程中使用它们。

将文件加载到HashMap中,n-gram =>重量。让我们调用该列表 ngramWeights 。我计划在 ngramWeights 地图上进行查找,因为n-gram由Spark生成。存储在地图中的ngrams是unigrams bigrams。因此,我的Spark代码需要生成这两种情况。

高级方法:

  • 阅读带有SQL查询的内容和" store"在数据框中。
  • 使用MLLib创建Tokenizer和NGram转换,N = {1,2}
  • 每行
    • 将ngrams列为清单
    • 遍历列表并通过 ngramWeights 地图运行,汇总分数
    • 返回一个Tuple2实例,其中 row_id 为关键字,总结得分为值。

前两次运行(N = 1,N = 2)的结果存储在相应的JavaPairRDD结构中。

  • 加入unigram和bigram分数,加入相应的JavaPairRDD 。连接在row_id上。
    • 总分是两个权重的总和。
  • 在JavaRDD中返回结果

代码:

这就是我用来为特定N的特定每一行打分的。

private static final JavaPairRDD<String, Double> scoreByNGrams( DataFrame dframe, int nGramSize, final Map<String, Double> ngramWeights ){

    Tokenizer tokenizer = new Tokenizer().setInputCol( "content" ).setOutputCol( "tokenized" );
    dframe = tokenizer.transform( dframe );

    NGram ngramTransform = new NGram().setN( nGramSize ).setInputCol( "tokenized" ).setOutputCol( "ngrams" );
    dframe = ngramTransform.transform( dframe );

    JavaPairRDD<String, Double> textScores = dframe.javaRDD().mapToPair(

        new PairFunction<Row, String, Double>(){

            public Tuple2<String, Double> call( Row row ) throws Exception{

                double score = 0.0;

                WrappedArray<String> wrappedArray = (WrappedArray<String>)row.getAs( "ngrams" );
                Iterator<String> iter = wrappedArray.iterator();
                while ( iter.hasNext() ){
                    String ngram = iter.next();
                    Double value = ngramWeights.get( ngram );
                    if ( value != null )
                        score += value;
                }

                String rowId = row.getAs( "row_id" ).toString();
                return new Tuple2<String, Double>( rowId, score );
            }
        });

    return textScores;
}

然后我按以下方式组合部分结果:

public static void main( String[] args ){

    Map<String, Double> ngramWeights = new HashMap<>();
    loadCoefficients( ngramWeights ); // simply reading from a file

    SparkConf sparkConf = new SparkConf().setAppName( "TestCase" );
    JavaSparkContext sc = new JavaSparkContext( sparkConf );
    HiveContext hiveContext = new HiveContext( sc.sc() );

    // Hive table is stored in PARQUET format
    hiveContext.setConf( "spark.sql.hive.convertMetastoreParquet", "false" );
    hiveContext.sql( "USE my_db" );

    DataFrame contentInfo = hiveContext.sql( "SELECT row_id, get_json_object( text, \"$.clean_text\" ) as content FROM mytable" );

    JavaPairRDD<String, Double> unigrams = scoreByNGrams( contentInfo, 1, ngramWeights );
    JavaPairRDD<String, Double> bigrams = scoreByNGrams( contentInfo, 2, ngramWeights );

    JavaPairRDD<String, Double> messageScores = unigrams.join( bigrams ).mapToPair( 

        new PairFunction<Tuple2<String, Tuple2<Double, Double>>(){

            @Override
            public Tuple2<String, Double> call( Tuple2<String, Tuple2<Double, Double>> t ){
                double sum = t._2()._1() + t._2()._2();
                return new Tuple2<String, Double>( t._1(), sum );
            }
        }
    );

    // I then proceed to store the result
    // ...
}

我编译我的代码,在内部创建包含所有依赖项的胖jar,将其放在HDFS上并使用以下命令运行它:

$ spark-submit --class my.package.MyClass --master yarn-cluster hdfs://my/hdfs/myfatjar.jar 

问题:

应用程序启动正常并且似乎正在执行,但是当它达到FINISHED状态时它立即抛出异常,说:

Exception in thread "main" org.apache.spark.SparkException: Application application_<id> finished with failed status
    at org.apache.spark.deploy.yarn.client.Client.run(Client.scala:1035)
    at org.apache.spark.deploy.yarn.client.Client$.main(Client.scala:1082)
    at org.apache.spark.deploy.yarn.client.Client.main(Client.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:731)
    at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:181)
    at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:206)
    at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:121)
    at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)

仔细检查此应用程序的日志会发现失败的任务存在以下问题:

java.lang.NullPointerException
    at org.apache.spark.ml.feature.Tokenizer$$anonfun$createTransformFunc$1.apply(Tokenizer.scala:39)
    at org.apache.spark.ml.feature.Tokenizer$$anonfun$createTransformFunc$1.apply(Tokenizer.scala:39)
    at org.apache.spark.sql.catalyst.expressions.GeneratedClass$SpecificUnsafeProjection.evalExpr10$(Unknown Source)
    at org.apache.spark.sql.catalyst.expressions.GeneratedClass$SpecificUnsafeProjection.apply(Unknown Source)
    at org.apache.spark.sql.execution.Project$$anonfun$1$$anonfun$apply$1.apply(basicOperators.scala:51)
    at org.apache.spark.sql.execution.Project$$anonfun$1$$anonfun$apply$1.apply(basicOperators.scala:49)
    at scala.collection.Iterator$$anon$11.next(Iterator.scala:328)
    at scala.collection.Iterator$$anon$11.next(Iterator.scala:328)
    at scala.collection.Iterator$$anon$11.next(Iterator.scala:328)
    at org.apache.spark.util.collection.ExternalSorter.insertAll(ExternalSorter.scala:194)
    at org.apache.spark.shuffle.sort.SortShuffleWriter.write(SortShuffleWriter.scala:64)
    at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:73)
    at org.apache.spark.scheduler.ShuffleMapTask.runTask(ShuffleMapTask.scala:41)
    at org.apache.spark.scheduler.Task.run(Task.scala:89)

以前有人遇到过这个问题吗?我使用标记器的唯一地方是我提供的功能,所以我不会在那里看到问题。

如果有人想知道,&#34;文字&#34; field是一个json字符串,总是有一个&#34; clean_text&#34;键。对DB运行以下查询:

SELECT * FROM mytable WHERE get_json_object( text, "$.clean_text" ) IS NULL

返回0结果。因此,不是读取内容为NULL的情况。

如果有任何不清楚或者您是否需要有关我正在执行的查询的其他信息,请与我们联系。

更新:我已删除了ML转换(tokenizer和ngram)并转换了代码,以便我使用自定义NGram tokenizer(直接获取内容)。对于某些行,Spark返回NULL(作为String),尽管 mytable 中有 NO null值。

有人对此有任何想法吗?再次感谢!

1 个答案:

答案 0 :(得分:0)

我不确定这是否仍然会引起任何问题,但是我使用Databricks遇到了相同的错误,发现问题是由pyspark.ml.feature模块中的VectorAssembler引起的。 在我的情况下,我为inputCols参数指定的列表顺序不相同,因为列出现在VectorAssembler转换的数据集中,这引起了问题。 通过确保我的inputCols列表的顺序与数据框列列表相匹配,我阻止了此java.lang.NullPointerException错误的发生。