使用结构化流一次将所有数据写入拼花文件

时间:2019-05-29 20:05:45

标签: apache-spark spark-structured-streaming

我希望将所有来自Kafka主题的汇总数据一次写入到一个Parquet文件中(或至少最后以一个Parquet文件结束)。

我运行一个单独的生产者应用程序,该应用程序将50条消息放在该主题上。 数据是在消费者应用中按时间(1天)汇总的,因此我需要收集1天以来的所有数据并进行计数。这项工作是这样完成的:

Dataset<Row> df = spark.readStream()
                .format("kafka")
                .option("kafka.bootstrap.servers", BOOTSTRAP_SERVER)
                .option("subscribe", "test")
                .option("startingOffsets", "latest")
                .option("group.id", "test")
                .option("failOnDataLoss", false)
                .option("key.deserializer", "org.apache.kafka.common.serialization.IntegerDeserializer")
                .option("value.deserializer", "org.apache.kafka.common.serialization.StringSerializer")
                .load()

// LEFT OUT CODE FOR READABILITY

                .withWatermark("timestamp", "1 minutes")
                .groupBy(
                        functions.window(new Column("timestamp"), "1 day", "1 day"),
                        new Column("container_nummer"))
                .count();

然后将结果写入像这样的镶木地板文件中:

StreamingQuery query = df.writeStream()
                .format("parquet")
                .option("truncate", "false")
                .option("checkpointLocation", "/tmp/kafka-logs")
                .start("/Users/**/kafka-path");

query.awaitTermination();

如果我将此写入控制台,最终我将获得批次1中每一天的正确计数。当尝试将其写入木地板时,我只会得到多个空的木地板文件。我这样阅读:

SparkSession spark = SparkSession
                .builder()
                .appName("test")
                .config("spark.master", "local")
                .config("spark.sql.session.timeZone", "UTC")
                .getOrCreate();

        Dataset<Row> df = spark.read()
                .parquet("/Users/**/kafka-path/part-00000-dd416263-8db1-4166-b243-caba470adac7-c000.snappy.parquet");

        df.explain();
        df.show(20);

所有实木复合地板文件似乎都是空的(与将它们写入控制台相反),上面的代码输出如下:

+------+----------------+-----+
|window|container_nummer|count|
+------+----------------+-----+
+------+----------------+-----+

我有两个问题:

  • 我的实木复合地板文件为空的可能原因是什么?
  • 最后是否可以有1个完整的镶木地板文件,其中包含所有数据?我想使用这些数据在其他程序中提供机器学习模型。

注意:它不需要在生产中运行。我只是希望有人知道一种解决方法。

谢谢!

1 个答案:

答案 0 :(得分:0)

读取正在进行的流涉及的组件是结构化流。因此,您基本上正在读取无限制的消息/记录流,这些消息/记录将在数据到达时和写入时进行写入。以此为基础,Spark将继续分配执行者来执行读/写操作,并且将在此过程中创建多个文件。因此,您将不会拥有一个包含所有数据的文件。以下是可用于写入镶木地板文件的语法:

df..writeStream.queryName("Loantxns_view").outputMode("append").format("parquet").option("path", "/user/root/Ln_sink2").option("checkpointLocation", "/user/root/Checkpoints2").start()

尝试使用以下机制读取镶木地板文件,看看是否获得了所需的数据(ParquetDF是通过读取镶木地板目录路径读取的新数据框):

val ParquetDF = spark.read.parquet("/user/root/Ln_sink2")
    ParquetDF.createOrReplaceTempView("xxxx_view");
    spark.sql("select * from xxxx_view").show(false);

尝试一下,看看数据是否可见。