Salah satu penyesuaian terbesar bagi pengguna yang baru mengenal DynamoDB dan NoSQL adalah cara memodelkan data untuk disaring di seluruh dataset. Misalnya, dalam game, kita perlu menemukan sesi game dengan tempat terbuka sehingga kita dapat menunjukkan kepada pengguna sesi game yang dapat mereka ikuti.
Dalam database relasional, Anda akan menulis beberapa SQL untuk membuat kueri pada data.

SELECT * FROM games
	WHERE status = “OPEN”

DynamoDB dapat memfilter hasil pada operasi Kueri atau Pindai,namun DynamoDB tidak berfungsi seperti database relasional. Filter DynamoDB diterapkan setelah item awal yang cocok dengan operasi Kueri atau Pindai dipulihkan. Filter mengurangi ukuran muatan yang dikirim dari layanan DynamoDB, tetapi jumlah item yang dipulihkan pada awalnya tergantung batas ukuran DynamoDB.

Untungnya, ada sejumlah cara untuk memungkinkan kueri yang difilter terhadap dataset Anda di DynamoDB. Untuk memberikan filter yang efisien pada tabel DynamoDB, Anda harus merencanakan filter ke dalam model data tabel Anda dari awal. Ingatlah pelajaran yang kita pelajari dalam modul kedua lab ini: Pertimbangkan pola akses Anda, kemudian rancang tabel Anda.

Pada langkah-langkah berikut, kita menggunakan indeks sekunder global untuk menemukan game terbuka. Kita akan menggunakan teknik indeks yang jarang secara khusus untuk menangani pola akses ini.

