สุ่มเลือกรายการ DynamoDB

ฉันมีตาราง DynamoDB ชื่อ URLArray ซึ่งมีรายการ URL (myURL) และชื่อวิดีโอที่ไม่ซ้ำกัน (myKey)

ดูตาราง URLArray ที่นี่

ฉันต้องทำสองสิ่ง:

  1. เมื่อผู้ใช้คลิกปุ่มวิดีโอถัดไป จะต้องเลือกรายการสุ่มจาก URLArray นี้ อาจมีแถวนับหมื่นแถวก็ได้

ผู้ใช้เข้าสู่ระบบแอป ทุกครั้งที่ดูวิดีโอจบ ชื่อวิดีโอเฉพาะของวิดีโอจะถูกบันทึก ดังนั้น....เมื่อผู้ใช้ดูวิดีโอ วิดีโอนั้นจะถูกเพิ่มลงในรายการในตารางชื่อ ผู้ใช้ ใต้แถวข้อมูลของผู้ใช้

  1. ซู...รายการสุ่มนี้ที่ถูกเลือกเมื่อผู้ใช้คลิกปุ่มวิดีโอถัดไปในจุดที่ 1 จะต้องถูกเปรียบเทียบกับรายการวิดีโอที่พวกเขาได้เห็นแล้ว เพื่อให้แน่ใจว่าจะไม่ปรากฏขึ้นแบบสุ่มอีกครั้งสำหรับผู้ใช้รายนั้น

จนถึงตอนนี้ฉันทำบางอย่างที่ไม่มีประสิทธิภาพมากนัก ซึ่งได้ผล แต่มันก็ไม่ได้ดีนัก:

อย่างไรก็ตาม ฉันใช้ AppSync + GraphQL เพื่อโต้ตอบกับตาราง DynamoDB ฉันได้รับสำเนา 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)
      }
   }

โดยภาพรวม เมื่อผู้ใช้คลิกเพื่อดูวิดีโอถัดไป:

     //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)
          
        }   
      }

ฉันสามารถแชร์โค้ดเพิ่มเติมได้อีกเล็กน้อยหากจำเป็น แต่โดยพื้นฐานแล้ว ฉันต้องการทราบวิธี:

  1. ให้ฟังก์ชัน Lambda เลือกตัวเลขสุ่มตามขนาด URLArray ปัจจุบัน (ฉันอาจต้องเก็บสำเนา URLArray ในเครื่องไว้อยู่แล้ว) แต่ผมคิดว่าข้อ 2 ที่นี่คือจุดที่มันไม่มีประสิทธิภาพจริงๆ..

  2. ให้ฟังก์ชัน Lambda ตรวจสอบ (ลูป while) กับตาราง Users ว่าเห็น myKey แล้วหรือไม่ โดยหลักแล้วเพื่อเปลี่ยนภาระการคำนวณนี้ไปยังคลาวด์แทนอุปกรณ์ในเครื่องที่แอปทำงานอยู่

หลังจากคิด................

ขอบคุณที่แนะนำเซธ ฉันคิดเรื่องนี้มาระยะหนึ่งแล้ว และแม้ว่าข้อกำหนดการสุ่มยังคงเป็นจริง ฉันคิดว่าสิ่งที่คุณแนะนำก็มีความจริงอยู่บ้าง เหตุผลที่ฉันต้องการการสุ่มก็คือเพื่อให้ผู้ใช้ 2 คนนั่งเคียงข้างกัน ไม่สามารถคาดเดาได้ว่าวิดีโอใดที่กำลังจะมาต่อไป ไม่ควรเป็นลำดับวิดีโอที่คาดเดาได้ ฉันไม่แน่ใจว่าฉันสามารถใช้ฟังก์ชัน Scan กับ AWS Amplify/GraphQL ได้ ดังนั้นโปรดจำไว้ว่ามี 2 สิ่งที่เกิดขึ้นที่นี่: (1) การอัปโหลดวิดีโอ โดยบันทึกไว้ใน URLArray อย่างสมเหตุสมผลเพื่อใช้อ้างอิงในอนาคต (2) ผู้ใช้ดูวิดีโอสุ่มที่ไม่เคยเห็นมาก่อน จากนั้นจึงย้ายไปยังวิดีโอสุ่มที่มองไม่เห็นอีกรายการหนึ่ง

*(1) ฉันชอบความคิดของคุณในการใช้ตัวเลขเพื่อสร้างดัชนี URLArray และมันช่วยให้ชีวิตง่ายขึ้นนิดหน่อย ดังนั้น URL แรกอยู่ที่ดัชนี 0, ถัดไปที่ 1 ฯลฯ...

