У меня есть таблица DynamoDB с именем URLArray, которая содержит список URL-адресов (myURL) и уникальное имя видео (myKey).
Мне нужно сделать две вещи:
- Когда пользователь нажимает кнопку следующего видео, из этого URLArray необходимо выбрать случайную запись. Потенциально могут быть десятки тысяч строк.
Пользователь авторизован в приложении. Каждый раз, когда они заканчивают просмотр видео, записывается уникальное название видео. Итак... когда пользователь просматривает видео, оно добавляется в список в таблице с именем Пользователи в строке информации о пользователе.
- Итак... Эта случайная запись, которая выбирается, когда пользователь нажимает кнопку следующего видео в точке 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)
}
}
Я могу поделиться еще немного кода, если это необходимо, но по сути я хотел знать, как:
Пусть функция Lambda выбирает случайное число на основе текущего размера URLArray (в любом случае мне может понадобиться сохранить локальную копию URLArray). Но я думаю, что пункт 2 здесь действительно неэффективен.
Пусть функция Lambda проверяет (цикл while) по таблице Users, был ли уже виден myKey. Главным образом для того, чтобы перенести эту вычислительную нагрузку на облако, а не на локальное устройство, на котором работает приложение.
ПОСЛЕ ПОДУМА...
Спасибо за предложение, Сет. Я думал об этом в течение некоторого времени, и хотя требование случайности все еще остается в силе, я думаю, что в том, что вы предложили, есть доля правды. Причина, по которой мне нужна случайность, заключается в том, чтобы, например, 2 пользователя сидели рядом и не могли предсказать, какое видео будет следующим. Это не должна быть предсказуемая последовательность видео. Я не уверен, что смогу использовать функцию Scan
с AWS Amplify/GraphQL. Так что помните, что здесь происходит две вещи: (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)
, и он либо пойдет снова, либо остановится, если newNumber не существует в списке. ТОГДА я могу выполнить запрос GSI и получить соответствующую информацию для отображения видео из URLArray.
Я думаю, что это indexOf()
является самой большой вычислительной нагрузкой для устройства и, очевидно, становится немного медленнее по мере увеличения seenList
. Но это должно быть быстрее с чистыми целыми числами, чем с буквенно-цифровым myKey
, как я использовал раньше. Любое другое предложение приветствуется :)
Я еще не пробовал, но это была просто идея, так как мне нужно сохранить случайный элемент. Но во-первых, знаете ли вы, как я могу легко найти количество строк или количество таблиц в URLArray?