В этом модуле мы рассмотрим ряд простых примеров получения нескольких элементов с помощью одного вызова API в DynamoDB. Вы также узнаете, как с помощью вторичных индексов включить дополнительные шаблоны запросов для таблиц DynamoDB.

Время, необходимое для прохождения модуля: 15 минут


В модуле 2 вы узнали, как получить одну книгу из таблицы DynamoDB с помощью вызова API GetItem. Этот шаблон доступа удобно использовать, но вашему приложению также необходима возможность получать несколько элементов с помощью одного вызова. Например, вам может потребоваться получить все книги, написанные Джоном Гришэмом (John Grisham), чтобы отобразить их для пользователей. В шаге 1 этого модуля вы получите все книги определенного автора с помощью API Query.

И при вызове API GetItem для получения одной книги, и при вызове API Query для получения всех книг определенного автора используется заданный первичный ключ в таблице Books. Тем не менее вам может потребоваться использовать дополнительные шаблоны доступа, например получать все книги в определенной категории, например в категории «История» или «Биографии». Атрибут Category не входит в состав первичного ключа таблицы, но вы можете создать вторичный индекс, чтобы использовать дополнительные шаблоны доступа. Вы создадите вторичный индекс и выполните запросы к нему в шагах 2 и 3 этого модуля.


  • Шаг 1. Получение нескольких элементов с помощью одного запроса

    Когда в таблице используется составной первичный ключ, вы можете получить все элементы с одним и тем же ключом хэша с помощью вызова API Query. Для вашего приложения это означает, что вы можете получить все книги с одинаковым значением атрибута 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)

    После запуска скрипта должны отобразиться две книги Джона Гришэма: 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 получение нескольких элементов с помощью одного вызова – распространенная практика, и это можно без труда сделать, совершив вызов API Query.

  • Шаг 2. Создание вторичного индекса

    В 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.

  • Шаг 3. Создание запроса по вторичному индексу

    Теперь, когда у вас есть индекс CategoryIndex, вы можете использовать его для получения всех книг определенной категории. Использование вторичного индекса для совершения запросов к таблице аналогично использованию вызова API Query. Теперь добавим имя индекса в вызов 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'}

    Запрос возвращает три книги двух разных авторов. Этот запрос трудно выполнить при использовании схемы основного ключа таблицы и легко – с помощью вторичных индексов.


    В следующем модуле вы узнаете, как обновить атрибуты существующего в таблице элемента с помощью API UpdateItem