我尝试使用Spark和Cassandra Spark Connector将流数据保存到Cassandra中。
我做了类似下面的事情:
创建一个模型类:
public class ContentModel {
String id;
String available_at; //may be null
public ContentModel(String id, String available_at){
this.id=id;
this.available_at=available_at,
}
}
将流媒体内容映射到模型:
JavaDStream<ContentModel> contentsToModel = myStream.map(new Function<String, ContentModel>() {
@Override
public ContentModel call(String content) throws Exception {
String[] parts = content.split(",");
return new ContentModel(parts[0], parts[1]);
}
});
保存:
CassandraStreamingJavaUtil.javaFunctions(contentsToModel).writerBuilder("data", "contents", CassandraJavaUtil.mapToRow(ContentModel.class)).saveToCassandra();
如果某些值为null
,则会出现以下错误:
com.datastax.spark.connector.types.TypeConversionException: Cannot convert object null to struct.ValueRepr.
有没有办法使用Spark Cassandra Connector存储空值?
答案 0 :(得分:0)
Cassandra没有null的概念。列是空的或已填充。我通过以下方式在scala中解决了这个问题:我使用了map方法并检查了null值。我用空字符串覆盖null。而已。工作真的很好。
答案 1 :(得分:0)
在scala中,您也可以使用选项。
答案 2 :(得分:0)
我们可以知道您的依赖项的版本(Spark,Connector,Cassandra等)
是的,有一种方法可以通过Cassandra连接器存储空值。我得到了您的示例,使其可以与简单应用程序一起正常工作,并进行了一些更改(添加Serializabe +将模型属性转换为Camel Case +相对getter和setter)。我对Java API不太熟悉(在做Spark时确实应该使用Scala,它使事情变得容易得多),但我的印象是对Model类的反思是在getter / setter级别完成的……可能是错误的。
模型
public class ModelClass implements Serializable {
String id;
String availableAt; //may be null
public ModelClass(String id, String availableAt){
this.id=id;
this.availableAt=availableAt;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getAvailableAt() {
return availableAt;
}
public void setAvailableAt(String availableAt) {
this.availableAt = availableAt;
}
}
驾驶员
public static void main(String ... args) {
SparkConf conf = new SparkConf();
conf.setAppName("Local App");
conf.setMaster("local[*]");
JavaSparkContext context = new JavaSparkContext(conf);
List<ModelClass> modelList = new ArrayList<>();
modelList.add(new ModelClass("Test", null));
modelList.add(new ModelClass("Test2", "test"));
context.parallelize(modelList);
JavaRDD<ModelClass> modelRDD = context.parallelize(modelList);
javaFunctions(modelRDD).writerBuilder("test", "model", mapToRow(ModelClass.class))
.saveToCassandra();
}
生产
cqlsh:test> select * from model;
id | available_at
-------+--------------
Test | null
Test2 | test
重要的是要知道如何“写”空值的含义。一般来说,由于Cassandra如何生成墓碑,我们希望避免空值写入。如果这些是初始写入,则将它们视为“未设置”。
全局将所有null都视为Unset
全局将所有空值视为Unset WriteConf现在还包含一个 可以使用SparkConf键设置的参数ignoreNulls spark.cassandra.output.ignoreNulls。默认为false,它将 导致将null视为以前的版本(被插入到 卡桑德拉(Cassandra)。设置为true时,所有null将被视为未设置。 可以与DataFrames一起使用,以跳过空记录并避免 墓碑。