我想创建一个看起来像这样的API
public Dataset<Row> getDataFromKafka(SparkContext sc, String topic, StructType schema);
这里
topic
- 是将从中消耗数据的Kafka主题名称。
schema
- 是数据集的架构信息
所以我的函数包含以下代码:
JavaStreamingContext jsc = new JavaStreamingContext(javaSparkContext, Durations.milliseconds(2000L));
JavaPairInputDStream<String, String> directStream = KafkaUtils.createDirectStream(
jsc, String.class, String.class,
StringDecoder.class, StringDecoder.class,
kafkaConsumerConfig(), topics
);
Dataset<Row> dataSet = sqlContext.createDataFrame(javaSparkContext.emptyRDD(), schema);
DataSetHolder holder = new DataSetHolder(dataSet);
LongAccumulator stopStreaming = sc.longAccumulator("stop");
directStream.foreachRDD(rdd -> {
RDD<Row> rows = rdd.values().map(value -> {
//get type of message from value
Row row = null;
if (END == msg) {
stopStreaming.add(1);
row = null;
} else {
row = new GenericRow(/*row data created from values*/);
}
return row;
}).filter(row -> row != null).rdd();
holder.union(sqlContext.createDataFrame(rows, schema));
holder.get().count();
});
jsc.start();
//stop stream if stopStreaming value is greater than 0 its spawned as new thread.
return holder.get();
此处DatasetHolder
是class
周围的包装Dataset
,用于合并所有rdds
的结果。
class DataSetHolder {
private Dataset<Row> df = null;
public DataSetHolder(Dataset<Row> df) {
this.df = df;
}
public void union(Dataset<Row> frame) {
this.df = df.union(frame);
}
public Dataset<Row> get() {
return df;
}
}
这看起来并不好,但我不得不这样做。我想知道这样做的好方法是什么。或者Spark是否有任何规定?
因此,在使用来自kafka主题的流中的所有数据之后,我们创建了一个数据帧,以便数据分析师可以将其注册为临时表,并可以触发任何查询以获得有意义的结果。