我知道如何使用NextToken在SimpleDB数据中向前翻页。但是,如何处理以前的页面呢?我正在.NET上工作,但我认为这并不重要。我更感兴趣的是一般策略。
Mike Culver的《Amazon SimpleDB简介》网络研讨会提到了面包屑导航的使用,但他在视频中没有实现它们。
编辑:视频提到了一个实现向后翻页的示例项目,但视频结束之前没有显示下载的URL。我找到的一个示例项目没有处理分页。
我知道如何使用NextToken在SimpleDB数据中向前翻页。但是,如何处理以前的页面呢?我正在.NET上工作,但我认为这并不重要。我更感兴趣的是一般策略。
Mike Culver的《Amazon SimpleDB简介》网络研讨会提到了面包屑导航的使用,但他在视频中没有实现它们。
编辑:视频提到了一个实现向后翻页的示例项目,但视频结束之前没有显示下载的URL。我找到的一个示例项目没有处理分页。
当需要跳转到下一页时,您可以通过仅允许“下一页”而不是任意分页来简化使用情况。在SimpleDB中,您可以使用LIMIT子句来实现此目的:
SELECT title, summary, votecount FROM posts WHERE userid = '000022656' LIMIT 25
你已经知道如何处理NextToken,但如果使用这种策略,可以通过存储下一个token的面包屑路径(例如在web会话中)并重新发出查询而不是后续查询来支持“上一页”。
然而,在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){...}
这是一个没有错误处理的概念,适用于任何页面,但不包括第一页。
我记得在其中一个“棕色袋午餐网络研讨会”中,曾经提到过可以重新提交令牌,然后您将获得相应的结果集。
我还没有尝试过,这只是一个想法,但是在向前分页时,如何构建令牌列表呢?那么,要返回,只需向后遍历列表并重新提交令牌(和选择语句)即可。
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;
}
我卡在获取令牌上了 - 这和RequestId是一回事吗?
我正在使用的PHP SimpleDB库似乎没有返回它。 http://sourceforge.net/projects/php-sdb/
这份文档似乎表明有一个nextToken元素,但在示例响应中,它显示RequestId...
我弄清楚了 - 我们的PHP库确实将nexttoken抽象化到我们无法访问的地方。深入研究了该库并找到了它。