Önceki modülde, DynamoDB'deki çekirdek öğelerinize erişim kurdunuz. Birincil anahtar yapı, bazı ana erişim şablonlarımızı çözdü. Bu, tek bir öğeyi okumak veya yazmak için tüm şablonları ve aynı zamanda belirli bir kullanıcıya ait tüm fotoğraflar gibi birden çok ilgili öğeyi almak için şablonları içerir.

Bu modülde, DynamoDB için ortak bir tasarım şablonu olan ters dizin kullanmayı öğreneceksiniz.

İkincil dizinler DynamoDB’deki önemli veri modelleme araçlarıdır. Alternatif sorgu modelleri için verilerinizi yeniden biçimlendirmenize olanak tanırlar.

Ters dizin, DynamoDB ile ortak bir ikincil dizin tasarım şablonudur. Ters dizin ile birlikte, tablonuz için birincil anahtarınızın tam tersi olan bir ikincil dizindir. Tablonuz için HASH tuşu, dizininizdeki RANGE anahtarı olur ve tablonuzun RANGE anahtarı dizininiz için birincil anahtar olur.

Ters dizin iki senaryoda yardımcı olur. İlk olarak, bir ters dizin çoktan çoka ilişkinin “diğer” tarafını sorgulamak için yararlıdır. Bu, Arkadaşlık öğeniz için geçerlidir. Birincil anahtar yapınızla, tablonun birincil anahtarına yönelik bir sorgu ile belirli bir kullanıcının tüm takipçilerini sorgulayabilirsiniz. Bir ters dizin eklediğinizde, ters dizini sorgulayarak bir kullanıcının takip ettiği kullanıcıları (“takip edilen”) bulabilirsiniz.

Bir ters dizin, kendisi bire çok ilişkisine konu olan bir öğe için bire çok ilişkisini sorgulamak için de yararlıdır. Bunu tablonuzdaki Tepki öğesi ile görebilirsiniz. Tek bir fotoğrafta birden fazla tepki olabilir ve her tepki, tepkinin geçerli olduğu fotoğrafı, reaksiyona giren kullanıcının kullanıcı adını ve tepki tipini içerecektir. Ancak, kullanıcının çok sayıda fotoğrafı olabileceğinden, fotoğrafın ana tanımlayıcısı, RANGE tuşunda -- PHOTO#<USERNAME>#<TIMESTAMP> yer alır. Bu nedenle, birincil anahtarınızı fotoğraflara yönelik tepkileri bağlamak için kullanamazsınız.

“Fotoğraf ve tepkileri görüntüle” erişim düzenini karşılamak için, veri modeli bir Tepki objesi için fotoğraf tanımlayıcısını RANGE tuşuna yerleştirir. Şimdi, ters dizini sorgularken, fotoğrafı ve tüm tepkilerini tek bir istekte seçmek için fotoğraf tanımlayıcıyı kullanabilirsiniz. Bu, aşağıda Adım 2’de gösterilmektedir.

