Pilih entri DynamoDB secara acak

Saya memiliki tabel DynamoDB bernama URLArray yang berisi daftar URL (myURL) dan nama video unik (myKey).

Lihat tabel URLArray di sini

Saya perlu melakukan dua hal:

  1. Saat pengguna mengklik tombol video berikutnya, entri acak harus dipilih dari URLArray ini. Mungkin ada puluhan ribu baris.

Pengguna masuk ke aplikasi. Setiap kali mereka selesai menonton video, nama video unik dari video tersebut direkam. Jadi....ketika pengguna telah melihat video, video tersebut akan ditambahkan ke daftar dalam tabel bernama Pengguna di bawah baris info pengguna.

  1. Soo...Entri acak yang dipilih ketika pengguna mengklik tombol video berikutnya di poin 1, harus dibandingkan dengan daftar video yang telah mereka lihat. Untuk memastikan bahwa itu tidak muncul lagi secara acak untuk pengguna tertentu.

Saya melakukan sesuatu yang sangat tidak efisien sejauh ini, berhasil, tetapi tidak bagus:

Omong-omong saya menggunakan AppSync + GraphQL untuk berinteraksi dengan tabel DynamoDB. Saya pertama kali mendapatkan salinan lokal URLArray:

 //Gets a list of the Key/URL pairs in the UrlArrays table in GraphQL   ****IN CONSTRUCTOR, so we have this URLArray data when componentDidMount()****
  listUrlArrays = async () => {  
    try {

      URLData = await API.graphql(graphqlOperation(ListUrlArrays)); //GraphQL query
      //URLData[] is available in the entire class
     
      this.setState({urlArrayLength: apiData.data.listURLArrays.items.length}); //gets the length of URLArray (i.e. how many videos are in the database)
      }
   }

Sebagai gambaran umum, saat pengguna mengklik video berikutnya:

     //When clicking next video
      async nextVideo(){
        
        await this.logVideosSeen(); //add myKey to the list of videos in *Users* table the logged in user has now seen
    
        await this.getURL();  //get the NEXT upcoming video's details, for Video Player to play and make sure it's not been seen before
    
      }
    

      //This will update the 'listOfVideosSeen[]' in Users table with videos unique myKey, the logged in user has seen
      logVideosSeen = async () => {     
           .......
      }

    async getURL() {  
        var dbIndex = this.getUniqueRandomNumber(this.state.urlArrayLength);  //Choose a number between 0 and N number of videos in URLArray
        
        //the hasVideoBeenSeen() basically gets the list of videos a user has already seen from `Users` table with the GraphQL getusers command, and creates a local copy of this list (can get big). I use javascripts indexOf() to check whether myKey already exists in the list 
        while(await this.hasVideoBeenSeen(this.state.URLData[dbIndex].myKey))  //while true i.e. user has seen that video before
        {
          dbIndex = this.getUniqueRandomNumber(this.state.urlArrayLength);  //get another random number to fetch a new myKey
        }
        
        //If false, we'll exit the loop and know we've got a not seen before myKey, proceed to set to play...
        if(dbIndex != null){
          this.setState({ playURL: this.state.URLData[dbIndex].vidURL });   //Retrieve the URL from the local URLArray that we're going to play (i.e. the next video to come)
          
        }   
      }

Saya dapat membagikan lebih banyak kode jika diperlukan, tetapi pada dasarnya saya ingin tahu caranya:

  1. Biarkan fungsi Lambda memilih nomor acak berdasarkan ukuran URLArray saat ini (saya mungkin tetap perlu menyimpan salinan lokal URLArray). Tapi menurut saya poin 2 di sini sangat tidak efisien..

  2. Biarkan fungsi Lambda memeriksa (perulangan while) terhadap tabel Pengguna apakah myKey sudah terlihat. Terutama untuk mengalihkan beban komputasi ini ke cloud, bukan ke perangkat lokal tempat aplikasi dijalankan.

SETELAH BERPIKIR................

Terima kasih atas sarannya Seth. Saya telah memikirkannya selama beberapa waktu, dan meskipun persyaratan keacakan masih berlaku, menurut saya saran Anda ada benarnya. Alasan saya memerlukan keacakan adalah agar 2 pengguna yang duduk berdampingan misalnya tidak dapat memprediksi video mana yang akan datang berikutnya. Ini bukanlah rangkaian video yang dapat diprediksi. Saya tidak yakin dapat menggunakan fungsi Scan dengan AWS Amplify/GraphQL. Jadi ingat ada 2 hal yang terjadi di sini: (1) unggahan video, rekam di URLArray dengan bijaksana untuk referensi di masa mendatang. (2) pengguna melihat video acak yang sebelumnya tidak terlihat, lalu berpindah ke video acak lain yang tidak terlihat

