feat(templateMatcher,dal): небольшой рефакторинг и добавлено журналирование промежуточных данных

This commit is contained in:
Mikhail Kuznetsov
2025-11-12 11:24:07 +10:00
parent 2950d21a69
commit 334595e81c
5 changed files with 111 additions and 46 deletions

View File

@@ -5,6 +5,7 @@ using PARR.DAL.Models.Job;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Unit;
using System.Net.NetworkInformation;
namespace PARR.DAL.DomainServices.Implementations
@@ -51,7 +52,11 @@ namespace PARR.DAL.DomainServices.Implementations
public async Task<IEnumerable<Guid>?> GetUnitsIdByJobFilterAsync(Job job, int? takeCount = null)
{
var result = new List<Guid>();
if (job.UnitFilters == null || !job.UnitFilters.Any())
{
logger.LogWarning("JobId={JobId} не содержит UnitFilters - пропускаем фильтрацию", job.Id);
return Array.Empty<Guid>();
}
var baseQuery = unitService
.Get().AsNoTracking()
@@ -76,53 +81,113 @@ namespace PARR.DAL.DomainServices.Implementations
.ThenInclude(t => t.UnitValues)
.ThenInclude(t => t.Value);
var result = new List<Guid>();
var filterIndex = 0;
foreach (var unitFilter in job.UnitFilters)
{
if (takeCount.HasValue && result.Count() > takeCount.Value)
break;
filterIndex++;
var query = baseQuery.Where(t => EF.Functions.ILike(t.Name, unitFilter.UnitFilter));
foreach (var fieldFilter in unitFilter.FieldFilters)
query = query.Where(t => t.UnitValues.Any(x => x.FieldId == fieldFilter.FieldId && (x.Value!.Value != null && EF.Functions.ILike(x.Value!.Value, fieldFilter.ValueMask))));
if (unitFilter.RelationshipFilters.Any())
if (takeCount.HasValue && result.Count >= takeCount.Value)
{
var parentFilters = unitFilter.RelationshipFilters.Where(t => t.IsParent == true).ToList();
foreach (var parentFilter in parentFilters)
logger.LogDebug("Достигнуто ограничение takeCount={TakeCount} после {FilterIndex} фильтров", takeCount.Value, filterIndex - 1);
break;
}
var remainig = takeCount.HasValue ? takeCount.Value - result.Count : int.MaxValue;
if (remainig <= 0) break;
try
{
//фильтруем по имени
var query = baseQuery.Where(t => EF.Functions.ILike(t.Name, unitFilter.UnitFilter));
//фильтруем по полям
foreach (var fieldFilter in unitFilter.FieldFilters)
{
if (parentFilter.IsInverse == false)
var fieldId = fieldFilter.FieldId;
var fieldValueMask = fieldFilter.ValueMask;
query = query.Where(t =>
t.UnitValues.Any(x =>
x.FieldId == fieldId &&
x.Value != null &&
x.Value.Value != null &&
EF.Functions.ILike(x.Value.Value, fieldValueMask)));
}
//фильтруем по значениям в связях
if (unitFilter.RelationshipFilters.Any())
{
var parentFilters = unitFilter.RelationshipFilters.Where(t => t.IsParent == true).ToList();
foreach (var parentFilter in parentFilters)
{
if (parentFilter.IsFullMatch)
query = query.Where(t => !t.ParentUnits.Any() || t.ParentUnits.All(p => p.ParentUnit!.UnitValues.Any(pf => pf.FieldId == parentFilter.FieldId && (pf.Value!.Value != null && EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask)))));
if (parentFilter.IsInverse == false)
{
if (parentFilter.IsFullMatch)
query = query.Where(t => !t.ParentUnits.Any() ||
t.ParentUnits.All(p => p.ParentUnit!.UnitValues.Any(pf =>
pf.FieldId == parentFilter.FieldId &&
pf.Value !=null &&
pf.Value.Value != null &&
EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask))));
else
query = query.Where(t => !t.ParentUnits.Any() ||
t.ParentUnits.Any(p => p.ParentUnit!.UnitValues.Any(pf =>
pf.FieldId == parentFilter.FieldId &&
pf.Value !=null &&
pf.Value!.Value != null &&
EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask))));
}
else
query = query.Where(t => !t.ParentUnits.Any() || t.ParentUnits.Any(p => p.ParentUnit!.UnitValues.Any(pf => pf.FieldId == parentFilter.FieldId && (pf.Value!.Value != null && EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask)))));
}
else
{
if (parentFilter.IsFullMatch)
query = query.Where(t => !t.ParentUnits.Any() || !t.ParentUnits.All(p => p.ParentUnit!.UnitValues.Any(pf => pf.FieldId == parentFilter.FieldId && (pf.Value!.Value != null && EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask)))));
else
query = query.Where(t => !t.ParentUnits.Any() || !t.ParentUnits.Any(p => p.ParentUnit!.UnitValues.Any(pf => pf.FieldId == parentFilter.FieldId && (pf.Value!.Value != null && EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask)))));
{
if (parentFilter.IsFullMatch)
query = query.Where(t => !t.ParentUnits.Any() ||
!t.ParentUnits.All(p => p.ParentUnit!.UnitValues.Any(pf =>
pf.FieldId == parentFilter.FieldId &&
pf.Value !=null &&
pf.Value!.Value != null &&
EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask))));
else
query = query.Where(t => !t.ParentUnits.Any() ||
!t.ParentUnits.Any(p => p.ParentUnit!.UnitValues.Any(pf =>
pf.FieldId == parentFilter.FieldId &&
pf.Value != null &&
pf.Value!.Value != null && EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask))));
}
}
}
}
if (job.Group?.IsUmbrella == true)
//фильтруем по количеству связей
if (job.Group?.IsUmbrella == true)
{
if (job.isParentRelationships == true)
query = query.Where(t => t.ParentUnits.Count >= job.MinValueRelationships && t.ParentUnits.Count <= job.MaxValueRelationships);
else
query = query.Where(t => t.ChildUnits.Count >= job.MinValueRelationships && t.ChildUnits.Count <= job.MaxValueRelationships);
}
var newUnits = await query
.Select(t => t.Id)
.Take(remainig)
.ToListAsync();
result.AddRange(newUnits);
logger.LogDebug("Фильтр {FilterIndex}: найдено {Count} Unit'ов (осталось набрать: {Remaining})",
filterIndex, newUnits.Count,Math.Max(0,takeCount.GetValueOrDefault(int.MaxValue)-result.Count));
}
catch (Exception ex)
{
if (job.isParentRelationships == true)
query = query.Where(t => t.ParentUnits.Count() >= job.MinValueRelationships && t.ParentUnits.Count() <= job.MaxValueRelationships);
else
query = query.Where(t => t.ChildUnits.Count() >= job.MinValueRelationships && t.ChildUnits.Count() <= job.MaxValueRelationships);
logger.LogError(ex, "Ошибка применения UnitFilter {FilterIndex} для JobId={JobId}", filterIndex, job.Id);
continue;
}
var newUnits = await query.Select(t => t.Id).ToListAsync();
result.AddRange(newUnits);
}
if (takeCount.HasValue && result.Count() > takeCount.Value)
if (takeCount.HasValue && result.Count > takeCount.Value)
result = result.Take(takeCount.Value).ToList();
logger.LogInformation("JobId={JobId}: обработано {FilterCount} фильтров, найдено {UnitCount} Unit'ов", job.Id, job.UnitFilters.Count, result.Count);
return result;
}

