public void TestIndexing() { List<ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> entries = new List<ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId>() { new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(3, new MalListEntry(1, CompletionStatus.Completed, 3)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(1, new MalListEntry(2, CompletionStatus.Completed, 1)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(9, new MalListEntry(3, CompletionStatus.Completed, 9)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(25, new MalListEntry(4, CompletionStatus.Completed, 25)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(2, new MalListEntry(5, CompletionStatus.Completed, 2)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(6, new MalListEntry(6, CompletionStatus.Completed, 6)) }; ReadOnlyMalListEntryDictionary dict = new ReadOnlyMalListEntryDictionary(entries); Assert.That(dict[3].NumEpisodesWatched, Is.EqualTo(3)); Assert.That(dict[1].NumEpisodesWatched, Is.EqualTo(1)); Assert.That(dict[9].NumEpisodesWatched, Is.EqualTo(9)); Assert.That(dict[25].NumEpisodesWatched, Is.EqualTo(25)); Assert.That(dict[2].NumEpisodesWatched, Is.EqualTo(2)); Assert.That(dict[6].NumEpisodesWatched, Is.EqualTo(6)); }
public void TestIndexing() { List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> entries = new List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId>() { new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(3, new MalListEntry(1, CompletionStatus.Completed, 3)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(1, new MalListEntry(2, CompletionStatus.Completed, 1)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(9, new MalListEntry(3, CompletionStatus.Completed, 9)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(25, new MalListEntry(4, CompletionStatus.Completed, 25)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(2, new MalListEntry(5, CompletionStatus.Completed, 2)), new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId(6, new MalListEntry(6, CompletionStatus.Completed, 6)) }; ReadOnlyMalListEntryDictionary dict = new ReadOnlyMalListEntryDictionary(entries); Assert.Equal(3, dict[3].NumEpisodesWatched); Assert.Equal(1, dict[1].NumEpisodesWatched); Assert.Equal(9, dict[9].NumEpisodesWatched); Assert.Equal(25, dict[25].NumEpisodesWatched); Assert.Equal(2, dict[2].NumEpisodesWatched); Assert.Equal(6, dict[6].NumEpisodesWatched); }
public MalTrainingData LoadMalTrainingData() { // Load all anime, then all users, then all entries Dictionary<int, mal_user> dbUsers = new Dictionary<int, mal_user>(); Logging.Log.Debug("Slurping anime from the database."); IEnumerable<mal_anime> dbAnimeSlurp = mal_anime.GetAll(m_conn, transaction: null); Logging.Log.Debug("Processing anime from the database."); Dictionary<int, MalAnime> animes = new Dictionary<int, MalAnime>(dbAnimeSlurp.Count()); foreach (mal_anime dbAnime in dbAnimeSlurp) { MalAnime anime = new MalAnime( malAnimeId: dbAnime.mal_anime_id, type: (MalAnimeType)dbAnime.mal_anime_type_id, title: dbAnime.title ); animes[dbAnime.mal_anime_id] = anime; } Logging.Log.DebugFormat("Done processing {0} anime from the database.", animes.Count); Logging.Log.Debug("Slurping users from the database."); IEnumerable<mal_user> dbUserSlurp = mal_user.GetAll(m_conn, transaction: null); Logging.Log.Debug("Processing users from the database."); foreach (mal_user dbUser in dbUserSlurp) { dbUsers[dbUser.mal_user_id] = dbUser; } Logging.Log.DebugFormat("Done processing {0} users from the database.", dbUsers.Count); string allEntriesSlimSql = @" SELECT mal_user_id, mal_anime_id, rating, mal_list_entry_status_id, num_episodes_watched FROM mal_list_entry "; Logging.Log.Debug("Slurping list entries from the database."); // Do not buffer list entries IEnumerable<mal_list_entry_slim> dbEntrySlurp = m_conn.Query<mal_list_entry_slim>(allEntriesSlimSql, buffered: false, commandTimeout: 60); Logging.Log.Debug("Processing list entries from the database."); long entryCount = 0; Dictionary<int, List<ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId>> entriesByUser = new Dictionary<int, List<ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId>>(); foreach (mal_list_entry_slim dbEntry in dbEntrySlurp) { entryCount++; mal_user dbUser; if (!dbUsers.TryGetValue(dbEntry.mal_user_id, out dbUser) || !animes.ContainsKey(dbEntry.mal_anime_id)) { // Entry for an anime or user that wasn't in the database...there must have been an update going on between the time we got users, anime, and list entries continue; } List<ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> animeList; if (!entriesByUser.TryGetValue(dbEntry.mal_user_id, out animeList)) { animeList = new List<ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId>(); entriesByUser[dbEntry.mal_user_id] = animeList; } animeList.Add(new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId( animeId: dbEntry.mal_anime_id, entry: new MalListEntry( rating: (byte?)dbEntry.rating, status: (CompletionStatus)dbEntry.mal_list_entry_status_id, numEpisodesWatched: dbEntry.num_episodes_watched ) )); } Dictionary<int, MalUserListEntries> users = new Dictionary<int, MalUserListEntries>(dbUserSlurp.Count()); foreach (int userId in entriesByUser.Keys) { List<ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> animeList = entriesByUser[userId]; animeList.Capacity = animeList.Count; ReadOnlyMalListEntryDictionary listEntries = new ReadOnlyMalListEntryDictionary(animeList); users[userId] = new MalUserListEntries(listEntries, animes, dbUsers[userId].mal_name, okToRecommendPredicate: null); } Logging.Log.DebugFormat("Done processing {0} list entries.", entryCount); return new MalTrainingData(users, animes); }
public async Task <MalTrainingData> LoadMalTrainingDataAsync(CancellationToken cancellationToken) { // Load all anime, users, and entries in parallel, then combine them into training data. try { Dictionary <int, MalAnime> animes; Dictionary <int, mal_user> dbUsers; IList <mal_list_entry_slim> dbEntrySlurp; using (CancellationTokenSource faultCanceler = new CancellationTokenSource()) using (CancellationTokenSource faultOrUserCancel = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, faultCanceler.Token)) { Task <Dictionary <int, MalAnime> > animeTask = AsyncUtils.EnsureExceptionsWrapped( () => SlurpAnimeAsync(faultOrUserCancel.Token)); CancellableTask cancellableAnimeTask = new CancellableTask(animeTask, faultCanceler); Task <Dictionary <int, mal_user> > userTask = AsyncUtils.EnsureExceptionsWrapped( () => SlurpUsersAsync(faultOrUserCancel.Token)); CancellableTask cancellableUserTask = new CancellableTask(userTask, faultCanceler); Task <IList <mal_list_entry_slim> > entryTask = AsyncUtils.EnsureExceptionsWrapped( () => SlurpEntriesAsync(faultOrUserCancel.Token)); CancellableTask cancellableEntryTask = new CancellableTask(entryTask, faultCanceler); await AsyncUtils.WhenAllCancelOnFirstExceptionDontWaitForCancellations(cancellableEntryTask, cancellableAnimeTask, cancellableUserTask).ConfigureAwait(false); animes = animeTask.Result; dbUsers = userTask.Result; dbEntrySlurp = entryTask.Result; } Logging.Log.Debug("Processing list entries from the database."); long entryCount = 0; Dictionary <int, List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> > entriesByUser = new Dictionary <int, List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> >(); foreach (mal_list_entry_slim dbEntry in dbEntrySlurp) { entryCount++; mal_user dbUser; if (!dbUsers.TryGetValue(dbEntry.mal_user_id, out dbUser) || !animes.ContainsKey(dbEntry.mal_anime_id)) { // Entry for an anime or user that wasn't in the database...there must have been an update going on between the time we got users, anime, and list entries continue; } List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> animeList; if (!entriesByUser.TryGetValue(dbEntry.mal_user_id, out animeList)) { animeList = new List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId>(); entriesByUser[dbEntry.mal_user_id] = animeList; } animeList.Add(new ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId( animeId: dbEntry.mal_anime_id, entry: new MalListEntry( rating: (byte?)dbEntry.rating, status: (CompletionStatus)dbEntry.mal_list_entry_status_id, numEpisodesWatched: dbEntry.num_episodes_watched ) )); } Dictionary <int, MalUserListEntries> users = new Dictionary <int, MalUserListEntries>(dbUsers.Count); foreach (int userId in entriesByUser.Keys) { List <ReadOnlyMalListEntryDictionary.ListEntryAndAnimeId> animeList = entriesByUser[userId]; animeList.Capacity = animeList.Count; ReadOnlyMalListEntryDictionary listEntries = new ReadOnlyMalListEntryDictionary(animeList); users[userId] = new MalUserListEntries(listEntries, animes, dbUsers[userId].mal_name, okToRecommendPredicate: null); } Logging.Log.DebugFormat("Done processing {0} list entries.", entryCount); return(new MalTrainingData(users, animes)); } catch (Exception ex) when(!(ex is OperationCanceledException)) { throw new Exception(string.Format("Error loading MAL training data: {0}", ex.Message), ex); } }