在上一個單元中,您已新增反向索引至資料表。反向索引為關聯式資料新增了其他查詢模式。但我們看到仍有問題。雖然我們可以查詢指定使用者實體的所有朋友關係實體,但朋友關係實體並不包含有關所關注使用者的資訊。

在本單元中,您將了解部份標準化。

在第二個單元中,我們看到您在使用 DynamoDB 建模時不得嘗試模擬關聯式模式。關聯式模型的一個核心租用戶是資料的標準化,這可讓您避免在多個位置重複資料。標準化是關聯式資料庫中一種很好的模式,但是在查詢時,您可能需要昂貴的聯接來重組資料。

使用 DynamoDB,您通常希望對資料非標準化。非標準化有助於避免聯接並提高查詢效能。為此,您可以將屬性從一個項目複製到參考該項目的另一個項目,以避免在查詢期間擷取兩個項目。

然而,有時非標準化會讓您的資料模型複雜化。例如,資料模型具有一個朋友關係實體,該實體既參考被關注的使用者,也參考關注的使用者。建立朋友關係實體時,可以將每個使用者實體的所有屬性複製到朋友關係實體中。然後,當您擷取朋友關係實體時,您還將擁有關於這兩個使用者的所有詳細資訊。

每當使用者變更其檔案中的資訊時,這可能會帶來問題。例如,若使用者變更其的檔案圖片,則包含該使用者的每個朋友關係實體中的資料都會過時。每當有更新時,您需要更新包含使用者的每個朋友關係實體。

在下面的步驟中,您將看到如何使用部份標準化和 BatchGetItem API 叫用來處理這種情況。

完成單元的時間:20 分鐘


  • 步驟 1:使用部份標準化來尋找被關注的使用者

    在此步驟中,您將看到如何尋找被關注的使用者。這些是特定使用者在您的應用程式中所關注的使用者。您還將看到如何擷取有關被關注使用者的所有資料。

    如本單元簡介中所述,您可能希望圍繞朋友關係和使用者來使用部份標準化技術。您可以使用 BatchGetItem API 來擷取朋友關係實體中使用者的相關資訊,而不是將每個使用者的相關完整資訊儲存在朋友關係實體中。

    在您下載的程式碼中,名稱為 find_and_enrich_following_for_user.py 的檔案位於 application/ 目錄。該指令碼的內容如下所示。

    import boto3
    
    from entities import User
    
    dynamodb = boto3.client('dynamodb')
    
    USERNAME = "haroldwatkins"
    
    
    def find_and_enrich_following_for_user(username):
        friend_value = "#FRIEND#{}".format(username)
        resp = dynamodb.query(
            TableName='quick-photos',
            IndexName='InvertedIndex',
            KeyConditionExpression="SK = :sk",
            ExpressionAttributeValues={":sk": {"S": friend_value}},
            ScanIndexForward=True
        )
    
        keys = [
            {
                "PK": {"S": "USER#{}".format(item["followedUser"]["S"])},
                "SK": {"S": "#METADATA#{}".format(item["followedUser"]["S"])},
            }
            for item in resp["Items"]
        ]
    
        friends = dynamodb.batch_get_item(
            RequestItems={
                "quick-photos": {
                    "Keys": keys
                }
            }
        )
    
        enriched_friends =  [User(item) for item in friends['Responses']['quick-photos']]
    
        return enriched_friends
    
    
    
    follows = find_and_enrich_following_for_user(USERNAME)
    
    print("Users followed by {}:".format(USERNAME))
    for follow in follows:
        print(follow)

    find_and_enrich_following_for_user 函數類似於您在上一個單元中使用的 find_follower_for_user 函數。該函數接受您要為其尋找關注使用者的使用者名稱。該函數首先使用反向索引進行查詢請求,以尋找指定使用者名稱所關注的所有使用者。然後組合 BatchGetItem,以便針對每個受關注使用者擷取完整的使用者實體,並傳回這些實體。

    這會產生兩個 DynamoDB 請求,而不是理想中的一個。然而,它滿足了相當複雜的存取模式,並且避免每次更新使用者檔案時都需要不斷更新朋友關係實體的情況。這種部份標準化可以很好地滿足您的建模需求。

    透過在終端機中執行以下命令來執行此指令碼。

    python application/find_and_enrich_following_for_user.py

    您的主控台應輸出指定使用者名稱所關注使用者的清單。

    Users followed by haroldwatkins:
    User<ppierce -- Ernest Mccarty>
    User<vpadilla -- Jonathan Scott>
    User<david25 -- Abigail Alvarez>
    User<jacksonjason -- John Perry>
    User<chasevang -- Leah Miller>
    User<frankhall -- Stephanie Fisher>
    User<nmitchell -- Amanda Green>
    User<tmartinez -- Kristin Stevens>
    User<natasha87 -- Walter Carlson>
    User<geoffrey32 -- Mary Martin>
    

    請注意,您現在正在處理使用者實體,而不是朋友關係實體。使用者實體將具有關於您的使用者最完整、最新的資訊。雖然透過兩個請求才能實現,但與完全非標準化以及由此產生的資料完整性問題相比,這仍然是一個更好的選擇。

  • 結論

    在本單元中,我們了解了部份標準化和 BatchGetItem API 叫用如何在保持查詢請求較少的同時,幫助維護物件間的資料完整性。

    在下一個單元中,我們將在新增相片回應或關注使用者時使用 DynamoDB 交易。