ความคิดของฉันที่นี่ (เพื่อหลีกเลี่ยงไม่ให้ฉันทำ ListUrlArrays() และนำอาเรย์ทั้งหมดมาไว้ในโทรศัพท์) คือการสร้าง GSI ชื่อ VideoNumber สำหรับตาราง URLArray นี่จะเป็นคอลัมน์ VideoNumber ที่ไม่ซ้ำกันซึ่งมีตัวเลข 0-N ลองจินตนาการถึงแผนภาพด้านบนที่มีคอลัมน์อื่นชื่อ VideoNumber แถว 1 มี VideoNumber ตั้งค่าเป็น 0, แถว 2 มี VideoNumber ตั้งค่าเป็น 1 ฯลฯ... จากนั้นสิ่งที่ฉันต้องทำคืออยู่ในอุปกรณ์ สร้างตัวเลขสุ่มระหว่าง 0-N เรียกใช้แบบสอบถาม getURLArrayIdbyVideoNumber() เฉพาะสำหรับ GSI นั้น ด้วย หมายเลขที่เราเพิ่งสร้างขึ้น และจะปลดล็อกข้อมูลที่ฉันต้องการจากแถวนั้น เอาล่ะ! ฉันคิดว่านั่นจะช่วยขจัดภาระหนักส่วนใหญ่ออกไปในตอนนี้

คำถาม: ก่อนอัปโหลดวิดีโอแต่ละรายการ ฉันจะรับจำนวนแถว N ทั้งหมดในปัจจุบันในตาราง (หรือจำนวนแถว) ได้อย่างง่ายดายได้อย่างไร จากนั้นฉันก็จะเพิ่มขึ้นทีละหนึ่ง

อีกสิ่งหนึ่งที่ฉันทำได้คือบันทึกหมายเลขการนับปัจจุบันนี้ในตาราง DynamoDB อื่นที่ฉันใช้สำหรับข้อมูลที่มีอยู่ อ่านตัวเลขจากที่นั่นก่อนอัปโหลด และเขียน N+1 หลังจากการอัปโหลดเพื่อเพิ่ม (2 การดำเนินการ DynamoDB ต่อการอัปโหลด) มันไม่เหมาะ

*(2) เมื่อผู้ใช้ดูวิดีโอเสร็จแล้ว ฉันสามารถเข้าสู่ระบบรายการ (ใต้ข้อมูลผู้ใช้ใน DynamoDB) ว่าพวกเขาเคยดูวิดีโอใดแล้ว ตัวอย่างเช่น ตอนนี้อาจเป็นรายการที่เห็นแล้ว: [3,12,73,108,57] สำหรับวิดีโอ 5 รายการที่พวกเขาดูจนถึงตอนนี้ เมื่อผู้ใช้คลิก nextVideo() เราจะสร้าง newNumber แบบสุ่ม และเปรียบเทียบกับหมายเลขใดๆ ในรายการที่เห็นทันที ฉันใช้ seenlist.indexOf(newNumber) และจะไปอีกครั้งหรือหยุดลงหากไม่มีหมายเลขใหม่อยู่ในรายการ จากนั้นฉันสามารถค้นหา GSI และดึงข้อมูลที่เกี่ยวข้องเพื่อแสดงวิดีโอจาก URLArray

ฉันคิดว่า indexOf() นี้เป็นภาระในการคำนวณที่ใหญ่ที่สุดบนอุปกรณ์ และเห็นได้ชัดว่าจะช้าลงเล็กน้อยเมื่อ seenList เพิ่มขึ้น แต่ควรจะเร็วกว่านี้ด้วยตัวเลขจำนวนเต็มล้วนๆ แล้วเป็นตัวอักษรและตัวเลข myKey อย่างที่ฉันเคยใช้ ข้อเสนอแนะอื่นใดจะยินดี :)

ฉันยังไม่ได้ลอง แต่มันก็เป็นแค่ไอเดียเท่านั้น เพราะฉันต้องเก็บองค์ประกอบแบบสุ่มเอาไว้ แต่ก่อนอื่น คุณรู้ไหมว่าฉันสามารถค้นหาจำนวนแถวหรือจำนวนตารางของ URLArray ได้อย่างไร


