LoginSignup
1
1

More than 3 years have passed since last update.

C# で DynamoDB から時系列データを GSI を使って範囲指定して検索する

Posted at

C# で Amazon DynamoDB に保存されている時系列データを GSI(グローバルセカンダリインデックス)を使って範囲指定して検索する方法です。

[事前準備1] データ

下記の構造のデータを保存できるよう、

[DynamoDBTable("SampleTable")]
public class Sample
{
    /// <summary>「SampleTable」テーブルのハッシュキー</summary>
    [DynamoDBHashKey]
    public string Id { get; set; }

    /// <summary>「SampleTable」テーブルのレンジキー</summary>
    [DynamoDBRangeKey]
    public string DateAndTime { get; set; }

    /// <summary>「Date-Time-index」GSI のハッシュキー</summary>
    [DynamoDBGlobalSecondaryIndexHashKey]
    public string Date { get; set; }

    /// <summary>「Date-Time-index」GSI のレンジキー</summary>
    [DynamoDBGlobalSecondaryIndexRangeKey]
    public string Time { get; set; }

    [DynamoDBProperty]
    public string Message { get; set; }

    public override string ToString()
    {
        return $"{Id} / {DateAndTime} / {Message}";
    }
}

AWS Console から IdDateAndTime をキーにした SampleTable テーブルを用意します。
table.png

次に、下記のように SaveAsync メソッドを使って 10件のデータを作成します。

// DynamoDB にアクセスするためのオブジェクトを用意
using var client = new AmazonDynamoDBClient(RegionEndpoint.APNortheast1);
using var context = new DynamoDBContext(client);

// 10件のデータを作成
for (var i = 0; i < 10; i++)
{
    var now = DateTime.Now;

    await context.SaveAsync(new Sample
    {
        Id = $"{i % 3 + 1:D3}",
        DateAndTime = $"{now:yyyy-MM-dd HH:mm:ss.fff}",
        Date = $"{now:yyyy-MM-dd}",
        Time = $"{now:HH:mm:ss}",
        Message = $"メッセージ - {i + 1}"
    });

    // 保存される時間をずらしたいので 500 msec 待機
    await Task.Delay(500);
}

下記のように ScanAsync メソッドを使って全データを取得します。

// 全データを取得
var listAll = await context.ScanAsync<Sample>(null).GetRemainingAsync();

Console.WriteLine("--- listAll");
listAll.OrderBy(n => n.DateAndTime).ToList().ForEach(Console.WriteLine);

そうすると、下記のようにデータを取得できます。

--- listAll
001 / 2020-08-11 11:40:40.236 / メッセージ - 1
002 / 2020-08-11 11:40:41.224 / メッセージ - 2
003 / 2020-08-11 11:40:41.756 / メッセージ - 3
001 / 2020-08-11 11:40:42.293 / メッセージ - 4
002 / 2020-08-11 11:40:42.824 / メッセージ - 5
003 / 2020-08-11 11:40:43.355 / メッセージ - 6
001 / 2020-08-11 11:40:43.877 / メッセージ - 7
002 / 2020-08-11 11:40:44.412 / メッセージ - 8
003 / 2020-08-11 11:40:44.936 / メッセージ - 9
001 / 2020-08-11 11:40:45.458 / メッセージ - 10

[事前準備2] GSI

AWS Console からは下記のようにデータが保存されていることを確認できます。
aws.png

事前準備の最後に、日時を範囲指定して検索できるよう、AWS Console から DateTime をキーにした Date-Time-index インデックス(GSI)を用意します。
gsi.png

これで準備は完了です。

[シナリオ1] Id = 001 のデータを取得したい

下記のようにハッシュキーに 001 を指定して QueryAsync() メソッドを使ってデータを取得します。

var list01 = await context.QueryAsync<Sample>("001").GetRemainingAsync();

Console.WriteLine("--- list01");
list01.OrderBy(n => n.DateAndTime).ToList().ForEach(Console.WriteLine);

そうすると、下記のようにデータを取得できます。

--- list01
001 / 2020-08-11 11:40:40.236 / メッセージ - 1
001 / 2020-08-11 11:40:42.293 / メッセージ - 4
001 / 2020-08-11 11:40:43.877 / メッセージ - 7
001 / 2020-08-11 11:40:45.458 / メッセージ - 10

Id が 001 のデータのみを取得できています。

[シナリオ2] 2020-08-11 の 11:40:42~11:40:43 のデータを取得したい

下記のように GSI の名称 Date-Time-index を指定し、ハッシュキーに 2020-08-11 を指定して、レンジキーには QueryOperator.Between11:40:42 - 11:40:43 を指定して QueryAsync() メソッドを使ってデータを取得します。

var list02 = await context.QueryAsync<Sample>(
    "2020-08-11",
    QueryOperator.Between,
    new List<object>
    {
        "11:40:42",
        "11:40:43"
    },
    new DynamoDBOperationConfig
    {
        IndexName = "Date-Time-index" // 利用する GSI を指定
    }).GetRemainingAsync();

Console.WriteLine("--- list02");
list02.OrderBy(n => n.DateAndTime).ToList().ForEach(Console.WriteLine);

そうすると、下記のようにデータを取得できます。

--- list02
001 / 2020-08-11 11:40:42.293 / メッセージ - 4
002 / 2020-08-11 11:40:42.824 / メッセージ - 5
003 / 2020-08-11 11:40:43.355 / メッセージ - 6
001 / 2020-08-11 11:40:43.877 / メッセージ - 7

SampleTable テーブルのハッシュキーである Id をまたいで 11:40:42 - 11:40:43 のデータのみを取得できています。

さいごに

GSI を使って日時を範囲指定して検索することはできました。
ただ、コスト面の考慮や NoSQL らしい設計についてはできているかというと、、

より良い方法があったら教えてください m(_ _)m

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1