我在从Cassandra加载的RDD上有一个简单的map
和reduce
工作。
代码看起来像这样
sc.cassandraTable("app","channels").select("id").toArray.foreach((o) => {
val orders = sc.cassandraTable("fam", "table")
.select("date", "f2", "f3", "f4")
.where("id = ?", o("id")) # This o("id") is the ID i want later append to the finished list
val month = orders
.map( oo => {
var total_revenue = List(oo.getIntOption("f2"), oo.getIntOption("f3"), oo.getIntOption("f4")).flatten.reduce(_ + _)
(getDateAs("hour", oo.getDate("date")), total_revenue)
})
.reduceByKey(_ + _)
})
所以这段代码总结收入并返回类似这样的内容
(2014-11-23 18:00:00, 12412)
(2014-11-23 19:00:00, 12511)
现在我想把它保存回Cassandra Table revenue_hour
,但我需要在该列表中以某种方式使用ID,就像那样。
(2014-11-23 18:00:00, 12412, "CH1")
(2014-11-23 19:00:00, 12511, "CH1")
如何使用更多(键,值)列表来完成此工作?我如何传递更多值,这些值不应该被转换,而只是传递到最后,以便我可以将它保存回Cassandra?
答案 0 :(得分:3)
也许你可以使用一个类并通过流程来处理它。我的意思是,定义RevenueHour类
case class RevenueHour(date: java.util.Date,revenue: Long, id: String)
然后在地图阶段构建一个中间RevenueHour,然后在reduce阶段构建另一个。
val map: RDD[(Date, RevenueHour)] = orders.map(row =>
(
getDateAs("hour", oo.getDate("date")),
RevenueHour(
row.getDate("date"),
List(row.getIntOption("f2"),row.getIntOption("f3"),row.getIntOption("f4")).flatten.reduce(_ + _),
row.getString("id")
)
)
).reduceByKey((o1: RevenueHour, o2: RevenueHour) => RevenueHour(getDateAs("hour", o1.date), o1.revenue + o2.revenue, o1.id))
我使用o1 RevenueHour,因为o1和o2都有相同的密钥和相同的id(因为之前的where子句)。
希望它有所帮助。
答案 1 :(得分:1)
该问题的方法是通过迭代一组id并仅对一个(可能很小的)数据子集应用Spark作业来对数据处理进行排序。
不知道'频道之间的关系如何?和'表'数据,我看到两个选项可以充分利用Spark并行处理数据的能力:
如果'表格中的数据为' table(称为" orders"从此处开始)包含报告中我们需要的所有id组,我们可以将报告逻辑应用于整个表:
基于这个问题,我们将使用这个C *架构:
CREATE TABLE example.orders (id text,
date TIMESTAMP,
f2 decimal,
f3 decimal,
f4 decimal,
PRIMARY KEY(id, date)
);
通过提供表示表格架构的案例类,可以更轻松地访问cassandra数据:
case class Order(id: String, date:Long, f2:Option[BigDecimal], f3:Option[BigDecimal], f4:Option[BigDecimal]) {
lazy val total = List(f2,f3,f4).flatten.sum
}
然后我们可以根据cassandra表定义一个rdd。当我们提供case类作为类型时,spark-cassandra驱动程序可以直接执行转换以方便我们:
val ordersRDD = sc.cassandraTable[Order]("example", "orders").select("id", "date", "f2", "f3", "f4")
val revenueByIDPerHour = ordersRDD.map{order => ((order.id, getDateAs("hour", order.date)), order.total)}.reduceByKey(_ + _)
最后回到卡桑德拉:
revenueByIDPerHour.map{ case ((id,date), revenue) => (id, date, revenue)}
.saveToCassandra("example","revenue", SomeColumns("id", "date", "total"))
如果(" app"," channels")表中包含的id应该用于过滤id组(例如有效ID),那么,我们可以加入带有订单的此表中的ID。这项工作将类似于之前的工作,增加了:
val idRDD = sc.cassandraTable("app","channels").select("id").map(_.getString)
val ordersRDD = sc.cassandraTable[Order]("example", "orders").select("id", "date", "f2", "f3", "f4")
val validOrders = idRDD.join(ordersRDD.map(order => (id,order))
这两种方式说明了如何使用Cassandra和Spark,利用Spark操作的分布式特性。它还应该比对“频道”中的每个ID执行查询要快得多。表