我知道如何通過使用NextToken使用SimpleDB數據向前翻頁。但是,如何處理前一頁呢?我在.NET上,但我不認爲這很重要。我對總體戰略更感興趣。如何使用simpledb進行分頁?
邁克卡爾弗的An Introduction to Amazon SimpleDB網絡研討會提到使用麪包屑,但他沒有在視頻中實現它們。
編輯:視頻提到了一個示例項目,它實現了向後分頁,但視頻結束之前可以顯示下載的URL。我發現的一個示例項目沒有處理分頁。
我知道如何通過使用NextToken使用SimpleDB數據向前翻頁。但是,如何處理前一頁呢?我在.NET上,但我不認爲這很重要。我對總體戰略更感興趣。如何使用simpledb進行分頁?
邁克卡爾弗的An Introduction to Amazon SimpleDB網絡研討會提到使用麪包屑,但他沒有在視頻中實現它們。
編輯:視頻提到了一個示例項目,它實現了向後分頁,但視頻結束之前可以顯示下載的URL。我發現的一個示例項目沒有處理分頁。
當進入下一頁時,您可以通過只允許「下一頁」而不是任意分頁來簡化用例。您可以通過使用LIMIT子句中的SimpleDB做到這一點:
SELECT title, summary, votecount FROM posts WHERE userid = '000022656' LIMIT 25
你已經知道如何處理的nextToken,但如果你使用這個戰術,你可以通過將下一個令牌的導航條支持「前一頁」 (例如在網絡會話中),並重新發出帶有前一個NextToken的查詢,而不是後續的查詢。
但是,在SimpleDB中處理任意分頁的一般情況與上一個和下一個一樣。在一般情況下,用戶可以點擊一個任意頁碼,如5,而不必訪問第4頁或第6頁。
你在SimpleDB中處理這個問題的方法是使用NextToken只需要WHERE子句成爲同樣工作正常。因此,不是通過按順序查詢每個頁面來拉下所有干預項目,通常可以分兩步進行。
所以在僞碼以提取實際的頁數據:
int targetPage, pageSize;
...
int jumpLimit = pageSize * (targetPage - 1);
String query = "SELECT %1 FROM posts WHERE userid = '000022656' LIMIT %2";
String output = "title, summary, votecount";
Result temp = sdb.select(query, "count(*)", jumpLimit);
Result data = sdb.select(query, output, pageSize, temp.getToken());
其中%1和%2是字符串替換,「sdb.select()」是一個虛構的方法,它包含字符串替換代碼和SimpleDB調用。
是否可以在SimpleDB的兩次調用中完成此操作(如代碼所示)將取決於WHERE子句的複雜性和數據集的大小。上面的代碼被簡化了,如果查詢花費了超過5秒的時間運行,臨時結果可能已經返回了部分計數。你真的想把這條線放在一個循環中,直到達到合適的數量。爲了使代碼更逼真我把它方法中,擺脫了字符串替換的:
private Result fetchPage(String query, int targetPage)
{
int pageSize = extractLimitValue(query);
int skipLimit = pageSize * (targetPage - 1);
String token = skipAhead(query, skipLimit);
return sdb.select(query, token);
}
private String skipAhead(String query, int skipLimit)
{
String tempQuery = replaceClause(query, "SELECT", "count(*)");
int accumulatedCount = 0;
String token = "";
do {
int tempLimit = skipLimit - accumulatedCount;
tempQuery = replaceClause(tempQuery , "LIMIT", tempLimit + "");
Result tempResult = sdb.select(query, token);
token = tempResult.getToken();
accumulatedCount += tempResult.getCount();
} while (accumulatedCount < skipLimit);
return token;
}
private int extractLimitValue(String query) {...}
private String replaceClause(String query, String clause, String value){...}
這是沒有錯誤處理的總體思路,並適用於任意的頁面,但不包括第1頁。
我被困在獲取令牌 - 是否與RequestId一樣?
我使用的PHP SimpleDB庫似乎沒有返回它。 http://sourceforge.net/projects/php-sdb/
這似乎表明,存在的nextToken元素,但在樣本響應,它顯示的requestId ...
想通了 - 我們的PHP LIB是的確可以從我們可以訪問的地方抽取出來。挖進圖書館並找到它。
我已經使用官方的SimpleDB API創建了上述Java抽樣樣本,可能這對任何人都有用。
private static Set<String> getSdbAttributes(AmazonSimpleDBClient client,
String domainName, int sampleSize) {
if (!client.listDomains().getDomainNames().contains(domainName)) {
throw new IllegalArgumentException("SimpleDB domain '" + domainName
+ "' not accessible from given client instance");
}
int domainCount = client.domainMetadata(
new DomainMetadataRequest(domainName)).getItemCount();
if (domainCount < sampleSize) {
throw new IllegalArgumentException("SimpleDB domain '" + domainName
+ "' does not have enough entries for accurate sampling.");
}
int avgSkipCount = domainCount/sampleSize;
int processedCount = 0;
String nextToken = null;
Set<String> attributeNames = new HashSet<String>();
Random r = new Random();
do {
int nextSkipCount = r.nextInt(avgSkipCount * 2) + 1;
SelectResult countResponse = client.select(new SelectRequest(
"select count(*) from `" + domainName + "` limit "
+ nextSkipCount).withNextToken(nextToken));
nextToken = countResponse.getNextToken();
processedCount += Integer.parseInt(countResponse.getItems().get(0)
.getAttributes().get(0).getValue());
SelectResult getResponse = client.select(new SelectRequest(
"select * from `" + domainName + "` limit 1")
.withNextToken(nextToken));
nextToken = getResponse.getNextToken();
processedCount++;
if (getResponse.getItems().size() > 0) {
for (Attribute a : getResponse.getItems().get(0)
.getAttributes()) {
attributeNames.add(a.getName());
}
}
} while (domainCount > processedCount);
return attributeNames;
}
感謝您的全面迴應! – royco 2009-12-04 00:55:02
很好的回答,謝謝 – theosp 2010-11-10 07:34:41
當我運行一個語句來計算一個限制,我沒有得到一個令牌在我的結果結束(即使當我循環令牌)我錯過了什麼? – 2011-08-02 21:44:56