Waktu untuk Menyelesaikan Modul: 40 Menit


  • Langkah 1: Pemodelan indeks sekunder yang jarang

    Indeks sekunder adalah alat pemodelan data yang sangat penting dalam DynamoDB. Indeks sekunder memungkinkan Anda membentuk kembali data Anda sebagai pola kueri alternatif. Untuk membuat indeks sekunder, Anda menentukan kunci utama indeks, sama seperti ketika Anda membuat tabel sebelumnya. Perhatikan bahwa kunci utama untuk indeks sekunder global tidak harus unik untuk setiap item. DynamoDB kemudian menyalin item ke dalam indeks berdasarkan atribut yang ditentukan, dan Anda dapat membuat kuerinya seperti yang Anda lakukan pada tabel.

    Penggunaan indeks sekunder yang jarang adalah strategi lanjutan di DynamoDB. Dengan indeks sekunder, DynamoDB menyalin item dari tabel asli hanya jika item memiliki elemen kunci utama dalam indeks sekunder. Item yang tidak memiliki elemen kunci utama tidak disalin, itulah sebabnya indeks sekunder ini disebut “jarang”.

    Mari kita lihat bagaimana hal ini berlaku untuk kita. Anda mungkin ingat bahwa kita memiliki dua pola akses untuk menemukan game terbuka:

    • Menemukan game terbuka (Baca)
    • Menemukan game terbuka melalui peta (Baca)

    Kita dapat membuat indeks sekunder menggunakan kunci primer komposit di mana kunci HASH adalah atribut peta untuk game dan kunci RANGE adalah atribut open_timestamp untuk game, yang menunjukkan waktu pembukaan game.

    Bagian penting bagi kita adalah ketika game penuh, atribut open_timestamp akan dihapus. Ketika atribut dihapus, game yang diisi dihapus dari indeks sekunder karena tidak memiliki nilai untuk atribut kunci RANGE. Inilah yang membuat indeks menjadi jarang: Ini hanya mencakup game terbuka yang memiliki atribut open_timestamp.

    Pada langkah berikutnya, kita membuat indeks sekunder.

  • Langkah 2: Pembutan indeks sekunder yang jarang

    Pada langkah ini, kita membuat indeks sekunder yang jarang untuk game terbuka (game yang belum penuh).

    Pembuatan indeks sekunder mirip dengan pembuatan tabel. Dalam kode yang Anda unduh, Anda akan menemukan file skrip di direktori scripts/ bernama add_secondary_index.py. Konten file tersebut antara lain.

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

    Setiap kali atribut digunakan dalam kunci utama untuk indeks sekunder atau tabel, atribut harus didefinisikan di AttributeDefinitions. Kemudian, kita Membuat indeks sekunder baru di properti GlobalSecondaryIndexUpdates. Untuk indeks sekunder ini, kita menentukan nama indeks, skema kunci utama, throughput yang disediakan, dan atribut yang ingin kita proyeksikan.

    Perhatikan bahwa kita tidak harus menentukan bahwa indeks sekunder dimaksudkan untuk digunakan sebagai indeks yang jarang. Maksud ini murni fungsi dari data yang Anda masukkan. Jika Anda menulis item ke tabel yang tidak memiliki atribut untuk indeks sekunder, item tidak akan disertakan dalam indeks sekunder Anda.

    Buat indeks sekunder Anda dengan menjalankan perintah berikut.

    python scripts/add_secondary_index.py

    Anda akan melihat pesan berikut di konsol: “Tabel berhasil diperbarui.”

    Pada langkah berikutnya, kita menggunakan indeks yang jarang untuk menemukan game terbuka melalui peta.

  • Langkah 3: Pembuatan kueri indeks sekunder yang jarang

    Sekarang kita telah mengonfigurasi indeks sekunder, mari kita gunakan untuk memenuhi beberapa pola akses.

    Untuk menggunakan indeks sekunder, Anda memiliki dua panggilan API yang tersedia: Kueri dan Pindai. Dengan Kueri, Anda harus menentukan kunci HASH, dan hasil yang ditargetkan akan muncul. Dengan Pindai, Anda tidak menentukan kunci HASH, dan operasi berjalan di seluruh tabel Anda. Pemindaian tidak disarankan dalam DynamoDB kecuali dalam keadaan tertentu karena pemindaian mengakses setiap item di database Anda. Jika Anda memiliki sejumlah besar data dalam tabel, pemindaian dapat memakan waktu yang sangat lama. Pada langkah berikutnya, kami menunjukkan kepada Anda mengapa Pemindaian dapat menjadi alat yang canggih ketika digunakan dengan indeks yang jarang.

    Kita dapat menggunakan API Kueri terhadap indeks sekunder yang dibuat pada langkah sebelumnya untuk menemukan semua game terbuka berdasarkan nama peta. Indeks sekunder dipartisi berdasarkan nama peta, sehingga kita dapat membuat kueri yang ditargetkan untuk menemukan game terbuka.

    Dalam kode yang Anda unduh, file find_open_games_by_map.py ada di direktori application/. Konten skrip ini antara lain.

    import boto3
    
    from entities import Game
    
    dynamodb = boto3.client('dynamodb')
    
    def find_open_games_by_map(map_name):
        resp = dynamodb.query(
            TableName='battle-royale',
            IndexName="OpenGamesIndex",
            KeyConditionExpression="#map = :map",
            ExpressionAttributeNames={
                "#map": "map"
            },
            ExpressionAttributeValues={
                ":map": { "S": map_name },
            },
            ScanIndexForward=True
        )
    
        games = [Game(item) for item in resp['Items']]
    
        return games
    
    games = find_open_games_by_map("Green Grasslands")
    for game in games:
        print(game)

    Dalam skrip sebelumnya, fungsi find_open_games_by_map serupa dengan fungsi yang Anda miliki di aplikasi Anda. Fungsi ini menerima nama peta dan membuat kueri terhadap OpenGamesIndex untuk menemukan semua game terbuka untuk peta. Fungsi ini kemudian merakit entitas yang dihasilkan ke objek Game yang dapat digunakan dalam aplikasi Anda.

    Eksekusi skrip ini dengan menjalankan perintah berikut di terminal Anda.

    python application/find_open_games_by_map.py

    Terminal akan menampilkan output berikut dengan empat game terbuka untuk peta Green Grasslands.

    Open games for Green Grasslands:
    Game<14c7f97e-8354-4ddf-985f-074970818215 -- Green Grasslands>
    Game<3d4285f0-e52b-401a-a59b-112b38c4a26b -- Green Grasslands>
    Game<683680f0-02b0-4e5e-a36a-be4e00fc93f3 -- Green Grasslands>
    Game<0ab37cf1-fc60-4d93-b72b-89335f759581 -- Green Grasslands>
    sudo cp -r wordpress/* /var/www/html/

    Pada langkah berikutnya, kami menggunakan API Pindai untuk memindai indeks sekunder yang jarang.

  • Langkah 4: Pemindaian indeks sekunder yang jarang

    Pada langkah sebelumnya, kita melihat cara menemukan game untuk peta tertentu. Beberapa pemain mungkin lebih suka memainkan peta tertentu, jadi langkah ini berguna. Pemain lain mungkin ingin bermain game di peta apa pun. Di bagian ini, kita menunjukkan cara menemukan game terbuka di aplikasi, apa pun jenis petanya. Untuk melakukannya, kita menggunakan API Pindai.

    Secara umum, Anda tidak ingin merancang tabel untuk menggunakan operasi Pindai DynamoDB karena DynamoDB dibuat untuk kueri bedah yang mengambil entitas yang tepat sesuai kebutuhan Anda. Operasi Pindai mengambil koleksi entitas acak di seluruh tabel Anda. Jadi, untuk menemukan kebutuhan entitas, diperlukan beberapa perjalanan bolak-balik ke database.

    Namun, terkadang Pindai bisa bermanfaat. Dalam situasi kita, kita memiliki indeks sekunder yang jarang, artinya indeks kita tidak boleh memiliki banyak entitas di dalamnya. Selain itu, indeks hanya menyertakan game yang terbuka, dan itulah yang kita butuhkan.

    Untuk kasus penggunaan ini, Pindai berfungsi dengan baik. Mari kita lihat cara kerjanya. Dalam kode yang Anda unduh, file find_open_games.py ada di direktor application/. Konten file akan mengikuti.

    import boto3
    
    from entities import Game
    
    dynamodb = boto3.client('dynamodb')
    
    def find_open_games():
        resp = dynamodb.scan(
            TableName='battle-royale',
            IndexName="OpenGamesIndex",
        )
    
        games = [Game(item) for item in resp['Items']]
    
        return games
    
    games = find_open_games()
    print("Open games:")
    for game in games:
        print(game)

    Kode ini serupa dengan kode pada langkah sebelumnya. Namun, alih-alih menggunakan metode kueri() pada klien DynamoDB, kita menggunakan metode pindai(). Karena kita menggunakan pindai(), kita tidak perlu menentukan apa pun tentang kondisi utama seperti yang dilakukan dengan kueri(). Kita baru saja meminta DynamoDB menghasilkan banyak item tanpa urutan tertentu.

    Jalankan skrip dengan perintah berikut di terminal Anda.

    python application/find_open_games.py

    Terminal Anda harus mencetak daftar sembilan game yang terbuka di berbagai peta.

    Open games:
    Game<c6f38a6a-d1c5-4bdf-8468-24692ccc4646 -- Urban Underground>
    Game<d06af94a-2363-441d-a69b-49e3f85e748a -- Dirty Desert>
    Game<873aaf13-0847-4661-ba26-21e0c66ebe64 -- Dirty Desert>
    Game<fe89e561-8a93-4e08-84d8-efa88bef383d -- Dirty Desert>
    Game<248dd9ef-6b17-42f0-9567-2cbd3dd63174 -- Juicy Jungle>
    Game<14c7f97e-8354-4ddf-985f-074970818215 -- Green Grasslands>
    Game<3d4285f0-e52b-401a-a59b-112b38c4a26b -- Green Grasslands>
    Game<683680f0-02b0-4e5e-a36a-be4e00fc93f3 -- Green Grasslands>
    Game<0ab37cf1-fc60-4d93-b72b-89335f759581 -- Green Grasslands>
    

    Pada langkah ini, kita melihat bagaimana penggunaan operasi Pindai dapat menjadi pilihan yang tepat dalam keadaan tertentu. Kita menggunakan Pindai untuk mengambil beragam entitas dari indeks sekunder yang jarang untuk menunjukkan game terbuka kepada pemain.

    Pada langkah berikutnya, kita memenuhi dua pola akses:

    • Bergabung ke game untuk pengguna (Tulis)
    • Mulai game (Tulis)

    Untuk memenuhi pola akses “Bergabung ke game untuk pengguna” dalam langkah berikutnya, kita akan menggunakan DynamoDB transactions. Transaksi dalam sistem relasional populer untuk operasi yang memengaruhi beberapa elemen data sekaligus. Misalnya, bayangkan Anda menjalankan bank. Satu pelanggan, Alejandra, mentransfer 100 USD ke pelanggan lain, Ana. Saat mencatat transaksi ini, Anda akan menggunakan transaksi untuk memastikan perubahan diterapkan pada saldo kedua pelanggan, bukan hanya salah satunya.

    Transaksi DynamoDB memudahkan pembuatan aplikasi yang mengubah beberapa item sebagai bagian dari satu operasi. Dengan transaksi, Anda dapat mengoperasikan hingga 10 item sebagai bagian dari satu permintaan transaksi.

    Dalam panggilan API TransactWriteItem, Anda dapat menggunakan operasi berikut:

    • Letakkan: Untuk memasukkan atau menimpa item.
    • Perbarui: Untuk memperbarui item yang sudah ada.
    • Hapus: Untuk menghapus item.
    • ConditionCheck: Untuk menyatakan suatu kondisi pada item yang ada tanpa mengubah item.

     

    Pada langkah berikutnya, kita menggunakan transaksi DynamoDB saat menambahkan pengguna baru ke game sekaligus mencegah game terlalu penuh.

  • Langkah 5: Penambahan pengguna ke game

    Pola akses pertama yang kita bahas dalam modul ini adalah penambahan pengguna baru ke game.

    Saat menambahkan pengguna baru ke game, kita harus:

    • Memastikan bahwa belum ada 50 pemain dalam game (setiap game dapat memiliki maksimal 50 pemain).
    • Memastikan bahwa pengguna belum masuk ke dalam game.
    • Buat entitas UserGameMapping baru untuk menambahkan pengguna ke game.
    • Tambahkan atribut orang pada entitas Game untuk melacak berapa banyak pemain yang ada dalam game.

    Perhatikan bahwa untuk menyelesaikan semua hal ini diperlukan tindakan penulisan di seluruh entitas Game yang ada dan entitas UserGameMapping baru serta logika kondisional untuk masing-masing entitas. Ini adalah jenis operasi yang sangat cocok untuk transaksi DynamoDB karena Anda harus bekerja di beberapa entitas dalam permintaan yang sama, dan Anda ingin seluruh permintaan berhasil atau gagal bersama.

    Dalam kode yang Anda unduh, skrip fetch_game_and_players.py ada di direktori application/. Fungsi dalam skrip tersebut menggunakan transaksi DynamoDB untuk menambahkan pengguna ke game.

    Konten skrip ini antar lain.

    import boto3
    
    from entities import Game, UserGameMapping
    
    dynamodb = boto3.client('dynamodb')
    
    GAME_ID = "c6f38a6a-d1c5-4bdf-8468-24692ccc4646"
    USERNAME = 'vlopez'
    
    
    def join_game_for_user(game_id, username):
        try:
            resp = dynamodb.transact_write_items(
                TransactItems=[
                    {
                        "Put": {
                            "TableName": "battle-royale",
                            "Item": {
                                "PK": {"S": "GAME#{}".format(game_id) },
                                "SK": {"S": "USER#{}".format(username) },
                                "game_id": {"S": game_id },
                                "username": {"S": username }
                            },
                            "ConditionExpression": "attribute_not_exists(SK)",
                            "ReturnValuesOnConditionCheckFailure": "ALL_OLD"
                        },
                    },
                    {
                        "Update": {
                            "TableName": "battle-royale",
                            "Key": {
                                "PK": { "S": "GAME#{}".format(game_id) },
                                "SK": { "S": "#METADATA#{}".format(game_id) },
                            },
                            "UpdateExpression": "SET people = people + :p",
                            "ConditionExpression": "people <= :limit",
                            "ExpressionAttributeValues": {
                                ":p": { "N": "1" },
                                ":limit": { "N": "50" }
                            },
                            "ReturnValuesOnConditionCheckFailure": "ALL_OLD"
                        }
                    }
                ]
            )
            print("Added {} to game {}".format(username, game_id))
            return True
        except Exception as e:
            print("Could not add user to game")
    
    join_game_for_user(GAME_ID, USERNAME)

    Dalam fungsi join_game_for_user pada skrip, metode transact_write_items() akan melakukan transaksi penulisan. Transaksi ini memiliki dua operasi.

    Dalam operasi pertama transaksi, kami menggunakan operasi Letakkan untuk menyisipkan entitas UserGameMapping baru. Sebagai bagian dari operasi tersebut, kita menentukan kondisi bahwa atribut SK tidak boleh ada untuk entitas ini. Ini memastikan bahwa entitas dengan PK dan SK ini tidak ada. Jika entitas seperti itu memang sudah ada, berarti pengguna ini sudah bergabung dengan game.

    Operasi kedua adalah operasi Perbarui pada entitas Game untuk menambah satu atribut orang. Sebagai bagian dari operasi ini, kita menambahkan pemeriksaan kondisional bahwa nilai orang saat ini tidak lebih dari 50. Segera setelah 50 orang bergabung dalam game, game sudah penuh dan siap dimulai.

    Jalankan skrip ini dengan perintah berikut di terminal Anda.

    python application/join_game.py

    Output di terminal Anda harus menunjukkan bahwa pengguna telah ditambahkan ke game.

    Added vlopez to game c6f38a6a-d1c5-4bdf-8468-24692ccc4646

    Perhatikan bahwa jika Anda mencoba menjalankan skrip lagi, fungsinya akan gagal. Pengguna vlopez telah ditambahkan ke game, jadi jika mencoba menambahkan pengguna lagi tidak akan memenuhi ketentuan yang kita tentukan.

    Penambahan transaksi DynamoDB sangat menyederhanakan alur kerja di sekitar operasi kompleks seperti ini. Tanpa transaksi, maka akan membutuhkan beberapa panggilan API dengan kondisi kompleks dan pemulihan manual jika terjadi konflik. Sekarang, kita dapat mengimplementasikan operasi yang kompleks tersebut dengan kurang dari 50 baris kode.

    Pada langkah berikutnya, kita menangani pola akses “Mulai game (Tulis)”.

  • Langkah 6: Memulai game

    Segera setelah game memiliki 50 pengguna, kreator game dapat memulai game untuk menginisiasi permainan. Pada langkah ini, kita menunjukkan cara menangani pola akses ini.

    Ketika backend aplikasi menerima permintaan untuk memulai game, kita memeriksa tiga hal:

    • Game ini memiliki 50 orang yang telah mendaftar.
    • Pengguna yang membuat permintaan adalah kreator game.
    • Game belum dimulai.

    Kita dapat menangani setiap pemeriksaan ini dalam ekspresi kondisi dalam permintaan untuk memperbarui game. Jika semua pemeriksaan ini lulus, kita harus memperbarui entitas dengan cara berikut:

    • Hapus atribut open_timestamp sehingga tidak muncul sebagai game terbuka di indeks sekunder yang jarang dari modul sebelumnya.
    • Tambahkan atribut start_time untuk menunjukkan kapan game dimulai.

    Dalam kode yang Anda unduh, skrip start_game.py ada di direktori application/. Konten file ini antara lain.

    import datetime
    
    import boto3
    
    from entities import Game
    
    dynamodb = boto3.client('dynamodb')
    
    GAME_ID = "c6f38a6a-d1c5-4bdf-8468-24692ccc4646"
    CREATOR = "gstanley"
    
    def start_game(game_id, requesting_user, start_time):
        try:
            resp = dynamodb.update_item(
                TableName='battle-royale',
                Key={
                    "PK": { "S": "GAME#{}".format(game_id) },
                    "SK": { "S": "#METADATA#{}".format(game_id) }
                },
                UpdateExpression="REMOVE open_timestamp SET start_time = :time",
                ConditionExpression="people = :limit AND creator = :requesting_user AND attribute_not_exists(start_time)",
                ExpressionAttributeValues={
                    ":time": { "S": start_time.isoformat() },
                    ":limit": { "N": "50" },
                    ":requesting_user": { "S": requesting_user }
                },
                ReturnValues="ALL_NEW"
            )
            return Game(resp['Attributes'])
        except Exception as e:
            print('Could not start game')
            return False
    
    game = start_game(GAME_ID, CREATOR, datetime.datetime(2019, 4, 16, 10, 15, 35))
    
    if game:
        print("Started game: {}".format(game))

    Dalam skrip ini, fungsi start_game serupa dengan fungsi yang Anda miliki di aplikasi Anda. Dibutuhkan game_id, requesting_user, dan start_time, dan fungsi ini menjalankan permintaan untuk memperbarui entitas Game guna memulai game.

    Parameter ConditionExpression dalam panggilan update_item() menentukan masing-masing dari tiga pemeriksaan yang kita sebutkan sebelumnya dalam langkah ini—game harus memiliki 50 orang, pengguna meminta agar permulaan game harus dimulai oleh kreator game, dan game tidak boleh memiliki atribut start_time, yang akan menunjukkan bahwa game telah dimulai.

    Di parameter UpdateExpression, Anda dapat melihat perubahan yang ingin dilakukan pada entitas kita. Pertama kita menghapus atribut open_timestamp dari entitas, lalu kita mengatur atribut start_time ke waktu mulai game.

    Jalankan skrip ini dengan perintah berikut di terminal Anda.

    python application/start_game.py

    Anda akan melihat output di terminal Anda yang menunjukkan bahwa game telah berhasil dimulai.

    Started game: Game<c6f38a6a-d1c5-4bdf-8468-24692ccc4646 -- Urban Underground>

    Coba jalankan skrip untuk kedua kalinya di terminal Anda. Kali ini, Anda akan melihat pesan kesalahan yang menunjukkan bahwa Anda tidak dapat memulai game. Ini karena Anda telah memulai game, jadi terdapat atribut start_time. Akibatnya, permintaan menggagalkan pemeriksaan kondisional pada entitas.

    Anda mungkin ingat bahwa ada hubungan banyak-ke-banyak antara entitas Game dan entitas Pengguna terkait, dan hubungan tersebut direpresentasikan oleh entitas UserGameMapping.

    Sering kali, Anda ingin membuat kueri pada kedua sisi hubungan. Dengan pengaturan kunci utama kami, kita dapat menemukan semua entitas Pengguna dalam Game. Kita dapat mengaktifkan pembuatan kueri pada semua entitas Game untuk Pengguna menggunakan indeks inversi.

    Di DynamoDB, indeks inversi adalah indeks sekunder yang merupakan inversi kunci utama Anda. Kunci RANGE menjadi kunci HASH dan sebaliknya. Pola ini membalik tabel Anda dan memungkinkan Anda membuat kueri pada sisi lain hubungan banyak-ke-banyak.

    Pada langkah berikut, kita menambahkan indeks inversi ke tabel dan menunjukkan cara menggunakannya untuk mengambil semua entitas Game bagi Pengguna tertentu. 

  • Langkah 7: Penambahan indeks inversi

    Pada langkah ini, kita menambahkan indeks inversi ke tabel. Indeks inversi dibuat seperti halnya indeks sekunder lainnya.

    Dalam kode yang Anda unduh, skrip add_inverted_index.py berada di direktori scripts/. Skrip Python ini menambahkan indeks inversi ke tabel Anda.

    Konten file tersebut antara lain.

    import boto3
    
    dynamodb = boto3.client('dynamodb')
    
    try:
        dynamodb.update_table(
            TableName='battle-royale',
            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": 1,
                            "WriteCapacityUnits": 1
                        }
                    }
                }
            ],
        )
        print("Table updated successfully.")
    except Exception as e:
        print("Could not update table. Error:")
        print(e)
    

    Dalam skrip ini, kita memanggil metode update_table() pada klien DynamoDB. Dalam metode ini, kita meneruskan detail indeks sekunder yang ingin dibuat, termasuk skema utama untuk indeks, throughput yang disediakan, dan atribut untuk diproyeksikan ke dalam indeks.

    Jalankan skrip dengan mengetik perintah berikut di terminal Anda.

    python scripts/add_inverted_index.py

    Terminal Anda akan menampilkan output bahwa indeks telah berhasil dibuat.

    Table updated successfully.

    Pada langkah berikutnya, kita menggunakan indeks inversi untuk mengambil semua entitas Game bagi Pengguna tertentu.

  • Langkah 8: Pengambilan game untuk pengguna

    Sekarang kita telah membuat indeks inversi, mari kita gunakan untuk mengambil entitas Game yang dimainkan oleh Pengguna. Untuk menanganinya, kita perlu membuat kueri pada indeks inversi dengan Pengguna yang entitas Game-nya ingin kita lihat.

    Dalam kode yang Anda unduh, skrip find_games_for_user.py ada dalam direktori application/. Konten file ini antara lain.

    import boto3
    
    from entities import UserGameMapping
    
    dynamodb = boto3.client('dynamodb')
    
    USERNAME = "carrpatrick"
    
    
    def find_games_for_user(username):
        try:
            resp = dynamodb.query(
                TableName='battle-royale',
                IndexName='InvertedIndex',
                KeyConditionExpression="SK = :sk",
                ExpressionAttributeValues={
                    ":sk": { "S": "USER#{}".format(username) }
                },
                ScanIndexForward=True
            )
        except Exception as e:
            print('Index is still backfilling. Please try again in a moment.')
            return None
    
        return [UserGameMapping(item) for item in resp['Items']]
    
    games = find_games_for_user(USERNAME)
    
    if games:
        print("Games played by {}:".format(USERNAME))
        for game in games:
            print(game)
    

    Dalam skrip ini, kita memiliki fungsi yang disebut find_games_for_user() yang serupa dengan fungsi yang akan Anda miliki dalam game. Fungsi ini mengambil nama pengguna dan menghasilkan semua game yang dimainkan oleh pengguna tertentu.

    Jalankan skrip di terminal Anda dengan perintah berikut.

    python application/find_games_for_user.py

    Skrip akan mencetak semua game yang dimainkan oleh pengguna carrpatrick.

    Games played by carrpatrick:
    UserGameMapping<25cec5bf-e498-483e-9a00-a5f93b9ea7c7 -- carrpatrick -- SILVER>
    UserGameMapping<c6f38a6a-d1c5-4bdf-8468-24692ccc4646 -- carrpatrick>
    UserGameMapping<c9c3917e-30f3-4ba4-82c4-2e9a0e4d1cfd -- carrpatrick>
    

    Dalam modul ini, kita menambahkan indeks sekunder ke tabel. Penambahan ini memenuhi dua pola akses tambahan:

    • Menemukan game terbuka melalui peta (Baca)
    • Menemukan game terbuka (Baca)

    Untuk mencapai hal ini, kita menggunakan indeks jarang yang hanya menyertakan game yang masih terbuka untuk pemain tambahan. Kemudian kita menggunakan API Kueri dan Pindai terhadap indeks untuk menemukan game terbuka.

    Kita juga melihat cara memenuhi operasi penulisan lanjutan dalam aplikasi. Pertama, kita menggunakan transaksi DynamoDB saat pengguna bergabung dengan game. Dengan transaksi, kita menangani penulisan kondisional yang kompleks di beberapa entitas dalam satu permintaan.

    Kedua, kita mengimplementasikan fungsi bagi pembuat game untuk memulai game ketika sudah siap. Dalam pola akses ini, kita memiliki operasi pembaruan yang mengharuskan pemeriksaan nilai tiga atribut dan pembaruan dua atribut. Anda dapat mengekspresikan logika kompleks ini dalam satu permintaan melalui kecanggihan ekspresi kondisi dan ekspresi pembaruan.

    Ketiga, kita memenuhi pola akses akhir dengan mengambil semua entitas Game yang dimainkan oleh Pengguna. Untuk menangani pola akses ini, kita membuat indeks sekunder menggunakan pola indeks inversi guna memungkinkan pembuatan kueri di sisi lain dari hubungan banyak-ke-banyak antara entitas Pengguna dan entitas Game.

    Pada modul berikutnya, kita membersihkan sumber daya yang dibuat.