Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/cdms 200 decision analytics #21

Merged
merged 5 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Btms.Analytics.Tests/Helpers/MultiSeriesDatasetAssertions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

namespace Btms.Analytics.Tests.Helpers;

public class MultiSeriesDatasetAssertions(List<MultiSeriesDataset>? test)
: GenericCollectionAssertions<MultiSeriesDataset>(test)
public class MultiSeriesDatasetAssertions(List<Series>? test)
: GenericCollectionAssertions<Series>(test)
{
[CustomAssertion]
public void BeSameLength(string because = "", params object[] becauseArgs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Btms.Analytics.Tests.Helpers;

public class SingleSeriesDatasetAssertions(SingeSeriesDataset? test)
public class SingleSeriesDatasetAssertions(SingleSeriesDataset? test)
{
[CustomAssertion]
public void HaveResults(string because = "", params object[] becauseArgs)
Expand Down
4 changes: 2 additions & 2 deletions Btms.Analytics.Tests/Helpers/TestAssertionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ namespace Btms.Analytics.Tests.Helpers;

public static class TestAssertionExtensions
{
public static MultiSeriesDatasetAssertions Should(this List<MultiSeriesDataset>? instance)
public static MultiSeriesDatasetAssertions Should(this List<Series>? instance)
{
return new MultiSeriesDatasetAssertions(instance);
}
public static SingleSeriesDatasetAssertions Should(this SingeSeriesDataset? instance)
public static SingleSeriesDatasetAssertions Should(this SingleSeriesDataset? instance)
{
return new SingleSeriesDatasetAssertions(instance);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public async Task WhenCalledNextMonth_ReturnExpectedAggregation()

var result = (await basicSampleDataTestFixture.ImportNotificationsAggregationService
.ByArrival(DateTime.Today, DateTime.Today.MonthLater()))
.Series
.ToList();

testOutputHelper.WriteLine($"{result.Count} aggregated items found");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public async Task WhenCalledLastWeek_ReturnExpectedAggregation()
testOutputHelper.WriteLine("Querying for aggregated data");
var result = (await multiItemDataTestFixture.ImportNotificationsAggregationService
.ByCommodityCount(DateTime.Today.WeekAgo(), DateTime.Today.Tomorrow()))
.Series
.ToList();

testOutputHelper.WriteLine("{0} aggregated items found", result.Count);
Expand Down
3 changes: 3 additions & 0 deletions Btms.Analytics.Tests/ImportNotificationsByCreatedDateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public async Task WhenCalledLast48Hours_ReturnExpectedAggregation()
{
var result = (await basicSampleDataTestFixture.ImportNotificationsAggregationService
.ByCreated(DateTime.Now.NextHour().AddDays(-2), DateTime.Now.NextHour(),AggregationPeriod.Hour))
.Series
.ToList();

testOutputHelper.WriteLine(result.ToJsonString());
Expand All @@ -36,6 +37,7 @@ public async Task WhenCalledLastMonth_ReturnExpectedAggregation()
{
var result = (await basicSampleDataTestFixture.ImportNotificationsAggregationService
.ByCreated(DateTime.Today.MonthAgo(), DateTime.Today.Tomorrow()))
.Series
.ToList();

testOutputHelper.WriteLine(result.ToJsonString());
Expand Down Expand Up @@ -63,6 +65,7 @@ public async Task WhenCalledWithTimePeriodYieldingNoResults_ReturnEmptyAggregati

var result = (await basicSampleDataTestFixture.ImportNotificationsAggregationService
.ByCreated(from, to, AggregationPeriod.Hour))
.Series
.ToList();

testOutputHelper.WriteLine(result.ToJsonString());
Expand Down
28 changes: 28 additions & 0 deletions Btms.Analytics.Tests/MovementHistoryTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using Btms.Common.Extensions;
using Xunit;
using Xunit.Abstractions;

using Btms.Analytics.Tests.Fixtures;
using Btms.Analytics.Tests.Helpers;
using FluentAssertions;

namespace Btms.Analytics.Tests;

[Collection(nameof(MultiItemDataTestCollection))]
public class MovementHistoryTests(
MultiItemDataTestFixture multiItemDataTestFixture,
ITestOutputHelper testOutputHelper)
{
[Fact]
public async Task WhenCalled_ReturnsHistory()
{
testOutputHelper.WriteLine("Querying for history");
var result = await multiItemDataTestFixture.MovementsAggregationService
.GetHistory("23GB9999001215000001");

testOutputHelper.WriteLine("{0} history items found", result.Items.Count());

result.Items.Should().HasValue();
result.Items.Select(a => a.AuditEntry.CreatedSource).Should().BeInAscendingOrder();
}
}
3 changes: 3 additions & 0 deletions Btms.Analytics.Tests/MovementsByCreatedDateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public async Task WhenCalledLast48Hours_ReturnExpectedAggregation()
{
var result = (await basicSampleDataTestFixture.MovementsAggregationService
.ByCreated(DateTime.Now.NextHour().AddDays(-2), DateTime.Now.NextHour(), AggregationPeriod.Hour))
.Series
.ToList();

testOutputHelper.WriteLine(result.ToJsonString());
Expand All @@ -38,6 +39,7 @@ public async Task WhenCalledWithTimePeriodYieldingNoResults_ReturnEmptyAggregati

var result = (await basicSampleDataTestFixture.MovementsAggregationService
.ByCreated(from, to, AggregationPeriod.Hour))
.Series
.ToList();

testOutputHelper.WriteLine(result.ToJsonString());
Expand All @@ -62,6 +64,7 @@ public async Task WhenCalledLastMonth_ReturnExpectedAggregation()
{
var result = (await basicSampleDataTestFixture.MovementsAggregationService
.ByCreated(DateTime.Today.MonthAgo(), DateTime.Today.Tomorrow()))
.Series
.ToList();

testOutputHelper.WriteLine(result.ToJsonString());
Expand Down
1 change: 1 addition & 0 deletions Btms.Analytics.Tests/MovementsByItemsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public async Task WhenCalledLastWeek_ReturnExpectedAggregation()
testOutputHelper.WriteLine("Querying for aggregated data");
var result = (await multiItemDataTestFixture.MovementsAggregationService
.ByItemCount(DateTime.Today.WeekAgo(), DateTime.Today.Tomorrow()))
.Series
.ToList();

testOutputHelper.WriteLine("{0} aggregated items found", result.Count);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public async Task WhenCalledLastWeek_ReturnExpectedAggregation()
testOutputHelper.WriteLine("Querying for aggregated data");
var result = (await multiItemDataTestFixture.MovementsAggregationService
.ByUniqueDocumentReferenceCount(DateTime.Today.WeekAgo(), DateTime.Today.Tomorrow()))
.Series
.ToList();

testOutputHelper.WriteLine("{0} aggregated items found", result.Count);
Expand Down
31 changes: 23 additions & 8 deletions Btms.Analytics/Extensions/AnalyticsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static IServiceCollection AddAnalyticsServices(this IServiceCollection se
return services;
}

public static string MetricsKey(this MultiSeriesDatetimeDataset ds)
public static string MetricsKey(this DatetimeSeries ds)
{
return ds.Name.Replace(" ", "-").ToLower();
}
Expand Down Expand Up @@ -64,17 +64,15 @@ public static Dictionary<DateTime, int> GetNamedSetAsDict(this Dictionary<string
: [];
}

public static MultiSeriesDatetimeDataset AsDataset(this Dictionary<string, BsonDocument> records, DateTime[] dateRange, string title)
public static DatetimeSeries AsDataset(this Dictionary<string, BsonDocument> records, DateTime[] dateRange,
string title)
{
var dates = records.GetNamedSetAsDict(title);
return new MultiSeriesDatetimeDataset(title)
return new DatetimeSeries(title)
{
Periods = dateRange
.Select(resultDate =>
new ByDateTimeResult
{
Period = resultDate, Value = dates.GetValueOrDefault(resultDate, 0)
})
new ByDateTimeResult { Period = resultDate, Value = dates.GetValueOrDefault(resultDate, 0) })
.Order(AnalyticsHelpers.ByDateTimeResultComparer)
.ToList()
};
Expand All @@ -89,7 +87,6 @@ public static T[] AsOrderedArray<T, TKey>(this IEnumerable<T> en, Func<T, TKey>

internal static IEnumerable<IGrouping<TKey, TSource>> Execute<TSource, TKey>(this IQueryable<IGrouping<TKey, TSource>> source, ILogger logger)
{

try
{
var aggregatedData = source.ToList();
Expand Down Expand Up @@ -138,4 +135,22 @@ private static void LogExecutedMongoString(this ILogger logger, IQueryable sourc

logger.LogInformation("[{Query}]", string.Join(",", stages.Select(s => s.ToString()).ToArray()));
}

public static async Task<IDataset> AsIDataset(this Task<MultiSeriesDatetimeDataset> ms)
{
await ms;
return (IDataset)ms.Result;
}

public static async Task<IDataset> AsIDataset(this Task<MultiSeriesDataset> ms)
{
await ms;
return (IDataset)ms.Result;
}

public static async Task<IDataset> AsIDataset(this Task<SingleSeriesDataset> ms)
{
await ms;
return (IDataset)ms.Result;
}
}
8 changes: 4 additions & 4 deletions Btms.Analytics/IImportNotificationsAggregationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ namespace Btms.Analytics;

public interface IImportNotificationsAggregationService
{
public Task<MultiSeriesDatetimeDataset[]> ByCreated(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day);
public Task<MultiSeriesDatetimeDataset[]> ByArrival(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day);
public Task<SingeSeriesDataset> ByStatus(DateTime from, DateTime to);
public Task<MultiSeriesDataset[]> ByCommodityCount(DateTime from, DateTime to);
public Task<MultiSeriesDatetimeDataset> ByCreated(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day);
public Task<MultiSeriesDatetimeDataset> ByArrival(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day);
public Task<SingleSeriesDataset> ByStatus(DateTime from, DateTime to);
public Task<MultiSeriesDataset> ByCommodityCount(DateTime from, DateTime to);
}
14 changes: 9 additions & 5 deletions Btms.Analytics/IMovementsAggregationService.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using Btms.Model.Auditing;

namespace Btms.Analytics;

public interface IMovementsAggregationService
{
public Task<MultiSeriesDatetimeDataset[]> ByCreated(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day);
public Task<SingeSeriesDataset> ByStatus(DateTime from, DateTime to);
public Task<MultiSeriesDataset[]> ByItemCount(DateTime from, DateTime to);
public Task<MultiSeriesDataset[]> ByUniqueDocumentReferenceCount(DateTime from, DateTime to);
public Task<SingeSeriesDataset> UniqueDocumentReferenceByMovementCount(DateTime from, DateTime to);
public Task<MultiSeriesDatetimeDataset> ByCreated(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day);
public Task<SingleSeriesDataset> ByStatus(DateTime from, DateTime to);
public Task<MultiSeriesDataset> ByItemCount(DateTime from, DateTime to);
public Task<MultiSeriesDataset> ByUniqueDocumentReferenceCount(DateTime from, DateTime to);
public Task<SingleSeriesDataset> UniqueDocumentReferenceByMovementCount(DateTime from, DateTime to);
public Task<MultiSeriesDataset> ByCheck(DateTime from, DateTime to);
public Task<EntityDataset<AuditHistory>> GetHistory(string movementId);
}
6 changes: 3 additions & 3 deletions Btms.Analytics/ImportNotificationMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ public async Task RecordCurrentState()
{
var metrics = await _importService.ByCreated(DateTime.Today, DateTime.Now.NextHour());

foreach (var dataset in metrics)
foreach (var series in metrics.Series)
{
var key = $"{AnalyticsMetricNames.MetricPrefix}.import-notifications.{dataset.MetricsKey()}.count";
var key = $"{AnalyticsMetricNames.MetricPrefix}.import-notifications.{series.MetricsKey()}.count";
if (_metrics.TryGetValue(key, out var instrument))
{
if (instrument is Gauge<int> g)
{
g.Record(dataset.Periods[0].Value);
g.Record(series.Periods[0].Value);
}
else
{
Expand Down
31 changes: 14 additions & 17 deletions Btms.Analytics/ImportNotificationsAggregationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace Btms.Analytics;

public class ImportNotificationsAggregationService(IMongoDbContext context, ILogger<ImportNotificationsAggregationService> logger) : IImportNotificationsAggregationService
{
public Task<MultiSeriesDatetimeDataset[]> ByCreated(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day)
public Task<MultiSeriesDatetimeDataset> ByCreated(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day)
{
var dateRange = AnalyticsHelpers.CreateDateRange(from, to, aggregateBy);

Expand All @@ -25,7 +25,7 @@ string CreateDatasetName(BsonDocument b) =>
return Aggregate(dateRange, CreateDatasetName, matchFilter, "$createdSource", aggregateBy);
}

public Task<MultiSeriesDatetimeDataset[]> ByArrival(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day)
public Task<MultiSeriesDatetimeDataset> ByArrival(DateTime from, DateTime to, AggregationPeriod aggregateBy = AggregationPeriod.Day)
{
var dateRange = AnalyticsHelpers.CreateDateRange(from, to, aggregateBy);

Expand All @@ -38,7 +38,7 @@ string CreateDatasetName(BsonDocument b) =>
return Aggregate(dateRange, CreateDatasetName, matchFilter, "$partOne.arrivesAt", aggregateBy);
}

public Task<SingeSeriesDataset> ByStatus(DateTime from, DateTime to)
public Task<SingleSeriesDataset> ByStatus(DateTime from, DateTime to)
{
var data = context
.Notifications
Expand All @@ -48,13 +48,13 @@ public Task<SingeSeriesDataset> ByStatus(DateTime from, DateTime to)
.ToDictionary(g => AnalyticsHelpers.GetLinkedName(g.Linked, g.ImportNotificationType.AsString()),
g => g.Count);

return Task.FromResult(new SingeSeriesDataset
return Task.FromResult(new SingleSeriesDataset
{
Values = AnalyticsHelpers.GetImportNotificationSegments().ToDictionary(title => title, title => data.GetValueOrDefault(title, 0))
});
}

public Task<MultiSeriesDataset[]> ByCommodityCount(DateTime from, DateTime to)
public Task<MultiSeriesDataset> ByCommodityCount(DateTime from, DateTime to)
{
var query = context
.Notifications
Expand All @@ -72,8 +72,6 @@ public Task<MultiSeriesDataset[]> ByCommodityCount(DateTime from, DateTime to)
.GroupBy(r => new { r.Key.ImportNotificationType, r.Key.Linked })
.ToList();

// var maxCommodities = result.Max(r => r.Max(i => i.Key.CommodityCount));

var maxCommodities = result.Count > 0 ?
result.Max(r => r.Any() ? r.Max(i => i.Key.CommodityCount) : 0) : 0;

Expand All @@ -94,24 +92,23 @@ public Task<MultiSeriesDataset[]> ByCommodityCount(DateTime from, DateTime to)
g => g.NotificationCount);


return Task.FromResult(
AnalyticsHelpers.GetImportNotificationSegments()
.Select(title => new MultiSeriesDataset(title, "ItemCount")
return Task.FromResult(new MultiSeriesDataset()
{
Series = AnalyticsHelpers.GetImportNotificationSegments()
.Select(title => new Series(title, "ItemCount")
{
// Results = asDictionary.AsResultList(title, maxCommodities)
Results = Enumerable.Range(0, maxCommodities)
.Select(i => new ByNumericDimensionResult
{
Dimension = i,
Value = asDictionary.GetValueOrDefault(new { Title=title, CommodityCount = i })
}).ToList()
}
)
.AsOrderedArray(d => d.Name)
);
})
.ToList()
});
}

private Task<MultiSeriesDatetimeDataset[]> Aggregate(DateTime[] dateRange, Func<BsonDocument, string> createDatasetName, Expression<Func<ImportNotification, bool>> filter, string dateField, AggregationPeriod aggregateBy)
private Task<MultiSeriesDatetimeDataset> Aggregate(DateTime[] dateRange, Func<BsonDocument, string> createDatasetName, Expression<Func<ImportNotification, bool>> filter, string dateField, AggregationPeriod aggregateBy)
{
var truncateBy = aggregateBy == AggregationPeriod.Hour ? "hour" : "day";

Expand All @@ -133,6 +130,6 @@ private Task<MultiSeriesDatetimeDataset[]> Aggregate(DateTime[] dateRange, Func<

logger.LogDebug("Aggregated Data {Result}", output.ToList().ToJsonString());

return Task.FromResult(output);
return Task.FromResult(new MultiSeriesDatetimeDataset() { Series = output.ToList() });
}
}
Loading
Loading