如何创建RowEncoder将元组<a,row>映射到Row?

时间:2017-06-01 13:49:30

标签: java apache-spark apache-spark-sql

我有一个spark数据集,我根据需要将数据分组并减少了数据。我需要摆脱元组,只保留Tuple2 :: _ 2。 我试图按如下方式映射数据集:

sparkSession.read()
            .parquet("s3://stuff/*")
            .groupByKey((MapFunction<Row, Long>) value -> {
                long stamp = value.getAs("timeStamp");
                return stamp / 600000;
            }, Encoders.LONG())
            .reduceGroups((ReduceFunction<Row>) (v1, v2) -> {
                int fare1 = v1.getAs("totalFare");
                int fare2 = v2.getAs("totalFare");
                return fare1 < fare2 ? v1 : v2;
            })
            .map((MapFunction<Tuple2<Long, Row>, Row>) Tuple2::_2, RowEncoder.apply(null))

无法弄清楚如何向RowEncoder :: apply提供架构。 我正在阅读带有this架构的镶木地板文件。

2 个答案:

答案 0 :(得分:2)

所以我最终这样做了。基本上读取1个元素以获得所需的&#34; ExpressionEncoder&#34;。我需要完整的&#34;行&#34;在最终输出中,所以无法继续使用@ Jacek的方法。

System.out.println("Starting");
System.out.println(Arrays.toString(args));
Row sampleRow = sparkSession.read().parquet(readFrom).head();
ExpressionEncoder<Row> rowEncoder = RowEncoder.apply(sampleRow.schema());

//read all elements, process and write back the result
sparkSession.read()
            .parquet(readFrom)
            .groupByKey((MapFunction<Row, Long>) value -> {
                long stamp = value.getAs("timeStamp");
                return stamp / 600000;
            }, Encoders.LONG())
            .reduceGroups((ReduceFunction<Row>) (v1, v2) -> {
                int fare1 = v1.getAs("totalFare");
                int fare2 = v2.getAs("totalFare");
                return fare1 < fare2 ? v1 : v2;
            })
            .map((MapFunction<Tuple2<Long, Row>, Row>) Tuple2::_2, rowEncoder)
            .write()
            .parquet(writeTo);
System.out.println("Done !!!!");

答案 1 :(得分:1)

我没有在Spark中使用Java,所以我不能更具体,但......

如果我没弄错,您只想使用timeStamptotalFare字段。 timeStamp属于long类型,而totalFare属于int类型。

我的第一个建议是使用as运算符将无类型Row保留为Dataset[Long, Int](在Scala中):

  

公共数据集为(编码器证据$ 2)返回一个新的数据集,其中每条记录都已映射到指定的类型。

这样你就可以避免处理这些令人不快的Row对象,你的转换看起来如下:

sparkSession.read()
            .parquet("s3://stuff/*")
            .as(Encoder...)  // <-- I don't know how to write a tuple of (long, int) in Java

完成此操作后,您关于map的问题将得到&#34;映射&#34;使用Encoders.INT()如果我没有弄错(试图将我的Scala思维映射到Java&#39; s)。

我提倡使用as运算符的原因是使用groupByKeyreduceGroups对我来说是非常强烈的希望留下无类型的RelationalGroupedDataset API输入KeyValueGroupedDataset