AWS ことはじめ その5 (DynamoDB - Part3)

前回に続いて、今度はデータの読み出し。

choge.hatenadiary.com

やっぱりIDとタイムスタンプ以外でも読み出したいとか、貯めておくのは一旦1ヶ月でいいとか、色々要望がぶれ始めているのでDynamoDBを本当に使うのか雲行きが怪しくなってきている。IDとタイムスタンプ以外で、という件は、Secondary Indexである程度対応できる気はしている。逆に貯めるのを1ヶ月だけでよい、というのは、そもそもKVSを使うほどの容量なのか?という話になってくる。悩ましいところ。

データ格納イメージ

復習。パーティションキーをもとに分散してデータを格納して、同一パーティション内はソートキーで順番にデータを並べる。

f:id:ch0ge:20180523231346p:plain

1. Primary Keyでアクセス

DynamoDB での項目の操作 - Amazon DynamoDB

最も高速。RDB的に言うとUNIQUE INDEXでアクセスしているようなもの。 f:id:ch0ge:20180523225354p:plain

2. Queryでのアクセス:

クエリの操作 - Amazon DynamoDB

パーティションキーで範囲を絞込み、その中で検索を行う。キャパシティユニットは、結果的に返ってくる項目のサイズによる。つまり、たくさんの属性を持つ項目を読み取ると、1属性だけを返したとしても全属性分のキャパシティユニットが消費される。 f:id:ch0ge:20180523230936p:plain

>>> sparse.attribute_definitions
[{'AttributeName': 'sid', 'AttributeType': 'S'}, {'AttributeName': 'unixtime', 'AttributeType': 'N'}]

>>> sparse.key_schema
[{'AttributeName': 'sid', 'KeyType': 'HASH'}, {'AttributeName': 'unixtime', 'KeyType': 'RANGE'}]

>>> res = sparse.query(
...     TableName='sparse-data',
...     Limit=10,  # 取得する件数を制限(任意)
...     ReturnConsumedCapacity='TOTAL', # 消費したキャパシティユニットの総量を返す
...     KeyConditionExpression='sid = :val', # 条件式。値は":sid"のようなPlaceholderにする
...     ExpressionAttributeValues={   # ↑で指定した Placeholderに対する値を記載する
...         ':val': 'ABC-1234567',
...     },
...     ConsistentRead=False,  # (結果整合性ではなく)強い整合性を持った読み込みを行うか
...     ScanIndexForward=False  # ソートキーの最初から読み込む(True)か、最後から読み込む(False)か
... )

>>> res['Count'], res['ScannedCount'] # 'Count': 結果の件数、 'ScannedCount': 実際に読み込んだ件数。今回は特にフィルタリングしていないので一致する。
(10, 10)

>>> res['ConsumedCapacity']  # 消費したキャパシティユニット。1回の結果整合性のみの読み取り、かつ、1KB以内なので、消費されたRCUは0.5
{'TableName': 'sparse-data', 'CapacityUnits': 0.5}

>>> res['LastEvaluatedKey'] # クエリーが読み取った最後の項目。複数のオペレーションに分けるときは、この値をExclusiveStartKeyに含める。
{'sid': 'ABC-1234567', 'unixtime': Decimal('1684587390')}

>>> res2 = sparse.query(
...     TableName='sparse-data',
...     ReturnConsumedCapacity='TOTAL',
...     KeyConditionExpression='sid = :sid AND unixtime BETWEEN :start_dt AND :end_dt',
...     # ソートキーの条件を指定。条件は一つだけなので、〜以上〜以下のようなケースはBETWEENを使う
...     ExpressionAttributeValues={
...         ':sid': 'ABC-1234567',
...         ':start_dt': decimal.Decimal(start_dt.timestamp()),  # Decimal!
...         ':end_dt'  : decimal.Decimal(end_dt.timestamp())
...     }
... )

ちなみに、boto3の(ドキュメント)http://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html#DynamoDB.Client.queryのExpressionAttributeValuesというセクションに条件で指定する値の書き方が書いてある。が、これ多分間違ってる。例が

    { ":avail":{"S":"Available"}, ":back":{"S":"Backordered"}, ":disc":{"S":"Discontinued"} }

となっているが、正しくは

     {":avail": "Available", ":back": "Backordered", ":disc": "Discontinued" }

のように、値部分はdictではなく単なる文字列とかを指定する。

3. Scanでのアクセス

テーブルをスキャンする - Amazon DynamoDB

テーブル全部を取得する。普通はこれをやる意味はない。全件取得しても大したことない小さなテーブルだとか、そもそもどこかにエクスポートするから全件取得したいとか、そういう特殊なケース向け。

f:id:ch0ge:20180523231139p:plain