Многие ко многим с тысячами ссылок - PullRequest
0 голосов
/ 06 мая 2018

В настоящее время у меня есть база данных SQL Server с таблицей, содержащей 400 000 фильмов. У меня есть еще одна таблица, содержащая тысячи пользователей.

CREATE TABLE [movie].[Header]
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [SourceId] [int] NOT NULL,
    [ReleaseDate] [Date] NOT NULL,
    [Title] [nvarchar](500) NOT NULL
)

CREATE TABLE [account].[Registration]
(
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Username] [varchar](50) NOT NULL,
    [PasswordHash] [varchar](1000) NOT NULL,
    [Email] [varchar](100) NOT NULL,
    [CreatedAt] [datetime] NOT NULL,
    [UpdatedAt] [datetime] NOT NULL
)

CREATE TABLE [movie].[Likes] 
(
    [Id] [uniqueidentifier] NOT NULL,
    [HeaderId] [int] NOT NULL,
    [UserId] [int] NOT NULL,
    [CreatedAt] [datetime] NOT NULL
)

CREATE TABLE [movie].[Dislikes]
(
    [Id] [uniqueidentifier] NOT NULL,
    [HeaderId] [int] NOT NULL,
    [UserId] [int] NOT NULL,
    [CreatedAt] [datetime] NOT NULL
)

Каждому пользователю показано 100 фильмов, начиная с двух недель в будущем. Затем они могут выполнять такие действия, как: нравится, не нравится, рекомендовать и т. Д.

Я нахожусь в процессе перевода всего приложения в безсерверную архитектуру. У меня API работают в AWS через Lambda + API Gateway, и теперь я смотрю на использование DynamoDB для базы данных. Я не думаю, что у меня есть что-то сверхъестественное, что помешало бы мне хранить данные в «Динамо», и их модель ценообразования / потребления, похоже, будет существенно дешевле, чем SQL Server (в настоящее время размещенный в Azure).

Единственное, с чем у меня проблемы, - это понимание того, как я буду моделировать пользователей, выполняющих действие над фильмом. Если им «нравится» фильм, он попадает в список лайков, к которому они могут вернуться и посетить. Там я представляю им всю запись о движении (которая на самом деле состоит из большего количества данных, таких как приведение / команда / рейтинги и т. Д. Я просто обрезал кабель, чтобы упростить его). Если бы я сохранил каждое «Мне нравится» как элемент в «Динамо» вместе со всем фильмом в качестве атрибута, я бы подумал, что документ пользователя станет очень большим.

Мне также нужно продолжать показывать пользователям фильмы, начиная с двух недель, когда они не выполняли никаких действий. Фильмы, над которыми они выполнили действия, нужно удалить из запроса. Сегодня я просто присоединяюсь к таблице фильмов и таблице действий пользователей, удаляя фильмы из запроса, который уже существует в таблице действий пользователей. Как бы я смоделировал это в NoSql с таким же конечным результатом?

Я могу объединить лайки / дислайки в один документ с атрибутом типа действия (представляющим лайк / дислайк и т. Д.) И массивом фильмов, над которыми было выполнено действие. Еще не уверен, как мне отфильтровать запрос [Header], чтобы фильмы в документе пользователя не возвращались.

Я подумал, что установлю хэш-ключ своих фильмов на дату выпуска шардинга, поскольку в среднем на каждую дату выпуска приходится примерно 10 фильмов. Это дает хорошее распределение. Я решил, что использовать идентификатор пользователя с ключом хеша для документа, содержащего все фильмы, над которыми пользователь выполнил действие; не уверен, что это правильный путь.

Я никогда не имел дела с NoSql, поэтому я хотел попросить ввода. Я не уверен, как лучше всего спроектировать что-то, что по сути является одно-многим, но с потенциалом для фильмов на пользователя, составляющих десятки тысяч.

1 Ответ

0 голосов
/ 08 мая 2018

