web-dev-qa-db-ja.com

日付によるDynamoDBのクエリ

リレーショナルデータベースのバックグラウンドから来て、AmazonのDynamoDBを使用しようとしています。

ハッシュキー「DataID」と範囲「CreatedAt」とその中のアイテムの束を持つテーブルがあります。

特定の日付以降に作成され、日付でソートされたすべてのアイテムを取得しようとしています。これは、リレーショナルデータベースでは非常に簡単です。

DynamoDBで私が見つけることができる最も近いものは、クエリとフィルターより大きい範囲キーを使用することです。唯一の問題は、クエリを実行するために、目的を無効にするハッシュキーが必要なことです。

だから私は何を間違っているのですか?私のテーブルスキーマは間違っていますか、ハッシュキーは一意ではありませんか?またはクエリする別の方法はありますか?

82
applechief

更新された回答:

DynamoDBでは、この種のクエリに役立つセカンダリインデックスを指定できます。セカンダリインデックスは、インデックスがハッシュキー全体でテーブル全体に広がることを意味するグローバル、またはインデックスが各ハッシュキーパーティション内に存在することを意味するローカルであるため、クエリを作成するときにハッシュキーも指定する必要があります。

この質問のユースケースでは、「CreatedAt」フィールドでグローバルセカンダリインデックスを使用します。

DynamoDBセカンダリインデックスの詳細 セカンダリインデックスのドキュメントを参照

元の回答:

DynamoDBでは、範囲キーのみのインデックス付き検索は許可されていません。ハッシュキーは、データを見つけるためにどのパーティションを調べるかをサービスが認識するために必要です。

もちろん、スキャン操作を実行して日付値でフィルタリングすることもできますが、これには全表スキャンが必要になるため、理想的ではありません。

複数のプライマリキーにわたって時間ごとにレコードのインデックス付きルックアップを実行する必要がある場合、DynamoDBは使用するのに理想的なサービスではないか、アイテムを格納するために別のテーブル(DynamoDBまたはリレーショナルストア)を利用する必要があるかもしれませんインデックス付きルックアップを実行できるメタデータ。

34
Mike Brant

現在のテーブル構造を考えると、これは現在DynamoDBでは不可能です。大きな課題は、テーブル(パーティション)のハッシュキーを個別のテーブルの作成として扱う必要があることを理解することです。いくつかの点で、これは非常に強力です(パーティションキーは、ユーザーまたは顧客ごとに新しいテーブルを作成するなどと考えてください)。

クエリは単一のパーティションでのみ実行できます。これで話は終わりです。つまり、日付でクエリを実行する場合(エポック以降はmsecを使用します)、1つのクエリで取得するすべてのアイテムに同じハッシュ(パーティションキー)が必要です。

これを修飾する必要があります。探している基準によってscanは絶対にできます。これは問題ありませんが、テーブル内のすべての行を調べ、その行にパラメーターと一致する日付があるかどうかを確認することを意味します。これは、特に最初から日付ごとにイベントを保存するビジネスの場合(つまり、行がたくさんある場合)、非常に高価です。

問題を解決するためにすべてのデータを単一のパーティションに入れたいと思うかもしれませんが、各パーティションが設定された合計量の一部しか受け取れないため、スループットは非常に低くなります。

最善の方法は、データを保存するために作成するより有用なパーティションを決定することです。

  • あなたは本当にすべての行を見る必要がありますか、それとも特定のユーザーによる行だけですか?

  • リストを最初に月で絞り込み、複数のクエリ(各月に1つ)を実行しても大丈夫でしょうか?または年ごと?

  • 時系列分析を行う場合、いくつかのオプションがあります。パーティションキーをPUTで計算されるものに変更してqueryを簡単にするか、追加するのに適したkinesisなどの別のAWS製品を使用します。ロギングのみ。

35
Warren Parad

ハッシュキー(プライマリのキー)は一意である必要があります(他の人が述べたような範囲がない限り)。

あなたの場合、テーブルをクエリするには、セカンダリインデックスが必要です。

