获取列表[Serializable]而不是List [(String,String)]

时间:2016-08-22 11:23:06

标签: scala apache-spark

我的初始RDD如下RDD[(String, List[(String,String)])]

(600,List((22,33),(55,88)))
(700,List((12,13),(15,18),(18,88)))

我想在每个条目中附加从Redis缓存DB获取的其他数据。为此,我使用Sedis,它是Scala的Jedis包装器。这是我的代码片段:

import org.sedis._
import redis.clients.jedis._

val redisPool = new Pool(new JedisPool(new JedisPoolConfig(), "localhost", 6379, 2000))

val appended = filtered.map({line => (line._1,
    redisPool.withJedisClient { client =>
    val additionalData: List[String] = Dress.up(client).hvals("member_id:"+line._1)
    line._2.union(additionalData)
    })
})

问题是appended的格式为RDD[(String, List[Serializable],而不是RDD[(String, List[(String,String)])]。我究竟做错了什么? 另外,我在redisPool内使用map的方式是否足够有效,还是有其他更好的选择?

1 个答案:

答案 0 :(得分:2)

  1. line._2.union(additionalData)创建line._2的联合,其类型为List[(String, String)]additionalData的类型为List[Sting]。结果必须是这两种不同类型中最准确的常见类型 - List[Serializable]。 如果additionalData的类型为List[(String, String)],则该类型为结果类型。

  2. 至于JedisPool使用的效率:通常,当从Spark转换打开与某些外部资源的连接时,您应该使用mapPartitions ,它们在每个上执行给定的函数RDD的分区为什么?在当前实现中,池在驱动程序应用程序上创建,然后序列化并发送到每个执行程序,以进行反序列化并在映射中使用。这通常失败,因为这样的池拥有某种类型的连接(可能是开放式套接字),它们并不存在于执行程序中,只存在于创建它的驱动程序上。一个(低效)替代方案是在map函数内创建池(每个记录)。更好的选择是使用mapPartitions:

    val appended = filtered.mapPartitions(iter => {
      val redisPool = new Pool(new JedisPool(new JedisPoolConfig(), "jedis-host", 6379, 2000))
    
      iter.map({line => (line._1,
        redisPool.withJedisClient { client =>
        val additionalData: List[String] = Dress.up(client).hvals("member_id:"+line._1)
        line._2.union(additionalData)
        })
      })
      // close the pool, if relevant
    })