模块 3:查询和全局二级索引
您将演练一些使用 DynamoDB 在一个 API 调用中检索多个条目的简单示例
概览
在本模块中,您将演练一些使用 DynamoDB 在一个 API 调用中检索多个条目的简单示例。您还将了解如何使用二级索引针对 DynamoDB 表启用其他查询模式。
应用程序用例
在模块 2 中,您学习了如何通过使用 GetItem API 调用从 DynamoDB 表中检索单本图书。这种访问模式非常有用,但您的应用程序还需要能够在一个调用中检索多个条目。例如,您可能想要检索由 John Grisham 撰写的所有图书,以便可以向用户显示它们。在本模块的步骤 1 中,您将使用 Query API 检索特定作者的所有图书。
用于获取单本图书的 GetItem API 调用和用于检索作者所有图书的 Query API 调用均使用 Books 表中指定的主键。但是,您可能希望启用其他访问模式,例如检索历史或传记等特定类别中的所有图书。Category 不是表主键的一部分,但您可以创建二级索引以允许使用其他访问模式。您将在本模块的步骤 2 和 3 中创建和查询二级索引。
完成所需时间
15 分钟
执行步骤
-
通过单次查询来检索多个条目
如果您的表使用复合主键,可以使用 Query API 调用来检索具有相同哈希键的所有条目。对于您的应用程序,这意味着您可以检索具有相同 Author 属性的所有图书。
在 AWS Cloud9 终端,运行以下命令。
$ python query_items.py
此命令运行以下脚本,检索由 John Grisham 编写的所有图书。
import boto3 from boto3.dynamodb.conditions import Key # boto3 is the AWS SDK library for Python. # The "resources" interface allows for a higher-level abstraction than the low-level client interface. # For more details, go to http://boto3.readthedocs.io/en/latest/guide/resources.html dynamodb = boto3.resource('dynamodb', region_name='us-east-1') table = dynamodb.Table('Books') # When making a Query API call, you use the KeyConditionExpression parameter to specify the hash key on which you want to query. # You’re using the Key object from the Boto 3 library to specify that you want the attribute name ("Author") # to equal "John Grisham" by using the ".eq()" method. resp = table.query(KeyConditionExpression=Key('Author').eq('John Grisham')) print("The query returned the following items:") for item in resp['Items']: print(item)
运行该脚本后,您应当会看到 John Grisham 的两本图书:The Firm 和 The Rainmaker。
$ python query_items.py The query returned the following items: {'Title': 'The Firm', 'Formats': {'Hardcover': 'Q7QWE3U2', 'Paperback': 'ZVZAYY4F', 'Audiobook': 'DJ9KS9NM'}, 'Author': 'John Grisham', 'Category': 'Suspense'} {'Title': 'The Rainmaker', 'Formats': {'Hardcover': 'J4SUKVGU', 'Paperback': 'D7YF4FCX'}, 'Author': 'John Grisham', 'Category': 'Suspense'}
在 DynamoDB 中,常见模式是通过单个调用来检索多个条目,这可以通过 Query API 调用轻松完成。
-
创建二级索引
DynamoDB 允许您创建二级索引以考虑表的其他数据访问模式。二级索引是为 DynamoDB 表提高查询灵活性的强大方法。
DynamoDB 有两种二级索引:全局二级索引和局部二级索引。在本部分中,您将向 Category 属性中添加一个全局二级索引,该索引将允许您检索特定类别中的所有图书。
以下示例脚本向现有表添加全局二级索引。
import boto3 # Boto3 is the AWS SDK library for Python. # You can use the low-level client to make API calls to DynamoDB. client = boto3.client('dynamodb', region_name='us-east-1') try: resp = client.update_table( TableName="Books", # Any attributes used in your new global secondary index must be declared in AttributeDefinitions AttributeDefinitions=[ { "AttributeName": "Category", "AttributeType": "S" }, ], # This is where you add, update, or delete any global secondary indexes on your table. GlobalSecondaryIndexUpdates=[ { "Create": { # You need to name your index and specifically refer to it when using it for queries. "IndexName": "CategoryIndex", # Like the table itself, you need to specify the key schema for an index. # For a global secondary index, you can use a simple or composite key schema. "KeySchema": [ { "AttributeName": "Category", "KeyType": "HASH" } ], # You can choose to copy only specific attributes from the original item into the index. # You might want to copy only a few attributes to save space. "Projection": { "ProjectionType": "ALL" }, # Global secondary indexes have read and write capacity separate from the underlying table. "ProvisionedThroughput": { "ReadCapacityUnits": 1, "WriteCapacityUnits": 1, } } } ], ) print("Secondary index added!") except Exception as e: print("Error updating table:") print(e)
创建全局二级索引与创建表有很多共同点。指定索引的名称、将位于索引中的属性、索引的键模式以及预配的吞吐量(应用程序可以从表或索引中使用的最大容量)。针对每个索引预配的吞吐量与针对表预配的吞吐量是分开的。这使您可以根据应用程序的需求按粒度定义吞吐量。
在终端运行以下命令来添加全局二级索引。
$ python add_secondary_index.py
此脚本将名为 CategoryIndex 的全局二级索引添加到 Books 表中。
-
查询二级索引
现在您已经有了 CategoryIndex,可以使用它来检索具有特定类别的所有图书。使用二级索引来查询表与使用 Query API 调用相似。现在向 API 调用中添加索引名称。
当您向现有表中添加全局二级索引时,DynamoDB 会使用表中的现有条目异步回填索引。所有条目回填后,可使用索引进行查询。回填时间因表大小不同而异。
可以使用 query_with_index.py 脚本来查询新索引。在终端使用以下命令运行该脚本。
$ python query_with_index.py
该命令运行以下脚本来检索商店中 Category 为 Suspense 的所有图书。
import time import boto3 from boto3.dynamodb.conditions import Key # Boto3 is the AWS SDK library for Python. # The "resources" interface allows for a higher-level abstraction than the low-level client interface. # For more details, go to http://boto3.readthedocs.io/en/latest/guide/resources.html dynamodb = boto3.resource('dynamodb', region_name='us-east-1') table = dynamodb.Table('Books') # When adding a global secondary index to an existing table, you cannot query the index until it has been backfilled. # This portion of the script waits until the index is in the “ACTIVE” status, indicating it is ready to be queried. while True: if not table.global_secondary_indexes or table.global_secondary_indexes[0]['IndexStatus'] != 'ACTIVE': print('Waiting for index to backfill...') time.sleep(5) table.reload() else: break # When making a Query call, you use the KeyConditionExpression parameter to specify the hash key on which you want to query. # If you want to use a specific index, you also need to pass the IndexName in our API call. resp = table.query( # Add the name of the index you want to use in your query. IndexName="CategoryIndex", KeyConditionExpression=Key('Category').eq('Suspense'), ) print("The query returned the following items:") for item in resp['Items']: print(item)
请注意,该脚本的一部分会等待索引可供查询。
您应当会在终端看到以下输出结果。
$ python query_with_index.py The query returned the following items: {'Title': 'The Firm', 'Formats': {'Hardcover': 'Q7QWE3U2', 'Paperback': 'ZVZAYY4F', 'Audiobook': 'DJ9KS9NM'}, 'Author': 'John Grisham', 'Category': 'Suspense'} {'Title': 'The Rainmaker', 'Formats': {'Hardcover': 'J4SUKVGU', 'Paperback': 'D7YF4FCX'}, 'Author': 'John Grisham', 'Category': 'Suspense'} {'Title': 'Along Came a Spider', 'Formats': {'Hardcover': 'C9NR6RJ7', 'Paperback': '37JVGDZG', 'Audiobook': '6348WX3U'}, 'Author': 'James Patterson', 'Category': 'Suspense'}
该查询返回两位不同作者的三本图书。这查询模式借助于表的主键模式很难实现,但借助于二级索引的强大功能很易实现。
在下一个模块中,您将学习如何使用 UpdateItem API 更新表中现有条目的属性。