如何使用密钥对卡桑德拉实现分页?

时间:2018-11-07 12:07:30

标签: cassandra datastax-java-driver cqlsh spring-data-cassandra

我正在尝试为我的应用程序实现某种分页功能,该功能在后端使用cassandra。

CREATE TABLE sample (
    some_pk int,
    some_id int,
    name1 txt,
    name2 text,
    value text,
    PRIMARY KEY (some_pk, some_id, name1, name2)
)
WITH CLUSTERING ORDER BY(some_id DESC)

我想查询100条记录,然后将最后一条记录键存储在内存中,以备后用。

+---------+---------+-------+-------+-------+
| sample_pk| some_id | name1 | name2 | value |
+---------+---------+-------+-------+-------+
| 1       | 125     | x     | ''    | ''    |
+---------+---------+-------+-------+-------+
| 1       | 124     | a     | ''    | ''    |
+---------+---------+-------+-------+-------+
| 1       | 124     | b     | ''    | ''    |
+---------+---------+-------+-------+-------+
| 1       | 123     | y     | ''    | ''    |
+---------+---------+-------+-------+-------+

(为简单起见,我将一些列留空。分区键(sample_pk)并不重要)

假设我的页面大小为2。

select * from sample where sample_pk=1 limit 2;

返回前2行。现在我将最后一条记录存储在查询结果中,然后再次运行查询以获取下2行;

这是由于单个非EQ关系的限制而无法使用的查询

select * from where sample_pk=1 and some_id <= 124 and name1>='a' and name2>='' limit 2; 

此结果返回错误的结果,因为some_id按降序排列,而name列按升序排列。

select * from where sample_pk=1 and (some_id, name1, name2) <= (124, 'a', '') limit 2; 

所以我被困住了。如何实现分页?

2 个答案:

答案 0 :(得分:2)

您可以运行第二个查询,例如

.vcproj

现在,在提取记录之后,请忽略已读取的记录(之所以可以这样做,是因为您要存储上一个选择查询中的最后一条记录)。

如果忽略这些记录,如果您最终得到的行/记录为空列表,则意味着您已遍历所有记录,否则将继续执行此分页任务。

答案 1 :(得分:1)

您不必在内存中存储任何密钥,也不需要在cqlsh查询中使用limit。只需在应用程序代码中使用datastax driver的功能来进行分页,就像下面的代码一样:

public Response getFromCassandra(Integer itemsPerPage, String pageIndex) {
    Response response = new Response();
    String query = "select * from sample where sample_pk=1";
    Statement statement = new SimpleStatement(query).setFetchSize(itemsPerPage); // set the number of items we want per page (fetch size)
    // imagine page '0' indicates the first page, so if pageIndex = '0' then there is no paging state
    if (!pageIndex.equals("0")) {
        statement.setPagingState(PagingState.fromString(pageIndex));
    }
    ResultSet rows = session.execute(statement); // execute the query
    Integer numberOfRows = rows.getAvailableWithoutFetching(); // this should get only number of rows = fetchSize (itemsPerPage)
    Iterator<Row> iterator = rows.iterator();
    while (numberOfRows-- != 0) {
        response.getRows.add(iterator.next());
    }
    PagingState pagingState = rows.getExecutionInfo().getPagingState();
    if(pagingState != null) { // there is still remaining pages
        response.setNextPageIndex(pagingState.toString());
    }
    return response;
}

请注意,如果您使while循环如下所示:

while(iterator.hasNext()) {
    response.getRows.add(iterator.next());
}

它将首先获取与我们设置的获取大小相等的行数,然后,只要查询仍与Cassandra中的某些行匹配,它将再次从cassandra中获取,直到从cassandra中获取与查询匹配的所有行,这可能如果要实现分页功能,则不适用

来源:https://docs.datastax.com/en/developer/java-driver/3.2/manual/paging/