person chai86    schedule 11.08.2020    source แหล่งที่มา
comment
คุณลักษณะใดที่ทำหน้าที่เป็นพาร์ติชันคีย์ของคุณ (ช่อง ID?) คุณใช้คีย์การเรียงลำดับหรือไม่? วิดีโอถัดไปจำเป็นต้องสุ่มจริงๆ หรือเป็นเพียงสิ่งที่ผู้ใช้ไม่เคยเห็นมาก่อน   -  person Seth Geoghegan    schedule 12.08.2020
comment
@ chai86 ฉันขอแนะนำให้ตรวจสอบกระทู้นี้ stackoverflow.com/questions/10666364/   -  person Traycho Ivanov    schedule 14.08.2020
comment
@SethGeoghegan ไม่มีคีย์การเรียงลำดับ สาเหตุหลักของการสุ่มแบบสุ่มคืออย่างที่คุณพูด มันต้องเข้าถึงรายการที่ผู้ใช้ไม่เคยเห็นมาก่อน ฉันได้บันทึกรายการที่ผู้ใช้ที่เข้าสู่ระบบได้เห็นแล้วเพื่อเปรียบเทียบ ฉันยังไม่พบวิธีแก้ปัญหาที่ตรงไปตรงมาสำหรับบางสิ่งที่ดูเหมือนง่ายสำหรับฐานข้อมูลที่จะสามารถทำได้   -  person chai86    schedule 29.09.2020


คำตอบ (1)


ฉันคิดว่าคุณจะมีเวลาในการแก้ไขปัญหานี้ได้ง่ายขึ้น หากคุณละทิ้งข้อกำหนดการสุ่ม ดูเหมือนว่าข้อกำหนดที่สำคัญกว่านั้นคือการนำเสนอวิดีโอที่พวกเขาไม่เคยเห็นมาก่อนแก่ผู้ใช้

หากถูกต้อง ดูเหมือนว่ารูปแบบการเข้าถึงของคุณอาจถูกระบุเป็น

ดึงวิดีโอที่ไม่เคยเห็นมาก่อนสำหรับผู้ใช้

ซึ่งเป็นปัญหาที่แก้ไขได้ง่ายกว่า

ต่างจากฐานข้อมูล SQL ตรงที่มีหลายวิธีในการใช้รูปแบบการเข้าถึงที่กำหนดใน DynamoDB คำตอบของฉันที่นี่เป็นเพียง ทางเดียว

ลองนึกภาพตาราง URLArray ของคุณเป็นอาร์เรย์ขนาดยักษ์ URL แรกอยู่ที่ดัชนี 0 URL ถัดไปอยู่ที่ดัชนี 1 URL ที่สองอยู่ที่ดัชนี 2 และอื่นๆ ผู้ใช้แอปพลิเคชันของคุณแต่ละคนจะเริ่มต้นด้วยการดูวิดีโอที่ดัชนี URL 0 จากนั้นดัชนี URL 1 ฯลฯ ซึ่งจะทำให้ผู้ใช้มั่นใจได้ว่าจะไม่มีวันดูวิดีโอเดียวกันซ้ำอีก คุณไม่จำเป็นต้องจัดเก็บรายการทั้งหมดวิดีโอที่พวกเขาดู แต่คุณสามารถจัดเก็บดัชนีของวิดีโอ ล่าสุด ที่พวกเขาเห็นแทน

แอปพลิเคชันของคุณสามารถดึงวิดีโอ n รายการแรกจากตารางมานำเสนอต่อผู้ใช้ของคุณ เมื่อรายการนั้นหมดลงแล้ว ก็สามารถไปคว้าวิดีโอถัดไป n รายการได้ และอื่นๆ...

สิ่งที่ฉันได้อธิบายไว้ ณ ที่นี้คือวิธีการใช้ การแบ่งหน้าใน DynamoDB. เพื่อนำนามธรรมนี้กลับมาสู่โลกของ DynamoDB อัลกอริทึมของคุณอาจมีลักษณะดังนี้:

  • สแกนตาราง URLArray เพื่อดูหน้าแรกของ URL (การดำเนินการ scan โดยไม่มีเกณฑ์ตัวกรอง)
  • นอกจากผลลัพธ์แล้ว DynamoDB จะตอบกลับด้วย LastEvaluatedKey ซึ่งจะช่วยให้คุณสามารถดึงผลลัพธ์หน้าถัดไปเริ่มต้นจากตำแหน่งนี้
  • นำเสนอวิดีโอแต่ละรายการที่คุณดึงกลับมาจากการดำเนินการ scan ให้ผู้ใช้ของคุณ ตรวจสอบให้แน่ใจว่าได้บันทึก id (คีย์หลัก) ของวิดีโอสุดท้ายที่พวกเขาเห็น
  • เมื่อคุณใช้ URL จากขั้นตอนที่ 1 หมดแล้ว ให้ดำเนินการ scan อีกครั้งโดยตั้งค่า ExclusiveStartKey เป็น LastEvaluatedKey ที่ส่งคืนจากขั้นตอนที่ 2
  • เมื่อผู้ใช้กลับมาที่แอปพลิเคชันของคุณ ให้ค้นหาหน้าถัดไปจากตาราง URLArray โดยตั้งค่า ExclusiveStartKey เป็น id ของวิดีโอล่าสุดที่พวกเขาดู

