如何在流式查询中使用from_json标准函数(在select中)?

时间:2019-09-08 20:06:00

标签: java json apache-spark apache-spark-sql spark-structured-streaming

我使用以下JSON结构处理来自Kafka的消息:

{"unix_time": 1557678233, "category_id": 1000, "ip": "172.10.34.17", "type": "view"}

我想打印出我收到的内容。这是我已经完成的工作的代码片段:

JavaSparkContext sc = createJavaSparkContext();
JavaStreamingContext streamingContext =
                new JavaStreamingContext(sc, Durations.seconds(BATCH_DURATION_IN_SECONDS));

SparkSession sparkSession = SparkSession
        .builder()
        .config(new SparkConf())
        .getOrCreate();

Dataset<Row> df = sparkSession
        .readStream()
        .format("kafka")
        .option("kafka.bootstrap.servers", CommonUtils.KAFKA_HOST_PORT)
        .option("subscribe", KAFKA_TOPIC)
        .load();

StreamingQuery query = df.selectExpr("CAST(value AS STRING)")
            .select(from_json(new Column("value"), getSchema())).as("data").
                    select("data.category_id").writeStream().foreach(new ForeachWriter<Row>() {
                @Override
                public void process(Row value) {
                    System.out.println(value);
                }

                @Override
                public void close(Throwable errorOrNull) {

                }

                @Override
                public boolean open(long partitionId, long version) {
                    return true;
                }
            })
            .start();

    query.awaitTermination();

模式方法:

private static StructType getSchema() {
    return new StructType(new StructField[]{
            new StructField(UNIX_TIME, DataTypes.TimestampType, false, Metadata.empty()),
            new StructField(CATEGORY_ID, DataTypes.IntegerType, false, Metadata.empty()),
            new StructField(IP, DataTypes.StringType, false, Metadata.empty()),
            new StructField(TYPE, DataTypes.StringType, false, Metadata.empty()),
    });
}

问题是我在从Spark写入时不断收到错误:

  

线程“ main” org.apache.spark.sql.AnalysisException中的异常:   给定输入列,无法解析“ data.category_id”:   [jsontostruct(value)] ;; '项目['data.category_id]   +-SubqueryAlias数据+-工程[jsontostruct(StructField(unix_time,TimestampType,false),   StructField(category_id,IntegerType,false),   StructField(ip,StringType,false),StructField(type,StringType,false),   value#15)AS jsontostruct(value)#18]

如何克服这个问题?有什么建议吗?

1 个答案:

答案 0 :(得分:2)

这部分异常会告诉您确切的位置:

  

在给定输入列的情况下无法解析“ data.category_id”:[jsontostruct(value)]

换句话说,可用列中没有列data.category_id,只有一个jsontostruct(value)

这意味着流查询中唯一的select不起作用。而且原因很简单(我可以将其归类为错字)-Column以及Dataset类型的as("data")之前都有太多的右括号。

总而言之,替换查询的以下部分:

.select(from_json(new Column("value"), getSchema())).as("data")

到以下:

.select(from_json(new Column("value"), getSchema()).as("data"))

请注意,我将一个右括号移到了末尾。