Commit 0c04e0b5 by luoqi

perf(plan): selectHits 子场景可选并行 — 83K 实测 1.6-2.6×,逐 hit 等价

10 个子场景(K00-K09)查询彼此独立,合并/去重与顺序无关。新增 PAC_RECALL_SUBSCENARIO_CONCURRENCY env(>1 开分块 Promise.all 并行,默认 1 串行、行为不变)。83K 患者本地实测:串行 50s→并行(conc=4)31s(warm 1.6×)/ cold 123s→47s(2.6×),固定 now 下两路 59032 hits 逐 hit 完全一致(等价性证实)。规则零改动,仅改执行方式。prod 建议设 =4。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parent ea857067
......@@ -199,12 +199,23 @@ export class TreatmentInitiationRecallScenario implements PlanScenarioPlugin {
constructor(private readonly prisma: PrismaService) {}
async selectHits(scope: ScenarioScope): Promise<ScenarioHit[]> {
const entries = Object.entries(TreatmentInitiationRecallScenario.SUB_SCENARIOS);
const hits: ScenarioHit[] = [];
for (const [subKey, cfg] of Object.entries(
TreatmentInitiationRecallScenario.SUB_SCENARIOS,
)) {
const subHits = await this.runSubScenario(scope, subKey, cfg);
hits.push(...subHits);
// 10 个子场景查询彼此独立(各自 SQL + union-find 合并 + 打分,无共享状态);
// 合并/去重(下游 hitsByPatient Map + max 分 + Set 比对)与顺序无关 → 并行 = 结果逐字节相同。
// PAC_RECALL_SUBSCENARIO_CONCURRENCY=N(>1)开并行(分块 Promise.all);默认串行,行为不变。
const conc = Math.max(1, Number(process.env.PAC_RECALL_SUBSCENARIO_CONCURRENCY) || 1);
if (conc > 1) {
for (let i = 0; i < entries.length; i += conc) {
const chunk = await Promise.all(
entries.slice(i, i + conc).map(([subKey, cfg]) => this.runSubScenario(scope, subKey, cfg)),
);
for (const subHits of chunk) hits.push(...subHits);
}
} else {
for (const [subKey, cfg] of entries) {
hits.push(...(await this.runSubScenario(scope, subKey, cfg)));
}
}
this.logger.debug(
`initiation total hits: ${hits.length}(missing_tooth/caries/perio 合计)`,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment