SparkSQL + Java:使用数据集时使用表格格式的Pojo

时间:2017-10-02 10:53:16

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

我对Spark SQL很陌生。在执行其中一项培训任务时,我遇到了以下问题但无法找到答案(以下所有示例都有点愚蠢,但仍应该用于演示目的)。

我的应用程序读取镶木地板文件并根据其内容创建数据集:

DataFrame input = sqlContext.read().parquet("src/test/resources/integration/input/source.gz.parquet");
Dataset<Row> dataset = input.as(RowEncoder$.MODULE$.apply(input.schema()));

dataset.show()调用结果为:

+------------+----------------+--------+
+    Names   +       Gender   +   Age  +
+------------+----------------+--------+
| Jack, Jill |  Male, Female  | 30, 25 |

然后我将数据集转换为Person类型内的新数据集:

public static Dataset<Person> transformToPerson(Dataset<Row> rawData) {
    return rawData
            .flatMap((Row sourceRow) -> {
                // code to parse an input row and split person data goes here
                Person person1 = new Person(name1, gender1, age1);
                Person person2 = new Person(name2, gender2, age2);
                return Arrays.asList(person1, person2);
            }, Encoders.bean(Person.class));
}

,其中

public abstract class Human implements Serializable {
   protected String name;
   protected String gender;
   // getters/setters go here
   // default constructor + constructor with the name and gender params
 }
 public class Person extends Human {
   private String age;
   // getters/setters for the age param go here
   // default constructor + constructor with the age, name and gender params
   // overriden toString() method which returns the string: (<name>, <gender>, <age>)
 }

最后,当我展示数据集的内容时,我希望看到

 +------------+----------------+--------+
 +    name    +       gender   +   age  +
 +------------+----------------+--------+
 |     Jack   |     Male       |   30   |
 |     Jill   |     Femail     |   25   |

但是,我看到了

+-------------------+----------------+--------+
+      name         +       gender   +   age  +
+-------------------+----------------+--------+
|(Jack, Male, 30)   |                |        |
|(Jill, Femail, 25) |                |        |

这是toString()方法的结果,而标题是正确的。 我相信编码器有问题,只要我使用Encoders.javaSerizlization(T)或Encoders.kryo(T)它就会显示

+------------------+
+        value     +
+------------------+
|(Jack, Male, 30)  |
|(Jill, Femail, 25)|

最让我担心的是,编码器的错误使用可能导致不正确的SerDe和/或性能损失。 我无法在所有可以找到的Spark Java示例中看到任何特别的东西......

你能否建议我做错了什么?

更新1

以下是我的项目依赖项:

    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-core_2.10</artifactId>
        <version>1.6.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-sql_2.10</artifactId>
        <version>1.6.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.spark</groupId>
        <artifactId>spark-hive_2.10</artifactId>
        <version>1.6.2</version>
    </dependency>

正如abaghel建议我将版本升级到2.0.2(请注意版本2.0.0上有the bug for Windows),在我的代码中到处使用数据集而不是DataFrames(似乎DataFrames不是其中的一部分) Apache Spark starting from 2.0.0),并使用基于迭代器的flatMap函数从Row转换为Person。

只是为了分享,使用TraversableOnce-based flatMap版本1.6.2的方法对我来说不起作用,因为它抛出了'MyPersonConversion $ function1而不是Serializable&#39;异常。

现在一切都按预期工作了。

1 个答案:

答案 0 :(得分:1)

您使用的Spark版本是什么?您提供的flatMap的方法未使用2.2.0版进行编译。所需的退货类型为import subprocess in_file = '/path/input.mp4' out_file = '/path/output.mp4' crop_dimensions = subprocess.Popen(['ffmpeg -i ' + in_file + ' -vf cropdetect -f null - 2>&1 | awk \'/crop/ { print $NF }\' | tail -1'], shell=True, stdout=subprocess.PIPE).stdout.read().strip() cmd = [ 'ffmpeg', '-y', '-i', in_file, '-vf', crop_dimensions, out_file ] subprocess.Popen(cmd, stdout = subprocess.PIPE, bufsize=10**8) 。请在FlatMapFunction下方使用,您将获得所需的输出。

Iterator<Person>