การดำเนินการนี้ใช้การดำเนินการ scan เพื่อค้นหาตาราง URLArray ของคุณทีละหน้าอย่างมีประสิทธิภาพ แอปพลิเคชันของคุณจะสามารถค้นหาตารางจากบนลงล่างได้อย่างมีประสิทธิภาพ โดยติดตามว่าผู้ใช้แต่ละรายอยู่ที่ไหนในเวลาใดก็ตาม เมื่อผู้ใช้กลับมาที่แอปพลิเคชันของคุณอีกครั้ง เพียงเริ่มต้นจากจุดที่พวกเขาค้างไว้

เพื่อตอบสนองต่อการแก้ไขของคุณ:

หากกรณีการใช้งานของคุณกำหนดให้วิดีโอถัดไปไม่สามารถคาดเดาได้ (เช่น ไม่มีผู้ใช้ 2 รายที่สามารถคาดเดาได้ว่าวิดีโอใดเป็นวิดีโอถัดไป) คุณมีปัญหาบางประการที่ต้องแก้ไขในเวลาเดียวกัน:

  1. การเลือกรายการในลักษณะที่ไม่สามารถคาดเดา/สุ่มได้
  2. ติดตามสิ่งที่ผู้ใช้ได้เห็นแล้ว

การรวมข้อกำหนดทั้งสองนี้เข้าด้วยกันทำให้เกิดรูปแบบการเข้าถึงที่ยุ่งยาก สมมติว่าคุณมีวิดีโอ N รายการในตารางของคุณ และผู้ใช้ได้ดูวิดีโอเหล่านี้แล้ว N-1 รายการ โดยเหลือเพียงวิดีโอเดียวที่มองไม่เห็น หากคุณกำลังเรียกวิดีโอถัดไปของคุณแบบสุ่ม และ ต้องการให้แน่ใจว่ายังไม่ได้รับชม คุณจะค้นหาวิดีโอที่ยังไม่ได้ดูล่าสุดได้อย่างไร คุณต้องเดากี่ครั้งก่อนจะเจอวิดีโอที่มองไม่เห็นเพียงวิดีโอเดียว การดำเนินการค้นหา/สแกนใดที่คุณสามารถทำได้ในคำขอเดียวไปยัง DDB ฉันไม่ได้บอกว่ามันเป็นไปไม่ได้ มันแค่... ซับซ้อน

ฉันคิดว่าเป็นการดีกว่าที่จะสร้างกลยุทธ์ที่ผู้ใช้คาดเดาไม่ได้ แต่จะคาดเดาได้สำหรับคุณเมื่อต้องเลือกวิดีโอที่มองไม่เห็นถัดไป

ตัวอย่างเช่น คุณสามารถคำนวณลำดับดัชนีแบบสุ่มล่วงหน้าได้ตั้งแต่ 1..N ล่วงหน้า ซึ่งจะแสดงถึงลำดับที่คุณนำเสนอวิดีโอให้กับผู้ใช้ที่กำหนด คุณสามารถอ่านรายการนั้นตามลำดับ โดยติดตามดัชนีที่เห็นล่าสุด ด้วยวิธีนี้ คุณจะรู้ได้เสมอว่าวิดีโอใดคือวิดีโอถัดไป และ ว่าผู้ใช้รายนี้ไม่เคยเห็นวิดีโอนี้มาก่อน การเรียกวิดีโอนั้นจะเป็นการดำเนินการค้นหาแบบง่ายๆ ไปยัง DDB

คุณยังถามถึงวิธีค้นหาจำนวนรายการใน DynamoDB ขออภัย ไม่มี DynamoDB ที่เทียบเท่ากับการดำเนินการ SQL count คำตอบสำหรับคำถามนี้ไม่ตรงไปตรงมา เพื่อประโยชน์ของชุมชน (และเพื่อให้ได้คำตอบที่หลากหลาย) ฉันขอแนะนำให้คุณตั้งคำถามแยกต่างหากเกี่ยวกับ Stackoverflow เกี่ยวกับจำนวนรายการในตาราง DDB

person Seth Geoghegan    schedule 29.09.2020
comment
สวัสดี Seth เพิ่งอัปเดตโพสต์ต้นฉบับที่เริ่มต้น 'หลังจากคิด' โดยที่ฉันอยู่ :) - person chai86; 07.10.2020