Java 使用DataStax Spark连接器在Cassandra中保存空值

Java 使用DataStax Spark连接器在Cassandra中保存空值,java,cassandra,apache-spark,Java,Cassandra,Apache Spark,我尝试使用Spark和Cassandra Spark连接器将流数据保存到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=availab

我尝试使用Spark和Cassandra Spark连接器将流数据保存到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]);
        }
    });
如果某些值为
null
I,则会出现以下错误:

com.datastax.spark.connector.types.TypeConversionException: Cannot convert object null to struct.ValueRepr.

有没有办法使用Spark Cassandra连接器存储空值?

Cassandra没有空值的概念。列为空或已填充。我在scala中通过以下方式解决了这个问题:我使用map方法并检查空值。我用空字符串覆盖null。就这样。工作非常好。

在scala中,您也可以为此使用选项。

我们可以知道您的依赖项(Spark、Connector、Cassandra等)的版本吗

是的,有一种方法可以使用Cassandra连接器存储空值。我让您的示例通过一个简单的应用程序和一些更改(添加Serializabe+将您的模型属性转换为Camel-Case+相对的getter和setter)正常工作。我对JavaAPI不太熟悉(在执行Spark时,您真的应该使用Scala,它使事情变得更简单),但我的印象是,对模型类的反射是在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();
}

不过,了解如何“写入”空值的含义很重要。一般来说,我们希望避免写空,因为Cassandra是如何生成墓碑的。如果这些是初始写入,您将希望将它们视为“未设置”

全局将所有空值视为未设置 全局地将所有空值视为未设置的WriteConf现在还包含 可通过使用SparkConf键设置的参数ignoreNulls spark.cassandra.output.ignoreNulls。默认值为false,这将 使空值与以前的版本一样处理(插入到 卡桑德拉(原样)。当设置为true时,所有空值都将被视为未设置。 这可以与数据帧一起使用,以跳过空记录并避免 墓碑


编辑:我应该澄清一下,在内部,Cassandra没有存储实际的空值-它只是未设置。但是我们可以用Cassandra在应用程序级别使用null进行推理。

提供同样的更多细节,我不这么认为。我已经尝试使用Datastax的java映射驱动程序将空值插入Cassandra表,并且成功了,即使列类型是int和float。Cassandra也显示null并返回null,因此“Cassandra没有null的概念”这句话就不太令人信服了。遇到这个错误:java.lang.NoSuchMethodError:org.apache.SparkContext.getExecutorStorageStatus()[Lorg/apache/spark/storage/StorageStatus;在com.datastax.spark.connector.cql.CassandraConnector$.apply(CassandraConnector.scala:204)位于com.datastax.spark.connector.RDDFunctions.saveToCassandra$default$5(RDDFunctions.scala:32)…53 elidedSpark版本:2.4。3@SumitAgarwal当您的spark连接器版本与您的spark版本不兼容时,您会发现这是一个例外。您可以检查兼容性矩阵:谢谢您的帮助,如果可能的话,您可以查看一下吗:
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