C# 如何使用simpledb进行分页?

C# 如何使用simpledb进行分页?,c#,amazon-simpledb,C#,Amazon Simpledb,我知道如何使用NextToken向前翻页SimpleDB数据。然而,如何准确地处理之前的页面?我在.NET上,但我认为这不重要。我对总体战略更感兴趣 Mike Culver的网络研讨会提到使用面包屑,但他没有在视频中实现它们 编辑:视频提到了一个实现向后分页的示例项目,但视频在显示下载URL之前结束。我发现的一个示例项目没有处理分页问题。我记得在一次brown bag网络研讨会上,顺便提到可以重新提交令牌,并且您会得到相应的结果集 我还并没有尝试过,这只是一个想法,但在您向前翻页时构建一个令牌列

我知道如何使用NextToken向前翻页SimpleDB数据。然而,如何准确地处理之前的页面?我在.NET上,但我认为这不重要。我对总体战略更感兴趣

Mike Culver的网络研讨会提到使用面包屑,但他没有在视频中实现它们


编辑:视频提到了一个实现向后分页的示例项目,但视频在显示下载URL之前结束。我发现的一个示例项目没有处理分页问题。

我记得在一次brown bag网络研讨会上,顺便提到可以重新提交令牌,并且您会得到相应的结果集


我还并没有尝试过,这只是一个想法,但在您向前翻页时构建一个令牌列表怎么样?然后,要返回,只需向后遍历列表并重新提交令牌(和select语句)

当转到下一页时,您可以通过只允许“下一页”而不允许任意分页来简化用例。您可以在SimpleDB中使用LIMIT子句执行此操作:

SELECT title, summary, votecount FROM posts WHERE userid = '000022656' LIMIT 25
您已经知道如何处理NextToken,但是如果您使用这种策略,您可以通过存储下一个令牌的面包屑痕迹(例如在web会话中)并使用上一个NextToken而不是后续的NextToken重新发出查询来支持“上一页”

但是,在SimpleDB中处理任意分页的一般情况与上一个和下一个相同。在一般情况下,用户可以单击任意页码,如5,而从未访问过第4页或第6页

在SimpleDB中,您可以使用这样一个事实来处理这个问题,即NextToken只要求WHERE子句相同才能正常工作。因此,您通常可以分两个步骤来完成,而不是按顺序查询每个页面并下拉所有中间项

  • 使用所需页面的起始位置的限制值发出查询,并选择count(*),而不是所需的实际属性
  • 使用第一步中的NextToken,使用所需属性和页面大小作为限制来获取实际页面数据
  • 所以在伪代码中:

    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秒,temp结果可能返回了部分计数。您可能真的希望将该行放入循环中,直到达到正确的计数。为了使代码更真实一些,我将把它放在方法中,并去掉字符串替换:

    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 Result fetchPage(字符串查询,int targetPage)
    {
    int pageSize=extractLimitValue(查询);
    int skipLimit=pageSize*(targetPage-1);
    字符串标记=skiphead(查询,skipLimit);
    返回sdb.select(查询、令牌);
    }
    私有字符串skiphead(字符串查询,int skipLimit)
    {
    字符串tempQuery=replaceClause(查询,“选择”,“计数(*));
    int累计计数=0;
    字符串标记=”;
    做{
    int tempLimit=skipLimit—累计计数;
    tempQuery=replaceClause(tempQuery,“LIMIT”,tempLimit+“”);
    Result tempResult=sdb.select(查询、令牌);
    token=tempResult.getToken();
    累计计数+=tempResult.getCount();
    }while(累计计数

    这是没有错误处理的一般想法,适用于任何任意页面,不包括第1页

    我一直在获取令牌-这和RequestId是一样的吗

    我使用的PHP SimpleDB库似乎没有返回它。

    找到了这个文档

    这似乎表明有一个nextToken元素,但在示例响应中,它显示了RequestId


    我们的PHP库确实将nexttoken从我们可以访问的地方抽象出来了。我已经用官方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;
    }
    
    私有静态集getSdbAttributes(AmazonSimpleDBClient,
    字符串域名,int-sampleSize){
    如果(!client.listDomains().getDomainNames().contains(domainName)){
    抛出新的IllegalArgumentException(“SimpleDB域””+域名
    +“‘无法从给定客户端实例访问’”;
    }
    int domainCount=client.domainMetadata(
    新建DomainMetadataRequest(domainName)).getItemCount();
    if(domainCount