1616from openeogeotrellis .constants import EVAL_ENV_KEY
1717
1818import openeogeotrellis .load_stac
19+ from openeogeotrellis .util .caching import GetOrCallCache , GetOrCallCacheInterface , AlwaysCallWithoutCache
1920from openeogeotrellis .util .geometry import BoundingBoxMerger
2021from openeogeotrellis .util .math import logarithmic_round
2122
@@ -56,14 +57,15 @@ def __init__(
5657 def __repr__ (self ) -> str :
5758 return f"_GridInfo(crs={ self .crs_raw !r} , resolution={ self .resolution !r} , extent_x={ self .extent_x !r} , extent_y={ self .extent_y !r} )"
5859
60+ def _key (self ) -> tuple :
61+ return (self .crs_raw , self .resolution , self .extent_x , self .extent_y )
62+
63+ def __hash__ (self ):
64+ return hash (self ._key ())
5965 def __eq__ (self , other ) -> bool :
60- return (
61- isinstance (other , _GridInfo )
62- and self .crs_raw == other .crs_raw
63- and self .resolution == other .resolution
64- and self .extent_x == other .extent_x
65- and self .extent_y == other .extent_y
66- )
66+ if isinstance (other , _GridInfo ):
67+ return self ._key () == other ._key ()
68+ return NotImplemented
6769
6870 @classmethod
6971 def from_datacube_metadata (cls , metadata : dict ) -> _GridInfo :
@@ -196,7 +198,10 @@ class AlignedExtentResult:
196198
197199
198200def _extract_spatial_extent_from_constraint (
199- source_constraint : SourceConstraint , * , catalog : AbstractCollectionCatalog
201+ source_constraint : SourceConstraint ,
202+ * ,
203+ catalog : AbstractCollectionCatalog ,
204+ cache : Optional [GetOrCallCacheInterface ] = None ,
200205) -> Union [None , AlignedExtentResult ]:
201206 """
202207 Extract spatial extent from given source constraint (if any), and align it to target grid.
@@ -209,18 +214,22 @@ def _extract_spatial_extent_from_constraint(
209214 if source_process == "load_collection" :
210215 collection_id = source_id [1 ][0 ]
211216 return _extract_spatial_extent_from_constraint_load_collection (
212- collection_id = collection_id , constraint = constraint , catalog = catalog
217+ collection_id = collection_id , constraint = constraint , catalog = catalog , cache = cache
213218 )
214219 elif source_process == "load_stac" :
215220 url = source_id [1 ][0 ]
216- return _extract_spatial_extent_from_constraint_load_stac (stac_url = url , constraint = constraint )
221+ return _extract_spatial_extent_from_constraint_load_stac (stac_url = url , constraint = constraint , cache = cache )
217222 else :
218223 # TODO?
219224 return None
220225
221226
222227def _extract_spatial_extent_from_constraint_load_collection (
223- collection_id : str , * , constraint : dict , catalog : AbstractCollectionCatalog
228+ collection_id : str ,
229+ * ,
230+ constraint : dict ,
231+ catalog : AbstractCollectionCatalog ,
232+ cache : Optional [GetOrCallCacheInterface ] = None ,
224233) -> Union [None , AlignedExtentResult ]:
225234 try :
226235 metadata = catalog .get_collection_metadata (collection_id )
@@ -229,7 +238,7 @@ def _extract_spatial_extent_from_constraint_load_collection(
229238
230239 if deep_get (metadata , "_vito" , "data_source" , "type" , default = None ) == "stac" :
231240 stac_url = deep_get (metadata , "_vito" , "data_source" , "url" )
232- return _extract_spatial_extent_from_constraint_load_stac (stac_url = stac_url , constraint = constraint )
241+ return _extract_spatial_extent_from_constraint_load_stac (stac_url = stac_url , constraint = constraint , cache = cache )
233242
234243 # TODO Extracting pixel grid info from collection metadata might might be unreliable
235244 # and should be replaced by more precise item-level metadata where possible.
@@ -267,7 +276,10 @@ def _extract_spatial_extent_from_constraint_load_collection(
267276
268277
269278def _extract_spatial_extent_from_constraint_load_stac (
270- stac_url : str , * , constraint : dict
279+ stac_url : str ,
280+ * ,
281+ constraint : dict ,
282+ cache : Optional [GetOrCallCacheInterface ] = None ,
271283) -> Union [None , AlignedExtentResult ]:
272284 spatial_extent_from_pg = constraint .get ("spatial_extent" ) or constraint .get ("weak_spatial_extent" )
273285 spatiotemporal_extent = openeogeotrellis .load_stac ._spatiotemporal_extent_from_load_params (
@@ -288,12 +300,21 @@ def _extract_spatial_extent_from_constraint_load_stac(
288300
289301 pixel_buffer_size = deep_get (constraint , "pixel_buffer" , "buffer_size" , default = None )
290302
291- return _extract_spatial_extent_from_load_stac_item_collection (
292- stac_url = stac_url ,
293- spatiotemporal_extent = spatiotemporal_extent ,
294- property_filter_pg_map = property_filter_pg_map ,
295- resample_grid = resample_grid ,
296- pixel_buffer_size = pixel_buffer_size ,
303+ return (cache or AlwaysCallWithoutCache ()).get_or_call (
304+ key = (
305+ stac_url ,
306+ spatiotemporal_extent ,
307+ str (property_filter_pg_map ),
308+ resample_grid ,
309+ pixel_buffer_size ,
310+ ),
311+ callback = lambda : _extract_spatial_extent_from_load_stac_item_collection (
312+ stac_url = stac_url ,
313+ spatiotemporal_extent = spatiotemporal_extent ,
314+ property_filter_pg_map = property_filter_pg_map ,
315+ resample_grid = resample_grid ,
316+ pixel_buffer_size = pixel_buffer_size ,
317+ ),
297318 )
298319
299320
@@ -412,6 +433,7 @@ def determine_global_extent(
412433 * ,
413434 source_constraints : List [SourceConstraint ],
414435 catalog : AbstractCollectionCatalog ,
436+ cache : Optional [GetOrCallCacheInterface ] = None ,
415437) -> dict :
416438 """
417439 Go through all source constraints, extract the aligned extent from each (possibly with variations)
@@ -421,9 +443,16 @@ def determine_global_extent(
421443 # e.g. add stats to AlignedExtentResult for better informed decision?
422444 aligned_merger = BoundingBoxMerger ()
423445 variant_mergers : Dict [str , BoundingBoxMerger ] = collections .defaultdict (BoundingBoxMerger )
446+ # Enable the implementation to use caching
447+ # when going through all these source constraints
448+ # as there might be duplication that's hidden
449+ # by differences from non-relevant details
450+ cache = cache or GetOrCallCache (max_size = 100 )
424451 for source_id , constraint in source_constraints :
425452 try :
426- aligned_extent_result = _extract_spatial_extent_from_constraint ((source_id , constraint ), catalog = catalog )
453+ aligned_extent_result = _extract_spatial_extent_from_constraint (
454+ (source_id , constraint ), catalog = catalog , cache = cache
455+ )
427456 except Exception as e :
428457 raise SpatialExtentExtractionError (
429458 f"Failed to extract spatial extent from { source_id = } with { constraint = } : { e = } "
@@ -438,6 +467,7 @@ def determine_global_extent(
438467 _log .info (
439468 f"determine_global_extent: skipping { name = } from { source_id = } with { aligned_extent_result .variants = } "
440469 )
470+ _log .info (f"_extract_spatial_extent_from_constraint cache stats: { cache !s} " )
441471
442472 global_extent : BoundingBox = aligned_merger .get ()
443473 global_extent_variants : Dict [str , BoundingBox ] = {name : merger .get () for name , merger in variant_mergers .items ()}
0 commit comments