*(1) Saya menyukai ide Anda dalam menggunakan angka untuk mengindeks URLArray, dan ini membantu membuat hidup menjadi lebih mudah. Jadi URL pertama berada di indeks 0, berikutnya di 1 dst…

Pemikiran saya di sini (untuk menghindari saya melakukan ListUrlArrays() dan membawa array SELURUH secara lokal ke telepon), adalah membuat GSI bernama VideoNumber untuk tabel URLArray. Ini akan menjadi kolom VideoNumber unik dengan angka 0-N. Jadi bayangkan diagram di atas memiliki kolom lain bernama VideoNumber. Baris 1 dengan VideoNumber disetel ke 0, Baris 2 dengan VideoNumber disetel ke 1, dll… MAKA yang perlu saya lakukan adalah secara lokal di perangkat, membuat nomor acak antara 0-N, memanggil kueri getURLArrayIdbyVideoNumber() khusus untuk GSI tersebut, dengan nomor yang baru saja kita buat, dan itu akan membuka informasi yang saya perlukan dari baris tersebut. Voila! Saya pikir hal ini akan menghilangkan sebagian besar beban berat itu sekarang.

Pertanyaan: Sebelum setiap video diunggah, bagaimana cara dengan mudah mendapatkan jumlah total baris N saat ini dalam tabel (atau jumlah baris)? Saya kemudian akan menambahnya satu per satu.

Hal lain yang dapat saya lakukan adalah menyimpan nomor hitungan saat ini di tabel DynamoDB lain yang saya gunakan untuk data yang disimpan, membaca nomor dari sana sebelum mengunggah, dan menulis N+1 setelah mengunggah untuk menambahnya (2 operasi DynamoDB per unggahan). Itu tidak ideal.

*(2) Ketika pengguna selesai menonton video, saya dapat masuk ke daftar (di bawah informasi pengguna di DynamoDB), video mana yang sudah mereka lihat. Jadi misalnya sekarang ini bisa menjadi daftar yang terlihat: [3,12,73,108,57] untuk 5 video yang telah mereka lihat sejauh ini. Ketika pengguna mengklik nextVideo() kami akan menghasilkan nomor baru secara acak, dan langsung membandingkannya dengan nomor mana pun dalam daftar yang terlihat. Saya menggunakan seenlist.indexOf(newNumber) dan itu akan berjalan lagi atau berhenti jika Nomor baru tidak ada dalam daftar. LALU saya dapat menelusuri kueri GSI, dan mengambil informasi yang relevan untuk menampilkan video dari URLArray.

Menurut saya indexOf() ini adalah beban komputasi terbesar pada perangkat, dan jelas menjadi sedikit lebih lambat seiring dengan meningkatnya seenList. Tapi itu harus lebih cepat dengan bilangan bulat murni daripada myKey alfanumerik seperti yang saya gunakan sebelumnya. Saran lain akan diterima :)

Saya belum mencobanya, tapi itu hanya sebuah ide, karena saya harus menjaga elemen acaknya. Tapi pertama-tama, tahukah Anda bagaimana saya bisa dengan mudah menemukan jumlah baris atau jumlah tabel URLArray?


person chai86    schedule 11.08.2020    source sumber
comment
Atribut mana yang berfungsi sebagai kunci partisi Anda (bidang ID?). Apakah Anda menggunakan kunci pengurutan? Apakah video berikutnya benar-benar harus dibuat secara acak, atau hanya sesuatu yang belum pernah dilihat pengguna sebelumnya?   -  person Seth Geoghegan    schedule 12.08.2020
comment
@ chai86 Saya akan merekomendasikan memeriksa thread ini stackoverflow.com/questions/10666364/   -  person Traycho Ivanov    schedule 14.08.2020
comment
@SethGeoghegan Tidak ada kunci pengurutan. Alasan utama pengacakan acak adalah seperti yang Anda katakan, itu harus mengenai entri yang belum pernah dilihat pengguna sebelumnya. Saya memiliki catatan dalam daftar item yang telah dilihat oleh pengguna yang masuk, untuk dibandingkan. Saya masih belum menemukan solusi langsung untuk sesuatu yang tampaknya sederhana untuk dapat dilakukan oleh database   -  person chai86    schedule 29.09.2020


Jawaban (1)


Saya rasa Anda akan lebih mudah menemukan solusi untuk masalah ini jika Anda menghilangkan persyaratan keacakan. Sepertinya persyaratan yang lebih penting adalah menyajikan video yang belum pernah mereka lihat sebelumnya kepada pengguna.

Jika benar, sepertinya pola akses Anda dapat dinyatakan sebagai

Ambil video yang sebelumnya tidak terlihat untuk pengguna

yang merupakan masalah yang lebih mudah untuk dipecahkan.

Tidak seperti database SQL, sering kali terdapat banyak cara untuk mengimplementasikan pola akses tertentu di DynamoDB. Jawaban saya di sini hanyalah satu cara.

