Spark on Java - 在所有工作者上拥有静态对象的正确方法是什么

时间:2016-01-26 15:51:18

标签: java static apache-spark

我需要在Spark中的所有执行程序的函数中使用不可序列化的第三方类,例如:

JavaRDD<String> resRdd = origRdd
    .flatMap(new FlatMapFunction<String, String>() {
        @Override
        public Iterable<String> call(String t) throws Exception {

        //A DynamoDB mapper I don't want to initialise every time
        DynamoDBMapper mapper = new DynamoDBMapper(new AmazonDynamoDBClient(credentials));

        Set<String> userFav = mapper.load(userDataDocument.class, userId).getFav();

        return userFav;
    }
});

我希望有一个静态DynamoDBMapper mapper,我为每个执行者初始化一次,并且能够一遍又一遍地使用它。

由于它不是可序列化的,我无法在驱动器中初始化它并进行广播。

注意:这是一个答案(What is the right way to have a static object on all workers),但它仅适用于Scala。

1 个答案:

答案 0 :(得分:6)

您可以使用mapPartitionforeachPartition。以下是摘自Learning Spark

的摘录
  

通过使用基于分区的操作,我们可以共享连接池   到这个数据库,以避免建立多个连接,并重用我们的   JSON解析器。如例6-10至6-12所示,我们使用了   mapPartitions()函数,它为我们提供了元素的迭代器   在输入RDD的每个分区中,并期望我们返回一个   我们的结果的迭代器。

这允许我们为每个执行器初始化一个连接,然后根据您的需要迭代分区中的元素。这对于将数据保存到某个外部数据库或创建昂贵的可重用对象非常有用。

这是一个从链接书中获取的简单示例。如果需要,可以将其转换为java。这里是为了展示mapPartition和foreachPartition的一个简单用例。

ipAddressRequestCount.foreachRDD { rdd => rdd.foreachPartition { partition =>
    // Open connection to storage system (e.g. a database connection)
    partition.foreach { item =>
    // Use connection to push item to system
    }
    // Close connection
    } 
}

Here is a link到java示例。