列的注释@ClusteringColumn 的排序值无效?

Invalid ordering value for annotation @ClusteringColumn of column?

我正在使用 Cassandra 2.2.1。我有一个 table job_status 和以下键:

主键(job_id、is_complete、last_run_at) WITH CLUSTERING ORDER BY (is_complete ASC, last_run_at DESC)

排序

我有以下 java class:

@Table(keyspace = "storakle", name = "import_job_status")
public class JobStatus
{
    @PartitionKey
    @Column(name = "job_id")
    private String jobId;   

    @ClusteringColumn
    @Column(name = "is_complete")
    private boolean isComplete;

    @ClusteringColumn
    @Column(name = "last_run_at")
    private Date lastRunAt;

    @Column(name = "run_number_of_times")
    private int runNumberOfTimes;
}

我想通过 Cassandra Java 驱动程序中的 Mapper class 查询我的 job_status table,如下所示:

public JobStatus getIncompleteJobStatusById(String jobId)
{
        Mapper<JobStatus> mapper = new   MappingManager(_cassandraDatabaseManager.getSession()).mapper(JobStatus.class);

        boolean isComplete = false;
        JobStatus jobStatus = mapper.get(jobId, isComplete);

        return jobStatus;
}

但是我收到以下错误:

"Invalid ordering value 0 for annotation @ClusteringColumn of column lastRunAt, was expecting 1"

我明白为什么会这样了。映射器获取在 JobStatus class 中注释的所有主键和集群键,并检查调用以获取 mapper.get 方法中提供的键是否与注释中的键的编号相同 class.

但我认为在 Cassandra 中可以查询 table 而无需指定所有聚类键,只要您省略的那些在最后?

在这种情况下我不应该使用 Mapper 吗?

如果你检查 get on mapper 做了什么:

/** * Fetch an entity based on its primary key. *

* This method is basically equivalent to: {@code map(getManager().getSession().execute(getQuery(primaryKey))).one()}.

这是为了从数据库中获取映射class的单个实体,因此必须指定完整的主键。

正如我从您的示例中了解到的那样,您希望根据 last_run_at 排序的作业 ID 和状态查看作业列表 运行,这是范围查询。您可以创建 Datastax accessor interface、添加范围查询并在您的代码中使用它。

@Accessor
public interface JobStatusAccessor {

    @Query("SELECT * FROM import_job_status WHERE job_id = :jobId AND "
        + "is_complete = :isComplete;")
    Statement getJobRunsByStatus(@Param("jobId") String jobId,
        @Param("isComplete") boolean isComplete);

}

而且在你的代码中你可以这样做:

public JobStatus getIncompleteJobStatusById(String jobId)
{
        JobStatusAccessor jobStatusAccessor = new   MappingManager(_cassandraDatabaseManager.getSession()).createAccessor(JobStatusAccessor.class);

        boolean isComplete = false;
        List<JobStatus> jobRunsByStatus = jobStatusAccessor.getJobRunsByStatus(jobId, isComplete);

        return jobStatus.get(0); //here I suppose you need last one
}

通过查看您的模型,您正在存储作业列表 运行,首先按状态聚集,然后按 运行 时间戳聚集。因此,当您提供工作 ID 和状态时,您将获得工作列表 运行,因此您的模型可能不正确(映射的名称 class 应该是 JobRun,而不是 JobStatus ).如果您只需要作业 运行 的最后状态,您可以从集群键中删除 lastRunAt 并执行更新插入,这将只保留最新的 运行 状态,因此您将拥有每个作业 ID 和每个状态只有一个条目。

您遇到此错误是因为您有多个分区键。

集群列是复合主键定义的一部分,但不是第一列。 列聚集在单个分区内的多行中。聚簇顺序由列在复合主键定义中的位置决定。

作为驱动的官方java文档,解决方案是当分区键有多个组件时使用Ordinal int。

正确的配置可能是这样的:

@Table(keyspace = "storakle", name = "import_job_status")
public class JobStatus
{
    @PartitionKey(0)
    @Column(name = "job_id")
    private String jobId;   

    @ClusteringColumn(1)
    @Column(name = "is_complete")
    private boolean isComplete;

    @ClusteringColumn(2)
    @Column(name = "last_run_at")
    private Date lastRunAt;

    @Column(name = "run_number_of_times")
    private int runNumberOfTimes;
}

正如已经提到的答案,您缺少分区键和集群键的序号。 正确的配置是

@Table(keyspace = "storakle", name = "import_job_status")
public class JobStatus
{
  @PartitionKey(0)
  @Column(name = "job_id")
  private String jobId;   

  @ClusteringColumn(0)
  @Column(name = "is_complete")
  private boolean isComplete;

  @ClusteringColumn(1)
  @Column(name = "last_run_at")
  private Date lastRunAt;

  @Column(name = "run_number_of_times")
  private int runNumberOfTimes;
}