Итак, основываясь на ваших комментариях, я добавлю предложение. Это не значит, что это правильный ответ, я тоже могу ошибаться или пропустить точку

Прежде всего, пожалуйста, прочитайте каждый сегмент Best Practices снова и снова. Существуют шаблоны, о которых вы никогда не задумывались, но они все еще возможны при использовании NoSQL. Это очень полезно и полезно (если учесть, что вы новичок в NoSQL). В вашем случае есть сходства, и вы можете создать свой собственный ответ на основе передового опыта.

Я могу предложить следующее:

NoSQL очень плохо подходит для запросов на "не существует". Большая хитрость NoSQL в том, что он точно знает, где найти данные, которые вы ищете, а не где не найти. Поэтому сложно найти пользователей, которые еще не выполнили никаких действий над фильмом. Если вы можете использовать боковую базу данных, такую ​​как Redis, вы можете легко это осуществить. С помощью структур данных Redis вы можете запросить, кому еще не понравился или не понравился пользователь, и получить оставшиеся данные фильма из DynamoDB. Но пока отложим стороннюю базу данных Redis и используем только подход DynamoDB.

Один из подходов может состоять в том, что когда каждый фильм поступает в БД (новый фильм), вы можете добавить их каждому пользователю с типом действия not-actioned-yet. И теперь для всех пользователей вы можете запросить их очень легко и очень быстро. (Теперь он знает, где находятся данные;)) Но это не правильно, потому что если есть 10.000 пользователей, то для каждого фильма вы делаете 10.000 записей.

Другой подход может заключаться в том, что у вас есть элемент в таблице, в котором хранится дата последнего запроса пользователя «получить список еще не выполненных действий». Теперь, через некоторое время, пользователь возвращается по тому же запросу, и теперь вам нужно прочитать эту дату и получить все фильмы, которые добавлены в вашу БД после этой даты. С датами и временем в качестве ключей сортировки вы можете запрашивать фильмы, начиная с этой даты. Допустим, после последнего запроса пользователей добавлено 10 фильмов (это определенно еще не выполненные действия пользователя). Теперь вы добавляете эти 10 фильмов в таблицу как элемент not-actioned-yet. После этого у вас будут все фильмы, которые пользователь еще не снимал. «not-actioned-while» также типа «нравится, не нравится». Отныне вы можете легко их запрашивать.

Пример структуры таблицы:

Вы можете использовать разреженные индексы или подход таблицы временных рядов , чтобы отделить новые фильмы (в следующие 2 недели) от других. Таким образом, вы запрашиваете или сканируете только их эффективно. Идем с разреженными индексами здесь

Кино стол

| Id (Hash Key|Primary Key) | StartingDateUnix(GSI SK) | IsIn2Weeks (GSI) |
|:-------------------------:|-------------------------:|:----------------:|
| MovieId1                  |        1234567           |     1     
| MovieId2                  |        1234568           |     1    
| MovieId3                  |        001123            |     null     

Чтобы получить фильмы после unix 1234567, вам нужно запросить GSI с ключом сортировки, превышающим время unix.

Таблица действий пользователя

| UserId (Hash Key) | ActionType_ForMovie(Sort Key) | CreatedAt (LSI) |
|:-----------------:|:-----------------------------:|:---------------:|
| UserId1           |       no-action::MovieId1     |      1234567    |
| UserId1           |       no-action::MovieId2     |      1234568    |   
| UserId1           |       like::MovieId3          |      1234569    | 
| UserId1           |       like::MovieId4          |      1234561    |     
| UserId1           |       dislike::MovieId5       |      1234562    |   

Используя ключи сортировки, вы можете запрашивать все неприязни, которые еще не выполнены ... и вы можете сортировать их по датам. Вы также можете разбивать на страницы.

Я потратил некоторое время на эту проблему, потому что это также хороший вызов для меня, и я был бы признателен за обратную связь. Надеюсь, это поможет каким-то образом

...