public async Task <int> GenerateRecommendation(RecommendationParameters parameters) { var context = new Database.DatabaseContext(_dbContextOptions); var recommendedMovieIds = await GetRecommendedMovieIds(context, parameters); var recommendation = new Database.Recommendation() { Date = DateTime.Now, UserId = parameters.UserId }; context.Add(recommendation); await context.SaveChangesAsync(); var recommendedMovies = recommendedMovieIds.Select(rm => new Database.RecommendedMovie() { RecommendationId = recommendation.Id, MovieId = rm, PossibleRating = 0.0f, }); context.AddRange(recommendedMovies); await context.SaveChangesAsync(); return(0); }
public int Add(RecommendationParameters parameters) { var id = GetNewRecommendationId(); var hash = new HashEntry[] { new HashEntry("recommendationParameters", JsonConvert.SerializeObject(parameters)), new HashEntry("status", (int)RecommendationStatus.Queued), new HashEntry("startTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture)), }; DataBase.HashSet($"recommendation:{id}", hash); return(id); }
public int Add(RecommendationParameters parameters) { var recommendation = new QueuedRecommendation { Id = GetNewRecommendationId(), RecommendationParameters = parameters, Status = Database.RecommendationStatus.Queued, StartTime = DateTime.Now }; _recommendations.Add(recommendation); return(recommendation.Id); }
public async Task <int> GenerateRecommendation(RecommendationParameters parameters) { var context = new Database.DatabaseContext(_dbContextOptions); var recommendedMovies = ( from movies in context.Movies join tags in context.MovieTags on movies.Id equals tags.MovieId where parameters.RequestedTagIds.Contains(tags.TagId) select new { movies.Id, Rating = movies.AverageRating, } ).Distinct().OrderByDescending(movie => movie.Rating).Take(10); if (recommendedMovies.Count() == 0) { return(0); } var recommendation = new Database.Recommendation() { UserId = parameters.UserId, }; context.Recommendations.Attach(recommendation); context.Recommendations.Add(recommendation); await context.SaveChangesAsync(); foreach (var movie in await recommendedMovies.ToListAsync()) { var recommendedMovie = new Database.RecommendedMovie() { MovieId = movie.Id, PossibleRating = movie.Rating, RecommendationId = recommendation.Id, }; context.RecommendedMovies.Attach(recommendedMovie); context.RecommendedMovies.Add(recommendedMovie); } await context.SaveChangesAsync(); context.Dispose(); return(recommendation.Id); }
private bool[] CreateSimilarityMatrixFilter( double[][] similarityMatrix, int[] movieIds, Database.DatabaseContext context, RecommendationParameters parameters, IEnumerable <UserMovie> userMovies) { var movies = context.Movies.Include(m => m.Tags).ToArray(); var isSimilarityAllowedFilters = new bool[similarityMatrix.GetLength(0)]; var userMovieIds = userMovies.Select(um => um.Id).ToHashSet(); for (int i = 0; i < movieIds.Length; i++) { var movieId = movieIds[i]; var movie = movies.First(m => m.Id == movieId); isSimilarityAllowedFilters[i] = DoesMovieContainTags(movie, parameters.RequestedTagIds) && !userMovieIds.Contains(movieId); } return(isSimilarityAllowedFilters); }
private IQueryable <int> GetMostPopularMovies(Database.DatabaseContext context, RecommendationParameters parameters) => context.Movies.Include(m => m.Tags) .Where(m => DoesMovieContainTags(m.Tags.Select(t => t.TagId), parameters.RequestedTagIds)) .Select(m => m.Id) .Take(RecommendedMovieLimit);
private IQueryable <UserMovie> GetUserMoviesByGenres(Database.DatabaseContext context, RecommendationParameters parameters) => context.UserMovies.Include(um => um.Movie.Tags) .Where(um => um.UserId == parameters.UserId && DoesMovieContainTags(um.Movie.Tags.Select(t => t.TagId), parameters.RequestedTagIds)) .Select(um => new UserMovie { Id = um.MovieId, Rating = um.Rating });
private async Task <IEnumerable <int> > GetRecommendedMovieIds(Database.DatabaseContext context, RecommendationParameters parameters) { if (!_cache.IsPopulated) { await PrepareData(); } var movieIds = _cache.RetrieveMovieIdsFromCache(); var similarityMatrix = _cache.RetrieveSimilarityMatrixFromCache(movieIds); var userMovies = GetUserMoviesByGenres(context, parameters); if (userMovies.Count() == 0) { userMovies = GetUserMovies(context); } if (userMovies.Count() == 0) { return(GetMostPopularMovies(context, parameters)); } // Limit matrix to only include requested tags and exclude user movies var isSimilarityAllowedFilters = CreateSimilarityMatrixFilter(similarityMatrix, movieIds, context, parameters, userMovies); // Gather the most similar movies var allSimilarities = new List <SimilarityObject>(); foreach (var userMovie in userMovies) { var movieIndex = FindMovieIndex(movieIds, userMovie.Id); // Weight similarities by how good the movies are rated and include indicies in selection var similarities = similarityMatrix[movieIndex] .Select((s, index) => new SimilarityObject { Similarity = s * (userMovie.Rating / 10), Index = index }) .Where(s => isSimilarityAllowedFilters[s.Index]) .OrderByDescending(s => s.Similarity) .Take(RecommendedMovieLimit); allSimilarities.AddRange(similarities); } var equalityComparer = new SimilarityObjectComparer(); // Get top recommended movie ids var userMoviesIds = userMovies.Select(um => um.Id); return(allSimilarities .Distinct(equalityComparer) .Where(id => !userMoviesIds.Contains(id.Index)) .OrderByDescending(s => s.Similarity) .Take(RecommendedMovieLimit) .Select(s => movieIds[s.Index])); }