Files
auto-solution/scheme.md
2026-03-27 10:20:45 +08:00

324 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 火力规则实现方案scheme— 详细版
本文档供**后续智能体或开发人员**按步骤实现代码使用。依据 [requirements.md](requirements.md) 与样例 JSON`区域防御场景设计_2026-01-14 11_49_10_带注释.json`)。需求中提及但样例中**未出现**的字段(如 `threatLevel``warTerritory``airspaceType`)在代码中预留 **Optional / 占位事实类字段**,规则写骨架注释即可,**不要阻塞主流程编译**。
---
## 1. 目标与边界(实现时必须遵守)
| 项 | 说明 |
|----|------|
| 输入 | 单份超大军事场景 JSON约 1.3MB 级),**无数据库** |
| 输出 | **同一 JSON 结构**;仅对**红方任务**下业务约定字段做补全;其它键值保持输入原样 |
| 引擎 | Drools 7.x`auto-solution-rule/pom.xml``drools.version` |
| 注释规范Java/DRL | 与 requirements 一致:**禁止行尾注释**;类/公开 API 用 `/** */`;字段与函数体内用 `//` |
| 不参与匹配 | `ScenarioBase``Options``taskName``Groups`;任务开始/结束时间 |
| 允许 | 红方武器不足以覆盖蓝方;红方任务部分字段匹配不上则**保持空或原值** |
---
## 2. JSON 结构参考(实现时的路径依据)
根路径:`MilitaryScenario`(注意:样例文件在部分 key 后带有 `// 注释`**标准 Jackson 默认不能解析**。实现时三选一:① 调用方传标准 JSON② 服务端先 **strip 行尾 `//...`** 再解析;③ 使用 `jackson-core` 自定义或第三方「带注释 JSON」解析。下文路径均指**去掉注释后的逻辑结构**。)
### 2.1 顶层键(与 `MilitaryScenario` 同级)
实现时至少关心:
```
MilitaryScenario
├── RefAttributeObject # Mapkey=设备 refId字符串value=属性对象数组
├── ForceSides # 数组:阵营
├── Equipments # 数组:装备
├── Tasks # 数组:任务(红+蓝+…)
├── Environment # 可选,默认可不进规则
├── ScenarioBase # 忽略
└── Options # 忽略
```
(若实际文件还有其它顶层字段,**原样透传**,不要删除。)
### 2.2 `ForceSides[]`(阵营表)
每条典型字段:
- `ObjectHandle`:阵营 UUID字符串
- `ForceSideName`:如「红方」「蓝方」「白方」
**实现要点**:建立 `Map<String, String>``sideUuid -> sideName`,以及反向查询。红方 UUID 用于与 `Equipments.OwnerForceSide``task.task.sideId` 等比对。
### 2.3 `RefAttributeObject`(属性字典)
- 类型:对象,**子 key 为 refId**(与装备里 `device.refId``device.id` 等引用对齐)。
- 值:数组,元素字段包括但不限于:`attDef``attDefaultValue``attExplain``attName`
**实现要点**:不必把所有属性塞进 Drools。解析阶段可构建
- `Map<String, Map<String, String>> refIdToAttDefValue`:仅保留规则会用到的 `attDef`(若未知则先存全量 **按 refId 分桶的 List**,但单桶过大时要按 attDef 过滤,避免 OOM
### 2.4 `Equipments[]`(装备)
典型字段:
- `OwnerForceSide`:所属阵营 UUID
- `EquipmentID`:装备实例 id
- `SupportType``Platform_type``Name` 等:用于类型与展示
- `SubComponents`:对象,键如 `weapon``sensor``platform``jammer``communication` 等,值为**组件数组**
组件项常见字段:
- `ObjectHandle``deviceId``soleId`
- `device``{ id, name, refId }`
- `ParentPlat`:父平台 id
- `platform` 类下可能有 `positions``[经度, 纬度, 高度]`
**实现要点**:为规则准备**红方装备摘要列表**(扁平结构,见第 5 节),不要 deep clone 整个 `SubComponents`
### 2.5 `Tasks[]`(任务)
外层常见:
- `id`:任务 id
- `side`:字符串,如「蓝方」(**以样例为准**
- `dataType`:如 `taskPlane`
- `task`:内层大对象
内层 `task` 常见:
- `side``sideId`(阵营 UUID
- `type`:任务类型,如 `interference``assault``policePatrol`
- `speed`:数值
- `execute`**数组**,每项含 `type` 及多种列表字段
`execute[]` 内常见列表(名称以样例为准):
- `targetList[]`:常含 `weaponId``targetId``ID`、以及若干战术字段
- `disturbList[]`:干扰相关,可含 `weaponId``targetId`
- 其它 `*List`:按任务类型存在与否不同
**红方识别**(实现逻辑,按优先级):
1. `task.task.sideId` 或外层推导的阵营 UUID **等于** 红方 `ForceSides.ObjectHandle`;或
2. `task.side` / 外层 `side` 字符串等于「红方」(需与 `ForceSideName` 一致)。
**仅对识别为红方的任务**执行写回;蓝方任务只读,用于生成「对手事实」。
### 2.6 需求字段与样例缺失
| 需求字段 | 样例中状态 | 代码策略 |
|----------|------------|----------|
| `threatLevel` (13) | 未检索到 | Java 事实类保留 `Integer threatLevel`,默认 nullDRL 用 `threatLevel != null` Guard |
| `warTerritory``airspaceType` | 未检索到 | 事实类预留 `String`/`Integer`;阵位规则文件先写注释骨架 |
---
## 3. 总体数据流(智能体实现顺序)
```mermaid
flowchart TB
P1[预处理可选: 去注释]
P2[第一遍流式: 建索引]
P3[第二遍或同遍: 收集蓝方摘要 + 红方可写槽位]
P4[组装 Drools 事实]
P5[KieSession fireAllRules]
P6[应用 Rule 输出到内存补丁结构]
P7[写回 JSON: Tree 或 流式]
P1 --> P2 --> P3 --> P4 --> P5 --> P6 --> P7
```
---
## 4. OOM 与解析策略(必须写进实现)
### 4.1 禁止
- 使用 `ObjectMapper.readTree(整个 InputStream)` 默认把 1.3MB+ 全树常驻且复制多份。
- `insertAll(全部 Equipment)``insertAll(全部 Task)` 进入 KieSession。
- 无界 `String` 拼接整文件多次。
### 4.2 推荐
1. **Jackson `JsonParser` + `JsonToken`** 顺序扫描;仅当 `currentName` 属于目标段时深入读取。
2. **分块构建索引**`RefAttributeObject``ForceSides``Equipments` 各用 `Map` / 紧凑 DTO 列表;数字与字符串优先,避免嵌套 `Map` 过深。
3. **Tasks**:流式读数组,每元素解析为「任务摘要对象」或**仅红方**保留完整 `task` 子树的 **JsonNode 引用**(若采用 DOM 则只保留红方子树,蓝方只保留摘要)。
4. **写回**
- **方案 A推荐起步**:第一遍用流式解析 + 若内存允许用 `JsonNode` 仅替换 `Tasks` 下红方节点(需评估内存);
- **方案 B**:两遍文件:第一遍偏移量/路径索引,第二遍 `JsonGenerator` 复制并覆盖红方字段。
智能体实现时可先 **方案 A + 设置 Jackson 流式配置**,在压测后再切方案 B。
### 4.3 Drools 工作内存
- 单次 `fireAllRules` 前插入事实数建议:**O(蓝方任务数 + 红方候选装备数 + 红方待填槽位数)**,每项为**小对象**&lt; 1KB 量级为宜)。
- 规则执行完后 **`dispose()`** KieSession避免泄漏。
---
## 5. Java 侧建议类型(包名可按项目调整)
建议包:`com.solution.rule.firepower`(或沿用 `com.solution.rule` 下子包),避免与旧 `WarplaneHandler` 混在同一责任链。
### 5.1 索引与上下文(非 Drools Fact解析阶段使用
| 类名(建议) | 职责 |
|--------------|------|
| `ScenarioIndexes` | 持有 `sideIdToName``redSideId``blueSideId`(可多蓝多红时扩展为 Set`refAttributes` 精简索引 |
| `EquipmentSummary` | 单条红方可用装备:`equipmentId``ownerSideId``platformType``weaponComponentIds`List&lt;String&gt;)、可选 `positionLonLatAlt` |
| `BlueTaskFact` | 单条蓝方任务摘要:`taskId``taskType``speed``sideId`、从 `execute` 抽出的 **打击/干扰目标 id 列表**、**航迹摘要**(见下) |
| `TrackSummary` | 可选:`routeId` 或关键点 `List&lt;double[]&gt;`(经纬高),从蓝方编队/平台关联推导(若样例中路径复杂,第一版可只填 `speed` + 单点位置) |
| `RedTaskFillSlot` | 描述一处待填写位置:`taskId``executeIndex``listName`(如 `targetList`)、`itemIndex`、指向 Map 或 JsonNode 的**可变引用**(或用 `Consumer` 写回) |
### 5.2 Drools 事实(插入 KieSession
| 类名(建议) | 说明 |
|--------------|------|
| `OpponentContext` | 当前正在处理的蓝方任务/目标封装(可多条规则共享) |
| `RedInventory` | 红方可用武器/装备 id 及剩余数量(数量规则 3.1 用) |
| `MatchResult` | 规则填写结果:`selectedWeaponId``targetId``reasonCode`(便于日志) |
| `ThreatContext` | 预留 `Integer threatLevel` |
| `PositionContext` | 预留防区/作战区相关字段 |
事实类使用 **可修改 JavaBean**Drools 7 常用),在规则中 `modify()` 或 **通过全局服务**写回 `RedTaskFillSlot`(若用全局服务,需 `KieSession.setGlobal(...)`)。
### 5.3 规则与 Java 交互方式(二选一,文档推荐前者)
1. **纯规则修改 Fact**`MatchResult` 填好后Java 在 `fireAllRules` 后遍历 Fact 应用到 JSON。
2. **全局写回器**`globals.put("fillService", bean)`drl 中调用 `fillService.apply(...)`(需在 drl 声明 `import``global`)。
智能体选一种即可,**全项目统一**。
---
## 6. Drools 规则文件组织
目录:[`auto-solution-rule/src/main/resources/rules/`](auto-solution-rule/src/main/resources/rules/)(以实际 `DroolsConfig``classpath*:rules/*.*` 为准)。
| 文件 | package 建议 | 内容 |
|------|----------------|------|
| `fire-package.drl` | `rules.fire` | 仅 `package``import`、**中文块注释说明修改须知** |
| `fire-task-type.drl` | 同上 | `task.type`:干扰 vs 打击 vs 巡逻等分支salience 最高或单独 agenda-group `task-type` |
| `fire-equipment-match.drl` | 同上 | 装备类型、数量 ≥ 蓝方、`weaponId`/`targetId` 绑定;引用 `RedInventory` |
| `fire-position.drl` | 同上 | 阵位:预留条件,注释写「待 warTerritory/airspaceType 路径确认」 |
| `fire-track.drl` | 同上 | 航迹:高度、速度、航向、经纬高;注释说明可调参数 |
| `fire-fallback.drl` | 同上 | 无匹配时的默认策略或显式「不填写」 |
**删除或覆盖**无效的 [`fire-rule.drl`](auto-solution-rule/src/main/resources/rules/fire-rule.drl) 占位内容,保证 `KieBuilder``buildAll()` 成功。
**Salience 建议**(数值越大越先执行,按项目再调):
- 任务类型分支100
- 装备匹配80
- 阵位60
- 航迹40
- 兜底:-10
**agenda-group**(可选):`task-type``equipment``position``track`Java 中按序 `getAgenda().getAgendaGroup("xxx").setFocus()`
---
## 7. 规则与需求章节映射DRL 注释必须写清)
| requirements 章节 | DRL 落点 | 注释必须说明 |
|-------------------|----------|--------------|
| 3.1 装备匹配 | `fire-equipment-match.drl` | 依据哪些 Fact 字段;如何改「优先级」 |
| 3.2 阵位 | `fire-position.drl` | 红方防区/作战区判定条件(占位) |
| 3.3 航迹 | `fire-track.drl` | 最短距离/绕后等可选策略的切换方式 |
| 3.4 任务类型(干扰↔反干扰) | `fire-task-type.drl` | 与 3.1 的差异 |
| 3.5 贴合实际、不考虑时间 | 各文件 | 不写时间条件 |
---
## 8. 解析算法伪代码(供智能体翻译为 Java
```
function process(inputStream) -> OutputStream:
bytesOrReader = optionalStripJsonComments(inputStream) // 若需要
indexes = new ScenarioIndexes()
blueFacts = new ArrayList<BlueTaskFact>()
redSlots = new ArrayList<RedTaskFillSlot>()
redEquipSummaries = new ArrayList<EquipmentSummary>()
parser = JsonFactory.createParser(bytesOrReader)
while parser.nextToken() != END_OBJECT:
if field == "RefAttributeObject":
indexes.refAttributes = parseRefAttributeObjectStream(parser)
else if field == "ForceSides":
indexes.parseForceSides(parser) // 设置 redSideId / blueSideId
else if field == "Equipments":
for each equipment object in stream:
if owner == indexes.redSideId:
redEquipSummaries.add(summarize(equipment))
else if field == "Tasks":
for each task object in stream:
if isRedTask(task, indexes):
redSlots.addAll(collectFillSlots(task)) // 只记录需规则填的槽位
else if isBlueTask(task, indexes):
blueFacts.add(summarizeBlue(task))
session = kieBase.newKieSession()
try:
session.insert(new RedInventory(redEquipSummaries))
for b : blueFacts: session.insert(b)
for slot : redSlots: session.insert(slot)
// globals if needed
session.fireAllRules()
applyFactsToJson(modelOrPatches)
finally:
session.dispose()
return serialize(modelOrPatches)
```
`collectFillSlots`:遍历 `task.execute[*]` 下各 `*List`,对 `weaponId`/`targetId` 为空且业务约定需要填的项注册 `RedTaskFillSlot`(第一版可只处理 `targetList`)。
---
## 9. Spring 接口层建议
- **Controller**(可放在 `auto-solution-admin` 或独立 API 模块):
- `POST /api/firepower/plan`(路径自定)
- `Content-Type: application/json`
- 方法参数:`HttpServletRequest.getInputStream()``InputStreamResource`**不要** `@RequestBody String` 若可避免。
- **Service**`FirepowerRuleService#apply(InputStream in, OutputStream out)`,异常包装为业务码,**不要吞掉栈**。
---
## 10. 与现有模块的衔接(避免冲突)
| 文件/类 | 动作 |
|---------|------|
| [`DroolsConfig`](auto-solution-rule/src/main/java/com/solution/rule/config/DroolsConfig.java) | 保持;新增 drl 放入 `rules/` |
| [`JsonStreamParser`](auto-solution-rule/src/main/java/com/solution/rule/parser/JsonStreamParser.java) | 重写或新建 `MilitaryScenarioStreamParser`,与注释中假数据结构脱钩 |
| `TaskJsonDTO` 等 | 与样例不一致时:**以样例为准** 新建 `firepower` 包 DTO`JsonNode` |
| [`WarplaneHandler`](auto-solution-rule/src/main/java/com/solution/rule/handler/WarplaneHandler.java) | **不要**强行合并;新链路独立 Bean |
---
## 11. 测试与验收(智能体应补充用例)
1. **单元测试**`MilitaryScenarioStreamParser` 对**小样本 JSON**(截取 `Tasks` 一条 + `ForceSides` + 一条 `Equipments`)解析结果符合预期索引。
2. **规则测试**:使用 Drools `KieSessionTest` 或 JUnit 手动 `insert` 事实,断言 `MatchResult`
3. **集成测试**:完整样例文件跑通不 OOMJVM `-Xmx` 限制下观察);输出 JSON **除红方任务外字节级或键序**尽量一致(键序若难一致,至少结构等价)。
---
## 12. 实现检查清单(按顺序勾选)
1. [ ] 确定 JSON 注释处理策略并实现 `strip` 或约束调用方。
2. [ ] 实现 `ScenarioIndexes` + 流式解析 `RefAttributeObject``ForceSides``Equipments`
3. [ ] 实现 `Tasks` 遍历 + 红/蓝识别 + `RedTaskFillSlot` 收集。
4. [ ] 定义 Drools 事实类 + `kie-module` 可编译的 `fire-*.drl`
5. [ ] 实现 `FirepowerRuleService``newKieSession``insert``fireAllRules` → 应用结果。
6. [ ] 实现写回JsonNode 或流式生成。
7. [ ] Controller + 集成测试 + 日志(规则命中原因)。
---
## 13. 修订记录
| 日期 | 说明 |
|------|------|
| 2026-03-26 | 初稿 |
| 2026-03-26 | 详细版路径说明、类设计、伪代码、DRL 分层、检查清单、测试要求 |