2009-11-25 8 views
10

NextTokenを使用してSimpleDBデータを転送する方法を知っています。しかし、前のページはどのくらい正確に処理されますか?私は.NET上にいますが、それは重要ではないと思います。私はより一般的な戦略に興味があります。simpledbでページングを行う方法は?

ウェブマスターにはパンくずリストが使用されていると記載されていますが、ビデオには実装されていません。

EDIT:ビデオには、バックワードページングを実装するサンプルプロジェクトが含まれていますが、ダウンロードのURLが表示される前にビデオが終了します。私が見つけた1つのサンプルプロジェクトは、ページングを扱っていませんでした。

答えて

11

次のページに進むと、「次のページ」のみを許可し、任意のページングを許可しないことでユースケースを簡素化できます。あなたは、LIMIT句を使ってSimpleDBの中でこれを行うことができます:

SELECT title, summary, votecount FROM posts WHERE userid = '000022656' LIMIT 25 

はすでには、NextTokenを処理する方法を知っていますが、この戦術を使用する場合は、次のトークンのパンくずリストを格納することによって、「前のページ」をサポートすることができます(例えば、Webセッションで)、次のトークンではなく前のNextTokenを使用してクエリを再発行します。

ただし、SimpleDBの任意のページ番号を扱う一般的なケースは、前と次のページで同じです。一般的には、ユーザーはページ4または6を訪れていなくても、5などの任意のページ番号をクリックできます。

これは、NextTokenでWHERE句のみが必要であるという事実を使用してSimpleDBで処理します同じように正しく動作する。そのため、介入するすべてのアイテムを順番にすべてのページを照会するのではなく、通常は2つのステップで実行できます。

  1. 目的のページを開始する場所の制限値と、実際の属性の代わりにSELECTカウント(*)を使用してクエリを発行します。
  2. 使用は、NextToken LIMITそこで擬似コードで

として所望の属性とページ・サイズを使用して、実際のページデータを取得するステップ1から:

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呼び出しを含む架空のメソッドです。

コードで示されているように、2回の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ページを除く、任意のページのために動作します。

+1

あなたの徹底的な対応に感謝します! – royco

+0

偉大な答え、ありがとう – theosp

+0

私は限界にカウントするために文を実行するとき、私は結果の最後にトークンを取得しない(私はトークンをループするときでも)何かが不足している? –

1

茶色のバッグのウェビナーの1つでは、トークンを再送信することができ、対応する結果が返されることに言及しました。

私はそれを試していない、それはちょうどアイデアですが、あなたがページングしているようにトークンのリストを構築する方法についてはどうですか?戻るには、リストを逆方向にトラバースし、トークンを再サブミットします(そしてselect文)。

+0

はい、これは機能します。ありがとう。ブレッドクラム・トークンのリストを保存する最良の方法は何ですか? – royco

+0

私はLinkedList が良い選択だと思います。これは二重にリンクされているので、前後に移動できます。 – Darryl

0

私はトークンを手に入れません - それはRequestIdと同じですか?

私が使っているPHP SimpleDBライブラリは返さないようです。 nextToken要素があることを示しているようだが、サンプル応答では、それはRequestIdを示し、このドキュメント http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/index.html?SDB_API_Select.html

を発見 http://sourceforge.net/projects/php-sdb/

...

はそれを考え出した - 私たちのPHPのlibにしました私たちがアクセスした場所から離れたnexttokenを抽象化しています。図書館に掘って見つけた

0

公式の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; 
} 
関連する問題