[英]Cassandra pagination
我在 Cassandra 中有一個表,有 100 萬條記錄。 我想一次獲取 100 條記錄,所以如果我獲取前 100 條記錄,下一次獲取應該從項目 101 開始。我如何獲得這種分頁? 我也使用了PagingState
但它沒有用。
我的代碼如下:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.datastax.driver.core.PagingState;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.Session;
import com.datastax.driver.core.Statement;
/**
*
* The solution of skipping rows is that use page state rather than iterator
* rows one by one.
*
*/
public class CassandraPaging {
private Session session;
public CassandraPaging(Session session) {
this.session = session;
}
/**
* Retrieve rows for the specified page offset.
*
* @param statement
* @param start
* starting row (>1), inclusive
* @param size
* the maximum rows need to retrieve.
* @return List<Row>
*/
public List<Row> fetchRowsWithPage(Statement statement, int start, int size) {
ResultSet result = skipRows(statement, start, size);
return getRows(result, start, size);
}
private ResultSet skipRows(Statement statement, int start, int size) {
ResultSet result = null;
int skippingPages = getPageNumber(start, size);
String savingPageState = null;
statement.setFetchSize(size);
boolean isEnd = false;
for (int i = 0; i < skippingPages; i++) {
if (null != savingPageState) {
statement = statement.setPagingState(PagingState
.fromString(savingPageState));
}
result = session.execute(statement);
PagingState pagingState = result.getExecutionInfo()
.getPagingState();
if (null != pagingState) {
savingPageState = result.getExecutionInfo().getPagingState()
.toString();
}
if (result.isFullyFetched() && null == pagingState) {
// if hit the end more than once, then nothing to return,
// otherwise, mark the isEnd to 'true'
if (true == isEnd) {
return null;
} else {
isEnd = true;
}
}
}
return result;
}
private int getPageNumber(int start, int size) {
if (start < 1) {
throw new IllegalArgumentException(
"Starting row need to be larger than 1");
}
int page = 1;
if (start > size) {
page = (start - 1) / size + 1;
}
return page;
}
private List<Row> getRows(ResultSet result, int start, int size) {
List<Row> rows = new ArrayList<>(size);
if (null == result) {
return rows;
}
int skippingRows = (start - 1) % size;
int index = 0;
for (Iterator<Row> iter = result.iterator(); iter.hasNext()
&& rows.size() < size;) {
Row row = iter.next();
if (index >= skippingRows) {
rows.add(row);
}
index++;
}
return rows;
}
}
這是主要方法:
public static void main(String[] args) {
Cluster cluster = null;
Session session = null;
try {
cluster = Cluster.builder().addContactPoint("localhost").withPort(9042).build();
session = cluster.connect("mykeyspace");
Statement select = QueryBuilder.select().all().from("mykeyspace", "Mytable");
CassandraPaging cassandraPaging = new CassandraPaging(session);
System.out.println("*************First Page1 **************");
List<Row> firstPageRows = cassandraPaging.fetchRowsWithPage(select, 1, 5);
printUser(firstPageRows);
System.out.println("*************Second Page2 **************");
List<Row> secondPageRows = cassandraPaging.fetchRowsWithPage(select, 6, 5);
printUser(secondPageRows);
System.out.println("*************Third Page3 **************");
List<Row> thirdPageRows = cassandraPaging.fetchRowsWithPage(select, 6, 5);
printUser(thirdPageRows);
cluster.close();
session.close();
} catch(Exception exp) {
exp.printStackTrace();
} finally {
cluster.close();
session.close();
}
}
private static void printUser(final List<Row> inRows) {
for (Row row : inRows) {
System.out.println("Id is:" + row.getUUID("id"));
System.out.println("Name is:" + row.getInt("name"));
System.out.println("account is:" + row.getString("account"));
}
}
/*First, get the number of page states with page limit size (in my case 25):*/
int n=0;
PagingState pageStates=null;
Map<Integer, PagingState> stringMap=new HashMap<Integer, PagingState>();
do{
Statement select = QueryBuilder.select().all().from("keyspace", "tablename").setFetchSize(25).setPagingState(pageStates);
ResultSet resultSet=session.execute(select);
pageStates=resultSet.getExecutionInfo().getPagingState();
stringMap.put(++n,pageStates);
}while (pageStates!=null);
/*Then, find page index -> get the exact page state -> pass it in query
========================================================================
1.Get the page number
2.calculate the offset with pagelimit(in my case 25)
3.get the pageindex
4. pass pagestate of appropriate page index in query */
int pagenumber ;
int offset = (pagenumber * 25) - 25;
int pageindex=(offset/25)-1;
Statement selectq = QueryBuilder.select().all().from("keyspace", "tablename").setPagingState(stringMap.get(pageindex));
ResultSet resultSet = session.execute(selectq);
fourthPageRows=cassandraPaging.getRows(resultSet,offset,25);
要使用以下解決方案,您的類路徑中需要 spring-data 依賴項。
Spring 提供了PageRequest
,它是Pageable
一個實現,它接受pageNo
和size
(在頁面上顯示的記錄數)。
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
PageRequest(int page, int size)
示例
創建回購。
創建 repo 使用org.springframework.data.repository.PagingAndSortingRepository
class CasandraRepo extends PagingAndSortingRepository{
}
//在repository.findAll
使用這個pageReq
,如下圖;
Pageable pageReq = new PageRequest(0, 10);
CasandraRepo repo;
repo.findAll(pageReq);
為此,您需要在項目中導入 spring-cassandra-data 依賴項。
當我們發送除 0(或第一頁)以外的頁面時,不能使用 Simple PageRequest 來獲取可分頁對象。 它引發異常: “無法為第一頁 (0) 以外的索引頁創建 Cassandra 頁面請求。”
像這樣使用 CassandraPageRequest:
private static final int PAGE = 0;
private static final String DEFAULT_CURSOR_MARK = "-1";
private static final String SORT_FIELD = "test_name";
public TestResponse getData(int pageSize, String cursorMark) {
Pageable pageable = CassandraPageRequest.of(PageRequest.of(PAGE, pageSize, Sort.by(Sort.Direction.DESC, SORT_FIELD)), DEFAULT_CURSOR_MARK.equalsIgnoreCase(
cursorMark) ? null : PagingState.fromString(cursorMark));
Slice<Test> testSlice = testRepository.findAll(pageable);
TestResponse testResponse = new TestResponse();
testResponse.setRecords(testSlice.getContent());
if(!testSlice.isLast()) {
testResponse.setNextCursorMark(((CassandraPageRequest)testSlice.getPageable()).getPagingState().toString());
} else {
testResponse.setNextCursorMark(DEFAULT_CURSOR_MARK);
}
return testResponse;
}
對於所有進一步的請求,PAGE 將保持為 0,因為當我們傳遞 cursorMark(或 Cassandra 中的 PagingState)時它沒有意義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.