Bayangkan tabel URLArray Anda sebagai array raksasa. URL pertama berada di indeks 0, URL berikutnya berada di indeks 1, URL kedua berada di indeks 2, dan seterusnya. Setiap pengguna aplikasi Anda akan memulai dengan menonton video pada indeks URL 0, lalu indeks URL 1, dan seterusnya. Hal ini akan memastikan pengguna tidak pernah melihat video yang sama dua kali. Anda tidak perlu menyimpan daftar semua video yang telah mereka lihat. Sebagai gantinya, Anda dapat menyimpan indeks video terakhir yang mereka lihat.

Aplikasi Anda dapat mengambil n video pertama dari tabel untuk disajikan kepada pengguna Anda. Setelah daftar tersebut habis, ia dapat mengambil video berikutnya n. Dan seterusnya...

Apa yang saya jelaskan di sini pada dasarnya adalah bagaimana pagination diimplementasikan di DynamoDB. Untuk mengembalikan abstraksi ini ke dunia DynamoDB, algoritme Anda akan terlihat seperti ini:

  • Pindai tabel URLArray untuk halaman pertama URL (operasi scan tanpa kriteria filter)
  • Bersamaan dengan hasilnya, DynamoDB akan merespons dengan LastEvaluatedKey, yang memungkinkan Anda mengambil halaman hasil berikutnya mulai dari posisi ini
  • Sajikan kepada pengguna Anda setiap video yang Anda tarik kembali dari operasi scan, pastikan untuk merekam id (Kunci Utama) video terakhir yang mereka lihat.
  • Saat Anda menghabiskan URL dari langkah 1, jalankan operasi scan lainnya dengan ExclusiveStartKey disetel ke LastEvaluatedKey yang dikembalikan dari langkah 2.
  • Saat pengguna kembali ke aplikasi Anda, buat kueri untuk halaman berikutnya dari tabel URLArray dengan ExclusiveStartKey disetel ke id dari video terakhir yang mereka lihat.

Ini secara efektif menggunakan operasi scan untuk menelusuri tabel URLArray Anda satu halaman dalam satu waktu. Aplikasi Anda akan secara efektif menelusuri tabel dari atas ke bawah, melacak keberadaan setiap pengguna pada waktu tertentu. Saat pengguna mengunjungi kembali aplikasi Anda, mulailah dari bagian terakhir yang mereka tinggalkan.

Sebagai tanggapan terhadap hasil edit Anda:

Jika kasus penggunaan Anda mengharuskan video berikutnya tidak dapat diprediksi (misalnya tidak ada 2 pengguna yang dapat memprediksi video apa berikutnya), Anda memiliki beberapa masalah yang harus diselesaikan secara bersamaan:

  1. Memilih item dengan cara yang tidak dapat diprediksi/acak
  2. Melacak apa yang telah dilihat pengguna

Menggabungkan kedua persyaratan tersebut menghasilkan pola akses yang rumit. Katakanlah Anda memiliki N video di tabel Anda, dan pengguna telah menonton N-1 dari video tersebut sehingga hanya satu video yang tidak terlihat. Jika Anda mengambil video berikutnya secara acak dan perlu memastikan video tersebut belum ditonton, bagaimana Anda menemukan video terakhir yang belum dilihat? Berapa kali Anda perlu menebak sebelum Anda menemukan satu-satunya video yang tidak terlihat? Operasi kueri/pemindaian apa yang dapat Anda lakukan yang melakukan hal ini dalam satu permintaan ke DDB? Saya tidak mengatakan itu tidak mungkin, hanya saja...rumit.

Menurut saya, lebih baik membuat strategi yang tidak dapat diprediksi oleh pengguna, namun dapat diprediksi oleh Anda saat memilih video berikutnya yang tidak terlihat.

Misalnya, Anda dapat menghitung terlebih dahulu urutan indeks acak dari 1..N, yang akan mewakili urutan Anda menyajikan video untuk pengguna tertentu. Anda dapat menelusuri daftar itu secara berurutan, melacak indeks yang terakhir dilihat. Dengan begitu, Anda akan selalu mengetahui video mana yang berikutnya dan video tersebut belum pernah dilihat oleh pengguna ini sebelumnya. Mengambil video itu akan menjadi operasi kueri sederhana ke DDB.

Anda juga menanyakan cara menemukan jumlah item di DynamoDB. Sayangnya, tidak ada DynamoDB yang setara dengan operasi SQL count. Jawaban atas pertanyaan ini tidaklah mudah. Demi kepentingan komunitas (dan untuk mendapatkan beragam jawaban), saya sarankan Anda membuat pertanyaan terpisah di Stackoverflow mengenai jumlah item dalam tabel DDB.

person Seth Geoghegan    schedule 29.09.2020
comment
Hai Seth, baru saja memperbarui postingan asli yang diawali 'AFTER A THINK' dengan tempat saya berada :) - person chai86; 07.10.2020