refactor(db)!: adopt project-routed pooled databases
Reorganize WNDB by responsibility and remove legacy scheme endpoints.\n\nRoute analysis and time-series access through project pools, preserve transactional realtime replacement, and refresh GIS materialized views after writes.\n\nAdd database architecture documentation, live pooling coverage, API contract updates, and executable container verification.\n\nBREAKING CHANGE: legacy scheme APIs and flat app.native.wndb module imports are removed.
This commit is contained in:
@@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
from collections import Counter
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Any
|
||||
from uuid import UUID
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
@@ -49,8 +50,7 @@ def run_burst_detection(
|
||||
sensor_nodes: list[str] | None = None,
|
||||
scheme_name: str | None = None,
|
||||
data_source: str = "monitoring",
|
||||
simulation_scheme_name: str | None = None,
|
||||
simulation_scheme_type: str | None = None,
|
||||
simulation_run_id: UUID | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""
|
||||
运行爆管侦测服务入口。
|
||||
@@ -153,18 +153,17 @@ def run_burst_detection(
|
||||
else _get_pressure_sensor_nodes(network)
|
||||
)
|
||||
if data_source == "simulation":
|
||||
if not simulation_scheme_name:
|
||||
raise ValueError("模拟方案模式必须提供 simulation_scheme_name。")
|
||||
if not simulation_run_id:
|
||||
raise ValueError("模拟数据模式必须提供 simulation_run_id。")
|
||||
observed_df = _build_observed_pressure_from_simulation(
|
||||
network=network,
|
||||
sensor_nodes=scada_sensor_nodes,
|
||||
scada_start=scada_start,
|
||||
scada_end=scada_end,
|
||||
simulation_scheme_name=simulation_scheme_name,
|
||||
simulation_scheme_type=simulation_scheme_type,
|
||||
simulation_run_id=simulation_run_id,
|
||||
)
|
||||
observed_input = observed_df
|
||||
observed_source = "simulation_scheme_timerange"
|
||||
observed_source = "analysis_run_timerange"
|
||||
else:
|
||||
observed_df = _build_observed_pressure_from_scada(
|
||||
network=network,
|
||||
@@ -224,9 +223,8 @@ def run_burst_detection(
|
||||
}
|
||||
if data_source == "simulation":
|
||||
payload["data_source"] = "simulation"
|
||||
payload["simulation_scheme"] = {
|
||||
"name": simulation_scheme_name,
|
||||
"type": simulation_scheme_type,
|
||||
payload["simulation_run"] = {
|
||||
"run_id": str(simulation_run_id),
|
||||
}
|
||||
else:
|
||||
payload["data_source"] = "monitoring"
|
||||
@@ -299,11 +297,10 @@ def _build_observed_pressure_from_simulation(
|
||||
sensor_nodes: list[str],
|
||||
scada_start: datetime | str | None,
|
||||
scada_end: datetime | str | None,
|
||||
simulation_scheme_name: str | None,
|
||||
simulation_scheme_type: str | None = None,
|
||||
simulation_run_id: UUID,
|
||||
) -> pd.DataFrame:
|
||||
if scada_start is None or scada_end is None:
|
||||
raise ValueError("使用模拟方案查询时必须同时提供 scada_start 与 scada_end。")
|
||||
raise ValueError("使用分析模拟数据时必须同时提供 scada_start 与 scada_end。")
|
||||
|
||||
start_dt = _to_datetime(scada_start)
|
||||
end_dt = _to_datetime(scada_end)
|
||||
@@ -316,12 +313,9 @@ def _build_observed_pressure_from_simulation(
|
||||
# Check for missing nodes in simulation result if needed, but InternalQueries handles some of it.
|
||||
# We assume sensor_nodes are valid pressure nodes.
|
||||
|
||||
scheme_type = simulation_scheme_type or "burst_analysis"
|
||||
|
||||
simulation_data = InternalQueries.query_scheme_simulation_by_ids_timerange(
|
||||
simulation_data = InternalQueries.query_analysis_simulation_by_ids_timerange(
|
||||
db_name=network,
|
||||
scheme_type=scheme_type,
|
||||
scheme_name=simulation_scheme_name,
|
||||
run_id=simulation_run_id,
|
||||
element_ids=sensor_nodes,
|
||||
start_time=start_dt.isoformat(),
|
||||
end_time=end_dt.isoformat(),
|
||||
@@ -646,8 +640,8 @@ def _resolve_sampling_interval_minutes(
|
||||
inferred_intervals = [
|
||||
parsed
|
||||
for item in get_all_scada_info(network)
|
||||
if str(item.get("type", "")).lower() == "pressure"
|
||||
and str(item.get("associated_element_id", "")) in selected_nodes
|
||||
if str(item.get("device_type", "")).lower() == "pressure"
|
||||
and str(item.get("node_id", "")) in selected_nodes
|
||||
and (
|
||||
parsed := _parse_sampling_interval_minutes(
|
||||
item.get("transmission_frequency")
|
||||
@@ -685,9 +679,9 @@ def _parse_sampling_interval_minutes(value: Any) -> int | None:
|
||||
def _get_pressure_sensor_mapping(network: str) -> dict[str, str]:
|
||||
node_query_id: dict[str, str] = {}
|
||||
for item in get_all_scada_info(network):
|
||||
if str(item.get("type", "")).lower() != "pressure":
|
||||
if str(item.get("device_type", "")).lower() != "pressure":
|
||||
continue
|
||||
node_id = item.get("associated_element_id")
|
||||
node_id = item.get("node_id")
|
||||
query_id = item.get("api_query_id")
|
||||
if node_id and query_id is not None:
|
||||
node_query_id[str(node_id)] = str(query_id)
|
||||
@@ -697,14 +691,16 @@ def _get_pressure_sensor_mapping(network: str) -> dict[str, str]:
|
||||
def _get_pressure_sensor_nodes(network: str) -> list[str]:
|
||||
sensor_nodes: list[str] = []
|
||||
for item in get_all_scada_info(network):
|
||||
if str(item.get("type", "")).lower() != "pressure":
|
||||
if str(item.get("device_type", "")).lower() != "pressure":
|
||||
continue
|
||||
node_id = item.get("associated_element_id")
|
||||
node_id = item.get("node_id")
|
||||
if isinstance(node_id, str) and node_id:
|
||||
sensor_nodes.append(node_id)
|
||||
sensor_nodes = list(dict.fromkeys(sensor_nodes))
|
||||
if not sensor_nodes:
|
||||
raise ValueError("未找到压力传感器对应节点(scada_info.type=pressure)。")
|
||||
raise ValueError(
|
||||
"未找到压力传感器对应节点(asset.scada_devices.device_type=pressure)。"
|
||||
)
|
||||
return sensor_nodes
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user