- add documentation governance and cleanup audit documents - update README and docs index to distinguish current vs historical sources - move superseded planning, SBAS, Gamma, and experiment notes into docs/archive - fix remaining archive text garbling in two documents
21 KiB
InSAR 配对系统重构方案
更新日期:2026-04-13
状态:待实施
适用范围:Z:\Code\Insar_management_system_v2 当前代码基线
1. 文档目标
这份文档不是抽象算法说明,而是基于当前系统现状给出的可落地重构方案,目标是:
- 重构 D-InSAR 配对内核,解决当前正确性、稳定性和可维护性问题
- 尽量复用现有数据库自动维护、root/cursor 自维护、manifest inventory、自检面板
- 明确开发机条件下的迁移策略
- 为后续实现提供分阶段执行顺序、表设计、接口边界和验收口径
2. 当前系统基础与约束
2.1 当前可直接复用的系统能力
当前系统已经具备以下基础设施,重构应直接接入,而不是另起一套平行机制:
- 数据库启动自维护
backend/app/db_maintenance.pyensure_database_ready()会在启动时创建表、补缺列、应用 SQL migration,并可在开发机上按环境变量执行整库 schema reset
- root 与 cursor 自维护
backend/app/services/root_registry_service.py- 启动时会根据
.env自动同步managed_roots与scan_cursors
- manifest inventory 自维护
backend/app/services/manifest_inventory_service.py- 会维护
path_inventory、scan_cursors.last_seen_*、fingerprint 与 root 缺失状态
- 结果目录自维护
backend/app/services/dinsar_scan_service.py- D-InSAR 统一扫描链路已经是“发布 -> manifest inventory -> catalog rebuild -> compat sync”
- 健康检查和一致性检查
backend/app/services/health_service.pyfrontend/src/HealthCheckPanel.jsx- 当前自检已包含:数据库 schema、worker、catalog、source roots、D-InSAR bridge、一致性统计、系统维护入口
2.2 当前配对系统的核心问题
现有配对系统的主要问题不是功能不够多,而是核心语义不稳定:
- SQL 路径和 Python fallback 路径不是同一算法
- 同日影像会出现反向重复配对
start_date在 SQL 主路径上已失效,但接口仍保留star策略没有固定参考像角色sequential对同日多景不稳定all策略排序与前端描述不一致aoi_overlap_threshold=0的语义前后端不一致- 当前任务命名与配对唯一性混在一起,业务主键不稳定
2.3 当前系统约束
- 当前扫描模式是 manual-only,调度器默认关闭
backend/app/scheduler.py
radar_data是当前源影像事实表,配对系统必须以它为唯一源dinsar_task_batches/dinsar_task_items已经是生产任务落地表result_products/dinsar_product_profiles已经承担结果资产追踪- 健康检查和统计接口已上线,新增配对系统状态应并入现有面板
3. 重构总目标
本轮重构的目标不是继续修补 find_dinsar_pairs_v2,而是将配对系统改造成四层结构:
- 影像事实层
- 配对指标缓存层
- 网络选择层
- 任务物化层
核心原则:
- 候选对生成与网络选择分层
- 所有策略共享同一候选池
- 所有配对方向统一规范化
- 所有结果可追溯到策略版本、参数快照和候选边来源
- 不再保留“算法不等价的 fallback”
4. 目标架构
4.1 Layer A:影像事实层
沿用现有 radar_data 表作为唯一源影像事实表。
重构要求:
radar_data.id继续作为数据库主键- 引入明确的场景业务键
scene_uid- 优先复用
radar_data.unique_id - 若历史数据存在
unique_id缺失或不稳定,启动时执行一次回填 - 回填规则:
hash(normalized file_path),并写入新列或标准化字段
- 优先复用
- 所有配对相关对象都基于
scene_uid或radar_data.id建立引用
建议:
- 本轮实现阶段直接在
radar_data上新增:scene_uidscene_signaturepairing_eligiblepairing_updated_at
- 如果希望减少变更面,也可以只新增
scene_uid与pairing_updated_at
4.2 Layer B:配对指标缓存层
这是本次重构的核心。
目标:
- 将“任意两个影像是否可配、其基础指标是什么”从请求时临时计算,改为可维护的持久化缓存
- 缓存只保存与 AOI 无关的基础指标
- AOI 相关指标在请求时动态叠加计算
建议新增表:
pairing_metric_cache
一行代表一个规范化后的影像对。
建议字段:
idmaster_scene_ref_idslave_scene_ref_idmaster_scene_uidslave_scene_uidpair_uidmetric_versionorientation_rule_versiontime_baseline_daysspatial_baseline_metersscene_overlap_ratioorbit_directionsame_satellitesame_imaging_modesame_polarizationmaster_imaging_dateslave_imaging_datemaster_satelliteslave_satellitemaster_imaging_modeslave_imaging_modemaster_polarizationslave_polarizationmaster_file_pathslave_file_pathstatuscomputed_at
唯一约束:
unique(master_scene_ref_id, slave_scene_ref_id, metric_version)
关键约定:
master/slave不是请求期可变概念,而是规范化方向- 规范化规则:
- 早时间 = master
- 同时间时,较小
scene_uid或较小id= master
4.3 Layer C:缓存状态与脏队列
为了接入现有“自动维护 + 健康检查”体系,建议新增两张状态表。
pairing_cache_state
建议设计为单例表或按 cache_scope='global' 管理。
字段建议:
idcache_scopemetric_versionstatusscene_countpair_countdirty_scene_countlast_full_rebuild_atlast_incremental_reconcile_atlast_errorupdated_at
状态建议:
READYDIRTYREBUILDINGDEGRADEDFAILED
pairing_dirty_scenes
用于增量维护。
字段建议:
idscene_ref_idscene_uidreasonmarked_atresolved_atstatus
唯一约束建议:
unique(scene_ref_id, status='PENDING')或代码层去重
4.4 Layer D:网络选择层
网络选择层不直接查 radar_data,而是查 pairing_metric_cache。
建议新增:
pairing_network_runs
代表一次配对请求或一次已保存的网络。
字段建议:
idnetwork_run_idstrategypolicy_versionrequest_hashrequest_params_jsonaoi_sourceaoi_hashaoi_summary_jsoncandidate_countselected_edge_countwarning_countstatusfallback_usedcreated_bycreated_at
pairing_network_edges
代表某个网络 run 选中的边。
字段建议:
idnetwork_run_ref_idmetric_cache_ref_idedge_rankselection_reasonselection_scoreselection_meta_jsonis_reference_edgecreated_at
唯一约束:
unique(network_run_ref_id, metric_cache_ref_id)
4.5 Layer E:任务物化层
当前 dinsar_task_batches / dinsar_task_items 可继续保留。
但建议增加可追溯字段:
在 dinsar_task_items 上新增:
network_run_idnetwork_edge_idpolicy_versionselection_strategyscene_pair_uid
在结果侧建议同步补充:
result_products.pair_key继续保留- 在
dinsar_product_profiles或params_json中补充:network_run_idnetwork_edge_idpolicy_versionmaster_scene_uidslave_scene_uid
这样最终可以把:
- 配对网络
- 任务项
- 生产结果
串成一条可追踪链路。
5. 配对算法设计
5.1 候选对生成
候选对生成只负责回答:
- 这两个场景在基础事实上是否可配
- 基础指标是什么
不负责回答:
- 用什么策略选
- 最后是否进入任务
基础硬约束:
master != slave- 方向规范化后只保留一个方向
- 同轨向
- 日期格式合法
- 几何相交
基础指标:
time_baseline_daysspatial_baseline_metersscene_overlap_ratio
注意:
same_satellitesame_imaging_modesame_polarization
只作为缓存事实,不在缓存层提前删边,以便不同请求复用同一缓存。
5.2 请求期过滤
请求期过滤发生在 pairing_metric_cache 之上:
time_baseline_min/maxspatial_baseline_max_metersoverlap_thresholdallowed_satellitescross_satellite_pairingrequire_same_imaging_moderequire_same_polarizationmaster_date_from/toslave_date_from/toaoi_overlap_threshold
AOI 处理原则:
- AOI 不进入持久化 pair cache 主键
- AOI 相关 overlap 在请求时动态计算
0不再表示数值阈值,而统一转成null- 前后端统一语义:
null= 不启用 AOI 覆盖阈值0 < x <= 1= 启用阈值
5.3 四种策略的正式定义
all
- 返回全部合法候选边
- 排序统一为稳定顺序:
master_imaging_dateslave_imaging_dateselection_score descpair_uid
不再使用“数据库返回顺序”作为结果语义。
sequential
- 基于稳定时间序列排序构图
- 排序键:
acquisition_time_utc- 无则
imaging_date - 再无则
scene_uid
- 每景连接后续
N景 - 同日多景必须稳定,不允许受候选池原始顺序影响
star
- 参考像必须固定角色
- 本系统建议统一采用:
- 参考像始终为
master
- 参考像始终为
- 若物理上参考像日期晚于目标像,则在选择层进行拒绝或显式反转并记录相位方向规则
本轮建议:
- 为降低复杂度,先采用“参考像必须是 master”的严格规则
- 如果用户选择的参考像晚于部分场景,则这些边不入网,并给出 warning
sbas
本轮不采用“简单按 overlap 贪心去重”的旧实现。
建议目标:
- 图连通
- 每景至少达到最小连接数
- 时间覆盖尽量连续
- 每景度数受控,避免过密
- AOI 覆盖尽量多样
可落地实现:
- 从合法候选边中先构造基础时间邻接骨架
- 保证每个场景至少连接前后最近邻
- 再按综合评分补边
- 每补一条边,对已覆盖区域施加惩罚
- 达到目标连通性和最大边数后停止
综合评分建议:
selection_score = w_time * time_score + w_spatial * spatial_score + w_overlap * overlap_score + w_aoi * aoi_gain - w_redundancy * redundancy_penalty
5.4 删除旧 fallback 的原则
本轮不再保留“Python 语义独立 fallback”。
替代方案:
- 候选边缓存是主路径
- 如果缓存不存在或脏数据过多:
- 返回明确的
DEGRADED/DIRTY状态 - 允许管理员触发重建
- 或在安全阈值内自动执行增量重建
- 返回明确的
也就是说:
- 可以有“降级状态”
- 不能再有“悄悄换算法”
6. 与现有扫描和自动维护机制的集成
6.1 源影像扫描后的集成点
当前源影像扫描入口:
backend/app/services/data_service.py::scan_radar_databackend/app/scheduler.py::scan_data_job
建议改造:
在 scan_radar_data() 中,对新增、更新、删除的 radar_data 记录执行:
- 标记
pairing_dirty_scenes - 更新
pairing_cache_state.status = DIRTY - 根据变更规模决定是否立即增量重建
建议阈值:
- 变更场景数
<= SMALL_RECONCILE_LIMIT- 扫描结束后直接执行增量 reconcile
- 变更场景数
> SMALL_RECONCILE_LIMIT- 仅标脏,不在扫描链路内同步重建
- 由管理员在自检面板手动触发
这与当前 manual-only 模式兼容,不依赖后台常驻调度器。
6.2 启动期自维护
当前启动期会执行:
ensure_database_ready()root_registry_service.sync_from_settings()manifest_inventory_service.sync_manifest_roots()- catalog bootstrap
- health check
建议新增启动动作:
pairing_service.bootstrap_pairing_cache_state()
只做轻量检查:
- 新表是否存在
- 是否有缓存状态行
metric_version是否匹配当前版本- dirty scene 是否堆积
不建议启动即全量重建,避免启动时间失控。
6.3 数据库自动维护策略
当前数据库自维护具备两个模式:
- 常规模式:建表、补列、应用 migration
- 开发机强制 reset 模式:整库 schema reset
由于本轮是配对内核重构,且当前是开发机,推荐采用:
推荐落地策略
第一轮实施时直接执行一次开发机 schema reset。
原因:
- 旧配对 SQL 函数与新缓存设计语义完全不同
- 旧任务表中的配对数据没有保留价值
- 旧结果可以通过 manifest inventory 和结果 catalog 重建
- 源影像可以重新扫描
具体方式:
- 合并新 ORM 与 migration 后
- 启动前临时设置:
DB_SCHEMA_RESET_ON_MISMATCH=trueDB_SCHEMA_RESET_CONFIRM=true
- 启动一次后让
ensure_database_ready()重建 schema - 启动完成后恢复这两个环境变量为
false
6.4 migration 文件策略
当前 db_maintenance.py 中 migration 顺序为:
001_st_intersection_agg.sql002_spatial_functions.sql003_pairing_enhancement.sql
建议新增:
004_pairing_refactor.sql
该 migration 负责:
- 创建新 pairing 表
- 创建必要索引
- 创建候选边计算函数或 SQL helper view
- 如有需要,保留旧函数为 deprecated wrapper
建议:
- 不要在
004里继续强化find_dinsar_pairs_v2 - 将旧函数标记 deprecated,仅作为过渡壳
- 新逻辑直接走新 service + 新表
7. 自检与一致性检测升级
7.1 Health 接口扩展
当前健康检查聚合点:
backend/app/services/health_service.py::get_health_status
建议新增检查项:
pairing_system
字段建议:
okstatusmetric_versionscene_countpair_countdirty_scene_countnetwork_run_count_last_7dlast_full_rebuild_atlast_incremental_reconcile_atlast_errorduplicate_reverse_pair_countorphan_metric_scene_ref_counttask_without_network_ref_countresult_without_pair_trace_count
判定规则建议:
READY且无关键异常 ->ok=trueDIRTY但 dirty 数量较少 ->ok=false,级别warn- 存在重复反向边、孤儿引用、版本漂移 ->
ok=false,级别error
7.2 Health 面板扩展
当前 HealthCheckPanel.jsx 已能展示结构化卡片。
建议新增卡片:
配对系统
展示内容:
- 缓存状态
- 指标版本
- 场景数 / 缓存对数
- dirty scene 数
- 最近全量 / 增量时间
- 关键错误数
操作按钮建议:
增量修复配对缓存全量重建配对缓存清理旧网络记录
7.3 Statistics 接口扩展
当前 /statistics 已承担一致性统计角色。
建议追加:
pairing_consistency
字段建议:
metric_cache_countduplicate_reverse_pair_countinvalid_orientation_countnetwork_edge_orphan_counttask_orphan_countresult_trace_missing_count
8. API 重构计划
8.1 后端接口
当前接口:
POST /api/find-pairs
建议分两阶段改造。
Phase 1:保持前端可用
保留:
POST /api/find-pairs
但内部改为:
- 从
pairing_metric_cache查询 - 选择网络
- 返回
network_run_id + pairs
Phase 2:正式 API
新增:
POST /api/pairing/previewPOST /api/pairing/networks/{network_run_id}/materialize-batchPOST /api/pairing/reconcile-dirtyPOST /api/pairing/rebuild-cacheGET /api/pairing/healthGET /api/pairing/networks/{network_run_id}
8.2 请求模型
PairingRequest 应清理为正式语义:
- 删除
start_date aoi_overlap_threshold前端空值统一传nullstrategy继续保留:allsequentialstarsbas
reference_image_id仅在star时有效
8.3 返回模型
建议新增返回字段:
network_run_idpolicy_versioncandidate_countselected_edge_countdegradedwarnings
9. 前端改造计划
涉及文件:
frontend/src/components/PairingModal.jsxfrontend/src/hooks/usePairingLogic.jsfrontend/src/store/pairingStore.js
改造原则:
- 前端不再承载配对语义补丁
- 所有“0 表示不限”“默认排序说明”等语义统一交回后端协议
- 结果列表显示:
network_run_idstrategypolicy_version- warning
界面调整建议:
all策略文案改为“全部合法候选边,按稳定顺序展示”star明确说明“参考像固定为主像”sequential明确说明“同日多景按稳定键排序”- AOI 覆盖阈值为空时传
null
10. 旧代码处理策略
10.1 可以删除的内容
在新缓存路径稳定后,可以删除:
spatial_service.find_dinsar_pairs()中当前 Python fallback- 旧
_apply_star_strategy()非固定角色实现 - 旧
start_date兼容逻辑
10.2 需要保留过渡一段时间的内容
- 旧前端
find-pairs调用入口 - 旧
task_alias / pair_key命名辅助
但注意:
- 命名只能作为展示与兼容字段
- 不能继续作为算法主键
11. 实施阶段划分
Phase 0:开发机切换准备
- 确认当前开发机允许 DB reset
- 记录
.env中路径配置 - 保留现有
managed_roots/path_inventory/ manifest publish 目录,不做文件层清理 - 准备新 migration 与 ORM
验收:
- 可以安全启动一次 schema reset
Phase 1:数据模型落地
- 新增 pairing 相关 ORM
- 新增
004_pairing_refactor.sql - 接入
ensure_database_ready() - 建立
pairing_cache_state初始化逻辑
验收:
- 后端启动后新表自动创建
- 健康检查不报 schema 错
Phase 2:候选缓存引擎
- 实现
pairing_metric_cache全量构建 - 实现
pairing_dirty_scenes - 在
scan_radar_data()中接入 dirty 标记
验收:
- 能从
radar_data构建稳定 pair cache - 同日反向重复为 0
Phase 3:网络选择器
- 重写
all / sequential / star / sbas - 删除算法不等价 fallback
- 为
find-pairs接口切换到新内核
验收:
- 同一输入重复请求结果稳定
star固定参考像角色sequential同日多景稳定
Phase 4:任务物化与结果追踪
dinsar_task_items增加 network trace 字段- 结果 manifest / product profile 补充配对追踪字段
验收:
- 任一结果可追溯到 network edge
Phase 5:自维护与自检
- 健康检查新增
pairing_system - Health 面板新增配对卡片与修复按钮
- Statistics 新增 pairing consistency
验收:
- 能显示 dirty scene 数、缓存状态、重复边异常
- 能从 UI 触发增量修复与全量重建
Phase 6:清理旧逻辑
- 删除旧 fallback
- 删除
start_date - 下线旧语义说明
验收:
- 配对链路只剩单一语义实现
12. 测试矩阵
本轮至少补以下自动化测试:
12.1 候选缓存层
- 同日双景只生成单方向边
- 同日多景生成顺序稳定
- 不同轨向不生成边
- 时间基线越界不入缓存
12.2 请求过滤层
allowed_satellites生效cross_satellite_pairing=false生效require_same_imaging_mode/polarization生效aoi_overlap_threshold=null与0.2行为不同
12.3 策略层
all顺序稳定sequential连接数正确star参考像固定为 mastersbas至少满足基础连通性
12.4 集成层
- 扫描新增源影像后 dirty scene 正确增加
- 执行增量 reconcile 后 dirty scene 清零
find-pairs返回network_run_idmaterialize-batch后任务项带 network trace
12.5 自检层
- 重复边异常能被 health 检出
- 孤儿网络边能被 health 检出
- 任务无 network trace 能被 statistics 检出
13. 风险与取舍
13.1 本轮明确接受的取舍
- 开发机允许整库 reset
- 不迁移旧配对记录
- 不保留旧 fallback
13.2 需要重点控制的风险
- 首轮全量构建 pair cache 可能较慢
radar_data.unique_id可能不稳定,需要一次性规范- 旧结果如果缺少 trace 字段,需要通过 manifest/profile 尽可能补齐
- 若前端仍传
0,后端必须做强制归一化,不能再依赖 UI 自觉
14. 推荐实施顺序
建议严格按下面顺序推进:
- 先落表和缓存状态,不先改前端
- 再实现候选缓存和增量脏标记
- 再重写四种策略
- 再接任务物化追踪
- 最后接健康检查与自修复入口
不要反过来做:
- 不要先改 UI 文案
- 不要先修补
find_dinsar_pairs_v2 - 不要保留旧 fallback 到最后
15. 本轮结论
在当前代码基线上,最合理的重构路线不是继续维护“实时 SQL + Python fallback”模式,而是:
- 用
radar_data作为唯一事实层 - 用
pairing_metric_cache承载稳定候选对 - 用
pairing_network_runs / edges承载策略结果 - 用
pairing_cache_state / dirty_scenes承接自维护 - 用现有
HealthCheckPanel和/statistics承接自检
这样做的直接收益是:
- 正确性可锁定
- 结果可追溯
- 与现有 DB 自维护、扫描链路、自检体系自然对接
- 后续再接 SBAS、跨卫星和多引擎生产时不会继续堆积配对债务