我的初始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
的方式是否足够有效,还是有其他更好的选择?
答案 0 :(得分:2)
line._2.union(additionalData)
创建line._2
的联合,其类型为List[(String, String)]
,additionalData
的类型为List[Sting]
。结果必须是这两种不同类型中最准确的常见类型 - List[Serializable]
。
如果additionalData
的类型为List[(String, String)]
,则该类型为结果类型。
至于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
})