【问题标题】:Java driver delete partition by timestampJava驱动程序按时间戳删除分区
【发布时间】:2015-12-13 01:31:48
【问题描述】:

我正在从 Cassandra 检索数据并使用 Java 驱动程序中的内置对象映射 API 将其映射到一个类。处理完数据后,我想删除它。我的集群键是一个时间戳,它被映射到一个 Date 对象。当我尝试删除一个分区时,它不会被删除。我怀疑这是因为映射到 Date 对象并且那里丢失了一些数据?你有遇到过类似的问题吗?

访问者:

@Query("SELECT * FROM my_table WHERE id = ? AND event_time < ?")
    Result<MyObject> getAllObjectsByTime(UUID id, Date eventToTime);

对象的检索:

MappingManager manager = new MappingManager (_cassandraDatabaseManager.getSession());

        CassandraAccessor cassandraAccessor = manager.createAccessor(CassandraAccessor.class);
        Result<MyObject> myObjectResult = cassandraAccessor.getAllObjectsByTime(id, eventToTime);

我的对象:

@Table(keyspace = "myKeyspace", name = "my_table ")
public class MyObject
{
    @PartitionKey
    @Column(name = "id")
    private UUID id;

    @Column(name = "event_time")
    private Date eventTime;
}

删除逻辑:

 PreparedStatement statement = session
                .prepare("DELETE FROM my_table WHERE id = ? AND event_time = ?;");


        BatchStatement batch = new BatchStatement();

        for (MyObject myObject: myObjects)
        {     
            batch.add(statement.bind(myObject.getStoreId(), myObject.getEventTime()));
        }

        session.execute(batch);

编辑

经过大量调试后,我发现日期可能不是问题所在。似乎删除工作正常,但不适用于所有分区。当我调试 Java 应用程序时,我得到以下 CQL 语句:

DELETE FROM my_table WHERE id=86a2f31d-5e6e-448b-b16c-052fe92a87c9 AND event_time=1442491082128;

当它通过Cassandra Java Driver 执行时,分区不会被删除。如果我在CQLSH 控制台中执行它,分区就会被删除。我不知道发生了什么。我开始怀疑Cassandra Java Driver 有问题。有什么想法吗?


编辑 2

这是桌子:

CREATE TABLE my_table(
    id uuid,
    event_time timestamp,
    event_data text,
    PRIMARY KEY (id, event_time)
) WITH CLUSTERING ORDER BY (event_time DESC)

【问题讨论】:

    标签: java cassandra


    【解决方案1】:

    我需要查看更多代码以了解您是如何发出删除的,但也许您没有将时间戳指定为正确的删除精度。

    内部时间戳字段是以毫秒为单位的纪元时间。当您在 cqlsh 中查看时间戳时,它会显示向下舍入到最接近的秒的时间戳,如下所示:

    SELECT * from t12 where a=1 and b>'2015-09-16 12:51:49+0000';
    
     a | b
    ---+--------------------------
     1 | 2015-09-16 12:51:49+0000
    

    因此,如果您尝试使用该日期字符串进行删除,则它不会完全匹配,因为实际值类似于 2015-09-16 12:51:49.123+0000

    如果您将时间戳显示为以毫秒为单位的纪元时间,那么您可以将其删除:

    SELECT a, blobAsBigint(timestampAsBlob(b)) from t12;
     a | system.blobasbigint(system.timestampasblob(b))
    ---+------------------------------------------------
     1 |                                  1442407909964
    
    DELETE from t12 where a=1 and b=1442407909964;
    

    this

    【讨论】:

    • 另外一个来自我...*正是*我认为这里发生的事情也是。
    • 我认为这就是问题所在。你知道我如何使用 java 驱动程序和对象映射 API 来实现它吗?我认为我可以将 eventTime 属性设置为 long 并像这样使用它。但是有没有更好的方法(保持日期不变)?
    • 当您执行删除操作时,您可能需要在绑定语句中执行 myObject.getEventTime().getTime() 以便它使用以毫秒为单位的纪元,而不是一些默认转换。
    • 当我尝试得到以下异常com.datastax.driver.core.exceptions.InvalidTypeException: Invalid type for value 1 of CQL type timestamp, expecting class java.util.Date but class java.lang.Long provided
    • 那我不知道怎么解决。我通常不会尝试删除单个时间戳,通常使用 TTL 来处理删除。
    【解决方案2】:

    我发现批处理语句被丢弃或超时的问题。您尝试每批执行多少次删除?尝试降低批处理大小或完全删除批处理。

    请记住,Cassandra 中的批处理语句旨在以原子方式将更新应用于多个不同的表。它们真的不打算用来将几千个更新塞进一张表中。

    要详细了解批处理语句的工作原理,请观看来自 (DataStax MVP) Chris Batey 在Avoiding Cassandra Anti-Patterns 上的网络研讨会视频。在 16:00 分钟,他讨论了当集群应用批处理语句时(确切地)发生了什么。

    【讨论】:

    • 出于测试目的,我的批处理中只有 5-10 个删除语句。我也尝试使用QueryBuilder,但结果相同Delete.Where delete = QueryBuilder.delete() .from("my_table") .where(QueryBuilder.eq("id", myObject.getId())) .and(QueryBuilder.eq("event_time", myObject.getEventTime()));
    猜你喜欢
    • 2020-11-14
    • 2016-05-21
    • 2015-10-24
    • 2012-10-10
    • 1970-01-01
    • 2018-08-11
    • 2011-10-04
    • 1970-01-01
    • 2017-02-04
    相关资源
    最近更新 更多