【问题标题】:Infinite recursion in createDataFrame for avro typesavro 类型的 createDataFrame 中的无限递归
【发布时间】:2016-04-10 16:17:28
【问题描述】:

在此示例中,我从 createDataFrame 调用中得到了 StackOverflowError。它起源于涉及 java 类型推断的 scala 代码,该代码在无限循环中调用自身。

final EventParser parser = new EventParser();
JavaRDD<Event> eventRDD = sc.textFile(path)
        .map(new Function<String, Event>()
{
    public Event call(String line) throws Exception
    {
        Event event = parser.parse(line);
        log.info("event: "+event.toString());
        return event;
    }
});
log.info("eventRDD:" + eventRDD.toDebugString());

DataFrame df = sqlContext.createDataFrame(eventRDD, Event.class);
df.show();

堆栈跟踪的底部如下所示:

at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:108)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.mutable.ArrayOps$ofRef.map(ArrayOps.scala:108)
at org.apache.spark.sql.catalyst.JavaTypeInference$.org$apache$spark$sql$catalyst$JavaTypeInference$$inferDataType(JavaTypeInference.scala:102)
at org.apache.spark.sql.catalyst.JavaTypeInference$$anonfun$2.apply(JavaTypeInference.scala:104)
at org.apache.spark.sql.catalyst.JavaTypeInference$$anonfun$2.apply(JavaTypeInference.scala:102)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:108)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.mutable.ArrayOps$ofRef.map(ArrayOps.scala:108)

这看起来类似于http://apache-spark-developers-list.1001551.n3.nabble.com/Stackoverflow-in-createDataFrame-td11791.html 中报告的错误,但我使用的是 Spark 1.4.1,它比修复此错误时晚。

Event 类是由 avro 从这个 avsc 生成的。它确实包含已报告为导致问题的 double 和 long 字段,但用字符串替换 double 不会改变症状。

{
    "namespace": "mynamespace", 
    "type": "record", 
    "name": "Event", 
    "fields": [
        { "name": "ts", "type": "double", "doc": "Timestamp"},
        { "name": "uid", "type": "string", "doc": "Unique ID of Connection"},
        { "name": "idorigh", "type": "string", "doc": "Originating endpoint’s IP address (AKA ORIG)"},
        { "name": "idorigp", "type": "int", "doc": "Originating endpoint’s TCP/UDP port (or ICMP code)"},
        { "name": "idresph", "type": "string", "doc": "Responding endpoint’s IP address (AKA RESP)"},
        { "name": "idrespp", "type": "int", "doc": "Responding endpoint’s TCP/UDP port (or ICMP code)"},
        { "name": "proto", "type": "string", "doc": "Transport layer protocol of connection"},
        { "name": "service", "type": "string", "doc": "Dynamically detected application protocol, if any"},
        { "name": "duration", "type": "double", "doc": "Time of last packet seen – time of first packet seen"},
        { "name": "origbytes", "type": "int", "doc": "Originator payload bytes; from sequence numbers if TCP"},
        { "name": "respbytes", "type": "int", "doc": "Responder payload bytes; from sequence numbers if TCP"},
        { "name": "connstate", "type": "string", "doc": "Connection state (see conn.log:conn_state table)"},
        { "name": "localorig", "type": "boolean", "doc": "If conn originated locally T; if remotely F."},
        { "name": "localresp", "type": "boolean", "doc": "empty, always unset"},
        { "name": "missedbytes", "type": "int", "doc": "Number of missing bytes in content gaps"},
        { "name": "history", "type": "string", "doc": "Connection state history (see conn.log:history table)"},
        { "name": "origpkts", "type": [ "int", "null"], "doc": "Number of ORIG packets"},
        { "name": "origipbytes", "type": [ "int", "null"], "doc": "Number of RESP IP bytes (via IP total_length header field)"},
        { "name": "resppkts", "type": [ "int", "null"], "doc": "Number of RESP packets"},
        { "name": "respipbytes", "type": [ "int", "null"], "doc": "Number of RESP IP bytes (via IP total_length header field)"},
        { "name": "tunnelparents", "type": [ "string", "null"], "doc": "If tunneled, connection UID of encapsulating parent (s)"},
        { "name": "origcc", "type": ["string", "null"], "doc": "ORIG GeoIP Country Code"},
        { "name": "respcc", "type": ["string", "null"], "doc": "RESP GeoIP Country Code"}
    ]
}

有人可以建议吗?谢谢!

【问题讨论】:

  • 无限递归在哪里?请提供一个最小可重现的例子!
  • 递归从 scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:108) 开始,一直持续到堆栈溢出错误。最小的例子涉及一个复杂的 pom、一个 avsc 文件、一个解析器和其他几个。所以我把它们都打包在一个tgz中。我应该怎么把它给你?
  • 好吧,我想这会有点压倒性的。让我们隔离您的部分代码以找出问题所在。 e. g 在将 RDD 转换为 DataFrame 之前,执行计数操作和/或 RDD 收集。
  • 我真的很惊讶parser 连载。您只使用本地模式吗?
  • Parser 通过解析一行输入文本而不是序列化来创建 Event 实例。同一个类碰巧也实现了 Encoder 和 Decoder 以最小化类的数量(个人喜好),但这些类已经通过了单元测试。我已经放弃使用本地模式来诊断我通过 yarn-client 在集群上遇到的相同问题。

标签: apache-spark apache-spark-sql avro


【解决方案1】:

spark-avro 项目正在解决此问题,请参阅:https://github.com/databricks/spark-avro/pull/217https://github.com/databricks/spark-avro/pull/216

一旦合并,应该有一个函数将 Avro 对象的 RDD 转换为 DataSet(行的 DataSet 相当于 DataFrame),而生成的类中的 getSchema() 函数没有循环引用问题.

【讨论】:

    猜你喜欢
    • 2018-04-01
    • 2015-09-19
    • 2018-07-29
    • 2021-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2012-01-08
    相关资源
    最近更新 更多