Lambdaでクエリ実行(パーティションキー、ソートキー、セカンダリインデックスを使用した検索)

本日はDynamoDBについて、パーティションキー、ソートキー、ローカルセカンダリインデックス、グローバルセカンダリインデックスを使用した検索の方法についてご紹介いたします。まずは、キーとインデックスについて簡単な説明を行って、テーブルを作成し、クエリを投げていこうと思います。

パーティションキー、ソートキー、各種セカンダリインデックスの基礎知識

パーティションキー・・
テーブルにつき一つのみ設定可。
テーブルに必須。
クエリを投げる際にこのキーを指定して検索や挿入を行う。

ソートキー・・
テーブルにつき一つのみ設定可。
設定しないこともできる。
設定した際はクエリを投げる際にこのキーとパーティションキーを指定して検索や挿入を行わなければならない。
検索や挿入でパーティションキーとソートキーの二つを指定する必要がありますが、パーティションしかないテーブルより細かい指定ができる。

ローカルセカンダリインデックス(LSI)・・ 設定するかしないか自由。
今あるパーティションキーと新たなソートキーの新たな組み合わせを作成できる。
例えば、パーティションキーとソートキーを使用していたテーブルでLSIを使用した場合、以下の二つの方法で検索や挿入が可能になる。
①パーティションキーとソートキー
②パーティションキーとLSIのソートキー

グローバルセカンダリインデックス・・
設定するかしないか自由。
今あるパーティションキーとソートキーとは違う新しいパーティションキーと新しいソートキーの組み合わせを作成できる。
新しいパーティションキーと新しいソートキーの組み合わせで検索が可能になる。

・セカンダリインデックスの注意点
テーブルに書き込みを行った際にインデックスにもデータが反映されるので、その分のWCUを消費するので インデックスを増やすとコストもかかる。

2.テーブルの作成

まずはテーブルの作成を行います。 検索のやり方を紹介する時にLambdaを使用するので、 テーブルの作成もLambdaでやっちゃいます。

Lambdaの作成をデフォルトで作成し、作成の際にIAMロールにてDynamoDBのFullアクセスを付与しました。 Lambdaが作成されたら、Lambdaで以下コードを入力し、test実行します。

ちなみにコードの説明は以下になります。
コード内容:テーブルの作成
テーブルの項目:会社名、予約有無、部署(department)、ホテル、予約した人、日付
キーの種類:
パーティションキー、ハッシュキー・・会社名、部署名
ローカルセカンダリインデックス・・会社名、予約した人の組み合わせ
グローバルセカンダリインデックス・・ホテル、日付
ただの値(非キー属性)・・予約有無

・以下コード内の項目の説明 KeySchemaのKeyTypeのHASH、RANGE・・HASHがパーティションキーで、RANGEがソートキーになります。
AttributeDefinitionsのAttributeType・・SはString(文字列)、Nは数字(Number)の値を入れるキーということです。
ProjectionType・・何のキーの値を取り出すか指定します。今回は全属性を取得するのでALLとしています。

  1. import json
  2. import boto3
  3. resource = boto3.resource("dynamodb")
  4.  
  5. def lambda_handler(event, context):
  6.         response = resource.create_table(
  7.         AttributeDefinitions = [
  8.             {
  9.                 'AttributeName': 'company',
  10.                 'AttributeType': 'S'
  11.             },
  12.             {
  13.                 'AttributeName': 'department',
  14.                 'AttributeType': 'S'
  15.             },
  16.             {
  17.                 'AttributeName': 'name',
  18.                 'AttributeType': 'S'
  19.             },
  20.             {
  21.                 'AttributeName': 'hotel',
  22.                 'AttributeType': 'S'
  23.             },
  24.             {
  25.                 'AttributeName': 'date',
  26.                 'AttributeType': 'S'
  27.             },
  28.         ],
  29.         TableName = 'test-hotel-reservation',
  30.         KeySchema = [
  31.             {
  32.                 'AttributeName': 'company',
  33.                 'KeyType': 'HASH'
  34.             },
  35.             {
  36.                 'AttributeName': 'department',
  37.                 'KeyType': 'RANGE'
  38.             },
  39.         ],
  40.         ProvisionedThroughput = {
  41.             'ReadCapacityUnits': 1,
  42.             'WriteCapacityUnits': 1
  43.         },
  44.         LocalSecondaryIndexes=[
  45.             {
  46.                 'IndexName': 'departmentLSIndex',
  47.                 'KeySchema': [
  48.                     {
  49.                         'AttributeName': 'company',
  50.                         'KeyType': 'HASH'
  51.                     },
  52.                     {
  53.                         'AttributeName': 'name',
  54.                         'KeyType': 'RANGE'
  55.                     }
  56.                 ],
  57.                 'Projection': {
  58.                     'ProjectionType': 'ALL',
  59.                 }
  60.             },
  61.         ],
  62.         GlobalSecondaryIndexes=[
  63.             {
  64.                 'IndexName': 'hotel-nameGSIndex',
  65.                 'KeySchema': [
  66.                     {
  67.                         'AttributeName': 'hotel',
  68.                         'KeyType': 'HASH'
  69.                     },
  70.                     {
  71.                         'AttributeName': 'date',
  72.                         'KeyType': 'RANGE'
  73.                     },
  74.                 ],
  75.                 'Projection': {
  76.                     'ProjectionType': 'ALL',
  77.                 },
  78.                 'ProvisionedThroughput': {
  79.                     'ReadCapacityUnits': 1,
  80.                     'WriteCapacityUnits': 1
  81.                 }
  82.             },
  83.         ],
  84.     )


