perf(map): accelerate large spatial metrics
This commit is contained in:
@@ -11,7 +11,7 @@ from geoalchemy2.shape import to_shape
|
||||
from shapely.geometry import box, mapping, shape
|
||||
from shapely.ops import transform as transform_geometry
|
||||
from shapely.validation import make_valid
|
||||
from sqlalchemy import Float, String, cast, func
|
||||
from sqlalchemy import Float, String, case, cast, func
|
||||
|
||||
from app.core.errors import AppError
|
||||
from app.models import Dataset, VectorFeature
|
||||
@@ -778,12 +778,18 @@ class VectorFeatureService:
|
||||
)
|
||||
|
||||
if method == "intersection_area":
|
||||
measured_geometry = (
|
||||
VectorFeature.geometry
|
||||
if full_dataset_area
|
||||
else func.ST_Intersection(VectorFeature.geometry, selection_shape)
|
||||
)
|
||||
area_expression = func.ST_Area(func.ST_Transform(measured_geometry, 31370))
|
||||
source_area = func.ST_Area(func.ST_Transform(VectorFeature.geometry, 31370))
|
||||
if full_dataset_area:
|
||||
area_expression = source_area
|
||||
else:
|
||||
covered_by_selection = func.ST_CoveredBy(VectorFeature.geometry, selection_shape)
|
||||
intersection_area = func.ST_Area(
|
||||
func.ST_Transform(func.ST_Intersection(VectorFeature.geometry, selection_shape), 31370)
|
||||
)
|
||||
area_expression = case(
|
||||
(covered_by_selection, source_area),
|
||||
else_=intersection_area,
|
||||
)
|
||||
area_m2 = db.query(func.coalesce(func.sum(area_expression), 0.0)).filter(*metric_filter).scalar()
|
||||
divisor = 10_000.0 if unit == "ha" else 1.0
|
||||
metric_value = float(area_m2 or 0.0) / divisor
|
||||
@@ -808,12 +814,17 @@ class VectorFeatureService:
|
||||
)
|
||||
numeric_value = cast(VectorFeature.properties_json.op("->>")(property_name), Float)
|
||||
value_expression = numeric_value
|
||||
covered_by_selection = None
|
||||
if method == "area_weighted_sum" and not full_dataset_area:
|
||||
source_area = func.ST_Area(func.ST_Transform(VectorFeature.geometry, 31370))
|
||||
intersection_area = func.ST_Area(
|
||||
func.ST_Transform(func.ST_Intersection(VectorFeature.geometry, selection_shape), 31370)
|
||||
)
|
||||
coverage_ratio = intersection_area / func.nullif(source_area, 0.0)
|
||||
covered_by_selection = func.ST_CoveredBy(VectorFeature.geometry, selection_shape)
|
||||
coverage_ratio = case(
|
||||
(covered_by_selection, 1.0),
|
||||
else_=intersection_area / func.nullif(source_area, 0.0),
|
||||
)
|
||||
value_expression = numeric_value * coverage_ratio
|
||||
aggregate_function = {
|
||||
"mean": func.avg,
|
||||
@@ -831,7 +842,7 @@ class VectorFeatureService:
|
||||
partial_feature_count = (
|
||||
db.query(func.count(VectorFeature.id))
|
||||
.filter(*metric_filter)
|
||||
.filter(coverage_ratio < 0.999999)
|
||||
.filter(~covered_by_selection)
|
||||
.scalar()
|
||||
)
|
||||
is_estimate = bool(config.get("is_estimate", False)) or bool(partial_feature_count)
|
||||
|
||||
Reference in New Issue
Block a user