Optimize regional BWK municipality selection
This commit is contained in:
@@ -331,12 +331,19 @@ def select_vector_features(
|
|||||||
"limit": payload.limit,
|
"limit": payload.limit,
|
||||||
}
|
}
|
||||||
full_dataset_area = False
|
full_dataset_area = False
|
||||||
|
preclipped_partition_filter = None
|
||||||
if selection_area is not None:
|
if selection_area is not None:
|
||||||
full_dataset_area = VectorFeatureService.can_use_full_area_fast_path(dataset, selection_area.id)
|
full_dataset_area = VectorFeatureService.can_use_full_area_fast_path(dataset, selection_area.id)
|
||||||
|
if not full_dataset_area:
|
||||||
|
preclipped_partition_filter = VectorFeatureService.preclipped_partition_filter(
|
||||||
|
dataset,
|
||||||
|
getattr(selection_area, "name", None),
|
||||||
|
)
|
||||||
selection_kwargs.update(
|
selection_kwargs.update(
|
||||||
selection_geometry=selection_area.geometry,
|
selection_geometry=selection_area.geometry,
|
||||||
selection_area_id=selection_area.id,
|
selection_area_id=selection_area.id,
|
||||||
full_dataset_area=full_dataset_area,
|
full_dataset_area=full_dataset_area,
|
||||||
|
preclipped_partition_filter=preclipped_partition_filter,
|
||||||
)
|
)
|
||||||
result = VectorFeatureService.select_features_by_bbox(db, **selection_kwargs)
|
result = VectorFeatureService.select_features_by_bbox(db, **selection_kwargs)
|
||||||
if VectorFeatureService.supports_selection_summary(dataset):
|
if VectorFeatureService.supports_selection_summary(dataset):
|
||||||
@@ -348,6 +355,7 @@ def select_vector_features(
|
|||||||
if selection_area is not None:
|
if selection_area is not None:
|
||||||
summary_kwargs["selection_geometry"] = selection_area.geometry
|
summary_kwargs["selection_geometry"] = selection_area.geometry
|
||||||
summary_kwargs["full_dataset_area"] = full_dataset_area
|
summary_kwargs["full_dataset_area"] = full_dataset_area
|
||||||
|
summary_kwargs["preclipped_partition_filter"] = preclipped_partition_filter
|
||||||
result["summary"] = VectorFeatureService.summarize_features_by_bbox(db, **summary_kwargs)
|
result["summary"] = VectorFeatureService.summarize_features_by_bbox(db, **summary_kwargs)
|
||||||
return envelope(VectorSelectionResponse(**result).model_dump(exclude_none=True))
|
return envelope(VectorSelectionResponse(**result).model_dump(exclude_none=True))
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ SEMANTIC_METRICS_DISABLED_OPERATOR_TOOLS = {
|
|||||||
"provision_regional_historical_landuse.py",
|
"provision_regional_historical_landuse.py",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRECLIPPED_MUNICIPALITY_PARTITION_OPERATOR_TOOLS = {
|
||||||
|
"provision_regional_bwk_natura2000.py",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SEMANTIC_SELECTION_METRICS: dict[str, tuple[dict[str, Any], ...]] = {
|
SEMANTIC_SELECTION_METRICS: dict[str, tuple[dict[str, Any], ...]] = {
|
||||||
"buildings": (
|
"buildings": (
|
||||||
@@ -181,6 +185,30 @@ class VectorFeatureService:
|
|||||||
provenance = dataset.provenance_metadata if isinstance(dataset.provenance_metadata, dict) else {}
|
provenance = dataset.provenance_metadata if isinstance(dataset.provenance_metadata, dict) else {}
|
||||||
return provenance.get("operator_tool") in FULL_AREA_CLIPPED_OPERATOR_TOOLS
|
return provenance.get("operator_tool") in FULL_AREA_CLIPPED_OPERATOR_TOOLS
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def preclipped_partition_filter(dataset: Dataset, selection_area_name: str | None) -> tuple[str, str] | None:
|
||||||
|
provenance = dataset.provenance_metadata if isinstance(dataset.provenance_metadata, dict) else {}
|
||||||
|
if provenance.get("operator_tool") not in PRECLIPPED_MUNICIPALITY_PARTITION_OPERATOR_TOOLS:
|
||||||
|
return None
|
||||||
|
source_metadata = dataset.source_metadata if isinstance(dataset.source_metadata, dict) else {}
|
||||||
|
if (
|
||||||
|
source_metadata.get("partitioned_source_audit") is not True
|
||||||
|
or source_metadata.get("geometry_clipped_to_area") is not True
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
normalized_name = str(selection_area_name or "").strip()
|
||||||
|
prefix = "Gemeente "
|
||||||
|
suffixes = (" - officiële grens", " - officiele grens")
|
||||||
|
if not normalized_name.startswith(prefix):
|
||||||
|
return None
|
||||||
|
municipality = normalized_name[len(prefix):]
|
||||||
|
for suffix in suffixes:
|
||||||
|
if municipality.endswith(suffix):
|
||||||
|
municipality = municipality[: -len(suffix)]
|
||||||
|
break
|
||||||
|
municipality = municipality.strip()
|
||||||
|
return ("municipality", municipality) if municipality else None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _feature_row(dataset_id: UUID, feature: dict[str, Any], index: int, feature_class: str | None) -> VectorFeature | None:
|
def _feature_row(dataset_id: UUID, feature: dict[str, Any], index: int, feature_class: str | None) -> VectorFeature | None:
|
||||||
geometry_payload = feature.get("geometry")
|
geometry_payload = feature.get("geometry")
|
||||||
@@ -289,6 +317,7 @@ class VectorFeatureService:
|
|||||||
selection_geometry: Any | None = None,
|
selection_geometry: Any | None = None,
|
||||||
selection_area_id: UUID | None = None,
|
selection_area_id: UUID | None = None,
|
||||||
full_dataset_area: bool = False,
|
full_dataset_area: bool = False,
|
||||||
|
preclipped_partition_filter: tuple[str, str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
normalized_bbox = VectorFeatureService._normalize_selection_bbox(bbox)
|
normalized_bbox = VectorFeatureService._normalize_selection_bbox(bbox)
|
||||||
safe_limit = max(1, min(int(limit), 1000))
|
safe_limit = max(1, min(int(limit), 1000))
|
||||||
@@ -303,7 +332,10 @@ class VectorFeatureService:
|
|||||||
)
|
)
|
||||||
|
|
||||||
query = db.query(VectorFeature).filter(VectorFeature.dataset_id == dataset_id)
|
query = db.query(VectorFeature).filter(VectorFeature.dataset_id == dataset_id)
|
||||||
if not full_dataset_area:
|
if preclipped_partition_filter is not None:
|
||||||
|
partition_property, partition_value = preclipped_partition_filter
|
||||||
|
query = query.filter(VectorFeature.properties_json.op("->>")(partition_property) == partition_value)
|
||||||
|
elif not full_dataset_area:
|
||||||
query = query.filter(ST_Intersects(VectorFeature.geometry, selection_shape))
|
query = query.filter(ST_Intersects(VectorFeature.geometry, selection_shape))
|
||||||
if hasattr(query, "count"):
|
if hasattr(query, "count"):
|
||||||
total_feature_count = int(query.count())
|
total_feature_count = int(query.count())
|
||||||
@@ -327,6 +359,7 @@ class VectorFeatureService:
|
|||||||
total_feature_count=total_feature_count,
|
total_feature_count=total_feature_count,
|
||||||
selection_geometry=selection_geometry,
|
selection_geometry=selection_geometry,
|
||||||
full_dataset_area=full_dataset_area,
|
full_dataset_area=full_dataset_area,
|
||||||
|
preclipped_partition_filter=preclipped_partition_filter,
|
||||||
)
|
)
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
@@ -354,6 +387,7 @@ class VectorFeatureService:
|
|||||||
total_feature_count: int | None = None,
|
total_feature_count: int | None = None,
|
||||||
selection_geometry: Any | None = None,
|
selection_geometry: Any | None = None,
|
||||||
full_dataset_area: bool = False,
|
full_dataset_area: bool = False,
|
||||||
|
preclipped_partition_filter: tuple[str, str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
normalized_bbox = VectorFeatureService._normalize_selection_bbox(bbox)
|
normalized_bbox = VectorFeatureService._normalize_selection_bbox(bbox)
|
||||||
selection_shape = selection_geometry
|
selection_shape = selection_geometry
|
||||||
@@ -366,8 +400,14 @@ class VectorFeatureService:
|
|||||||
4326,
|
4326,
|
||||||
)
|
)
|
||||||
selection_filter = (VectorFeature.dataset_id == dataset.id,)
|
selection_filter = (VectorFeature.dataset_id == dataset.id,)
|
||||||
if not full_dataset_area:
|
if preclipped_partition_filter is not None:
|
||||||
|
partition_property, partition_value = preclipped_partition_filter
|
||||||
|
selection_filter += (
|
||||||
|
VectorFeature.properties_json.op("->>")(partition_property) == partition_value,
|
||||||
|
)
|
||||||
|
elif not full_dataset_area:
|
||||||
selection_filter += (ST_Intersects(VectorFeature.geometry, selection_shape),)
|
selection_filter += (ST_Intersects(VectorFeature.geometry, selection_shape),)
|
||||||
|
selection_is_preclipped = full_dataset_area or preclipped_partition_filter is not None
|
||||||
feature_count = total_feature_count
|
feature_count = total_feature_count
|
||||||
if feature_count is None:
|
if feature_count is None:
|
||||||
feature_count = int(db.query(func.count(VectorFeature.id)).filter(*selection_filter).scalar() or 0)
|
feature_count = int(db.query(func.count(VectorFeature.id)).filter(*selection_filter).scalar() or 0)
|
||||||
@@ -438,7 +478,7 @@ class VectorFeatureService:
|
|||||||
selection_filter=selection_filter,
|
selection_filter=selection_filter,
|
||||||
selection_shape=selection_shape,
|
selection_shape=selection_shape,
|
||||||
feature_count=feature_count,
|
feature_count=feature_count,
|
||||||
full_dataset_area=full_dataset_area,
|
full_dataset_area=selection_is_preclipped,
|
||||||
)
|
)
|
||||||
for metric_config in metric_configs
|
for metric_config in metric_configs
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ import sys
|
|||||||
import pytest
|
import pytest
|
||||||
from shapely.geometry import box, mapping, shape
|
from shapely.geometry import box, mapping, shape
|
||||||
|
|
||||||
|
from app.models import Dataset
|
||||||
|
from app.services.vector_feature_service import VectorFeatureService
|
||||||
|
|
||||||
|
|
||||||
ROOT = Path(__file__).resolve().parents[2]
|
ROOT = Path(__file__).resolve().parents[2]
|
||||||
SCRIPTS = ROOT / "scripts"
|
SCRIPTS = ROOT / "scripts"
|
||||||
@@ -240,3 +243,28 @@ def test_regional_operator_is_packaged_release_checked_and_exact_area_is_preferr
|
|||||||
assert '"provision_regional_bwk_natura2000.py"' in service
|
assert '"provision_regional_bwk_natura2000.py"' in service
|
||||||
assert "dataset.area_id === selectedAreaId ? 10_000_000" in workspace
|
assert "dataset.area_id === selectedAreaId ? 10_000_000" in workspace
|
||||||
assert "largestBwkSnapshot" in catalog
|
assert "largestBwkSnapshot" in catalog
|
||||||
|
|
||||||
|
|
||||||
|
def test_regional_bwk_uses_only_canonical_preclipped_municipality_partitions() -> None:
|
||||||
|
dataset = Dataset(
|
||||||
|
name="regional-bwk.geojson",
|
||||||
|
dataset_type="vector",
|
||||||
|
status="ready",
|
||||||
|
source_metadata={
|
||||||
|
"partitioned_source_audit": True,
|
||||||
|
"geometry_clipped_to_area": True,
|
||||||
|
},
|
||||||
|
provenance_metadata={"operator_tool": "provision_regional_bwk_natura2000.py"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert VectorFeatureService.preclipped_partition_filter(
|
||||||
|
dataset, "Gemeente Mol - officiële grens"
|
||||||
|
) == ("municipality", "Mol")
|
||||||
|
assert VectorFeatureService.preclipped_partition_filter(
|
||||||
|
dataset, "Vervoerregio Kempen - officiële operationele grens"
|
||||||
|
) is None
|
||||||
|
|
||||||
|
dataset.provenance_metadata = {"operator_tool": "unrelated_operator.py"}
|
||||||
|
assert VectorFeatureService.preclipped_partition_filter(
|
||||||
|
dataset, "Gemeente Mol - officiële grens"
|
||||||
|
) is None
|
||||||
|
|||||||
Reference in New Issue
Block a user