テーブルが作成されました。インデックスも設定されています。

3.データ(値)を挿入

続いてデータの挿入を行います。 Lambdaを使用し、以下のようにデータの挿入をしました。データ挿入時にLambdaで使用したコードの内容も記載いたします。

・Lambdaのコード

  1. import json
  2. import boto3
  3. resource = boto3.resource("dynamodb")
  4.  
  5. def lambda_handler(event, context):
  6.     table = resource.Table("test-hotel-reservation")
  7.     with table.batch_writer() as batch:
  8.         batch.put_item(
  9.             Item={
  10.                 'company': 'A社',
  11.                 'department': '営業部',
  12.                 'name': 'A社鈴木',
  13.                 'hotel': '山のホテル',
  14.                 'date': 202202,
  15.                 'reservation': 'Yes'
  16.             }
  17.         )
  18.         batch.put_item(
  19.             Item={
  20.                 'company': 'A社',
  21.                 'department': '人事部',
  22.                 'name': 'A社山口',
  23.                 'hotel': '川のホテル',
  24.                 'date': 202202,
  25.                 'reservation': 'Yes'
  26.             }
  27.         )
  28.         batch.put_item(
  29.             Item={
  30.                 'company': 'A社',
  31.                 'department': '総務部',
  32.                 'name': 'A社下田',
  33.                 'hotel': '都内ホテル',
  34.                 'date': 202202,
  35.                 'reservation': 'No'
  36.             }
  37.         )
  38.         batch.put_item(
  39.             Item={
  40.                 'company': 'B社',
  41.                 'department': '人事部',
  42.                 'name': 'B社金井',
  43.                 'hotel': '山のホテル',
  44.                 'date': 202204,
  45.                 'reservation': 'Yes'
  46.             }
  47.         )
  48.         batch.put_item(
  49.             Item={
  50.                 'company': 'B社',
  51.                 'department': '経理部',
  52.                 'name': 'B社田川',
  53.                 'hotel': '川のホテル',
  54.                 'date': 202204,
  55.                 'reservation': 'No'
  56.             }
  57.         )
  58.         batch.put_item(
  59.             Item={
  60.                 'company': 'C社',
  61.                 'department': '営業部',
  62.                 'name': 'C社太田',
  63.                 'hotel': '都内ホテル',
  64.                 'date': 202308,
  65.                 'reservation': 'Yes'
  66.             }
  67.         )




(本編)パーティションキー、ソートキーを使用した読み込み

続いてパーティションキー、ソートキーの検索についてです。 まずはパーティションキー(社名)のみで検索をかけてみます。

ではB社の情報を取得してみましょう。

冒頭に「from boto3.dynamodb.conditions import Key」がありますが、これがないと8行目でエラーになります。

  1. import boto3
  2. from boto3.dynamodb.conditions import Key
  3. dynamodb = boto3.resource('dynamodb')
  4.  
  5. def lambda_handler(event, context):
  6.     table = dynamodb.Table("test-hotel-reservation")
  7.     response = table.query(
  8.         KeyConditionExpression = Key('company').eq('B社')
  9.     )
  10.     print(response)


2件検索されました。
・出力結果


