Pra*_*oni 1 scala apache-spark-sql
我试图通过在 Scala 程序中创建列数超过 200 的 RDD 来创建 Spark SQL 表。当我将架构创建为以下内容时,编译(sbt 编译)失败并出现 java.lang.StackOverflowError 异常:
StructField("RT", StringType,nullable = true) ::
StructField("SERIALNO", StringType,nullable = true) ::
StructField("SPORDER", StringType,nullable = true) ::
// ... remaining 200+ columns
Run Code Online (Sandbox Code Playgroud)
无法粘贴堆栈跟踪,因为它超过 1.5k 行将
列数减少到大约 100-120 编译成功。另外,当我使用架构字符串创建架构(拆分架构字符串,然后创建它的映射)时,编译成功(https://spark.apache.org/docs/1.3中标题“以编程方式指定架构”下的第一个示例。 0/sql-programming-guide.html)。
手动指定导致异常的模式似乎有什么问题?
这里的基本问题是,您在每个步骤中为每个 StructField 执行列表串联。运算符 :: 实际上是 List 的成员而不是 StructField。代码如下:
val fields = field1 :: field2 :: field3 :: Nil
Run Code Online (Sandbox Code Playgroud)
这相当于:
val fields = field1 :: (field2 :: (field3 :: Nil))
Run Code Online (Sandbox Code Playgroud)
甚至
val fields = Nil.::(field1).::(field2).::(field3)
Run Code Online (Sandbox Code Playgroud)
因此,在执行时,JVM 需要递归地评估对该::方法的调用。JVM 根据列表中的项目数量按比例增加堆栈深度。拆分字段名称字符串和映射起作用的原因是它迭代字段名称的拆分字符串而不是使用递归。
这不是 Spark 问题。一旦您进入数百个项目,您就可以在 Scala repl 中的一系列任何类型的列表串联上重现相同的堆栈溢出错误。只需使用其他方法之一来创建不会导致堆栈溢出的 StructFields 列表。
例如,这样的事情就可以正常工作:
val structure = StructType(
List(
StructField("RT", StringType,nullable = true),
StructField("SERIALNO", StringType,nullable = true),
StructField("SPORDER", StringType,nullable = true),
// Other Fields
StructField("LASTFIELD", StringType,nullable = true)
)
)
Run Code Online (Sandbox Code Playgroud)