Apache Spark:尝试索引字符串列时出现 ***Error

Posted

技术标签:

【中文标题】Apache Spark:尝试索引字符串列时出现 ***Error【英文标题】:Apache Spark: ***Error when trying to indexing string columns 【发布时间】:2016-11-07 10:50:54 【问题描述】:

我有大约 5000 行和 950 列的 csv 文件。首先我将它加载到 DataFrame:

val data = sqlContext.read
  .format(csvFormat)
  .option("header", "true")
  .option("inferSchema", "true")
  .load(file)
  .cache()

之后我搜索所有字符串列

val featuresToIndex = data.schema
  .filter(_.dataType == StringType)
  .map(field => field.name)

并且想要索引它们。为此,我为每个字符串列创建索引器

val stringIndexers = featuresToIndex.map(colName =>
  new StringIndexer()
    .setInputCol(colName)
    .setOutputCol(colName + "Indexed"))

并创建管道

val pipeline = new Pipeline().setStages(stringIndexers.toArray)

但是当我尝试使用此管道转换我的初始数据帧时

val indexedDf = pipeline.fit(data).transform(data)

我得到 ***Error

16/07/05 16:55:12 INFO DAGScheduler: Job 4 finished: countByValue at StringIndexer.scala:86, took 7.882774 s
Exception in thread "main" java.lang.***Error
at scala.collection.immutable.Set$Set1.contains(Set.scala:84)
at scala.collection.immutable.Set$Set1.$plus(Set.scala:86)
at scala.collection.immutable.Set$Set1.$plus(Set.scala:81)
at scala.collection.mutable.SetBuilder.$plus$eq(SetBuilder.scala:22)
at scala.collection.mutable.SetBuilder.$plus$eq(SetBuilder.scala:20)
at scala.collection.generic.Growable$class.loop$1(Growable.scala:53)
at scala.collection.generic.Growable$class.$plus$plus$eq(Growable.scala:57)
at scala.collection.mutable.SetBuilder.$plus$plus$eq(SetBuilder.scala:20)
at scala.collection.TraversableLike$class.to(TraversableLike.scala:590)
at scala.collection.AbstractTraversable.to(Traversable.scala:104)
at scala.collection.TraversableOnce$class.toSet(TraversableOnce.scala:304)
at scala.collection.AbstractTraversable.toSet(Traversable.scala:104)
at org.apache.spark.sql.catalyst.trees.TreeNode.containsChild$lzycompute(TreeNode.scala:86)
at org.apache.spark.sql.catalyst.trees.TreeNode.containsChild(TreeNode.scala:86)
at org.apache.spark.sql.catalyst.trees.TreeNode$$anonfun$4.apply(TreeNode.scala:280)
at scala.collection.Iterator$$anon$11.next(Iterator.scala:409)
...

我做错了什么? 谢谢。

【问题讨论】:

能否提供完整的异常跟踪? 你使用的是哪个版本的JDK? 我试过 jdk 1.8.0_60 和 1.8.0_101。这里完整跟踪pastebin.com/g9MsNtDp 【参考方案1】:

似乎我找到了一种解决方案 - 使用 spark 2.0。以前,我使用的是 1.6.2 - 它是发布时的最新版本。我尝试使用2.0的预览版,但也有问题重现。

【讨论】:

【参考方案2】:

很可能没有足够的内存来保存所有堆栈帧。我在训练 RandomForestModel 时遇到了类似的情况。对我有用的解决方法是使用附加参数运行我的驱动程序应用程序(即 Web 服务):

-XX:ThreadStackSize=81920 -Dspark.executor.extraJavaOptions='-XX:ThreadStackSize=81920'

【讨论】:

我实际上面临着同样的问题,我怎样才能找到默认的堆栈大小?此外,我看到它增加了执行程序的堆栈大小,而不是驱动程序,对吗? @h.z.这对双方都有利,因为双方都在共同努力。 ThreadStackSize 用于驱动程序。 for executors 来自 executor.extraJavaOptions。我不确定是否可以测量尺寸,我只是增加了我的尺寸,直到它开始工作。我假设对于更大的数据集它仍然会失败。 @evgenii 我们在 jupyter notebook 的哪里添加这些参数? :) 在火花初始化或其他地方?【参考方案3】:

Java 中的 ***Error 当 Java 应用程序调用函数调用时,会在调用堆栈上分配一个堆栈帧。堆栈帧包含被调用方法的参数、其本地参数和方法的返回地址。返回地址表示被调用方法返回后程序继续执行的执行点。如果没有空间用于新的堆栈帧,则 Java 虚拟机 (JVM) 会抛出 ***Error。 可能耗尽 Java 应用程序堆栈的最常见情况是递归。在递归中,方法在执行期间调用自身。递归被认为是一种强大的通用编程技术,但必须谨慎使用,以避免 ***Error。

可能的解决方案是 1.默认情况下,Spark 只使用内存 RDD 序列化。尝试使用持久化磁盘选项

2. 尝试增加驱动程序的 JVM 堆栈大小,在驱动程序选项中添加 -Xss5m 之类的内容。当您检查 data.schema 中的列类型时,可能会发生一些递归

--driver-java-options "-Xss 100M"

如果可能,共享文件并完成异常跟踪。

【讨论】:

以上是关于Apache Spark:尝试索引字符串列时出现 ***Error的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用 apache spark 加载模块时出现 Databricks 错误 [重复]

从 apache Spark 运行 java 程序时出现 ClassNotFound 异常

在 Apache Spark Dataset<Row> 上应用 flatMap 操作时出现意外的编码器行为

在apache spark中使用distinct时出现***错误

调用 saveAsTable 时出现 org.apache.spark.sql.AnalysisException

为啥在尝试从 api 获取数据时出现此错误“TypeError:字符串索引必须是整数”?