Modülü Tamamlama Süresi: 40 Dakika


  • Adım 1: Bir ikincil dizin oluşturun

    Bir ikincil dizin oluşturmak için, daha önce bir tablo oluşturmada yaptığınız gibi dizinin birincil anahtarını belirlersiniz. Bir genel ikincil dizin için birincil anahtarın eşsiz olmasına gerek yoktur. DynamoDB daha sonra bildirilen özniteliklere göre ögeleri dizine kopyalar ve tablonuzda yaptığınız gibi sorgulayabilirsiniz.

    Ters dizin, tablonuzun birincil anahtarının tersi olan bir ikincil dizin oluşturduğunuz DynamoDB'de yaygın bir modeldir. Tablonuz için HASH anahtarı ikincil dizininizde RANGE anahtarı olarak, tablonuz için RANGE anahtarı ikincil dizininizdeki HASH anahtarı olarak belirtilir.

    Bir ikincil dizinin oluşturulması bir tablonun oluşturulmasına benzemektedir. İndirdiğiniz kodda, add_inverted_index.py betiği scripts/ dizinindedir. Bu dosyanın içerikleri aşağıda gösterilmektedir.

    import boto3
    
    dynamodb = boto3.client('dynamodb')
    
    try:
        dynamodb.update_table(
            TableName='quick-photos',
            AttributeDefinitions=[
                {
                    "AttributeName": "PK",
                    "AttributeType": "S"
                },
                {
                    "AttributeName": "SK",
                    "AttributeType": "S"
                }
            ],
            GlobalSecondaryIndexUpdates=[
                {
                    "Create": {
                        "IndexName": "InvertedIndex",
                        "KeySchema": [
                            {
                                "AttributeName": "SK",
                                "KeyType": "HASH"
                            },
                            {
                                "AttributeName": "PK",
                                "KeyType": "RANGE"
                            }
                        ],
                        "Projection": {
                            "ProjectionType": "ALL"
                        },
                        "ProvisionedThroughput": {
                            "ReadCapacityUnits": 5,
                            "WriteCapacityUnits": 5
                        }
                    }
                }
            ],
        )
        print("Table updated successfully.")
    except Exception as e:
        print("Could not update table. Error:")
        print(e)
    

    Öznitelikler bir tablo ya da ikincil dizin için bir birincil anahtarda kullanıldıklarında AttributeDefinitions (Öznitelik Tanımları) kapsamında tanımlanmalıdır. ArdındanGlobalSecondaryIndexUpdates özelliği kapsamında yeni bir ikincil dizin Oluştururuz. Söz konusu ikincil dizin için dizin adını, birincil anahtar şemasını, öngörülen aktarım hızını ve planlamak istediğimiz öznitelikleri belirleriz.

    Bir ters dizinin DynamoDB'deki resmi bir özellik yerine bir tasarım şablonunun adı olduğunu unutmayın. Bir ters dizin oluşturmak, diğer ikincil dizinleri oluşturmak gibidir.

    Aşağıdaki komutu çalıştırarak ters dizininizi oluşturun.

    python scripts/add_inverted_index.py

    Konsolda şu mesajı görmeniz gerekmektedir: “Tablo başarıyla güncellendi.”

    Bir sonraki adımda, ters dizinimizin bir fotoğrafı bulmak için nasıl kullanılabileceğini göstereceğiz.

  • Adım 2: Bir fotoğrafın tepkilerini bulmak için ters dizini sorgulayın

    İkincil dizini yapılandırdığımıza göre bazı erişim modellerine yönelik olarak bu dizini kullanalım.

    Bir ikincil dizin kullanmak için sadece iki API çağrınız bulunmaktadır: Sorgula ve Tara. Sorgula seçeneği ileHASH anahtarı tanımlamanız gerekmektedir. Böylelikle, istenen sonuca ulaşabilirsiniz. Tarama seçeneğiyle birlikte bir HASH anahtar tanımlamazsınız ve operasyon da tüm tablo boyunca sürmektedir. Taramalar bazı özel durumlar haricinde DynamoDB’de pek desteklenmemektedir, çünkü veri tabanınızda her ögeye erişim sağlamaktadır. Tablonuzda ciddi miktarda veri varsa tarama işlemi çok uzun sürebilir.

    Belirli bir fotoğraftaki tüm tepkileri bulmak için Sorgu API’ını ikincil dizinimize yönelik kullanabiliriz. Önceki modülde görmüş olduğunuz gibi, bu sorguyu tek bir komutta iki tür öğe almak için kullanabilirsiniz. Bu sorguda, hem bir fotoğrafı hem de buna yönelik tepkileri alabilirsiniz.

    İndirdiğiniz kodda, application/ dizininde fetch_photo_and_reactions.py isimli bir dosya vardır. Bu betiğin içerikleri aşağıda gösterilmektedir.

    import boto3
    
    from entities import Photo, Reaction
    
    dynamodb = boto3.client('dynamodb')
    
    USER = "david25"
    TIMESTAMP = '2019-03-02T09:11:30'
    
    
    def fetch_photo_and_reactions(username, timestamp):
        try:
            resp = dynamodb.query(
                TableName='quick-photos',
                IndexName='InvertedIndex',
                KeyConditionExpression="SK = :sk AND PK BETWEEN :reactions AND :user",
                ExpressionAttributeValues={
                    ":sk": { "S": "PHOTO#{}#{}".format(username, timestamp) },
                    ":user": { "S": "USER$" },
                    ":reactions": { "S": "REACTION#" },
                },
                ScanIndexForward=True
            )
        except Exception as e:
            print("Index is still backfilling. Please try again in a moment.")
            return False
    
        items = resp['Items']
        items.reverse()
    
        photo = Photo(items[0])
        photo.reactions = [Reaction(item) for item in items[1:]]
    
        return photo
    
    
    photo = fetch_photo_and_reactions(USER, TIMESTAMP)
    
    if photo:
        print(photo)
        for reaction in photo.reactions:
            print(reaction)
    

    fetch_photo_and_reactions işlevi uygulamanızda yer alan işleve benzerdir. İşlev bir kullanıcı adı ve zaman damgasını kabul eder ve fotoğrafı ve tepkileri bulmak için InvertedIndex’e yönelik bir sorgu yapar. Ardından, döndürülen öğeleri bir Fotoğraf öğesi ve uygulamanızda kullanılabilecek birden fazla Tepki öğesi ile bir araya getirir.

    python application/fetch_photo_and_reactions.py

    Bir fotoğrafın çıktısını ve buna ait beş tepkiyi görmelisiniz.

    Photo<david25 -- 2019-03-02T09:11:30>
    Reaction<ylee -- PHOTO#david25#2019-03-02T09:11:30 -- smiley>
    Reaction<kennedyheather -- PHOTO#david25#2019-03-02T09:11:30 -- smiley>
    Reaction<jenniferharris -- PHOTO#david25#2019-03-02T09:11:30 -- +1>
    Reaction<geoffrey32 -- PHOTO#david25#2019-03-02T09:11:30 -- +1>
    Reaction<chasevang -- PHOTO#david25#2019-03-02T09:11:30 -- +1>

    İkincil dizinin geri dolmasının biraz zaman aldığını unutmayın. Geri doldurmanın devam ettiğini belirten bir hata iletisi alabilirsiniz. Eğer böyle olursa, birkaç dakika sonra yeniden deneyin.

    Bir sonraki adımda, belirli bir kullanıcının takip ettiği tüm kullanıcıları getirmek için ters dizinin nasıl kullanılacağını göreceğiz.

  • Adım 3: İzlenen kullanıcıları bulun

    Önceki adımda, bir ters dizin, kendisi bire çok ilişkisine konu olan bir öğe için bire çok ilişkisini sorgulamak için de yararlıdır. Bu adımda, çoktan çoka ilişkinin “diğer” tarafını getirmek için ters dizini kullanacaksınız.

    Tablodaki birincil anahtar, belirli bir kullanıcının tüm takipçilerini bulmanıza olanak tanır, ancak birisinin takip ettiği tüm kullanıcıları bulmanıza izin vermeyecektir. Ters dizin tersine çevrilerek belirli bir kullanıcı tarafından takip edilen tüm kullanıcıları bulabilirsiniz.

    İndirmiş olduğunuz kodda, find_following_for_user.py olarak adlandırılan application/ dizin içinde bir dosya var. Bu betiğin içerikleri şu şekildedir.

    import boto3
    
    from entities import Friendship
    
    dynamodb = boto3.client('dynamodb')
    
    USERNAME = "haroldwatkins"
    
    
    def find_following_for_user(username):
        resp = dynamodb.query(
            TableName='quick-photos',
            IndexName='InvertedIndex',
            KeyConditionExpression="SK = :sk",
            ExpressionAttributeValues={
                ":sk": { "S": "#FRIEND#{}".format(username) }
            },
            ScanIndexForward=True
        )
    
        return [Friendship(item) for item in resp['Items']]
    
    
    
    follows = find_following_for_user(USERNAME)
    
    print("Users followed by {}:".format(USERNAME))
    for follow in follows:
        print(follow)
    

    Dosya içerisindeki find_following_for_user işlevi uygulamanızda yer alan işleve benzerdir. Fonkisyon, takip edilen kullanıcıları bulmak istediğiniz kullanıcı adını kabul eder. İşlev daha sonra, takip eden kullanıcının verilen kullanıcı adı olduğu tüm Arkadaşlık öğelerini bulmak için ters dizini sorgular.

    Betiği aşağıdaki komutu terminalinizde çalıştırarak çalıştırın:

    python application/find_following_for_user.py

    Konsolunuz, girilen bir kullanıcı adını takiben bir kullanıcı listesi vermelidir:

    Users followed by haroldwatkins:
    Friendship<chasevang -- haroldwatkins>
    Friendship<david25 -- haroldwatkins>
    Friendship<frankhall -- haroldwatkins>
    Friendship<geoffrey32 -- haroldwatkins>
    Friendship<jacksonjason -- haroldwatkins>
    Friendship<natasha87 -- haroldwatkins>
    Friendship<nmitchell -- haroldwatkins>
    Friendship<ppierce -- haroldwatkins>
    Friendship<tmartinez -- haroldwatkins>
    Friendship<vpadilla -- haroldwatkins>

    Bu, bir kullanıcı için tüm Arkadaşlık öğelerini döndürürken, bir Arkadaşlık öğesindeki bilgilerin oldukça nadir olduğunu unutmayın. Yalnızca takip edilen kullanıcının kullanıcı adını içerir, ancak tam kullanıcı profilini içermez. Bir sonraki modülde, bu gibi durumları etkin bir şekilde ele almak için kısmi normalleştirmenin nasıl kullanılacağını konu edeceğiz.

  • Sonuç

    Bu modülde, ters dizin şablonunu kullanarak tablomuza ikincil bir dizin ekledik. Bu işlemle iki ek erişim modeli ortaya çıktı:

    • Fotoğraf ve tepkileri görüntüle (Okuma)
    • Kullanıcı için takip edilenleri görüntüle (Okuma)

    Bir kullanıcı için takip edilen tüm kullanıcıları alırken, her Arkadaşlık öğesinin takip eden kullanıcı hakkında bilgi eksikliği bağlamında bir sorun olduğunu gördük. Bir sonraki modülde, bu erişim şablonuna yardımcı olması için kısmi normalleştirmenin nasıl kullanılacağını göreceğiz.