134

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

ハッシュキー「DataID」と範囲「CreatedAt」、およびその中に多数のアイテムを持つテーブルがあります。

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

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

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

4

8 に答える 8

42

更新された回答:

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

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

DynamoDB セカンダリ インデックスの詳細については、セカンダリ インデックスのドキュメントを参照してください。

元の回答:

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

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

複数の主キー間でレコードのインデックス付きルックアップを実行する必要がある場合、DynamoDB は使用するのに理想的なサービスではないか、項目を格納するために別のテーブル (DynamoDB またはリレーショナル ストアのいずれか) を利用する必要がある場合があります。インデックス付きルックアップを実行できるメタデータ。

于 2013-02-12T17:18:08.180 に答える
26

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

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

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

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

于 2015-09-26T01:06:13.117 に答える
9

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

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

|  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 にも慣れています) にとっては、生産性を上げるための最速の方法です。スキーマに関して制約がないため、機能するものを作り上げることができ、最も効率的な方法で作業するための帯域幅ができたら、物事を変えることができます。

于 2015-07-02T18:53:34.437 に答える
4

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

于 2013-02-12T18:32:24.457 に答える
1

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

また、OP の時点でこれらがあったかどうかは覚えていませんが (あったとは思いません)、現在はローカル セカンダリ インデックスを提供しています。

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

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

セカンダリ インデックスに関する追加データは、Amazon の DynamoDB ドキュメント (こちら) に記載されています。

とにかく、うまくいけば、これはこのスレッドで発生した他の人の助けになります.

于 2014-02-13T22:38:41.300 に答える
-10

更新された回答 スループットが予測可能な Dynamo DB クエリを使用してこれを行う便利な方法はありません。1 つの (準最適) オプションは、人工的な HashKey と CreatedAt を使用して GSI を使用することです。次に、HashKey のみでクエリを実行し、ScanIndexForward を指定して結果を並べ替えます。自然な HashKey (アイテムのカテゴリなど) を思いつくことができれば、この方法が勝者です。一方、すべてのアイテムに同じ HashKey を保持すると、主にデータ セットが 10 GB (1 つのパーティション) を超えたときにスループットに影響します。

元の回答: GSI を使用して DynamoDB でこれを行うことができます。「CreatedAt」フィールドを GSI として作成し、(GT some_date) のようなクエリを発行します。この種のクエリでは、日付を数値 (エポックからのミリ秒) として保存します。

詳細はこちらから入手できます: Global Secondary Indexes - Amazon DynamoDB : http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Using

これは非常に強力な機能です。クエリは (EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN) 条件に制限されていることに注意してください

于 2014-02-14T18:02:26.013 に答える