随机选择DynamoDB条目

如何解决随机选择DynamoDB条目

我有一个名为 URLArray 的DynamoDB表,其中包含URL列表(myURL)和唯一的视频名称(myKey)。

See URLArray table here

我需要做两件事:

  1. 当用户单击下一个视频按钮时,需要从此URLArray中选择一个随机条目。可能有成千上万的行。

用户已登录到应用程序。每当他们观看完视频时,都会记录该视频的唯一视频名称。因此...当用户观看视频时,会将其添加到用户信息行下名为 Users 的表的列表中。

  1. S ...当用户单击点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函数对Users表进行检查(while循环)是否已经看到myKey。主要是将计算负担转移到云上,而不是将应用程序运行在本地设备上。

思考之后。

感谢塞思的建议。我已经考虑了一段时间了,尽管随机性要求仍然成立,但我认为您的建议中有些道理。我需要随机性的原因是,例如,两个用户并排坐着,无法预测接下来要播放哪个视频。这不应是可预测的视频序列。我不确定我可以将Scan函数与AWS Amplify / GraphQL一起使用。因此,请记住这里发生了两件事:(1)上传视频,并明智地将其记录在URLArray中,以备将来参考。 (2)用户先观看之前看不见的随机视频,然后再观看另一个看不见的随机视频

*(1) 我喜欢您使用数字对URLArray进行索引的想法,这有助于简化生活。因此,第一个URL的索引为0,下一个URL的索引为1,等等……

我在这里的想法(避免我做一个ListUrlArrays()并将整个WHOLE数组带到手机中)是为URLArray表创建一个名为VideoNumber的GSI。这将是唯一的VideoNumber列,其编号为0-N。因此,请想象上面的图表中还有另一列称为VideoNumber。将VideoNumber设置为0的第1行,将VideoNumber设置为1的第2行,等等……然后,我所要做的只是在设备本地,生成介于0-N之间的随机数,调用特定于getURLArrayIdbyVideoNumber()的查询该GSI,以及我们刚刚生成的数字,它将解锁该行中我需要的信息。瞧!我认为这现在已将大部分沉重负担转移了。

问题::在上传每个视频之前,如何轻松获得表格中当前的总行数N(或行数)?然后我将其递增一。

我可以做的另一件事是将当前计数值保存到另一个用于保存数据的DynamoDB表中,在上传之前从那里读取该数字,并在上传之后写入N + 1以对其进行递增操作(每个操作2个DynamoDB操作上传)。这不理想。

*(2) 用户观看完视频后,我可以登录一个列表(在DynamoDB中的用户信息下),他们已经看过这些视频。因此,举例来说,这可能是一个可见的列表:[3,12,73,108,57]他们到目前为止看过的5个视频。当用户单击nextVideo()时,我们将生成一个随机的newNumber,并立即将其与可见列表中的任何数字进行比较。我使用seenlist.indexOf(newNumber),如果newNumber在列表中不存在,它将再次出现或停止。然后,我可以通过GSI查询,并检索相关信息以显示URLArray中的视频。

我认为这个indexOf()是设备上最大的计算负担,并且显然随着seenList的增加而变慢。但是使用纯整数应该比我以前使用的字母数字myKey更快。任何其他建议都将受到欢迎:)

我还没有尝试过,但这只是一个主意,因为我需要保留随机元素。但是首先,您知道我如何轻松找到URLArray的行数或表计数吗?

解决方法

如果您放弃了随机性要求,我想您将可以轻松解决这个问题。听起来更重要的要求是向用户呈现他们以前从未看过的视频。

如果是正确的话,听起来您的访问模式可以说成

为用户获取以前看不见的视频

这是一个更容易解决的问题。

与SQL数据库不同,通常有很多方法可以在DynamoDB中实现给定的访问模式。我的回答只是一种方式。

将您的URLArray表想象成一个巨大的数组。第一个URL的索引为0,下一个URL的索引为1,第二个URL的索引为2,依此类推。应用程序的每个用户都将从在URL索引0,然后URL索引1等处观看视频开始。这将确保用户永远不会两次观看同一视频。您无需存储他们观看过的所有视频的列表。相反,您可以存储他们看到的最后视频的索引。

您的应用程序可以从表格中获取前 n 个视频,以呈现给您的用户。该列表用尽后,就可以抓取 next n 个视频。等等...

我在这里描述的实际上是pagination is implemented in DynamoDB的方式。为了使这种抽象回到DynamoDB的世界中,您的算法应如下所示:

  • URLArray表中查找URL的第一个“页面”(scan操作,没有过滤条件)
  • 连同结果一起,DynamoDB将以LastEvaluatedKey进行响应,这将使您从该位置开始检索结果的下一页
  • 将您从scan操作撤回的每个视频呈现给用户,并确保将他们最近观看的视频记录在id(主键)上。
  • 在步骤1中用尽URL时,请执行另一个scan操作,并将ExclusiveStartKey设置为从步骤2返回的LastEvaluatedKey
  • 当用户返回到您的应用程序时,请从URLArray表中查询下一页,并将ExclusiveStartKey设置为他们最近观看的视频的id

这有效地使用了scan操作一次在您的URLArray表中搜索一页。您的应用程序将有效地从上到下搜索表格,跟踪每个用户在任何给定时间的位置。当用户重新访问您的应用程序时,只需从他们停止的地方开始。

针对您的修改:

如果您的用例要求下一个视频不可预测(例如,没有2个用户可以预测下一个视频),那么您需要同时解决一些问题:

  1. 以不可预测/随机的方式选择项目
  2. 跟踪用户已经看到的内容

将这两个要求放在一起将构成一个棘手的访问模式。假设您的桌子上有N个视频,并且用户观看了这些视频中的N-1个,而其中只有一个视频不可见。如果您要随机提取下一个视频 ,并且需要确保尚未看到该视频,那么如何找到最近看不到的视频?在看完唯一一部看不见的视频之前,您需要猜测多少次?在对DDB的单个请求中,您可以执行哪种查询/扫描操作?我并不是说这是不可能的,只是...很复杂。

我认为最好生成一种对用户来说是不可预测的策略,但是对于选择下一个看不见的视频来说,对您来说却是可预测的。

例如,您可以提前1..N预先计算索引的随机顺序,这将代表您为给定用户呈现视频的顺序。您可以按顺序浏览该列表,并跟踪最后看到的索引。这样,您将始终知道下一个视频是 ,并且该用户以前没有看过该视频。提取视频将是对DDB的简单查询操作。

您还询问了如何在DynamoDB中查找项目数。不幸的是,没有DynamoDB等效于SQL count操作。这个问题的答案并不简单。为了社区的利益(并获得多样化的答案),建议您在Stackoverflow上对DDB表中的项目数提出一个单独的问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 <select id="xxx"> SELECT di.id, di.name, di.work_type, di.updated... <where> <if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 <property name="dynamic.classpath" value="tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams['font.sans-serif'] = ['SimHei'] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -> systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping("/hires") public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate<String
使用vite构建项目报错 C:\Users\ychen\work>npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-