Spark SQL UDF任务不可序列化

时间:2016-03-23 10:45:34

标签: scala apache-spark apache-spark-sql datastax

Cassandra& DataStax社区,我有一个问题,我希望有人可以帮助我。

我们正在将我们的分析代码从Hadoop迁移到运行在Cassandra之上的Spark(通过DataStax Enterprise)。 DSE 4.7正在生产中,但4.8正在开发中。

Java 7正在开发中,Java 7/8正在开发中。

我们需要进行一些DataFrame转换,并且我们认为通过Spark SQLContext对内存DataFrame编写的UDF将完成这项工作。其中主要是:

  1. 我们数据的每个文本值都以前缀为前缀,后缀为“。即“某些数据”这非常令人讨厌,所以我们想要清理这些数据。
  2. 我们想要添加一个包含由多个其他列组成的散列键的列。
  3. 我们的代码如下。这运行良好,没有在sqlContext中包含UDF调用,但是一旦添加它们我们就得到“任务不可序列化”错误

    线程中的异常" main" org.apache.spark.SparkException:任务不可序列化

    我已经尝试将“implements Serializable”作为此类(以及许多其他类)的基类,它将错误类更改为链中的下一个类,但是这会导致异常类失败而不是可序列化...这可能意味着我正走向错误的方向。

    我也尝试将UDF实现为lambda,并且也会导致相同的错误。

    如果有人能指出我做错了什么,我将不胜感激!

    public class entities implements Serializable{
        private spark_context m_spx = null;
        private DataFrame m_entities = null;
        private String m_timekey = null;
    
        public entities(spark_context _spx, String _timekey){
            m_spx = _spx;
            m_timekey = _timekey;
        }
    
    
        public DataFrame get_dimension(){
            if(m_entities == null) {
    
                DataFrame df = m_spx.get_flat_data(m_timekey).select("event", "url");
    
                //UDF to generate hashed ids
                UDF2 get_hashed_id = new UDF2<String, String, String>() {
                    public String call(String o, String o2) throws Exception {
                        return o.concat(o2);
                    }
                };
    
    
                //UDF to clean the " from strings
                UDF1 clean_string = new UDF1<String, String>() {
                    public String call(String o) throws Exception {
                        return o.replace("\"","");
                    }
                };
    
    
                //Get the Spark SQL Context from SC.
                SQLContext sqlContext = new SQLContext(m_spx.sc());
    
    
                //Register the UDFs
                sqlContext.udf().register("getid", get_hashed_id, DataTypes.StringType);
                sqlContext.udf().register("clean_string", clean_string, DataTypes.StringType);
    
    
                //Register the DF as a table.
                sqlContext.registerDataFrameAsTable(df, "entities");
                m_entities = sqlContext.sql("SELECT getid(event, url) as event_key, clean_string(event) as event_cleaned, clean_string(url) as url_cleaned FROM entities");
            }
    
            return m_entities;
        }
    }
    

1 个答案:

答案 0 :(得分:6)

您的665328 // before everything started 4295684088 // 4 GiB allocated 4295684296 // did GC (for certain! (really?)) 5812441672 // allocated a long string, took new memory 类包含entities成员 - 因此无法序列化(SparkContexts在国际上不可序列化,您不应该序列化它们)。

由于SparkContext不可序列化,因此任何非静态方法/成员/匿名内部类都不可序列化(因为它们会尝试序列化{{ 1}}持有它们的实例)。

在这种情况下,最好的解决方法是将匿名UDF提取到类的静态成员中:

entities

然后您就可以在entities中使用它们了。