我一直在努力在DStream和RDD之间执行联接。设置场景:
RDD
我正在从CSV文件中读取RDD,拆分记录并生成一对RDD。
sku_prices = sc.textFile("sku-catalog.csv")\
.map(lambda line: line.split(","))\
.map(lambda fields: (fields[0], float(fields[1])))
这是sku_prices.collect()
的输出:
[('0003003001', 19.25),
('0001017002', 2.25),
('0001017003', 3.5),
('0003013001', 18.75),
('0004017002', 16.5),
('0002008001', 2.25),
('0004002001', 10.75),
('0005020002', 10.5),
('0001004002', 3.5),
('0002016003', 14.25)]
DStream
我正在从Kafka中读取DStream。
orders = kstream.map(lambda n: n[1]).map(lambda n: json.loads(n))
items = orders.map(lambda order: order['items'])\
.flatMap(lambda items: [(i['sku'], i['count']) for i in items])\
.reduceByKey(lambda x, y: x + y)
当我在pprint()
上运行orders
时,得到的输出如下:
-------------------------------------------
Time: 2018-09-03 06:57:20
-------------------------------------------
('0004002001', 3)
('0002016003', 1)
('0003013001', 1)
加入
现在,我想将items
DStream加入到sku_prices
RDD中。我知道我不能直接进行联接,但是我的阅读建议我可以在DStream上使用transform()
方法来完成这项工作。这就是我所拥有的:
items.transform(lambda rdd: rdd.join(sku_prices)).pprint()
我希望获得一个看起来像这样的DStream:
-------------------------------------------
Time: 2018-09-03 06:57:20
-------------------------------------------
('0004002001', (3, 10.75))
('0002016003', (1, 14.25))
('0003013001', (1, 18.75))
Spark documentation建议这样做应该起作用,并且确实起作用:结果正是我所得到的! :)
检查点
但是我也想做一个有状态的操作,所以我需要引入检查点。
ssc.checkpoint("checkpoint")
仅添加检查点会导致在transform()
上出现此错误:
您似乎正在尝试广播RDD或引用 动作或变换的RDD。 RDD转换和动作 只能由驱动程序调用,不能在其他内部调用 转变;例如rdd1.map(lambda x:rdd2.values.count()* x)无效,因为值转换和计数操作 不能在rdd1.map转换内部执行。
this thread的答案表明检查点和外部RDD不能混合使用。有没有解决的办法?当StreamingContext启用检查点功能时,是否可以加入DStream和RDD?
谢谢, 安德鲁。