@@ -50,6 +50,9 @@ def __init__(self, ontology: str):
5050
5151 """
5252 self .ontology = ontology
53+ # Cache the lowercased ontology name once; `_matches_ontology` is called
54+ # in hot loops over millions of entities/ancestors at NCBITaxon scale.
55+ self ._ontology_lc = ontology .lower ()
5356 self .ontology_db_path = self .download_and_prepare_ontology ()
5457 self .adapter = get_adapter (f"sqlite:{ self .ontology_db_path } " )
5558 self .adapter .precompute_lookups () # Optimize lookups
@@ -115,20 +118,24 @@ def _create_ontology_class(self, entity_id, is_obsolete=False):
115118
116119 return ontology_class
117120
121+ def _matches_ontology (self , entity_id : str ) -> bool :
122+ """Case-insensitive check that ``entity_id`` is a CURIE in this ontology."""
123+ head , sep , _ = entity_id .partition (":" )
124+ return bool (sep ) and head .lower () == self ._ontology_lc
125+
118126 def get_terms_and_metadata (self ):
119- """Retrieve all terms that start with the ontology prefix and return a list of OntologyClass objects."""
127+ """Retrieve all terms that belong to this ontology and return a list of OntologyClass objects."""
120128 ontology_classes = []
121- ontology_prefix = self .ontology .upper () + ":"
122129
123130 # Process non-obsolete entities
124131 for entity in self .adapter .entities (filter_obsoletes = True ):
125- if entity . startswith ( ontology_prefix ):
132+ if self . _matches_ontology ( entity ):
126133 ontology_class = self ._create_ontology_class (entity , is_obsolete = False )
127134 ontology_classes .append (ontology_class )
128135
129136 # Process obsolete entities
130137 for obsolete_entity in self .adapter .obsoletes ():
131- if obsolete_entity . startswith ( ontology_prefix ):
138+ if self . _matches_ontology ( obsolete_entity ):
132139 ontology_class = self ._create_ontology_class (obsolete_entity , is_obsolete = True )
133140 ontology_classes .append (ontology_class )
134141
@@ -143,15 +150,14 @@ def get_relations_closure(self, predicates=None, ontology_terms: list = None) ->
143150 :return: Tuple of (ontology_relations, updated_ontology_terms)
144151 """
145152 predicates = ["rdfs:subClassOf" , "BFO:0000050" ] if predicates is None else predicates
146- ontology_prefix = self .ontology .upper () + ":"
147153 ontology_relations = []
148154
149155 # Create dictionary for fast lookup of ontology terms
150156 ontology_terms_dict = {term .id : term for term in (ontology_terms or [])}
151157
152158 # Get all relevant entities in one pass
153159 logger .info ("Collecting relevant entities..." )
154- relevant_entities = set (entity for entity in self .adapter .entities () if entity . startswith ( ontology_prefix ))
160+ relevant_entities = set (entity for entity in self .adapter .entities () if self . _matches_ontology ( entity ))
155161 logger .info (f"Found { len (relevant_entities )} relevant entities" )
156162
157163 # Process all direct relationships in one batch
@@ -177,7 +183,7 @@ def get_relations_closure(self, predicates=None, ontology_terms: list = None) ->
177183 ancestors = set (
178184 ancestor
179185 for ancestor in self .adapter .ancestors (entity , reflexive = True , predicates = predicates )
180- if ancestor . startswith ( ontology_prefix )
186+ if self . _matches_ontology ( ancestor )
181187 )
182188
183189 # Create relations for each ancestor
0 commit comments