1. 目的
- AWSのデータベース関連サービスの復習をしている。DynamoDBについて、LSI/GSIがなんだかよく分からなかったため、これを機に動作確認する。
2. やったこと
- 練習用のDynamoDBテーブルを作成する。
- LSI/GSIを設定し、それらを用いてどのようなクエリができるのかを確認する。
3. 構成図
- EC2インスタンス内のPythonスクリプトからクエリを実行する。
- 練習用のDynamoDBテーブルの内容は以下の通り。(野菜・果物分類表的なイメージ)
4. 予習
- 分かりやすい解説のある記事は以下。
- LSI/GSIを付けておかないと、属性(列)を指定してのクエリができないということがなんとなく分かった。
5. 実機確認
5.1 DynamoDB テーブルとGSI/LSIの作成
- DynamoDBテーブル「mksamba-qiita」を作成する。パーティションキーを「Name」、ソートキーを「Color」とし、その組み合わせをプライマリーキーとする。
- LSIを作成する。
- LSIの場合、パーティションキーはプライマリーキーで使用したものと同じ「Name」である必要がある。
- ソートキーを「Kind」とする。
- 「ローカルセカンダリインデックスとしての作成」にチェックを付ける。チェックを付けないとGSIになってしまう。
- GSIを作成する。
- パーティションキーはプライマリーキーで使用したものとは別の「Country」とする。
- LSI/GSIが設定されていることを確認し、テーブルを作成する。
- 作成したテーブルにデータを入力する。
5.2 クエリの動作確認
- 「Name」が「Apple」の項目(行)を取得する。
- 「Name」がパーティションキーのため実行OK。2つヒットする。
query1.py
import boto3
from boto3.dynamodb.conditions import Key
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("mksamba-qiita")
response = table.query(
KeyConditionExpression=Key("Name").eq("Apple")
)
print(response["Items"])
[ec2-user@ip-10-0-0-232 ~]$ python3 query1.py
[{'Season': 'Winter', 'Color': 'Green', 'Country': 'NZ', 'Kind': 'Fruit', 'Name': 'Apple'}, {'Season': 'Winter', 'Color': 'Red', 'Country': 'Japan', 'Kind': 'Fruit', 'Name': 'Apple'}]
- 「Name」が「Apple」で、「Color」が「Red」の項目(行)を取得する。(Pythonコードはクエリ部分のみ記載)
- 「Color」がソートキーのため実行OK。1つヒットする。
query2.py
response = table.query(
KeyConditionExpression=Key("Name").eq("Apple") & Key("Color").eq("Red")
)
print(response["Items"])
[ec2-user@ip-10-0-0-232 ~]$ python3 query2.py
[{'Season': 'Winter', 'Color': 'Red', 'Country': 'Japan', 'Kind': 'Fruit', 'Name': 'Apple'}]
- 「Name」が「Apple」で、「Kind」が「Fruit」の項目(行)を取得する。
- 「Kind」がソートキーではないため、実行エラー。
query3.py
response = table.query(
KeyConditionExpression=Key("Name").eq("Apple") & Key("Kind").eq("Fruit")
)
print(response["Items"])
[ec2-user@ip-10-0-0-232 ~]$ python3 query3.py
Traceback (most recent call last):
File "query3.py", line 8, in <module>
~~
botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the Query operation: Query condition missed key schema element: Color
- 「Name」が「Apple」で、「Kind」が「Fruit」の項目(行)をクエリ時にLSIを指定して取得する。
- 「Kind」がLSIのソートキーになっているため、実行OKになる。2つヒットする。
query4.py
response = table.query(
IndexName='Name-Kind-index', KeyConditionExpression=Key("Name").eq("Apple") & Key("Kind").eq("Fruit")
)
print(response["Items"])
[ec2-user@ip-10-0-0-232 ~]$ python3 query4.py
3 [{'Season': 'Winter', 'Color': 'Green', 'Country': 'NZ', 'Kind': 'Fruit', 'Name': 'Apple'}, {'Season': 'Winter', 'Color': 'Red', 'Country': 'Japan', 'Kind': 'Fruit', 'Name': 'Apple'}]
- 「Country」が「Japan」の項目(行)を取得する。
- 「Country」がパーティションキーでないため、実行エラーになる。
query5.py
response = table.query(
KeyConditionExpression=Key("Country").eq("Japan")
)
print(response["Items"])
[ec2-user@ip-10-0-0-232 ~]$ python3 query5.py
Traceback (most recent call last):
File "query5.py", line 8, in <module>
~
botocore.exceptions.ClientError: An error occurred (ValidationException) when calling the Query operation: Query condition missed key schema element: Name
- 「Country]が「Japan」の項目(行)をクエリ時にGSIを指定して取得する。
- GSIにおいては「Country」がパーティションキーのため、実行OK。3つヒットする。
query6.py
response = table.query(
IndexName='Country-index', KeyConditionExpression=Key("Country").eq("Japan")
)
print(response["Items"])
[ec2-user@ip-10-0-0-232 ~]$ python3 query6.py
[{'Season': 'Winter', 'Color': 'Orange', 'Country': 'Japan', 'Kind': 'Vegetable', 'Name': 'Carrot'}, {'Season': 'Winter', 'Color': 'Red', 'Country': 'Japan', 'Kind': 'Fruit', 'Name': 'Apple'}, {'Season': 'Summer', 'Color': 'Red', 'Country': 'Japan', 'Kind': 'Vegetable', 'Name': 'Tomato'}]
6. 所感
- 使いこなせる感はないが、何となく設定する意味は分かるようになった。