我在mysql中有以下表结构:
创建表用户(
id INT NOT NULL,
name VARCHAR(20)NOT NULL,
年龄INT NOT NULL,
地址VARCHAR(100)NOT NULL);
现在,我想编写一个火花流式传输作业,从Kafka读取数据,进行一些处理和过滤,并在表格“用户”中写入RDBMS。
为此,我首先创建了表的POJO表示 -
@Data
class User implements Serializable {
private int id;
private String name;
private int age;
private String address;
}
下面,我编写了将rdd转换为数据帧的spark作业 -
JavaDStream<User> userStream = ... // created this stream with some processing
userStream.foreachRDD(rdd -> {
DataFrame df = sqlContext.createDataFrame(rdd,User.class);
df.write().mode(SaveMode.Append).jdbc(MYSQL_CONNECTION_URL, "user", new java.util.Properties());
});
现在,一旦我执行了这段代码,因为数据框是以灾难危险的方式形成的,并且它不与数据库模式同步。因此,它试图插入地址&#39;在&#39; id&#39;列和退出时带有sql异常。
我无法理解如何使数据框理解数据库的模式并相应地从User对象加载数据。有没有办法做到这一点?我认为 JavaRDD 可以映射到 JavaRDD ,但后来我无法理解该做些什么。
此外,我相信这个 createDataFrame() API流程使用反射(必须),因此,还存在性能影响的问题。你能告诉我是否有办法维护POJO和关系数据库之间的映射,并插入数据?
答案 0 :(得分:1)
这样做对我有用。
@Data
class User implements Serializable {
private int id;
private String name;
private int age;
private String address;
private static StructType structType = DataTypes.createStructType(new StructField[] {
DataTypes.createStructField("id", DataTypes.IntegerType, false),
DataTypes.createStructField("name", DataTypes.StringType, false),
DataTypes.createStructField("age", DataTypes.IntegerType, false),
DataTypes.createStructField("address", DataTypes.StringType, false)
});
public static StructType getStructType() {
return structType;
}
public Object[] getAllValues() {
return new Object[]{id, name, age, address};
}
}
火花工作 -
JavaDStream<User> userStream = ... // created this stream with some processing
userStream.map(e -> {
Row row = RowFactory.create(e.getAllValues());
return row;
}).foreachRDD(rdd -> {
DataFrame df = sqlContext.createDataFrame(rdd,User.getStructType());
df.write().mode(SaveMode.Append).jdbc(MYSQL_CONNECTION_URL, "user", new java.util.Properties());
});
我认为这是比以前更好的方法,因为在前一个数据框中,数据框使用反射将POJO映射到它自己的数据结构中。这是一种更干净的方式,因为我已经是Row是一种spark sql本身的格式,我已经提到了在 getAllValues() 中将数据插入数据帧的顺序 getStructType()
中的列映射如果我错了,请纠正我。