|  ID  | DataID | Created | Data |
|------+--------+---------+------|
| hash | xxxxx  | 1234567 | blah |

ハッシュキーはIDですセカンダリインデックスは次のように定義されます:DataID-Created-index(DynamoDBが使用する名前です)

次に、次のようなクエリを作成できます。

var params = {
    TableName: "Table",
    IndexName: "DataID-Created-index",
    KeyConditionExpression: "DataID = :v_ID AND Created > :v_created",
    ExpressionAttributeValues: {":v_ID": {S: "some_id"},
                                ":v_created": {N: "timestamp"}
    },
    ProjectionExpression: "ID, DataID, Created, Data"
};

ddb.query(params, function(err, data) {
    if (err) 
        console.log(err);
    else {
        data.Items.sort(function(a, b) {
            return parseFloat(a.Created.N) - parseFloat(b.Created.N);
        });
        // More code here
    }
});

基本的に、クエリは次のようになります。

SELECT * FROM TABLE WHERE DataID = "some_id" AND Created > timestamp;

セカンダリインデックスは、必要な読み取り/書き込みキャパシティーユニットを増やすため、それを考慮する必要があります。スキャンを実行するよりもはるかに優れており、読み取りと時間のコストがかかります(100アイテムに制限されています)。

これは最善の方法ではないかもしれませんが、RDに慣れている人(私はSQLにも慣れています)にとっては、生産性を得るための最速の方法です。スキーマに関する制約はないため、機能するものを作成することができ、最も効率的な方法で作業するための帯域幅を取得したら、状況を変更できます。

8
E.T

この問題を解決するために私が従ったアプローチは、以下のようにグローバルセカンダリインデックスを作成することです。これが最良のアプローチであるかどうかはわかりませんが、誰かに役立つかどうかを願っています。

Hash Key                 | Range Key
------------------------------------
Date value of CreatedAt  | CreatedAt

データを取得する日数を指定するためにHTTP APIユーザーに課される制限。デフォルトは24時間です。

このようにして、HashKeyを現在の日付として常に指定でき、RangeKeyは取得中に>および<演算子を使用できます。このようにして、データは複数のシャードに分散されます。

7
Gireesh

「製品カテゴリ」IDの行に沿ってハッシュキーを作成し、最後に一意のIDを追加したタイムスタンプの組み合わせとして範囲キーを作成できます。そうすれば、ハッシュキーを知っていて、それよりも大きい日付をクエリできます。

3
greg

同一のハッシュキーを複数持つことができます。ただし、範囲キーが異なる場合のみ。ファイル形式のように考えてください。形式が異なる限り、同じフォルダに同じ名前の2つのファイルを含めることができます。形式が同じ場合、名前は異なっている必要があります。同じ概念がDynamoDBのハッシュ/範囲キーに適用されます。ハッシュを名前、範囲を形式と考えてください。

また、OPの時点でこれらがあったかどうかは思い出せませんが(そうではないと思います)、ローカルセカンダリインデックスを提供するようになりました。

これらについての私の理解は、これでフルスキャンを実行することなく目的のクエリを実行できるようになるはずだということです。欠点は、これらのインデックスはテーブルの作成時に指定する必要があり、また、アイテムを作成するときに空白にできないことです。さらに、追加のスループット(通常はスキャンほどではありませんが)とストレージが必要になるため、一部の人にとっては完璧なソリューションではなく、実行可能な代替手段です。

ただし、DynamoDBを使用する好ましい方法として、マイクブラントの回答を引き続きお勧めします。自分でその方法を使用します。私の場合、IDとしてハッシュキーのみを持つ中央テーブルがあり、次にクエリ可能なハッシュと範囲を持つセカンダリテーブルがあり、アイテムがコードを中央テーブルの「関心のあるアイテム」に直接向けています。 。

セカンダリインデックスに関する追加データは、AmazonのDynamoDBドキュメントで見つけることができます こちら 興味のある方のために。

とにかく、うまくいけば、これはこのスレッドで発生する他の人を助けるでしょう。

1
DGolberg