في هذه الوحدة، يمكنك استعراض بعض الأمثلة البسيطة لاسترداد عناصر متعددة في استدعاء واجهة برمجة تطبيقات واحدة باستخدام DynamoDB. ستتعلم أيضًا كيفية استخدام الفهارس الثانوية لتمكين أنماط استعلام إضافية على جداول DynamoDB خاصتك.

الوقت اللازم لاستكمال الوحدة: 15 دقيقة


في الوحدة 2، تعرفت على كيفية استرداد كتاب واحد من جدول DynamoDB باستخدام استدعاء واجهة برمجة تطبيقات GetItem. يُعد نمط الوصول هذا مفيدًا، ولكن يحتاج تطبيقك أيضًا إلى القدرة على استرداد عناصر متعددة في استدعاء واحد. فعلى سبيل المثال، قد ترغب في استرداد جميع الكتب التي كتبها جون غريشام حتى تتمكن من عرضها للمستخدمين. في الخطوة 1 من هذه الوحدة، يمكنك استخدام واجهة برمجة تطبيقات Query لاسترداد جميع الكتب لمؤلف معين.

يستخدم استدعاء كل من واجهة برمجة تطبيقات GetItem للحصول على كتاب واحد واستدعاء واجهة برمجة تطبيقات Query لاسترداد كافة الكتب لأي مؤلف المفتاح الأساسي المحدد في جدول Books الخاص بك. ومع ذلك، قد ترغب في تمكين أنماط وصول إضافية، مثل استرداد جميع الكتب في فئة معينة مثل التاريخ أو السيرة الذاتية. الفئة ليست جزءًا من المفتاح الأساسي للجدول الخاص بك، ولكن يمكنك إنشاء فهرس ثانوي للسماح بأنماط وصول إضافية. ستقوم بإنشاء فهرس ثانوي والاستعلام عن الفهرس الثانوي في الخطوتين 2 و3 من هذه الوحدة.


  • الخطوة 1. استرداد عناصر متعددة باستعلام واحد

    عندما يستخدم الجدول الخاص بك مفتاحًا أساسيًا مركبًا، يمكنك استرداد جميع العناصر بنفس مفتاح التجزئة باستخدام استدعاء واجهة برمجة تطبيقات Query. بالنسبة إلى تطبيقك، يعني ذلك أنه يمكنك استرداد كل الكتب بنفس سمة المؤلف.

    قم بإجراء الأمر التالي في محطة AWS Cloud9 الطرفية.

    $ python query_items.py

    يقوم هذا الأمر بتشغيل البرنامج النصي التالي الذي يسترد جميع الكتب التي كتبها جون غريشام.

    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 نمطًا شائعًا وسهل التنفيذ من خلال استدعاء واجهة برمجة تطبيقات Query.

  • الخطوة 2. إنشاء فهرس ثانوي

    يتيح لك DynamoDB إنشاء فهارس ثانوية لمراعاة أنماط الوصول إلى البيانات الإضافية في جدولك. تُعد الفهارس الثانوية طريقة فعالة لإضافة مرونة الاستعلام إلى جدول DynamoDB.

    يحتوي DynamoDB على نوعين من الفهارس الثانوية: الفهارس الثانوية العامة والفهارس الثانوية المحلية. في هذا القسم، تضيف فهرسًا ثانويًا عامًا إلى سمة الفئة مما سيسمح لك باسترداد جميع الكتب في فئة معينة.

    يضيف البرنامج النصي في المثال التالي فهرسًا ثانويًا عامًا إلى جدول موجود.

    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، يمكنك استخدامه لاسترداد كافة الكتب في فئة معينة. يشبه استخدام فهرس ثانوي للاستعلام عن جدول استخدام استدعاء واجهة برمجة تطبيقات Query. يمكنك الآن إضافة اسم الفهرس إلى استدعاء واجهة برمجة تطبيقات.

    عند إضافة فهرس ثانوي عام إلى جدول موجود، يقوم DynamoDB بإعادة تعبئة الفهرس بشكل غير متزامن بالعناصر الموجودة في الجدول. الفهرس متاح للاستعلام بعد إعادة تعبئة جميع العناصر. يختلف الزمن المستغرق لإعادة التعبئة بناءً على حجم الجدول.

    يمكنك استخدام البرنامج النصي query_with_index.py للاستعلام عن الفهرس الجديد. قم بتشغيل البرنامج النصي في وحدتك الطرفية باستخدام الأمر التالي.

    $ python query_with_index.py

    يقوم هذا الأمر بتشغيل البرنامج النصي التالي لاسترداد كافة الكتب الموجودة في المخزن والتي تحتوي على فئةالانتظار.

    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