Ich komme aus einem relationalen Datenbankhintergrund und versuche, mit Amazon DynamoDB zu arbeiten
Ich habe eine Tabelle mit einem Hash-Schlüssel "DataID" und einem Bereich "CreatedAt" und einer Reihe von Elementen darin.
Ich versuche, alle Elemente abzurufen, die nach einem bestimmten Datum erstellt und nach Datum sortiert wurden. Was in einer relationalen Datenbank ziemlich einfach ist.
In DynamoDB ist das Nächste, was ich finden kann, eine Abfrage und die Verwendung des Bereichsschlüssels größer als Filter. Das einzige Problem ist, dass ich zum Ausführen einer Abfrage einen Hash-Schlüssel benötige, der den Zweck zunichte macht.
Also, was mache ich falsch? Ist mein Tabellenschema falsch, sollte der Hash-Schlüssel nicht eindeutig sein? oder gibt es eine andere Möglichkeit zum Abfragen?
quelle
CreatedAt
mehr als einem bestimmten Punkt abfragen können .Aufgrund Ihrer aktuellen Tabellenstruktur ist dies derzeit in DynamoDB nicht möglich. Die große Herausforderung besteht darin zu verstehen, dass der Hash-Schlüssel der Tabelle (Partition) als Erstellen separater Tabellen behandelt werden sollte. In mancher Hinsicht ist dies sehr leistungsfähig (denken Sie an Partitionsschlüssel als Erstellen einer neuen Tabelle für jeden Benutzer oder Kunden usw.).
Abfragen können nur in einer einzelnen Partition durchgeführt werden. Das ist wirklich das Ende der Geschichte. Wenn Sie also nach Datum abfragen möchten (Sie möchten seit der Epoche ms verwenden), müssen alle Elemente, die Sie in einer einzelnen Abfrage abrufen möchten, denselben Hash (Partitionsschlüssel) haben.
Ich sollte das qualifizieren. Sie können absolut
scan
nach dem Kriterium suchen, das Sie suchen, das ist kein Problem, aber das bedeutet, dass Sie jede einzelne Zeile in Ihrer Tabelle betrachten und dann prüfen, ob diese Zeile ein Datum hat, das Ihren Parametern entspricht. Dies ist sehr teuer, insbesondere wenn Sie in erster Linie Ereignisse nach Datum speichern möchten (dh Sie haben viele Zeilen).Sie könnten versucht sein, alle Daten in einer einzigen Partition zu speichern, um das Problem zu lösen, und Sie können dies absolut, jedoch ist Ihr Durchsatz schmerzhaft niedrig, da jede Partition nur einen Bruchteil der insgesamt festgelegten Menge erhält.
Am besten ermitteln Sie nützlichere Partitionen, die zum Speichern der Daten erstellt werden sollen:
Müssen Sie wirklich alle Zeilen betrachten oder sind es nur die Zeilen eines bestimmten Benutzers?
Wäre es in Ordnung, die Liste zuerst nach Monat einzugrenzen und mehrere Abfragen durchzuführen (eine für jeden Monat)? Oder nach Jahr?
Wenn Sie eine Zeitreihenanalyse durchführen, gibt es mehrere Optionen. Ändern Sie den Partitionsschlüssel in einen berechneten Schlüssel,
PUT
um dies zuquery
vereinfachen, oder verwenden Sie ein anderes aws-Produkt wie kinesis, das sich für die Protokollierung nur zum Anhängen eignet.quelle
yyyy
und einen Hash dafür, aber erstellencreated
Sie auch ein Datum, das Sie als Bereichsschlüssel verwenden können. Dann erhalten Sie 10 GB Daten pro Jahr (27 MB pro Tag), was für weitere Umstände wahrscheinlich in Ordnung ist. Es bedeutet zwar, dass Sie eine Abfrage pro Jahr erstellen müssen, wenn Datumsabfragen die Jahresgrenze überschreiten, aber zumindest funktioniert dies und es ist sicherer als das Erstellen eines Dummy-Hash-Schlüssels.Der Ansatz, den ich zur Lösung dieses Problems verfolgt habe, besteht darin, einen globalen Sekundärindex wie folgt zu erstellen. Ich bin mir nicht sicher, ob dies der beste Ansatz ist, aber hoffentlich, ob er für jemanden nützlich ist.
Dem HTTP-API-Benutzer auferlegte Einschränkung, die Anzahl der Tage zum Abrufen von Daten anzugeben, standardmäßig 24 Stunden.
Auf diese Weise kann ich den HashKey immer als Tag des aktuellen Datums angeben und RangeKey kann beim Abrufen die Operatoren> und <verwenden. Auf diese Weise werden die Daten auch auf mehrere Shards verteilt.
quelle
Ihr Hash-Schlüssel (primär sortiert) muss eindeutig sein (es sei denn, Sie haben einen Bereich, wie er von anderen angegeben wurde).
In Ihrem Fall sollten Sie zum Abfragen Ihrer Tabelle einen Sekundärindex haben.
Ihr Hash-Schlüssel ist ID. Ihr Sekundärindex ist definiert als: DataID-Created-Index (das ist der Name, den DynamoDB verwendet)
Dann können Sie eine Abfrage wie folgt durchführen:
Im Wesentlichen sieht Ihre Anfrage so aus:
Der Sekundärindex erhöht die erforderlichen Lese- / Schreibkapazitätseinheiten, sodass Sie dies berücksichtigen müssen. Es ist immer noch viel besser als ein Scan, der in Lese- und Zeitaufwand teuer ist (und meiner Meinung nach auf 100 Artikel begrenzt ist).
Dies ist vielleicht nicht der beste Weg, aber für jemanden, der an RD gewöhnt ist (ich bin auch an SQL gewöhnt), ist es der schnellste Weg, um produktiv zu werden. Da es keine Einschränkungen hinsichtlich des Schemas gibt, können Sie etwas erstellen, das funktioniert, und sobald Sie die Bandbreite haben, um auf die effizienteste Weise zu arbeiten, können Sie Änderungen vornehmen.
quelle
Sie können den Hash-Schlüssel in Anlehnung an eine 'Produktkategorie'-ID und dann den Bereichsschlüssel als Kombination eines Zeitstempels mit einer eindeutigen ID am Ende festlegen. Auf diese Weise kennen Sie den Hash-Schlüssel und können das Datum immer noch mit größer als abfragen.
quelle
Sie können mehrere identische Hash-Schlüssel haben. aber nur, wenn Sie eine Bereichstaste haben, die variiert. Stellen Sie es sich wie Dateiformate vor. Sie können 2 Dateien mit demselben Namen im selben Ordner haben, solange ihr Format unterschiedlich ist. Wenn ihr Format gleich ist, muss ihr Name unterschiedlich sein. Das gleiche Konzept gilt für die Hash- / Range-Schlüssel von DynamoDB. Stellen Sie sich den Hash als Namen und den Bereich als Format vor.
Ich erinnere mich auch nicht, ob sie diese zum Zeitpunkt des OP hatten (ich glaube nicht, dass sie es getan haben), aber sie bieten jetzt lokale Sekundärindizes an.
Nach meinem Verständnis sollten Sie jetzt die gewünschten Abfragen ausführen können, ohne einen vollständigen Scan durchführen zu müssen. Der Nachteil ist, dass diese Indizes bei der Tabellenerstellung angegeben werden müssen und auch (glaube ich) beim Erstellen eines Elements nicht leer sein dürfen. Darüber hinaus erfordern sie zusätzlichen Durchsatz (obwohl normalerweise nicht so viel wie ein Scan) und Speicherplatz, sodass dies für einige keine perfekte Lösung, sondern eine praktikable Alternative ist.
Ich empfehle jedoch immer noch die Antwort von Mike Brant als bevorzugte Methode zur Verwendung von DynamoDB. und benutze diese Methode selbst. In meinem Fall habe ich nur eine zentrale Tabelle mit nur einem Hash-Schlüssel als ID, dann sekundäre Tabellen mit einem Hash und einem Bereich, die abgefragt werden können. Dann zeigt das Element den Code direkt auf das "interessierende Element" der zentralen Tabelle .
Weitere Daten zu den Sekundärindizes finden Sie in der DynamoDB-Dokumentation von Amazon hier für Interessenten.
Wie auch immer, hoffentlich hilft dies allen anderen, die auf diesen Thread stoßen.
quelle
Aktualisierte Antwort Es gibt keine bequeme Möglichkeit, dies mit Dynamo DB-Abfragen mit vorhersehbarem Durchsatz zu tun. Eine (suboptimale) Option ist die Verwendung einer GSI mit einem künstlichen HashKey & CreatedAt. Fragen Sie dann nur nach HashKey und erwähnen Sie ScanIndexForward, um die Ergebnisse zu ordnen. Wenn Sie einen natürlichen HashKey finden können (z. B. die Kategorie des Artikels usw.), ist diese Methode ein Gewinner. Wenn Sie andererseits für alle Elemente denselben HashKey beibehalten, wirkt sich dies hauptsächlich dann auf den Durchsatz aus, wenn Ihr Datensatz über 10 GB (eine Partition) hinauswächst.
Ursprüngliche Antwort: Sie können dies jetzt in DynamoDB mithilfe von GSI tun. Machen Sie das Feld "CreatedAt" als GSI und stellen Sie Abfragen wie (GT some_date). Speichern Sie das Datum als Zahl (ms seit der Epoche) für diese Art von Abfragen.
Details finden Sie hier: Globale Sekundärindizes - Amazon DynamoDB: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GSI.html#GSI.Using
Dies ist eine sehr mächtige Funktion. Beachten Sie, dass die Abfrage auf (EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN) Bedingung beschränkt ist - Amazon DynamoDB: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html
quelle
CreatedAt
dies der Bereichsschlüssel der GSI sein soll, müssen Sie einen Hash-Schlüssel auswählen - und dann sind Sie wieder da, wo Sie begonnen haben, da Sie GTCreatedAt
nur für einen bestimmten Wert des abfragen können Hash-Schlüssel.