Initial import of NavSea pbf project
This commit is contained in:
660
navsea_relayer.py
Normal file
660
navsea_relayer.py
Normal file
@@ -0,0 +1,660 @@
|
||||
import json
|
||||
from collections import Counter, defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
import pymysql
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
STYLE_JSON_PATH = ROOT / "src" / "pbf" / "style.json"
|
||||
|
||||
MANUAL_OBJECT_RULES = {
|
||||
"P754ククリ": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Source-preserved clip/outline layer.",
|
||||
},
|
||||
"P危険界ククリ": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Source-preserved clip/outline layer.",
|
||||
},
|
||||
"P基本線ククリ": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Source-preserved clip/outline layer.",
|
||||
},
|
||||
"P投錨注意障害物ククリ": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Source-preserved clip/outline layer.",
|
||||
},
|
||||
"P施設・境界線等ククリ": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Source-preserved clip/outline layer.",
|
||||
},
|
||||
"P航路ククリ": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Source-preserved clip/outline layer.",
|
||||
},
|
||||
"P穴": {
|
||||
"family": "surface",
|
||||
"allowed_geom_types": ["Polygon", "MultiPolygon"],
|
||||
"notes": "Source-preserved area layer.",
|
||||
},
|
||||
"P陸域": {
|
||||
"family": "surface",
|
||||
"allowed_geom_types": ["Polygon", "MultiPolygon"],
|
||||
"notes": "Source-preserved area layer.",
|
||||
},
|
||||
"L海底地形": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Source-preserved bathymetry line layer.",
|
||||
},
|
||||
"p地名": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Source-preserved place label layer.",
|
||||
},
|
||||
"p地名陸": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Source-preserved place label layer.",
|
||||
},
|
||||
"p高さ制限": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Source-preserved point annotation layer.",
|
||||
},
|
||||
"p錨泊地等": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Source-preserved point annotation layer.",
|
||||
},
|
||||
"サンドウェーブ": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Same object appears in multiple source layers but remains a point hazard.",
|
||||
},
|
||||
"海底設置物、放水口、取水口": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Stable point object despite multiple source layers.",
|
||||
},
|
||||
"全沈没船 (危険なし)": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Stable point object despite multiple source layers.",
|
||||
},
|
||||
"測定済みの沈船": {
|
||||
"family": "symbol",
|
||||
"allowed_geom_types": ["Point"],
|
||||
"notes": "Stable point object despite multiple source layers.",
|
||||
},
|
||||
"道路": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Road centerlines legitimately appear in multi-part line form.",
|
||||
},
|
||||
"等深線": {
|
||||
"family": "line",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString"],
|
||||
"notes": "Depth contours legitimately appear in multi-part line form.",
|
||||
},
|
||||
"防波堤": {
|
||||
"family": "surface",
|
||||
"allowed_geom_types": ["Polygon", "MultiPolygon"],
|
||||
"notes": "Breakwaters are modeled as areas, including multipart polygons.",
|
||||
},
|
||||
"障害物": {
|
||||
"family": "mixed",
|
||||
"allowed_geom_types": ["Point", "Polygon", "MultiPolygon"],
|
||||
"notes": "Obstacle objects can be rendered as symbols or area extents.",
|
||||
},
|
||||
"未測海域": {
|
||||
"family": "mixed",
|
||||
"allowed_geom_types": ["LineString", "Polygon", "MultiPolygon"],
|
||||
"notes": "Unsurveyed regions appear as boundaries and areas.",
|
||||
},
|
||||
"浮施設・桟橋": {
|
||||
"family": "mixed",
|
||||
"allowed_geom_types": ["LineString", "MultiLineString", "Polygon", "MultiPolygon"],
|
||||
"notes": "Floating facilities and piers appear as line and area geometry.",
|
||||
},
|
||||
"航路 (法律による航路)": {
|
||||
"family": "mixed",
|
||||
"allowed_geom_types": ["LineString", "Polygon", "MultiPolygon"],
|
||||
"notes": "Legally defined routes appear as lines and areas.",
|
||||
},
|
||||
"険悪物": {
|
||||
"family": "mixed",
|
||||
"allowed_geom_types": ["Point", "Polygon", "MultiPolygon"],
|
||||
"notes": "Hazards may be represented as point symbols or area extents.",
|
||||
},
|
||||
"魚礁": {
|
||||
"family": "mixed",
|
||||
"allowed_geom_types": ["Point", "Polygon", "MultiPolygon"],
|
||||
"notes": "Artificial reefs may be represented as point symbols or area extents.",
|
||||
},
|
||||
"養殖場": {
|
||||
"family": "surface",
|
||||
"allowed_geom_types": ["Polygon", "MultiPolygon"],
|
||||
"notes": "Aquaculture zones are area features.",
|
||||
},
|
||||
"漁網": {
|
||||
"family": "surface",
|
||||
"allowed_geom_types": ["Polygon", "MultiPolygon"],
|
||||
"notes": "Fishing nets are area extents in this dataset.",
|
||||
},
|
||||
"錨泊 (指定)地": {
|
||||
"family": "mixed",
|
||||
"allowed_geom_types": ["Point", "Polygon", "MultiPolygon"],
|
||||
"notes": "Anchorage can appear as symbol or area depending on source layer.",
|
||||
},
|
||||
"ケーソン仮置き場": {
|
||||
"family": "surface",
|
||||
"allowed_geom_types": ["Polygon", "MultiPolygon"],
|
||||
"notes": "Caisson storage areas are polygons.",
|
||||
},
|
||||
"土砂捨て場": {
|
||||
"family": "surface",
|
||||
"allowed_geom_types": ["Polygon", "MultiPolygon"],
|
||||
"notes": "Spoil grounds are polygons.",
|
||||
},
|
||||
}
|
||||
|
||||
DEFAULT_GEOMETRIES = {
|
||||
"symbol": ["Point"],
|
||||
"line": ["LineString", "MultiLineString"],
|
||||
"surface": ["Polygon", "MultiPolygon"],
|
||||
"mixed": [],
|
||||
}
|
||||
|
||||
|
||||
def connect():
|
||||
return pymysql.connect(
|
||||
host="localhost",
|
||||
user="root",
|
||||
password="2chi9ks2",
|
||||
database="pbf_analysis",
|
||||
charset="utf8mb4",
|
||||
unix_socket="/tmp/mysql.sock",
|
||||
autocommit=False,
|
||||
)
|
||||
|
||||
|
||||
def load_style_source_layers():
|
||||
style = json.loads(STYLE_JSON_PATH.read_text(encoding="utf-8"))
|
||||
layers = {}
|
||||
for layer in style.get("layers", []):
|
||||
source_layer = layer.get("source-layer")
|
||||
if not source_layer:
|
||||
continue
|
||||
layers.setdefault(source_layer, {"style_rows": 0, "layer_types": set()})
|
||||
layers[source_layer]["style_rows"] += 1
|
||||
if layer.get("type"):
|
||||
layers[source_layer]["layer_types"].add(layer["type"])
|
||||
return layers
|
||||
|
||||
|
||||
def geom_bucket(geom_type: str | None) -> str:
|
||||
if geom_type in {"Point", "MultiPoint"}:
|
||||
return "symbol"
|
||||
if geom_type in {"LineString", "MultiLineString"}:
|
||||
return "line"
|
||||
if geom_type in {"Polygon", "MultiPolygon"}:
|
||||
return "surface"
|
||||
return "mixed"
|
||||
|
||||
|
||||
def infer_family(geom_types: set[str]) -> str:
|
||||
buckets = {geom_bucket(geom_type) for geom_type in geom_types if geom_type}
|
||||
if not buckets:
|
||||
return "mixed"
|
||||
if len(buckets) == 1:
|
||||
return next(iter(buckets))
|
||||
return "mixed"
|
||||
|
||||
|
||||
def choose_allowed_geometries(object_type: str, family: str, observed_geom_types: list[str]) -> tuple[list[str], str]:
|
||||
manual = MANUAL_OBJECT_RULES.get(object_type)
|
||||
if manual:
|
||||
return manual["allowed_geom_types"], "manual_override"
|
||||
defaults = DEFAULT_GEOMETRIES.get(family, [])
|
||||
if defaults:
|
||||
return defaults, "family_default"
|
||||
return observed_geom_types, "observed_fallback"
|
||||
|
||||
|
||||
def build_canonical_layer_rules(cur, style_layers):
|
||||
cur.execute("DROP TABLE IF EXISTS canonical_layer_rules")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE canonical_layer_rules (
|
||||
source_layer VARCHAR(100) NOT NULL,
|
||||
semantic_granularity VARCHAR(50) NOT NULL,
|
||||
canonical_family VARCHAR(100) NOT NULL,
|
||||
render_strategy VARCHAR(50) NOT NULL,
|
||||
preserve_source_layer TINYINT(1) NOT NULL DEFAULT 1,
|
||||
style_bound TINYINT(1) NOT NULL DEFAULT 1,
|
||||
style_rows INT NOT NULL DEFAULT 0,
|
||||
style_types VARCHAR(200) NULL,
|
||||
notes TEXT NULL,
|
||||
PRIMARY KEY (source_layer)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
"""
|
||||
)
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
vt_layer,
|
||||
SUM(feature_count) AS feature_count,
|
||||
COUNT(DISTINCT COALESCE(NULLIF(class_name, ''), NULLIF(shape_name, ''), vt_layer)) AS semantic_type_count,
|
||||
SUM(CASE WHEN class_name IS NULL OR class_name='' THEN feature_count ELSE 0 END) AS missing_class_count,
|
||||
SUM(CASE WHEN shape_name IS NULL OR shape_name='' THEN feature_count ELSE 0 END) AS missing_shape_count
|
||||
FROM object_catalog
|
||||
GROUP BY vt_layer
|
||||
"""
|
||||
)
|
||||
|
||||
inserts = []
|
||||
for vt_layer, feature_count, semantic_type_count, missing_class_count, missing_shape_count in cur.fetchall():
|
||||
style_info = style_layers.get(vt_layer, {"style_rows": 0, "layer_types": set()})
|
||||
|
||||
if vt_layer.startswith("p"):
|
||||
canonical_family = "symbol"
|
||||
elif vt_layer.startswith("L"):
|
||||
canonical_family = "line"
|
||||
elif vt_layer.startswith("P"):
|
||||
canonical_family = "surface"
|
||||
else:
|
||||
canonical_family = "mixed"
|
||||
|
||||
if semantic_type_count >= 5 and (vt_layer.startswith("P") or vt_layer.startswith("L")):
|
||||
semantic_granularity = "container_layer"
|
||||
notes = (
|
||||
f"Layer contains {semantic_type_count} semantic types across {feature_count} features; "
|
||||
"retain source layer for rendering and derive semantic overlays for analysis."
|
||||
)
|
||||
elif missing_class_count == feature_count and missing_shape_count == feature_count:
|
||||
semantic_granularity = "style_or_source_layer"
|
||||
notes = "Layer has no semantic class/shape annotations; source layer remains the stable identity."
|
||||
else:
|
||||
semantic_granularity = "semantic_layer"
|
||||
notes = "Layer is close to a stable semantic object and can be preserved as-is."
|
||||
|
||||
inserts.append(
|
||||
(
|
||||
vt_layer,
|
||||
semantic_granularity,
|
||||
canonical_family,
|
||||
"keep_source_layer",
|
||||
1,
|
||||
1 if style_info["style_rows"] > 0 else 0,
|
||||
style_info["style_rows"],
|
||||
",".join(sorted(style_info["layer_types"])) or None,
|
||||
notes,
|
||||
)
|
||||
)
|
||||
|
||||
cur.executemany(
|
||||
"""
|
||||
INSERT INTO canonical_layer_rules (
|
||||
source_layer,
|
||||
semantic_granularity,
|
||||
canonical_family,
|
||||
render_strategy,
|
||||
preserve_source_layer,
|
||||
style_bound,
|
||||
style_rows,
|
||||
style_types,
|
||||
notes
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
inserts,
|
||||
)
|
||||
|
||||
|
||||
def build_canonical_object_rules(cur):
|
||||
cur.execute("DROP TABLE IF EXISTS canonical_object_rules")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE canonical_object_rules (
|
||||
canonical_object_type VARCHAR(191) NOT NULL,
|
||||
canonical_family VARCHAR(100) NOT NULL,
|
||||
classification_basis VARCHAR(50) NOT NULL,
|
||||
source_layer_scope VARCHAR(50) NOT NULL,
|
||||
source_layer_count INT NOT NULL,
|
||||
geom_type_count INT NOT NULL,
|
||||
object_type_sources VARCHAR(100) NOT NULL,
|
||||
source_layers TEXT NULL,
|
||||
observed_geom_types VARCHAR(200) NULL,
|
||||
allowed_geom_types VARCHAR(200) NULL,
|
||||
preferred_geom_type VARCHAR(20) NULL,
|
||||
geometry_rule_source VARCHAR(50) NOT NULL,
|
||||
notes TEXT NULL,
|
||||
PRIMARY KEY (canonical_object_type)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
"""
|
||||
)
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
COALESCE(NULLIF(class_name, ''), NULLIF(shape_name, ''), vt_layer) AS object_type,
|
||||
GROUP_CONCAT(
|
||||
DISTINCT CASE
|
||||
WHEN class_name IS NOT NULL AND class_name <> '' THEN 'class_name'
|
||||
WHEN shape_name IS NOT NULL AND shape_name <> '' THEN 'shape_name'
|
||||
ELSE 'vt_layer'
|
||||
END
|
||||
ORDER BY 1 SEPARATOR ','
|
||||
) AS object_type_sources,
|
||||
SUM(feature_count) AS feature_count,
|
||||
COUNT(DISTINCT vt_layer) AS source_layer_count,
|
||||
GROUP_CONCAT(DISTINCT vt_layer ORDER BY vt_layer SEPARATOR ',') AS source_layers,
|
||||
COUNT(DISTINCT geom_type) AS geom_type_count,
|
||||
GROUP_CONCAT(DISTINCT geom_type ORDER BY geom_type SEPARATOR ',') AS observed_geom_types
|
||||
FROM object_catalog
|
||||
GROUP BY COALESCE(NULLIF(class_name, ''), NULLIF(shape_name, ''), vt_layer)
|
||||
"""
|
||||
)
|
||||
object_rows = cur.fetchall()
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
object_type,
|
||||
geom_type,
|
||||
feature_count
|
||||
FROM object_type_stats
|
||||
"""
|
||||
)
|
||||
geom_counts: dict[str, Counter[str]] = defaultdict(Counter)
|
||||
for object_type, geom_type, feature_count in cur.fetchall():
|
||||
geom_counts[object_type][geom_type] = feature_count
|
||||
|
||||
inserts = []
|
||||
for (
|
||||
object_type,
|
||||
object_type_sources,
|
||||
feature_count,
|
||||
source_layer_count,
|
||||
source_layers,
|
||||
geom_type_count,
|
||||
observed_geom_types,
|
||||
) in object_rows:
|
||||
observed_geom_list = [part for part in (observed_geom_types or "").split(",") if part]
|
||||
observed_geom_set = set(observed_geom_list)
|
||||
manual = MANUAL_OBJECT_RULES.get(object_type)
|
||||
canonical_family = manual["family"] if manual else infer_family(observed_geom_set)
|
||||
classification_basis = (
|
||||
"source_layer_preserved"
|
||||
if object_type_sources == "vt_layer"
|
||||
else "semantic_object"
|
||||
)
|
||||
source_layer_scope = "multi_source" if source_layer_count > 1 else "single_source"
|
||||
allowed_geom_types, geometry_rule_source = choose_allowed_geometries(
|
||||
object_type,
|
||||
canonical_family,
|
||||
observed_geom_list,
|
||||
)
|
||||
preferred_geom_type = None
|
||||
if geom_counts.get(object_type):
|
||||
preferred_geom_type = geom_counts[object_type].most_common(1)[0][0]
|
||||
notes = (
|
||||
manual["notes"]
|
||||
if manual
|
||||
else (
|
||||
"Source-preserved object type derived from vt_layer only."
|
||||
if classification_basis == "source_layer_preserved"
|
||||
else "Semantic object type derived from class_name/shape_name."
|
||||
)
|
||||
)
|
||||
inserts.append(
|
||||
(
|
||||
object_type,
|
||||
canonical_family,
|
||||
classification_basis,
|
||||
source_layer_scope,
|
||||
source_layer_count,
|
||||
geom_type_count,
|
||||
object_type_sources,
|
||||
source_layers,
|
||||
",".join(observed_geom_list) or None,
|
||||
",".join(allowed_geom_types) or None,
|
||||
preferred_geom_type,
|
||||
geometry_rule_source,
|
||||
notes,
|
||||
)
|
||||
)
|
||||
|
||||
cur.executemany(
|
||||
"""
|
||||
INSERT INTO canonical_object_rules (
|
||||
canonical_object_type,
|
||||
canonical_family,
|
||||
classification_basis,
|
||||
source_layer_scope,
|
||||
source_layer_count,
|
||||
geom_type_count,
|
||||
object_type_sources,
|
||||
source_layers,
|
||||
observed_geom_types,
|
||||
allowed_geom_types,
|
||||
preferred_geom_type,
|
||||
geometry_rule_source,
|
||||
notes
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||
""",
|
||||
inserts,
|
||||
)
|
||||
|
||||
|
||||
def build_object_geometry_allowlist(cur):
|
||||
cur.execute("DROP TABLE IF EXISTS object_geometry_allowlist")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE object_geometry_allowlist (
|
||||
canonical_object_type VARCHAR(191) NOT NULL,
|
||||
geometry_type VARCHAR(20) NOT NULL,
|
||||
rule_source VARCHAR(50) NOT NULL,
|
||||
is_allowed TINYINT(1) NOT NULL DEFAULT 1,
|
||||
notes TEXT NULL,
|
||||
PRIMARY KEY (canonical_object_type, geometry_type)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
"""
|
||||
)
|
||||
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
canonical_object_type,
|
||||
geometry_rule_source,
|
||||
allowed_geom_types,
|
||||
notes
|
||||
FROM canonical_object_rules
|
||||
"""
|
||||
)
|
||||
|
||||
inserts = []
|
||||
for canonical_object_type, geometry_rule_source, allowed_geom_types, notes in cur.fetchall():
|
||||
for geometry_type in [part for part in (allowed_geom_types or "").split(",") if part]:
|
||||
inserts.append(
|
||||
(
|
||||
canonical_object_type,
|
||||
geometry_type,
|
||||
geometry_rule_source,
|
||||
1,
|
||||
notes,
|
||||
)
|
||||
)
|
||||
|
||||
if inserts:
|
||||
cur.executemany(
|
||||
"""
|
||||
INSERT INTO object_geometry_allowlist (
|
||||
canonical_object_type,
|
||||
geometry_type,
|
||||
rule_source,
|
||||
is_allowed,
|
||||
notes
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
""",
|
||||
inserts,
|
||||
)
|
||||
|
||||
|
||||
def build_relayer_outputs(cur):
|
||||
cur.execute("DROP TABLE IF EXISTS pbf_relayer_candidates")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE pbf_relayer_candidates AS
|
||||
SELECT
|
||||
o.feature_id,
|
||||
s.z,
|
||||
s.x,
|
||||
s.y,
|
||||
s.vt_layer AS source_layer,
|
||||
s.geom_type,
|
||||
s.class_name,
|
||||
s.shape_name,
|
||||
s.layer_name,
|
||||
o.object_type_source,
|
||||
o.object_type AS canonical_object_type,
|
||||
r.semantic_granularity,
|
||||
obj.canonical_family,
|
||||
obj.classification_basis,
|
||||
obj.source_layer_scope,
|
||||
r.render_strategy,
|
||||
r.preserve_source_layer,
|
||||
r.style_bound,
|
||||
CASE
|
||||
WHEN obj.classification_basis = 'source_layer_preserved' THEN CONCAT('source:', s.vt_layer)
|
||||
ELSE CONCAT(obj.canonical_family, ':', o.object_type)
|
||||
END AS semantic_key,
|
||||
CASE
|
||||
WHEN obj.classification_basis = 'source_layer_preserved' THEN CONCAT(obj.canonical_family, ':', s.vt_layer)
|
||||
ELSE CONCAT(obj.canonical_family, ':', o.object_type)
|
||||
END AS detection_key,
|
||||
CASE
|
||||
WHEN r.preserve_source_layer = 1 THEN s.vt_layer
|
||||
ELSE o.object_type
|
||||
END AS render_layer
|
||||
FROM feature_semantic s
|
||||
JOIN object_type_candidates o
|
||||
ON s.feature_id = o.feature_id
|
||||
JOIN canonical_layer_rules r
|
||||
ON s.vt_layer = r.source_layer
|
||||
JOIN canonical_object_rules obj
|
||||
ON o.object_type = obj.canonical_object_type
|
||||
"""
|
||||
)
|
||||
|
||||
cur.execute("DROP TABLE IF EXISTS pbf_source_object_stats")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE pbf_source_object_stats AS
|
||||
SELECT
|
||||
source_layer,
|
||||
render_layer,
|
||||
canonical_family,
|
||||
classification_basis,
|
||||
source_layer_scope,
|
||||
semantic_granularity,
|
||||
style_bound,
|
||||
canonical_object_type,
|
||||
geom_type,
|
||||
detection_key,
|
||||
semantic_key,
|
||||
COUNT(*) AS feature_count
|
||||
FROM pbf_relayer_candidates
|
||||
GROUP BY
|
||||
source_layer,
|
||||
render_layer,
|
||||
canonical_family,
|
||||
classification_basis,
|
||||
source_layer_scope,
|
||||
semantic_granularity,
|
||||
style_bound,
|
||||
canonical_object_type,
|
||||
geom_type,
|
||||
detection_key,
|
||||
semantic_key
|
||||
"""
|
||||
)
|
||||
cur.execute("ALTER TABLE pbf_source_object_stats ADD KEY idx_source_layer (source_layer(100))")
|
||||
cur.execute("ALTER TABLE pbf_source_object_stats ADD KEY idx_render_layer (render_layer(100))")
|
||||
cur.execute("ALTER TABLE pbf_source_object_stats ADD KEY idx_detection_key (detection_key(50))")
|
||||
|
||||
cur.execute("DROP TABLE IF EXISTS pbf_render_compatibility")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE pbf_render_compatibility AS
|
||||
SELECT
|
||||
s.source_layer,
|
||||
s.render_layer,
|
||||
s.canonical_family,
|
||||
s.semantic_granularity,
|
||||
s.style_bound,
|
||||
SUM(s.feature_count) AS feature_count,
|
||||
COUNT(*) AS canonical_object_types
|
||||
FROM pbf_source_object_stats s
|
||||
GROUP BY
|
||||
s.source_layer,
|
||||
s.render_layer,
|
||||
s.canonical_family,
|
||||
s.semantic_granularity,
|
||||
s.style_bound
|
||||
"""
|
||||
)
|
||||
|
||||
cur.execute("DROP TABLE IF EXISTS pbf_detection_catalog")
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE pbf_detection_catalog AS
|
||||
SELECT
|
||||
detection_key,
|
||||
canonical_family,
|
||||
canonical_object_type,
|
||||
geom_type,
|
||||
SUM(feature_count) AS feature_count,
|
||||
COUNT(DISTINCT source_layer) AS source_layers
|
||||
FROM pbf_source_object_stats
|
||||
GROUP BY
|
||||
detection_key,
|
||||
canonical_family,
|
||||
canonical_object_type,
|
||||
geom_type
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def refresh_relayer_tables():
|
||||
style_layers = load_style_source_layers()
|
||||
|
||||
with connect() as conn:
|
||||
with conn.cursor() as cur:
|
||||
build_canonical_layer_rules(cur, style_layers)
|
||||
build_canonical_object_rules(cur)
|
||||
build_object_geometry_allowlist(cur)
|
||||
build_relayer_outputs(cur)
|
||||
conn.commit()
|
||||
|
||||
|
||||
def main():
|
||||
refresh_relayer_tables()
|
||||
print(
|
||||
"Built canonical_layer_rules, canonical_object_rules, object_geometry_allowlist, "
|
||||
"pbf_relayer_candidates, pbf_render_compatibility, pbf_detection_catalog"
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user