使用DataStax Spark Connector在Cassandra中保存空值

时间:2015-10-07 14:13:36

标签: java cassandra apache-spark

我尝试使用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存储空值?

3 个答案:

答案 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一起使用,以跳过空记录并避免   墓碑。

https://github.com/datastax/spark-cassandra-connector/blob/master/doc/5_saving.md#globally-treating-all-nulls-as-unset