【问题标题】:Spark Cassandra Connector behaves different from CQL shell - Insert issueSpark Cassandra 连接器的行为与 CQL shell 不同 - 插入问题
【发布时间】:2017-06-05 05:01:59
【问题描述】:

我有以下 Cassandra DM:

  CREATE TABLE table (
    id uuid,
    timestamp timestamp STATIC,
    value1 text STATIC,
    value2 int,
    value3 text,
    data map <text,text>,
    PRIMARY KEY ( id, value2 )
);

到目前为止一切顺利。现在我必须先插入我想插入的格式类型:

INSERT INTO table (id, timestamp, value1)
VALUES (<uuid>,<timestamp>,<some-string>);

INSERT INTO table (id, value2, value3, data)
VALUES (<some-id>,<some-int>,<some-string>, <some-simple-json-map>)

两个 CQL 语句都可以正常工作。 现在我正在开发我的 spark 流应用程序来获取数据并将其格式化为类似于我的 CQL 语句样式的数据帧。我为每组语句 1 得到几组语句 2。

现在我在保存数据帧时遇到问题,例如第一个 CQL 语句 spark 引发 cassandra 异常:

    java.lang.IllegalArgumentException: 

        Some primary key columns are missing in RDD or have not been selected: value2
            at com.datastax.spark.connector.writer.TableWriter$.checkMissingPrimaryKeyColumns(TableWriter.scala:190)
            at com.datastax.spark.connector.writer.TableWriter$.checkColumns(TableWriter.scala:257)
            at com.datastax.spark.connector.writer.TableWriter$.apply(TableWriter.scala:275)
            at com.datastax.spark.connector.RDDFunctions.saveToCassandra(RDDFunctions.scala:36)
           ...

这里是我的数据框的架构:

 root
  |-- id: string (nullable = true)
  |-- timestamp: long (nullable = true)
  |-- value1: string (nullable = true)

我的存档:

 data.select("id", "timeStamp", "value1")
    .write.format("org.apache.spark.sql.cassandra")
      .mode(SaveMode.Append)
      .options(Map("keyspace" -> "some_keyspace","table" -> "table"))
      .save()

当我将值 2 列添加到我的数据框时,该语句工作正常。

root
 |-- id: string (nullable = true)
 |-- timestamp: long (nullable = true)
 |-- value1: string (nullable = true)
 |-- value2: integer (nullable = false)

有没有办法让它像 CQL 语句一样工作而不更改数据模型?

【问题讨论】:

  • 看起来像静态列的错误,你应该提交一个 Jira

标签: apache-spark cassandra apache-spark-sql cql spark-cassandra-connector


【解决方案1】:

静态列是由同一分区的所有行共享的特殊列。在第一个插入示例中,CQL 允许您为分区插入仅静态数据:

插入 ctest (id, timestamp, value1) VALUES (233177ff-439b-4a2d-a8b0-4db742b4bc1b, '2013-01-01 00:05+0000', 'one');

从 ctest 中选择 *;

 id                                   | value2 | timestamp                | value1 | data | value3
--------------------------------------+--------+--------------------------+--------+------+--------
 233177ff-439b-4a2d-a8b0-4db742b4bc1b |   null | 2013-01-01 00:05:00+0000 |    one | null |   null

这将创建一个合成行;它看起来像一行,但它只是一个分区键和一个静态列。如果插入具有主键的真实行,则空值将消失:

插入 ctest (id, value2) VALUES (233177ff-439b-4a2d-a8b0-4db742b4bc1b, 1);

从 ctest 中选择 *;

 id                                   | value2 | timestamp                | value1 | data | value3
--------------------------------------+--------+--------------------------+--------+------+--------
 233177ff-439b-4a2d-a8b0-4db742b4bc1b |      1 | 2013-01-01 00:05:00+0000 |    one | null |   null

(1 rows)

执行了两次插入后,您只有一行。

Spark-Cassandra 连接器更加严格,不允许您为分区插入仅静态数据。连接器代码检查是否定义了主键中的所有列。它在主键( id, value2 )中找到两列,仅设置一列并引发错误。下面是 com.datastax.spark.connector.writer.TableWriter 中的检查:

 private def checkMissingPrimaryKeyColumns(table: TableDef, columnNames: Seq[String]) {
    val primaryKeyColumnNames = table.primaryKey.map(_.columnName)
    val missingPrimaryKeyColumns = primaryKeyColumnNames.toSet -- columnNames
    if (missingPrimaryKeyColumns.nonEmpty)
      throw new IllegalArgumentException(
        s"Some primary key columns are missing in RDD or have not been selected: ${missingPrimaryKeyColumns.mkString(", ")}")
  }

有关这方面的更多背景知识,Mat Brown 所著的Learning Apache Cassandra一书在第 53-54 页讨论了仅静态插入。

【讨论】:

  • 谢谢。这很有帮助。
猜你喜欢
  • 2018-11-28
  • 1970-01-01
  • 2015-07-02
  • 2016-08-11
  • 2021-12-10
  • 1970-01-01
  • 2015-09-13
  • 1970-01-01
  • 2019-06-29
相关资源
最近更新 更多