feature: NEWS2 Composite Scoring Engine
This commit is contained in:
@@ -201,8 +201,10 @@ public class EsIndexerService : BackgroundService
|
||||
private async Task HandleAlertGeneratedAsync(string payload, CancellationToken ct)
|
||||
{
|
||||
var evt = JsonSerializer.Deserialize<AlertGeneratedEvent>(payload, EventJsonOptions)!;
|
||||
using var payloadDoc = JsonDocument.Parse(payload);
|
||||
var root = payloadDoc.RootElement;
|
||||
|
||||
var doc = new ClinicalAlertDocument
|
||||
var alertDoc = new ClinicalAlertDocument
|
||||
{
|
||||
AlertId = evt.AlertId.ToString(),
|
||||
EncounterId = evt.EncounterId.ToString(),
|
||||
@@ -215,29 +217,47 @@ public class EsIndexerService : BackgroundService
|
||||
};
|
||||
|
||||
var indexResp = await _elastic.IndexAsync(
|
||||
doc,
|
||||
i => i.Index(_esOptions.Indices.ClinicalAlerts).Id(doc.AlertId),
|
||||
alertDoc,
|
||||
i => i.Index(_esOptions.Indices.ClinicalAlerts).Id(alertDoc.AlertId),
|
||||
ct);
|
||||
|
||||
if (!indexResp.IsValidResponse)
|
||||
throw new InvalidOperationException(
|
||||
$"ES index failed for alert {evt.AlertId}: {indexResp.DebugInformation}");
|
||||
|
||||
// Increment openAlertCount on the parent encounter document
|
||||
// Increment openAlertCount on the parent encounter document.
|
||||
// NEWS2 alerts also carry news2Score/news2RiskLevel in the Kafka payload;
|
||||
// stamp those on patient_encounters so ward dashboards can filter by acuity.
|
||||
var scriptLines = new List<string> { "ctx._source.openAlertCount += 1" };
|
||||
Dictionary<string, object>? scriptParams = null;
|
||||
|
||||
if (root.TryGetProperty("news2Score", out var scoreElem) &&
|
||||
root.TryGetProperty("news2RiskLevel", out var riskElem))
|
||||
{
|
||||
scriptLines.Add("ctx._source.news2Score = params.score");
|
||||
scriptLines.Add("ctx._source.news2RiskLevel = params.riskLevel");
|
||||
scriptParams = new Dictionary<string, object>
|
||||
{
|
||||
["score"] = scoreElem.GetInt32(),
|
||||
["riskLevel"] = riskElem.GetString()!
|
||||
};
|
||||
}
|
||||
|
||||
var updateResp = await _elastic.UpdateAsync<PatientEncounterDocument, object>(
|
||||
_esOptions.Indices.PatientEncounters,
|
||||
evt.EncounterId.ToString(),
|
||||
u => u
|
||||
.Script(new Script(new InlineScript
|
||||
{
|
||||
Source = "ctx._source.openAlertCount += 1",
|
||||
Language = ScriptLanguage.Painless
|
||||
Source = string.Join(";\n", scriptLines),
|
||||
Language = ScriptLanguage.Painless,
|
||||
Params = scriptParams
|
||||
}))
|
||||
.RetryOnConflict(3),
|
||||
ct);
|
||||
|
||||
if (!updateResp.IsValidResponse && updateResp.Result != Result.NotFound)
|
||||
_logger.LogWarning(
|
||||
"Could not increment openAlertCount for encounter {Id}", evt.EncounterId);
|
||||
"Could not update patient_encounters for alert on encounter {Id}", evt.EncounterId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user