From fe28df93e7fc50fa26d2dfe6322b7bf3d81dca0e Mon Sep 17 00:00:00 2001 From: Olga Nemt Date: Thu, 1 Feb 2024 13:44:27 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D1=80=D0=B5=D0=B7=D1=83=D0=BB=D1=8C=D1=82=D0=B0=D1=82?= =?UTF-8?q?=D0=B0=D0=BC=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repositories/ITelemetryDataCache.cs | 7 ++ ...060511_Add_Table_DataSaubStat.Designer.cs} | 22 +++-- ... 20240201060511_Add_Table_DataSaubStat.cs} | 13 ++- .../AsbCloudDbContextModelSnapshot.cs | 20 +++- AsbCloudDb/Model/DataSaubStat.cs | 8 +- .../PeriodicWorks/WorkDataSaubStat.cs | 97 +++++++++++-------- .../Services/SAUB/TelemetryDataCache.cs | 22 +++++ 7 files changed, 133 insertions(+), 56 deletions(-) rename AsbCloudDb/Migrations/{20240131104814_Add_Table_DataSaubStat.Designer.cs => 20240201060511_Add_Table_DataSaubStat.Designer.cs} (99%) rename AsbCloudDb/Migrations/{20240131104814_Add_Table_DataSaubStat.cs => 20240201060511_Add_Table_DataSaubStat.cs} (87%) diff --git a/AsbCloudApp/Repositories/ITelemetryDataCache.cs b/AsbCloudApp/Repositories/ITelemetryDataCache.cs index bce8d328..f90f2ac4 100644 --- a/AsbCloudApp/Repositories/ITelemetryDataCache.cs +++ b/AsbCloudApp/Repositories/ITelemetryDataCache.cs @@ -72,5 +72,12 @@ namespace AsbCloudApp.Repositories /// /// IEnumerable GetStat(); + + /// + /// Получить ключи телеметрии по параметрам запроса + /// + /// + /// + IEnumerable? GetIds(TelemetryDataRequest request); } } \ No newline at end of file diff --git a/AsbCloudDb/Migrations/20240131104814_Add_Table_DataSaubStat.Designer.cs b/AsbCloudDb/Migrations/20240201060511_Add_Table_DataSaubStat.Designer.cs similarity index 99% rename from AsbCloudDb/Migrations/20240131104814_Add_Table_DataSaubStat.Designer.cs rename to AsbCloudDb/Migrations/20240201060511_Add_Table_DataSaubStat.Designer.cs index 953a220c..702cb1ea 100644 --- a/AsbCloudDb/Migrations/20240131104814_Add_Table_DataSaubStat.Designer.cs +++ b/AsbCloudDb/Migrations/20240201060511_Add_Table_DataSaubStat.Designer.cs @@ -13,7 +13,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace AsbCloudDb.Migrations { [DbContext(typeof(AsbCloudDbContext))] - [Migration("20240131104814_Add_Table_DataSaubStat")] + [Migration("20240201060511_Add_Table_DataSaubStat")] partial class Add_Table_DataSaubStat { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -368,11 +368,6 @@ namespace AsbCloudDb.Migrations .HasColumnName("depth_start") .HasComment("Глубина забоя по стволу начальная"); - b.Property("DetectedOperationCategoryId") - .HasColumnType("integer") - .HasColumnName("detected_operation_category_id") - .HasComment("Название автоопределённой операции"); - b.Property("EnabledSubsystems") .HasColumnType("integer") .HasColumnName("enabled_subsystems") @@ -388,6 +383,11 @@ namespace AsbCloudDb.Migrations .HasColumnName("has_oscillation") .HasComment("Наличие или отсутствие осцилляции"); + b.Property("IdCategory") + .HasColumnType("integer") + .HasColumnName("id_category") + .HasComment("Название автоопределённой операции"); + b.Property("IdFeedRegulator") .HasColumnType("smallint") .HasColumnName("id_feed_regulator") @@ -440,6 +440,8 @@ namespace AsbCloudDb.Migrations b.HasKey("Id"); + b.HasIndex("IdCategory"); + b.HasIndex("IdTelemetry"); b.ToTable("t_data_saub_stat"); @@ -8424,12 +8426,20 @@ namespace AsbCloudDb.Migrations modelBuilder.Entity("AsbCloudDb.Model.DataSaubStat", b => { + b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory") + .WithMany() + .HasForeignKey("IdCategory") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry") .WithMany() .HasForeignKey("IdTelemetry") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.Navigation("OperationCategory"); + b.Navigation("Telemetry"); }); diff --git a/AsbCloudDb/Migrations/20240131104814_Add_Table_DataSaubStat.cs b/AsbCloudDb/Migrations/20240201060511_Add_Table_DataSaubStat.cs similarity index 87% rename from AsbCloudDb/Migrations/20240131104814_Add_Table_DataSaubStat.cs rename to AsbCloudDb/Migrations/20240201060511_Add_Table_DataSaubStat.cs index a2b6d38f..fbe4048e 100644 --- a/AsbCloudDb/Migrations/20240131104814_Add_Table_DataSaubStat.cs +++ b/AsbCloudDb/Migrations/20240201060511_Add_Table_DataSaubStat.cs @@ -33,7 +33,7 @@ namespace AsbCloudDb.Migrations rotor_torque_limit_max = table.Column(type: "double precision", nullable: true, comment: "Максимально допустимый момент"), id_feed_regulator = table.Column(type: "smallint", nullable: true, comment: "Работа при достижении ограничения"), rotor_speed = table.Column(type: "double precision", nullable: false, comment: "Фактическая скорость оборотов ВСП"), - detected_operation_category_id = table.Column(type: "integer", nullable: false, comment: "Название автоопределённой операции"), + id_category = table.Column(type: "integer", nullable: false, comment: "Название автоопределённой операции"), enabled_subsystems = table.Column(type: "integer", nullable: false, comment: "Флаги подсистем"), has_oscillation = table.Column(type: "boolean", nullable: false, comment: "Наличие или отсутствие осцилляции"), flow = table.Column(type: "double precision", nullable: false, comment: "Фактический расход"), @@ -48,9 +48,20 @@ namespace AsbCloudDb.Migrations principalTable: "t_telemetry", principalColumn: "id", onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_t_data_saub_stat_t_well_operation_category_id_category", + column: x => x.id_category, + principalTable: "t_well_operation_category", + principalColumn: "id", + onDelete: ReferentialAction.Cascade); }, comment: "Кеш-таблица для хранения данных для РТК-отчета"); + migrationBuilder.CreateIndex( + name: "IX_t_data_saub_stat_id_category", + table: "t_data_saub_stat", + column: "id_category"); + migrationBuilder.CreateIndex( name: "IX_t_data_saub_stat_id_telemetry", table: "t_data_saub_stat", diff --git a/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs b/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs index 82cd365a..eeb9ad9b 100644 --- a/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs +++ b/AsbCloudDb/Migrations/AsbCloudDbContextModelSnapshot.cs @@ -366,11 +366,6 @@ namespace AsbCloudDb.Migrations .HasColumnName("depth_start") .HasComment("Глубина забоя по стволу начальная"); - b.Property("DetectedOperationCategoryId") - .HasColumnType("integer") - .HasColumnName("detected_operation_category_id") - .HasComment("Название автоопределённой операции"); - b.Property("EnabledSubsystems") .HasColumnType("integer") .HasColumnName("enabled_subsystems") @@ -386,6 +381,11 @@ namespace AsbCloudDb.Migrations .HasColumnName("has_oscillation") .HasComment("Наличие или отсутствие осцилляции"); + b.Property("IdCategory") + .HasColumnType("integer") + .HasColumnName("id_category") + .HasComment("Название автоопределённой операции"); + b.Property("IdFeedRegulator") .HasColumnType("smallint") .HasColumnName("id_feed_regulator") @@ -438,6 +438,8 @@ namespace AsbCloudDb.Migrations b.HasKey("Id"); + b.HasIndex("IdCategory"); + b.HasIndex("IdTelemetry"); b.ToTable("t_data_saub_stat"); @@ -8422,12 +8424,20 @@ namespace AsbCloudDb.Migrations modelBuilder.Entity("AsbCloudDb.Model.DataSaubStat", b => { + b.HasOne("AsbCloudDb.Model.WellOperationCategory", "OperationCategory") + .WithMany() + .HasForeignKey("IdCategory") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + b.HasOne("AsbCloudDb.Model.Telemetry", "Telemetry") .WithMany() .HasForeignKey("IdTelemetry") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); + b.Navigation("OperationCategory"); + b.Navigation("Telemetry"); }); diff --git a/AsbCloudDb/Model/DataSaubStat.cs b/AsbCloudDb/Model/DataSaubStat.cs index 8b22367b..8871b598 100644 --- a/AsbCloudDb/Model/DataSaubStat.cs +++ b/AsbCloudDb/Model/DataSaubStat.cs @@ -64,8 +64,8 @@ namespace AsbCloudDb.Model [Column("rotor_speed"), Comment("Фактическая скорость оборотов ВСП")] public double RotorSpeed { get; set; } - [Column("detected_operation_category_id"), Comment("Название автоопределённой операции")] - public int DetectedOperationCategoryId { get; set; } + [Column("id_category"), Comment("Название автоопределённой операции")] + public int IdCategory { get; set; } [Column("enabled_subsystems"), Comment("Флаги подсистем")] public int EnabledSubsystems { get; set; } @@ -81,5 +81,9 @@ namespace AsbCloudDb.Model [ForeignKey(nameof(IdTelemetry))] public virtual Telemetry Telemetry { get; set; } = null!; + + [JsonIgnore] + [ForeignKey(nameof(IdCategory))] + public virtual WellOperationCategory OperationCategory { get; set; } = null!; } } diff --git a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs b/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs index 15f3cd34..8369ffa2 100644 --- a/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs +++ b/AsbCloudInfrastructure/Background/PeriodicWorks/WorkDataSaubStat.cs @@ -1,7 +1,12 @@ -using AsbCloudDb.Model; +using AsbCloudApp.Data.SAUB; +using AsbCloudApp.Repositories; +using AsbCloudApp.Requests; +using AsbCloudDb.Model; using AsbCloudInfrastructure.Services.DetectOperations.Detectors; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using System; +using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -14,72 +19,81 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks internal class WorkDataSaubStat : Work { private int MechanicalDrillingCategoryId = 4001; + private int Gap = 60; public WorkDataSaubStat() : base("Generate DataSaubStat entries and save them into Db") { Timeout = TimeSpan.FromMinutes(10); } - protected override Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) + protected override async Task Action(string id, IServiceProvider services, Action onProgressCallback, CancellationToken token) { - //1 найти последнюю запись в кеш-таблице (по полям "Дата до") - //2 определяем дату с которой начинаем анализ - //3 находим автоопределнные операции по скважине, начиная с начальной даты из пункта 2 - // 3.1 только те, которые связанные с бурением (idParent = 4001) - // 3.2 выбираем 500 операций - // 3.3. выбираем минимальную дату начала и максимальную дату окончания - //4 по полученным в пункте выше данным выбираем записи из telemetry_data_saub - // 4.1.выбираем те у которых (bit_depth == well_depth) - //5. для каждой операции из 3.2 находим соответствующий ей кусок телеметрии (по дате начала и окончания) - // и храним индексы этого куска в виде span - //6. кусок телеметрии, полученный в пункте 5 (span) и соответствующая ей операция направляется на разбивку диапазонов - - //7/ разбивка диапазонов: - // параметры метода: массив из - using var db = services.GetRequiredService(); + var telemetryDataCache = services.GetRequiredService>(); + + var telemetryIds = telemetryDataCache.GetIds(new TelemetryDataRequest() + { + GeDate = DateTime.UtcNow.AddDays(-Gap) + }); + + if (telemetryIds == null || !telemetryIds.Any()) + return; + var dateEnd = db.Set() .OrderByDescending(c => c.DateEnd) .FirstOrDefault()?.DateEnd ?? DateTimeOffset.MinValue; - var detectedOperations = db.Set() + var detectedOperations = await db.Set() .Where(o => o.DateStart > dateEnd) .Where(o => o.OperationCategory.IdParent == MechanicalDrillingCategoryId) + .Where(o => telemetryIds.Contains(o.IdTelemetry)) .OrderBy(o => o.DateStart) .Take(500) - .ToArray(); + .ToArrayAsync(token); + + if (!detectedOperations.Any()) + return; var minDate = detectedOperations.FirstOrDefault()?.DateStart; var maxDate = detectedOperations.OrderByDescending(d => d.DateEnd).FirstOrDefault()?.DateEnd; - var telemetryDataSaub = db.Set() + var telemetryDataSaub = (await db.Set() .Where(t => t.DateTime >= minDate) .Where(t => t.DateTime <= maxDate) .Where(t => Math.Abs(t.BitDepth - t.WellDepth) < 0.0001) - .OrderBy(t => t.DateTime) - .ToArray(); + .Where(t => telemetryIds.Contains(t.IdTelemetry)) + .ToArrayAsync(token)) + .GroupBy(t => t.IdTelemetry) + .ToDictionary(g => g.Key, g => g.OrderBy(t => t.DateTime).ToArray()); + CreateDataSaubStat(db, detectedOperations, telemetryDataSaub); + } + + private static void CreateDataSaubStat(IAsbCloudDbContext db, DetectedOperation[] detectedOperations, Dictionary telemetryDataSaub) + { var indexStart = 0; var indexEnd = 0; foreach (var operation in detectedOperations) { - indexStart = Array.FindIndex(telemetryDataSaub, indexEnd, t => t.DateTime >= operation.DateStart); - indexEnd = Array.FindIndex(telemetryDataSaub, indexStart, t => t.DateTime > operation.DateEnd) - 1; + if (!telemetryDataSaub.TryGetValue(operation.IdTelemetry, out TelemetryDataSaub[]? telemetryDataSaubPart)) + break; + + indexStart = Array.FindIndex(telemetryDataSaubPart, indexEnd, t => t.DateTime >= operation.DateStart); + indexEnd = Array.FindIndex(telemetryDataSaubPart, indexStart, t => t.DateTime > operation.DateEnd) - 1; if (indexStart >= 0 && indexEnd >= indexStart) { var length = indexEnd - indexStart; - var subset = telemetryDataSaub.AsSpan(indexStart, length + 1); - var result = CalcStats(operation, subset, db); + var subset = telemetryDataSaubPart.AsSpan(indexStart, length + 1); + CalcStats(operation, subset, db); + db.SaveChanges(); } } - - return Task.CompletedTask; } - private int CalcStats(DetectedOperation operation, Span telemetryDataSaub, IAsbCloudDbContext db) + private static void CalcStats(DetectedOperation operation, Span telemetryDataSaub, IAsbCloudDbContext db) { var indexStart = 0; for (var i = 1; i < telemetryDataSaub.Length; i++) @@ -96,15 +110,14 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks db.Set().Add(dataSaubStatItem); } } - return db.SaveChanges(); } - private DataSaubStat CalcStat(DetectedOperation operation, Span span) + private static DataSaubStat CalcStat(DetectedOperation operation, Span span) { var hasOscillation = operation.ExtraData.TryGetValue(DetectorDrilling.ExtraDataKeyHasOscillation, out object? hasOscillationObject) && hasOscillationObject is true; - var wavg = CalcWavg(span); + var aggregatedValues = CalcAggregate(span); var processMapDrillingCacheItem = new DataSaubStat { DateStart = operation.DateStart, @@ -113,33 +126,33 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks DepthEnd = operation.DepthEnd, Speed = (operation.DepthEnd - operation.DepthStart) / ((operation.DateEnd - operation.DateStart).TotalHours), BlockSpeedSp = span[0].BlockSpeedSp, - Pressure = wavg.Pressure, + Pressure = aggregatedValues.Pressure, PressureIdle = span[0].PressureIdle, PressureSp = span[0].PressureSp, - AxialLoad = wavg.AxialLoad, + AxialLoad = aggregatedValues.AxialLoad, AxialLoadSp = span[0].AxialLoadSp, AxialLoadLimitMax = span[0].AxialLoadLimitMax, - RotorTorque = wavg.RotorTorque, + RotorTorque = aggregatedValues.RotorTorque, RotorTorqueSp = span[0].RotorTorqueSp, RotorTorqueLimitMax = span[0].RotorTorqueLimitMax, IdFeedRegulator = span[0].IdFeedRegulator, - RotorSpeed = wavg.RotorSpeed, - DetectedOperationCategoryId = operation.IdCategory, + RotorSpeed = aggregatedValues.RotorSpeed, + IdCategory = operation.IdCategory, EnabledSubsystems = operation.EnabledSubsystems, HasOscillation = hasOscillation, IdTelemetry = operation.IdTelemetry, - Flow = wavg.Flow + Flow = aggregatedValues.Flow }; return processMapDrillingCacheItem; } - private ( + private static ( double Pressure, double AxialLoad, double RotorTorque, double RotorSpeed, double Flow - ) CalcWavg(Span span) + ) CalcAggregate(Span span) { var sumPressure = 0.0; var sumAxialLoad = 0.0; @@ -154,7 +167,7 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks sumAxialLoad += weigth * span[i].AxialLoad; sumRotorTorque += weigth * span[i].RotorTorque; sumRotorSpeed += weigth * span[i].RotorSpeed; - flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 :flow; + flow = span[i + 1].Flow > flow ? span[i + 1].Flow ?? 0.0 : flow; } return ( Pressure: sumPressure / diffDepthTotal, @@ -165,7 +178,7 @@ namespace AsbCloudInfrastructure.Background.PeriodicWorks ); } - private bool IsNewCacheItem(TelemetryDataSaub previous, TelemetryDataSaub current) + private static bool IsNewCacheItem(TelemetryDataSaub previous, TelemetryDataSaub current) { return !(current.Mode == previous.Mode) || !(current.BlockSpeedSp == previous.BlockSpeedSp) diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs index 99983dd5..fef27bc3 100644 --- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs +++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs @@ -324,5 +324,27 @@ namespace AsbCloudInfrastructure.Services.SAUB return data; } + + public IEnumerable? GetIds(TelemetryDataRequest request) + { + var data = new Dictionary(); + + if (request.GeDate.HasValue) + { + data = caches + .Where(item => item.Value.LastData.Any(d => d.DateTime >= request.GeDate.Value.ToRemoteDateTime(item.Value.TimezoneHours))) + .ToDictionary(item => item.Key, item => item.Value); + } + + if (request.LeDate.HasValue) + { + data = caches + .Where(item => item.Value.LastData.Any(d => d.DateTime <= request.LeDate.Value.ToRemoteDateTime(item.Value.TimezoneHours))) + .ToDictionary(item => item.Key, item => item.Value); + } + + var telemetryIds = data.Select(item => item.Key); + return telemetryIds; + } } }