public Task AddViewAsync(string space, string itemId, string userId) { if (string.IsNullOrEmpty(itemId)) { throw new ArgumentNullException("itemId"); } // Writing to all required key families const SignalType signal = SignalType.View; DateTime dateTime = DateTime.UtcNow; var tasks = new List<Task>(); // 1. Item and user relations // Building composite row key to isolated different spaces of statistics string itemRowKey = BuildGlobalId(space, itemId); // Item cumulative counts tasks.Add(_itemCountsRepository.IncViewsAsync(itemRowKey)); if (!string.IsNullOrEmpty(userId)) { // Building composite row key to isolated different spaces of statistics string userRowKey = BuildGlobalId(space, userId); // User cumulative counts tasks.Add(_userCountsRepository.IncViewsAsync(userRowKey)); // Users who viewed an item tasks.Add(_itemSignalsRepository.AddAsync(new ItemSignalsInsertDeleteOptions { ItemId = itemRowKey, UserId = userId, DateTime = dateTime, Signal = signal })); // User viewed items tasks.Add(Task.Run(() => { // add new view signal var addTasks = new List<Task>(); var userSignal = new UserSignalsInsertDeleteOptions { ItemId = itemId, UserId = userRowKey, DateTime = dateTime, Signal = signal }; addTasks.Add(_userSignalsRepository.AddAsync(userSignal)); addTasks.Add(_userSignalsUnorderedRepository.AddAsync(userSignal)); return Task.WhenAll(addTasks); })); } // 2. Affinity groups IEnumerable<string> affinityGroups = BuildAffinityGroups(dateTime); foreach (string affinityGroup in affinityGroups) { // Building composite row keys to isolated different spaces of statistics string groupId = BuildGlobalId(space, affinityGroup); // Affinity group most viewed tasks.Add(Task.Run(async () => { // getting current version of most viewed items AffinityGroupMostSignaledVersionEntity currentVersion = await _affinityGroupMostSignaledVersionRepository.GetAsync(groupId, signal); // getting item counts IEnumerable<AffinityGroupItemCountsEntity> itemCounts = await _affinityGroupItemCountsRepository.GetSequenceAsync(groupId, signal, 1000); // building new version of most viewed items Dictionary<string, AffinityGroupItemCountsEntity> itemCountsDict = itemCounts.ToDictionary(i => i.ItemId); var insertOptions = new List<AffinityGroupMostSignaledInsertOptions>(); foreach (var i in itemCountsDict) { var insertItem = new AffinityGroupMostSignaledInsertOptions { ItemId = i.Key, Count = i.Value.Count }; if (insertItem.ItemId == itemId) { insertItem.Count = insertItem.Count + 1; } insertOptions.Add(insertItem); } // ensuring current item if (!itemCountsDict.ContainsKey(itemId)) { insertOptions.Add(new AffinityGroupMostSignaledInsertOptions { ItemId = itemId, Count = 1 }); } await _affinityGroupMostSignaledRepository.AddAsync(groupId, signal, currentVersion.Version + 1, insertOptions); // incrementing counter of itemId await _affinityGroupItemCountsRepository.IncAsync(groupId, signal, itemId); // incrementing version await _affinityGroupMostSignaledVersionRepository.UpdateAsync(groupId, signal, currentVersion.Version + 1); })); // incrementing affinity group cumulative counts tasks.Add(_affinityGroupCountsRepository.IncAsync(groupId, signal)); } // 3. Time series string eventId = BuildTimeSeriesRowKey(itemRowKey, signal); // Rollups var rollupOptions = new TimeSeriesRollupsInsertOptions { EventId = eventId, DateTime = dateTime }; // Rollups for days tasks.Add(_timeSeriesRollupsDayRepository.IncAsync(rollupOptions)); // Rollups for hour tasks.Add(_timeSeriesRollupsHourRepository.IncAsync(rollupOptions)); // Rollups for minute tasks.Add(_timeSeriesRollupsMinuteRepository.IncAsync(rollupOptions)); return Task.WhenAll(tasks); }
public async Task DeleteDislikeAsync(string space, string itemId, string userId) { if (string.IsNullOrEmpty(itemId)) { throw new ArgumentNullException("itemId"); } if (string.IsNullOrEmpty(userId)) { throw new ArgumentNullException("userId"); } // Writing to all required key families const SignalType signal = SignalType.Dislike; DateTime dateTime = DateTime.UtcNow; var tasks = new List<Task>(); // 1. Item and user relations // Building composite row key to isolated different spaces of statistics string itemRowKey = BuildGlobalId(space, itemId); string userRowKey = BuildGlobalId(space, userId); // Item cumulative counts tasks.Add(_itemCountsRepository.DecDislikesAsync(itemRowKey)); // User cumulative counts tasks.Add(_userCountsRepository.DecDislikesAsync(userRowKey)); // User dislikes tasks.Add(Task.Run(() => { // cancel dislike var deleteTasks = new List<Task>(); var deleteOptions = new UserSignalsInsertDeleteOptions { ItemId = itemId, Signal = signal, UserId = userRowKey, DateTime = dateTime }; deleteTasks.Add(_userSignalsUnorderedRepository.DeleteAsync(deleteOptions)); deleteTasks.Add(_userSignalsRepository.DeleteAsync(deleteOptions)); return Task.WhenAll(deleteTasks); })); // Users who disliked an item tasks.Add(_itemSignalsRepository.DeleteAsync(new ItemSignalsInsertDeleteOptions { ItemId = itemRowKey, UserId = userId, Signal = signal, DateTime = dateTime })); // 2. Affinity groups IEnumerable<string> affinityGroups = BuildAffinityGroups(dateTime); foreach (string affinityGroup in affinityGroups) { // Building composite row keys to isolated different spaces of statistics string groupId = BuildGlobalId(space, affinityGroup); // Affinity group most liked tasks.Add(Task.Run(async () => { // getting current version of most signaled items AffinityGroupMostSignaledVersionEntity currentVersion = await _affinityGroupMostSignaledVersionRepository.GetAsync(groupId, signal); // getting item counts IEnumerable<AffinityGroupItemCountsEntity> itemCounts = await _affinityGroupItemCountsRepository.GetSequenceAsync(groupId, signal, 1000); // building new version of most liked Dictionary<string, AffinityGroupItemCountsEntity> itemCountsDict = itemCounts.ToDictionary(i => i.ItemId); var insertOptions = new List<AffinityGroupMostSignaledInsertOptions>(); foreach (var i in itemCountsDict) { var insertItem = new AffinityGroupMostSignaledInsertOptions { ItemId = i.Key, Count = i.Value.Count }; if (insertItem.ItemId == itemId) { insertItem.Count = insertItem.Count - 1; } insertOptions.Add(insertItem); } await _affinityGroupMostSignaledRepository.AddAsync(groupId, signal, currentVersion.Version + 1, insertOptions); // decrementing counter of itemId await _affinityGroupItemCountsRepository.DecAsync(groupId, signal, itemId); // incrementing version await _affinityGroupMostSignaledVersionRepository.UpdateAsync(groupId, signal, currentVersion.Version + 1); })); // decrementing affinity group cumulative counts tasks.Add(_affinityGroupCountsRepository.DecAsync(groupId, signal)); } await Task.WhenAll(tasks); }