{'Items': [{'hotel': '山のホテル', 'department': '人事部', 'date': Decimal('202204'), 'company': 'B社', 'name': 'B社金井', 'reservation': 'Yes'}, {'hotel': '川のホテル', 'department': '経理部', 'date': Decimal('202204'), 'company': 'B社', 'name': 'B社田川', 'reservation': 'No'}], 'Count': 2,・・(省略)

整えるとこんな感じです。

{'Items': [
{'hotel': '山のホテル', 'department': '人事部', 'date': Decimal('202204'), 'company': 'B社', 'name': 'B社金井', 'reservation': 'Yes'},
{'hotel': '川のホテル', 'department': '経理部', 'date': Decimal('202204'), 'company': 'B社', 'name': 'B社田川', 'reservation': 'No'}
]

次はパーティションキー(社名)とソートキー(部署)で検索します。

  1. import boto3
  2. from boto3.dynamodb.conditions import Key
  3. dynamodb = boto3.resource('dynamodb')
  4.  
  5. def lambda_handler(event, context):
  6.     table = dynamodb.Table("test-hotel-reservation")
  7.     response = table.query(
  8.         KeyConditionExpression = Key('company').eq('A社') & Key('department').eq('営業部')
  9.     )
  10.     print(response)


B社の営業部は一件しかないのでひとつのみ検索されました。
・出力結果

{'Items': [{'hotel': '山のホテル', 'department': '営業部', 'date': Decimal('202202'), 'company': 'A社', 'name': 'A社鈴木', 'reservation': 'Yes'}], 'Count': 1・・(省略)

(本編)ローカルセカンダリインデックス(LSI)を使用した読み込み

ローカルセカンダリインデックスは同じようにqueryコマンドで検索できます。ただ、IndexNameでインデックス作成時に設定したインデックス名を指定しなければなりません。ローカルセカンダリインデックスは社名と予約者名に設定していましたね。
・コード

  1. import boto3
  2. from boto3.dynamodb.conditions import Key
  3. dynamodb = boto3.resource('dynamodb')
  4.  
  5. def lambda_handler(event, context):
  6.     table = dynamodb.Table("test-hotel-reservation")
  7.     response = table.query(
  8.         IndexName='departmentLSIndex',
  9.         KeyConditionExpression = Key('company').eq('A社') & Key('name').eq('A社下田')
  10.     )
  11.     print(response)


・出力結果

{'Items': [{'hotel': '都内ホテル', 'department': '総務部', 'date': Decimal('202202'), 'company': 'A社', 'reservation': 'No', 'name': 'A社下田'}], 'Count': 1, 'ScannedCount': 1・・(省略)

(本編)グローバルセカンダリインデックス(GSI)を使用した読み込み

GSIはLSIと同じでインデックス名と検索のコードで検索できます。GSIのパーティションキーはデフォルトで設定した社名と部署名ではなく以下に設定しましたね。
パーティションキー・・hotel (String)
ソートキー・・date (Number)

まずは、パーティションキーだけで検索します。

  1. import boto3
  2. from boto3.dynamodb.conditions import Key
  3. dynamodb = boto3.resource('dynamodb')
  4.  
  5. def lambda_handler(event, context):
  6.     table = dynamodb.Table("test-hotel-reservation")
  7.     response = table.query(
  8.         IndexName='hotel-nameGSIndex',
  9.         KeyConditionExpression = Key('hotel').eq('山のホテル')
  10.     )
  11.     print(response)


・出力結果

{'Items': [
{'hotel': '山のホテル', 'department': '営業部', 'date': Decimal('202202'), 'company': 'A社', 'name': 'A社鈴木', 'reservation': 'Yes'},
{'hotel': '山のホテル', 'department': '人事部', 'date': Decimal('202204'), 'company': 'B社', 'name': 'B社金井', 'reservation': 'Yes'}],
'Count': 2, 'ScannedCount': 2,・・(省略)

パーティションキー、ソートキーでの検索は以下になります。 ソートキーのdateは文字列ではなく数字なので、「’」で囲む必要はありません。

  1. import boto3
  2. from boto3.dynamodb.conditions import Key
  3. dynamodb = boto3.resource('dynamodb')
  4.  
  5. def lambda_handler(event, context):
  6.     table = dynamodb.Table("test-hotel-reservation")
  7.     response = table.query(
  8.         IndexName='hotel-nameGSIndex',
  9.         KeyConditionExpression = Key('hotel').eq('川のホテル') & Key('date').eq(202202)
  10.     )
  11.     print(response)


・出力結果

{'Items': [{'hotel': '川のホテル', 'department': '人事部', 'date': Decimal('202202'), 'company': 'A社', 'name': 'A社山口', 'reservation': 'Yes'}], 'Count': 1, 'ScannedCount': 1・・(省略)

本記事は以上となります。 最後までご覧いただきありがとうございました。

手順はたった2つ AWS Lambda環境変数の使い方!暗号化についても説明します

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です