1717from openeogeotrellis .constants import EVAL_ENV_KEY
1818
1919import openeogeotrellis .load_stac
20+ from openeogeotrellis .util .caching import GetOrCallCache , GetOrCallCacheInterface , AlwaysCallWithoutCache
2021from openeogeotrellis .util .geometry import BoundingBoxMerger
2122from openeogeotrellis .util .math import logarithmic_round
2223
@@ -57,14 +58,15 @@ def __init__(
5758 def __repr__ (self ) -> str :
5859 return f"_GridInfo(crs={ self .crs_raw !r} , resolution={ self .resolution !r} , extent_x={ self .extent_x !r} , extent_y={ self .extent_y !r} )"
5960
61+ def _key (self ) -> tuple :
62+ return (self .crs_raw , self .resolution , self .extent_x , self .extent_y )
63+
64+ def __hash__ (self ):
65+ return hash (self ._key ())
6066 def __eq__ (self , other ) -> bool :
61- return (
62- isinstance (other , _GridInfo )
63- and self .crs_raw == other .crs_raw
64- and self .resolution == other .resolution
65- and self .extent_x == other .extent_x
66- and self .extent_y == other .extent_y
67- )
67+ if isinstance (other , _GridInfo ):
68+ return self ._key () == other ._key ()
69+ return NotImplemented
6870
6971 @classmethod
7072 def from_datacube_metadata (cls , metadata : dict ) -> _GridInfo :
@@ -197,7 +199,10 @@ class AlignedExtentResult:
197199
198200
199201def _extract_spatial_extent_from_constraint (
200- source_constraint : SourceConstraint , * , catalog : AbstractCollectionCatalog
202+ source_constraint : SourceConstraint ,
203+ * ,
204+ catalog : AbstractCollectionCatalog ,
205+ cache : Optional [GetOrCallCacheInterface ] = None ,
201206) -> Union [None , AlignedExtentResult ]:
202207 """
203208 Extract spatial extent from given source constraint (if any), and align it to target grid.
@@ -210,18 +215,22 @@ def _extract_spatial_extent_from_constraint(
210215 if source_process == "load_collection" :
211216 collection_id = source_id [1 ][0 ]
212217 return _extract_spatial_extent_from_constraint_load_collection (
213- collection_id = collection_id , constraint = constraint , catalog = catalog
218+ collection_id = collection_id , constraint = constraint , catalog = catalog , cache = cache
214219 )
215220 elif source_process == "load_stac" :
216221 url = source_id [1 ][0 ]
217- return _extract_spatial_extent_from_constraint_load_stac (stac_url = url , constraint = constraint )
222+ return _extract_spatial_extent_from_constraint_load_stac (stac_url = url , constraint = constraint , cache = cache )
218223 else :
219224 # TODO?
220225 return None
221226
222227
223228def _extract_spatial_extent_from_constraint_load_collection (
224- collection_id : str , * , constraint : dict , catalog : AbstractCollectionCatalog
229+ collection_id : str ,
230+ * ,
231+ constraint : dict ,
232+ catalog : AbstractCollectionCatalog ,
233+ cache : Optional [GetOrCallCacheInterface ] = None ,
225234) -> Union [None , AlignedExtentResult ]:
226235 try :
227236 metadata = catalog .get_collection_metadata (collection_id )
@@ -232,7 +241,7 @@ def _extract_spatial_extent_from_constraint_load_collection(
232241 stac_url = deep_get (metadata , "_vito" , "data_source" , "url" )
233242 load_stac_feature_flags = deep_get (metadata , "_vito" , "data_source" , "load_stac_feature_flags" , default = {})
234243 return _extract_spatial_extent_from_constraint_load_stac (
235- stac_url = stac_url , constraint = constraint , feature_flags = load_stac_feature_flags
244+ stac_url = stac_url , constraint = constraint , feature_flags = load_stac_feature_flags , cache = cache
236245 )
237246
238247 # TODO Extracting pixel grid info from collection metadata might might be unreliable
@@ -271,7 +280,11 @@ def _extract_spatial_extent_from_constraint_load_collection(
271280
272281
273282def _extract_spatial_extent_from_constraint_load_stac (
274- stac_url : str , * , constraint : dict , feature_flags : Optional [dict ] = None
283+ stac_url : str ,
284+ * ,
285+ constraint : dict ,
286+ feature_flags : Optional [dict ] = None ,
287+ cache : Optional [GetOrCallCacheInterface ] = None ,
275288) -> Union [None , AlignedExtentResult ]:
276289 spatial_extent_from_pg = constraint .get ("spatial_extent" ) or constraint .get ("weak_spatial_extent" )
277290 spatiotemporal_extent = openeogeotrellis .load_stac ._spatiotemporal_extent_from_load_params (
@@ -292,12 +305,23 @@ def _extract_spatial_extent_from_constraint_load_stac(
292305
293306 pixel_buffer_size = deep_get (constraint , "pixel_buffer" , "buffer_size" , default = None )
294307
295- return _extract_spatial_extent_from_load_stac_item_collection (
296- stac_url = stac_url ,
297- spatiotemporal_extent = spatiotemporal_extent ,
298- property_filter_pg_map = property_filter_pg_map ,
299- resample_grid = resample_grid ,
300- pixel_buffer_size = pixel_buffer_size ,
308+ return (cache or AlwaysCallWithoutCache ()).get_or_call (
309+ key = (
310+ stac_url ,
311+ spatiotemporal_extent ,
312+ str (property_filter_pg_map ),
313+ resample_grid ,
314+ pixel_buffer_size ,
315+ str (feature_flags ),
316+ ),
317+ callback = lambda : _extract_spatial_extent_from_load_stac_item_collection (
318+ stac_url = stac_url ,
319+ spatiotemporal_extent = spatiotemporal_extent ,
320+ property_filter_pg_map = property_filter_pg_map ,
321+ resample_grid = resample_grid ,
322+ pixel_buffer_size = pixel_buffer_size ,
323+ feature_flags = feature_flags ,
324+ ),
301325 )
302326
303327
@@ -308,6 +332,7 @@ def _extract_spatial_extent_from_load_stac_item_collection(
308332 property_filter_pg_map : Optional [openeogeotrellis .load_stac .PropertyFilterPGMap ] = None ,
309333 resample_grid : Optional [_GridInfo ] = None ,
310334 pixel_buffer_size : Union [Tuple [float , float ], int , float , None ] = None ,
335+ feature_flags : Optional [dict ] = None ,
311336) -> Union [None , AlignedExtentResult ]:
312337 extent_orig : Union [BoundingBox , None ] = spatiotemporal_extent .spatial_extent .as_bbox ()
313338 extent_variants = {"original" : extent_orig }
@@ -429,6 +454,7 @@ def determine_global_extent(
429454 * ,
430455 source_constraints : List [SourceConstraint ],
431456 catalog : AbstractCollectionCatalog ,
457+ cache : Optional [GetOrCallCacheInterface ] = None ,
432458) -> dict :
433459 """
434460 Go through all source constraints, extract the aligned extent from each (possibly with variations)
@@ -438,9 +464,16 @@ def determine_global_extent(
438464 # e.g. add stats to AlignedExtentResult for better informed decision?
439465 aligned_merger = BoundingBoxMerger ()
440466 variant_mergers : Dict [str , BoundingBoxMerger ] = collections .defaultdict (BoundingBoxMerger )
467+ # Enable the implementation to use caching
468+ # when going through all these source constraints
469+ # as there might be duplication that's hidden
470+ # by differences from non-relevant details
471+ cache = cache or GetOrCallCache (max_size = 100 )
441472 for source_id , constraint in source_constraints :
442473 try :
443- aligned_extent_result = _extract_spatial_extent_from_constraint ((source_id , constraint ), catalog = catalog )
474+ aligned_extent_result = _extract_spatial_extent_from_constraint (
475+ (source_id , constraint ), catalog = catalog , cache = cache
476+ )
444477 except Exception as e :
445478 raise SpatialExtentExtractionError (
446479 f"Failed to extract spatial extent from { source_id = } with { constraint = } : { e = } "
@@ -455,6 +488,7 @@ def determine_global_extent(
455488 _log .info (
456489 f"determine_global_extent: skipping { name = } from { source_id = } with { aligned_extent_result .variants = } "
457490 )
491+ _log .info (f"_extract_spatial_extent_from_constraint cache stats: { cache !s} " )
458492
459493 global_extent : BoundingBox = aligned_merger .get ()
460494 global_extent_variants : Dict [str , BoundingBox ] = {name : merger .get () for name , merger in variant_mergers .items ()}
0 commit comments