Trong mô-đun này, bạn sẽ tìm hiểu một số ví dụ đơn giản về việc truy xuất nhiều mục trong một lệnh gọi API với DynamoDB. Bạn cũng tìm hiểu cách sử dụng chỉ mục phụ để kích hoạt các mẫu hình truy vấn bổ sung trên các bảng DynamoDB của mình.

Thời gian hoàn thành mô-đun: 15 phút


Trong Mô-đun 2, bạn đã thấy cách truy xuất một cuốn sách từ bảng DynamoDB bằng lệnh gọi API GetItem. Mẫu hình truy cập này rất hữu ích nhưng ứng dụng của bạn cũng cần khả năng truy xuất nhiều mục trong một lệnh gọi. Ví dụ: Bạn có thể muốn truy xuất tất cả các cuốn sách của tác giả John Grisham để hiển thị cho người dùng. Ở Bước 1 trong mô-đun này, bạn sử dụng API Query để truy xuất tất cả các cuốn sách của một tác giả cụ thể.

Cả lệnh gọi API GetItem để truy xuất một cuốn sách và lệnh gọi API Query để truy xuất tất cả các cuốn sách của một tác giả đều sử dụng khóa chính được chỉ định trên bảng Books của bạn. Tuy nhiên, bạn có thể muốn kích hoạt thêm các mẫu hình truy cập khác, chẳng hạn như truy xuất tất cả các cuốn sách trong một danh mục cụ thể như sách lịch sử hoặc tiểu sử. Category không phải là một phần của khóa chính trong bảng của bạn nhưng bạn có thể tạo một chỉ mục phụ để cho phép chạy các mẫu hình truy cập bổ sung. Bạn sẽ tạo một chỉ mục phụ và truy vấn chỉ mục phụ đó trong Bước 2 và 3 của mô-đun này.


  • Bước 1. Truy xuất nhiều mục bằng một truy vấn

    Khi bảng của bạn sử dụng khóa chính tổng hợp, bạn có thể truy xuất tất cả các mục có cùng khóa hash bằng lệnh gọi API Query. Đối với ứng dụng của bạn, điều này có nghĩa là bạn có thể truy xuất tất cả các cuốn sách có cùng thuộc tính Tác giả.

    Trong thiết bị đầu cuối AWS Cloud9, chạy lệnh sau.

    $ python query_items.py

    Lệnh này chạy tập lệnh sau để truy xuất tất cả các cuốn sách của tác giả 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)

    Sau khi chạy tập lệnh, bạn sẽ thấy hai cuốn sách của John Grisham, The FirmThe 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'}

    Truy xuất nhiều mục bằng một lệnh gọi trong DynamoDB là một mẫu hình phổ biến và dễ thực hiện với lệnh gọi API Query.

  • Bước 2. Tạo chỉ mục phụ

    DynamoDB cho phép bạn tạo các chỉ mục phụ để tính toán các mẫu hình truy cập dữ liệu bổ sung trên bảng của bạn. Các chỉ mục phụ là một cách thức mạnh mẽ để tăng tính linh hoạt truy vấn cho bảng DynamoDB.

    DynamoDB có hai loại chỉ mục phụ: chỉ mục phụ tổng thể và chỉ mục phụ cục bộ. Trong phần này, bạn thêm chỉ mục phụ tổng thể vào thuộc tính Danh mục để cho phép bạn truy xuất tất cả các cuốn sách thuộc một thể loại nhất định.

    Tập lệnh ví dụ sau đây thêm một chỉ mục phụ tổng thể vào một bảng hiện có.

    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)

    Việc tạo chỉ mục phụ tổng thể có nhiều điểm giống với việc tạo bảng. Bạn chỉ định tên cho chỉ mục, các thuộc tính sẽ có trong chỉ mục, lược đồ chính của chỉ mục và thông lượng cung cấp (công suất tối đa mà ứng dụng có thể xử lý từ một bảng hoặc chỉ mục). Thông lượng cung cấp trên mỗi chỉ mục tách biệt với thông lượng cung cấp trên bảng. Điều này cho phép bạn xác định thông lượng một cách chi tiết để đáp ứng nhu cầu ứng dụng của bạn.

    Chạy lệnh sau trong thiết bị đầu cuối của bạn để thêm chỉ mục phụ tổng thể.

    $ python add_secondary_index.py

    Tập lệnh này thêm một chỉ mục phụ tổng thể có tên là CategoryIndex vào bảng Books của bạn.

  • Bước 3. Truy vấn chỉ mục phụ

    Bây giờ bạn đã có CategoryIndex, bạn có thể sử dụng để truy xuất tất cả các sách trong một danh mục cụ thể. Việc sử dụng chỉ mục phụ để truy vấn bảng tương tự như sử dụng lệnh gọi API Query. Bây giờ bạn thêm tên chỉ mục vào lệnh gọi API.

    Khi bạn thêm một chỉ mục phụ tổng thể vào bảng hiện có, DynamoDB sẽ lấp đầy chỉ mục một cách không đồng bộ với các mục hiện có trong bảng. Chỉ mục sẽ có thể truy vấn sau khi tất cả các mục đã được lấp đầy. Thời gian lấp đầy phù thuộc vào kích thước của bảng.

    Bạn có thể sử dụng tập lệnh query_with_index.py để truy vấn chỉ mục mới. Chạy tập lệnh này với lệnh sau trong thiết bị đầu cuối của bạn.

    $ python query_with_index.py

    Lệnh đó sẽ chạy tập lệnh sau để truy xuất tất cả các cuốn sách trong cửa hàng có 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)

    Lưu ý rằng có một phần của tập lệnh chờ cho đến khi chỉ mục sẵn sàng cho phép truy vấn.

    Bạn sẽ thấy kết quả đầu ra như sau trong thiết bị đầu cuối của mình.

    $ 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'}

    Truy vấn trả về ba cuốn sách của hai tác giả khác nhau. Đây là một mẫu hình truy vấn có thể khó khăn với lược đồ khóa chính của bảng nhưng đã dễ dàng được thực hiện nhờ các chỉ mục phụ.


    Trong mô-đun tiếp theo, bạn sẽ tìm hiểu cách cập nhật các thuộc tính của một mục hiện có trong bảng bằng API UpdateItem