Amazon DynamoDB
開発者ガイド (API バージョン 2012-08-10)

テーブルおよびインデックスのスキャン: .NET

Scan オペレーションは、Amazon DynamoDB にあるテーブルまたはインデックスの全項目を読み込みます。

以下に、AWS SDK for .NET 低レベル API を使用してテーブルをスキャンする手順を示します。

  1. AmazonDynamoDBClient クラスのインスタンスを作成します。

  2. ScanRequest クラスのインスタンスを作成し、スキャンオペレーションのパラメータを指定します。

    必須のパラメータは、テーブル名だけです。

  3. Scan メソッドを実行し、前述のステップで作成した QueryRequest オブジェクトを指定します。

以下の Reply テーブルに、フォーラムスレッドに対する応答が格納されます。

>Reply ( <emphasis role="underline">Id</emphasis>, <emphasis role="underline">ReplyDateTime</emphasis>, Message, PostedBy )

このテーブルには、さまざまなフォーラムスレッドに対するすべての応答が保持されています。したがってプライマリキーは、Id (パーティションキー) と ReplyDateTime (ソートキー) の両方で構成されます。以下の C# コード例は、テーブル全体をスキャンする例を示しています。ScanRequest インスタンスで、スキャン対象のテーブルの名前を指定します。

AmazonDynamoDBClient client = new AmazonDynamoDBClient(); var request = new ScanRequest { TableName = "Reply", }; var response = client.Scan(request); var result = response.ScanResult; foreach (Dictionary<string, AttributeValue> item in response.ScanResult.Items) { // Process the result. PrintItem(item); }

オプションパラメータの指定

Scan メソッドでは、複数のオプションパラメータがサポートされています。たとえば、オプションとして、スキャンフィルタを使用してスキャン結果をフィルタリングすることができます。スキャンフィルタを使用すると、条件、およびその条件を評価するための属性名を指定できます。詳細については、「Scan」を参照してください。

以下の C# コードは、ProductCatalog テーブルをスキャンして、値が 0(ゼロ)未満の項目を検索する例を示しています。このサンプルでは、次のオプションパラメータが指定されています。

  • 値が 0 未満(エラー状態)の項目のみを取り出す FilterExpression パラメータ。

  • クエリ結果内の項目について取り出す属性のリストを指定する ProjectionExpression パラメータ。

以下の C# の例では、ProductCatalog テーブルをスキャンして、値が 0 未満の項目をすべて検索しています。

var forumScanRequest = new ScanRequest { TableName = "ProductCatalog", // Optional parameters. ExpressionAttributeValues = new Dictionary<string,AttributeValue> { {":val", new AttributeValue { N = "0" }} }, FilterExpression = "Price < :val", ProjectionExpression = "Id" };

また、オプションの Limit パラメータを追加することで、ページサイズ、またはページあたりの項目数を制限することもできます。Scan メソッドを実行するたびに、指定された数の項目が含まれる結果が 1 ページ取得されます。次のページを取り出すには、前のページで最終項目のプライマリキーの値を指定して、Scan メソッドを再度実行します。これにより、Scan メソッドで、次の項目のセットを返すことができます。この情報は、ExclusiveStartKey プロパティを設定することでリクエストに含めます。このプロパティは最初は null である場合があります。以降のページを取り出すには、このプロパティ値を更新して、前ページの最後の項目のプライマリキーにする必要があります。

以下の C# コード例では、ProductCatalog テーブルをスキャンしています。リクエストでは、オプションの Limit および ExclusiveStartKey パラメータを指定しています。do/while ループは、LastEvaluatedKey から null 値が返されるまで、一度に 1 ページのスキャンを継続します。

Dictionary<string, AttributeValue> lastKeyEvaluated = null; do { var request = new ScanRequest { TableName = "ProductCatalog", Limit = 10, ExclusiveStartKey = lastKeyEvaluated }; var response = client.Scan(request); foreach (Dictionary<string, AttributeValue> item in response.Items) { PrintItem(item); } lastKeyEvaluated = response.LastEvaluatedKey; } while (lastKeyEvaluated != null && lastKeyEvaluated.Count != 0);

例 – .NET を使用したスキャン

以下の C# コードは、ProductCatalog テーブルをスキャンして、値が 0 未満の項目を検索する、作業サンプル例を示しています。

以下の例をテストするための詳細な手順については、「.NET コード例」を参照してください。

/** * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * This file is licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. A copy of * the License is located at * * http://aws.amazon.com/apache2.0/ * * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ using System; using System.Collections.Generic; using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.Model; using Amazon.Runtime; namespace com.amazonaws.codesamples { class LowLevelScan { private static AmazonDynamoDBClient client = new AmazonDynamoDBClient(); static void Main(string[] args) { try { FindProductsForPriceLessThanZero(); Console.WriteLine("Example complete. To continue, press Enter"); Console.ReadLine(); } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine("To continue, press Enter"); Console.ReadLine(); } } private static void FindProductsForPriceLessThanZero() { Dictionary<string, AttributeValue> lastKeyEvaluated = null; do { var request = new ScanRequest { TableName = "ProductCatalog", Limit = 2, ExclusiveStartKey = lastKeyEvaluated, ExpressionAttributeValues = new Dictionary<string, AttributeValue> { {":val", new AttributeValue { N = "0" }} }, FilterExpression = "Price < :val", ProjectionExpression = "Id, Title, Price" }; var response = client.Scan(request); foreach (Dictionary<string, AttributeValue> item in response.Items) { Console.WriteLine("\nScanThreadTableUsePaging - printing....."); PrintItem(item); } lastKeyEvaluated = response.LastEvaluatedKey; } while (lastKeyEvaluated != null && lastKeyEvaluated.Count != 0); Console.WriteLine("To continue, press Enter"); Console.ReadLine(); } private static void PrintItem( Dictionary<string, AttributeValue> attributeList) { foreach (KeyValuePair<string, AttributeValue> kvp in attributeList) { string attributeName = kvp.Key; AttributeValue value = kvp.Value; Console.WriteLine( attributeName + " " + (value.S == null ? "" : "S=[" + value.S + "]") + (value.N == null ? "" : "N=[" + value.N + "]") + (value.SS == null ? "" : "SS=[" + string.Join(",", value.SS.ToArray()) + "]") + (value.NS == null ? "" : "NS=[" + string.Join(",", value.NS.ToArray()) + "]") ); } Console.WriteLine("************************************************"); } }

例 – .NET を使用したパラレルスキャン

以下の C# コード例は、パラレルスキャンの例です。このプログラムにより、ProductCatalog テーブルが削除後に再作成されてからこのテーブルにデータがロードされます。データのロードが終了すると、複数のスレッドが生成され、並列の Scan リクエストが発行されます。最後に、ランタイム統計の要約が印刷されます。

以下の例をテストするための詳細な手順については、「.NET コード例」を参照してください。

/** * Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * This file is licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. A copy of * the License is located at * * http://aws.amazon.com/apache2.0/ * * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using Amazon.DynamoDBv2; using Amazon.DynamoDBv2.Model; using Amazon.Runtime; namespace com.amazonaws.codesamples { class LowLevelParallelScan { private static AmazonDynamoDBClient client = new AmazonDynamoDBClient(); private static string tableName = "ProductCatalog"; private static int exampleItemCount = 100; private static int scanItemLimit = 10; private static int totalSegments = 5; static void Main(string[] args) { try { DeleteExampleTable(); CreateExampleTable(); UploadExampleData(); ParallelScanExampleTable(); } catch (AmazonDynamoDBException e) { Console.WriteLine(e.Message); } catch (AmazonServiceException e) { Console.WriteLine(e.Message); } catch (Exception e) { Console.WriteLine(e.Message); } Console.WriteLine("To continue, press Enter"); Console.ReadLine(); } private static void ParallelScanExampleTable() { Console.WriteLine("\n*** Creating {0} Parallel Scan Tasks to scan {1}", totalSegments, tableName); Task[] tasks = new Task[totalSegments]; for (int segment = 0; segment < totalSegments; segment++) { int tmpSegment = segment; Task task = Task.Factory.StartNew(() => { ScanSegment(totalSegments, tmpSegment); }); tasks[segment] = task; } Console.WriteLine("All scan tasks are created, waiting for them to complete."); Task.WaitAll(tasks); Console.WriteLine("All scan tasks are completed."); } private static void ScanSegment(int totalSegments, int segment) { Console.WriteLine("*** Starting to Scan Segment {0} of {1} out of {2} total segments ***", segment, tableName, totalSegments); Dictionary<string, AttributeValue> lastEvaluatedKey = null; int totalScannedItemCount = 0; int totalScanRequestCount = 0; do { var request = new ScanRequest { TableName = tableName, Limit = scanItemLimit, ExclusiveStartKey = lastEvaluatedKey, Segment = segment, TotalSegments = totalSegments }; var response = client.Scan(request); lastEvaluatedKey = response.LastEvaluatedKey; totalScanRequestCount++; totalScannedItemCount += response.ScannedCount; foreach (var item in response.Items) { Console.WriteLine("Segment: {0}, Scanned Item with Title: {1}", segment, item["Title"].S); } } while (lastEvaluatedKey.Count != 0); Console.WriteLine("*** Completed Scan Segment {0} of {1}. TotalScanRequestCount: {2}, TotalScannedItemCount: {3} ***", segment, tableName, totalScanRequestCount, totalScannedItemCount); } private static void UploadExampleData() { Console.WriteLine("\n*** Uploading {0} Example Items to {1} Table***", exampleItemCount, tableName); Console.Write("Uploading Items: "); for (int itemIndex = 0; itemIndex < exampleItemCount; itemIndex++) { Console.Write("{0}, ", itemIndex); CreateItem(itemIndex.ToString()); } Console.WriteLine(); } private static void CreateItem(string itemIndex) { var request = new PutItemRequest { TableName = tableName, Item = new Dictionary<string, AttributeValue>() { { "Id", new AttributeValue { N = itemIndex }}, { "Title", new AttributeValue { S = "Book " + itemIndex + " Title" }}, { "ISBN", new AttributeValue { S = "11-11-11-11" }}, { "Authors", new AttributeValue { SS = new List<string>{"Author1", "Author2" } }}, { "Price", new AttributeValue { N = "20.00" }}, { "Dimensions", new AttributeValue { S = "8.5x11.0x.75" }}, { "InPublication", new AttributeValue { BOOL = false } } } }; client.PutItem(request); } private static void CreateExampleTable() { Console.WriteLine("\n*** Creating {0} Table ***", tableName); var request = new CreateTableRequest { AttributeDefinitions = new List<AttributeDefinition>() { new AttributeDefinition { AttributeName = "Id", AttributeType = "N" } }, KeySchema = new List<KeySchemaElement> { new KeySchemaElement { AttributeName = "Id", KeyType = "HASH" //Partition key } }, ProvisionedThroughput = new ProvisionedThroughput { ReadCapacityUnits = 5, WriteCapacityUnits = 6 }, TableName = tableName }; var response = client.CreateTable(request); var result = response; var tableDescription = result.TableDescription; Console.WriteLine("{1}: {0} \t ReadsPerSec: {2} \t WritesPerSec: {3}", tableDescription.TableStatus, tableDescription.TableName, tableDescription.ProvisionedThroughput.ReadCapacityUnits, tableDescription.ProvisionedThroughput.WriteCapacityUnits); string status = tableDescription.TableStatus; Console.WriteLine(tableName + " - " + status); WaitUntilTableReady(tableName); } private static void DeleteExampleTable() { try { Console.WriteLine("\n*** Deleting {0} Table ***", tableName); var request = new DeleteTableRequest { TableName = tableName }; var response = client.DeleteTable(request); var result = response; Console.WriteLine("{0} is being deleted...", tableName); WaitUntilTableDeleted(tableName); } catch (ResourceNotFoundException) { Console.WriteLine("{0} Table delete failed: Table does not exist", tableName); } } private static void WaitUntilTableReady(string tableName) { string status = null; // Let us wait until table is created. Call DescribeTable. do { System.Threading.Thread.Sleep(5000); // Wait 5 seconds. try { var res = client.DescribeTable(new DescribeTableRequest { TableName = tableName }); Console.WriteLine("Table name: {0}, status: {1}", res.Table.TableName, res.Table.TableStatus); status = res.Table.TableStatus; } catch (ResourceNotFoundException) { // DescribeTable is eventually consistent. So you might // get resource not found. So we handle the potential exception. } } while (status != "ACTIVE"); } private static void WaitUntilTableDeleted(string tableName) { string status = null; // Let us wait until table is deleted. Call DescribeTable. do { System.Threading.Thread.Sleep(5000); // Wait 5 seconds. try { var res = client.DescribeTable(new DescribeTableRequest { TableName = tableName }); Console.WriteLine("Table name: {0}, status: {1}", res.Table.TableName, res.Table.TableStatus); status = res.Table.TableStatus; } catch (ResourceNotFoundException) { Console.WriteLine("Table name: {0} is not found. It is deleted", tableName); return; } } while (status == "DELETING"); } } }