View File

@@ -9,14 +9,14 @@ namespace PARR.TemplateMatcher
{
internal class MqTemplateMatcher : IMqTemplateMatcher
{
private readonly ILogger<IMqTemplateMatcher> logger;
private readonly ILogger<MqTemplateMatcher> logger;
private readonly MqSettings mqSettings;
private readonly IMqService mqService;
private readonly ITransformService transformService;
private readonly IServiceProvider serviceProvider;
public MqTemplateMatcher(
ILogger<IMqTemplateMatcher> logger,
ILogger<MqTemplateMatcher> logger,
MqSettings mqSettings,
IMqService mqService,
ITransformService transformService,

View File

@@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace PARR.TemplateMatcher.Settings
{
public class MqSettings
internal class MqSettings
{
public TemplateMatcher TemplateMatcher { get; set; } = new TemplateMatcher();
public TemplateGenerator TemplateGenerator { get; set; } = new TemplateGenerator();

View File

@@ -9,15 +9,15 @@ using System.Text.Json;
namespace PARR.TemplateMatcher
{
public class TemplateMatcher : ITemplateMatcher
internal class TemplateMatcher : ITemplateMatcher
{
private readonly Logger<TemplateMatcher> logger;
private readonly ILogger<TemplateMatcher> logger;
private readonly IUnitFilterService unitFilterService;
private readonly MqSettings mqSettings;
private readonly IMqService mqService;
public TemplateMatcher(
Logger<TemplateMatcher> logger,
ILogger<TemplateMatcher> logger,
IUnitFilterService unitFilterService,
MqSettings mqSettings,
IMqService mqService
@@ -46,7 +46,7 @@ namespace PARR.TemplateMatcher
var msg = JsonSerializer.Serialize(mqRequest);
var result = await mqService.SendAsync(mqSettings.TemplateGenerator, new[] { msg });
var result = new MqSendResult { IsSuccess = true };//TODO await mqService.SendAsync(mqSettings.TemplateGenerator, new[] { msg });
if (result.IsSuccess)
logger.LogInformation($"Отправлен запрос на создание шаблона: {msg}");

View File

@@ -4,27 +4,27 @@ namespace PARR.TemplateMatcherWorker
{
public class Worker : BackgroundService
{
private readonly ILogger<Worker> logger;
private readonly IMqTemplateMatcher mqTemplateTaskGenerator;
private readonly ILogger<Worker> _logger;
private readonly IMqTemplateMatcher mqTemplateMatcher;
public Worker(
ILogger<Worker> logger,
IMqTemplateMatcher mqTemplateTaskGenerator
IMqTemplateMatcher mqTemplateMatcher
)
{
logger = logger;
this.mqTemplateTaskGenerator = mqTemplateTaskGenerator;
_logger = logger;
this.mqTemplateMatcher = mqTemplateMatcher;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await mqTemplateTaskGenerator.StartAsync();
await mqTemplateMatcher.StartAsync();
}
public override Task StopAsync(CancellationToken cancellationToken)
{
mqTemplateTaskGenerator.StopAsync().Wait();
mqTemplateMatcher.StopAsync().Wait();
return base.StopAsync(cancellationToken);
}