Skip to content

Commit c9d735c

Browse files
authored
Add caching to embedding (#443)
1 parent 26920a2 commit c9d735c

5 files changed

Lines changed: 53 additions & 11 deletions

File tree

src/pyobo/api/embedding.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@
77
import curies
88
import numpy as np
99
import pandas as pd
10+
from tqdm import tqdm
11+
from typing_extensions import Unpack
1012

11-
from pyobo.api.names import get_definition, get_name, get_references
13+
from pyobo.api.names import get_definition, get_id_name_mapping, get_name
14+
from pyobo.api.utils import get_version_from_kwargs
15+
from pyobo.constants import GetOntologyKwargs, check_should_force
16+
from pyobo.identifier_utils import wrap_norm_prefix
17+
from pyobo.utils.path import CacheArtifact, get_cache_path
1218

1319
if TYPE_CHECKING:
1420
import sentence_transformers
@@ -31,38 +37,61 @@ def get_text_embedding_model() -> sentence_transformers.SentenceTransformer:
3137

3238
def _get_text(
3339
reference: str | curies.Reference | curies.ReferenceTuple,
40+
/,
41+
*,
42+
name: str | None = None,
43+
**kwargs: Unpack[GetOntologyKwargs],
3444
) -> str | None:
35-
name = get_name(reference)
45+
if name is None:
46+
name = get_name(reference, **kwargs)
3647
if name is None:
3748
return None
38-
description = get_definition(reference)
49+
description = get_definition(reference, **kwargs)
3950
if description:
4051
name += " " + description
4152
return name
4253

4354

55+
@wrap_norm_prefix
4456
def get_text_embeddings_df(
4557
prefix: str,
4658
*,
4759
model: sentence_transformers.SentenceTransformer | None = None,
60+
**kwargs: Unpack[GetOntologyKwargs],
4861
) -> pd.DataFrame:
4962
"""Get embeddings for all entities in the resource.
5063
5164
:param prefix: A reference, either as a string or Reference object
5265
:param model: A sentence transformer model. Defaults to ``all-MiniLM-L6-v2`` if not
5366
given.
67+
:param kwargs: The keyword arguments to forward to ontology getter functions for
68+
names, definitions, and version
69+
70+
:returns: A pandas dataframe with an index representing local unique identifiers and
71+
columns for the values of the model returned vectors
5472
"""
73+
path = get_cache_path(
74+
prefix, CacheArtifact.embeddings, version=get_version_from_kwargs(prefix, kwargs)
75+
)
76+
if path.is_file() and not check_should_force(kwargs):
77+
df = pd.read_csv(path, sep="\t").set_index(0)
78+
return df
79+
80+
id_to_name = get_id_name_mapping(prefix, **kwargs)
81+
5582
luids, texts = [], []
56-
for reference in get_references(prefix):
57-
text = _get_text(reference)
83+
for identifier, name in tqdm(id_to_name.items(), desc=f"[{prefix}] constructing text"):
84+
text = _get_text(curies.ReferenceTuple(prefix, identifier), name=name, **kwargs)
5885
if text is None:
5986
continue
60-
luids.append(reference.identifier)
87+
luids.append(identifier)
6188
texts.append(text)
6289
if model is None:
6390
model = get_text_embedding_model()
64-
res = model.encode(texts)
65-
return pd.DataFrame(res, index=luids)
91+
res = model.encode(texts, show_progress_bar=True)
92+
df = pd.DataFrame(res, index=luids)
93+
df.to_csv(path, sep="\t") # index is important here!
94+
return df
6695

6796

6897
def get_text_embedding(

src/pyobo/sources/bigg/bigg_compartment.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def get_compartments(*, force: bool = False, version: str | None = None) -> dict
5555
"""Get a dictionary of BiGG compartments."""
5656
rv = {}
5757
soup = get_soup(DATA_URL)
58-
table = soup.find(**{"class": "myTable"}) # type:ignore[arg-type]
58+
table = soup.find(class_="myTable")
5959
if table is None:
6060
raise ValueError
6161
for row in table.find_all("tr"): # type:ignore[attr-defined]

src/pyobo/sources/omim_ps.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import logging
44
from collections.abc import Iterable
5+
from typing import cast
56

67
from bioversions.utils import get_soup
78

@@ -34,9 +35,14 @@ def iter_terms(self, force: bool = False) -> Iterable[Term]:
3435
if tbody is None:
3536
raise ValueError("omim.ps failed - scraper could not find table body in HTML")
3637
for row in tbody.find_all("tr"):
37-
anchor = row.find("td").find("a")
38+
td = row.find("td")
39+
if td is None:
40+
continue
41+
anchor = td.find("a")
42+
if anchor is None or anchor.text is None:
43+
continue
3844
name = anchor.text.strip()
39-
identifier = anchor.attrs["href"][len("/phenotypicSeries/") :]
45+
identifier = cast(str, anchor.attrs["href"])[len("/phenotypicSeries/") :]
4046
yield Term.from_triple(PREFIX, identifier, name)
4147

4248

src/pyobo/utils/path.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ class CacheArtifact(enum.Enum):
151151
prefixes = "prefixes.json"
152152
metadata = "metadata.json"
153153

154+
embeddings = "embeddings.tsv.gz"
155+
154156

155157
def get_cache_path(
156158
ontology: str,

tests/test_struct/test_obo/test_struct_obo.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ def test_ror_metadata(self) -> None:
362362
property_value: foaf:homepage "https\://ror.org" xsd:anyURI
363363
property_value: doap:repository "https\://github.com/ror-community" xsd:anyURI
364364
property_value: foaf:logo "https\://ror.org/img/ror-logo.svg" xsd:anyURI
365+
property_value: doap:mailing-list "support@ror.org" xsd:string
365366
property_value: doap:maintainer orcid:0000-0002-2916-3423
366367
""", # add Maria Gould
367368
ontology,
@@ -386,6 +387,7 @@ def test_ror_metadata(self) -> None:
386387
Annotation(foaf:homepage "https://ror.org"^^xsd:anyURI)
387388
Annotation(doap:repository "https://github.com/ror-community"^^xsd:anyURI)
388389
Annotation(foaf:logo "https://ror.org/img/ror-logo.svg"^^xsd:anyURI)
390+
Annotation(doap:mailing-list "support@ror.org"^^xsd:string)
389391
Annotation(doap:maintainer orcid:0000-0002-2916-3423)
390392
)
391393
""",
@@ -411,6 +413,7 @@ def test_ror_metadata(self) -> None:
411413
operated by California Digital Library, Crossref, and Datacite.</dcterms:description>
412414
<dcterms:license>CC0-1.0</dcterms:license>
413415
<dcterms:title>Research Organization Registry</dcterms:title>
416+
<doap:mailing-list>support@ror.org</doap:mailing-list>
414417
<doap:maintainer rdf:resource="https://orcid.org/0000-0002-2916-3423"/>
415418
<doap:repository rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">https://github.com/ror-community</doap:repository>
416419
<foaf:homepage rdf:datatype="http://www.w3.org/2001/XMLSchema#anyURI">https://ror.org</foaf:homepage>
@@ -429,6 +432,8 @@ def test_ror_metadata(self) -> None:
429432
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/license"/>
430433
<!-- http://purl.org/dc/terms/title -->
431434
<owl:AnnotationProperty rdf:about="http://purl.org/dc/terms/title"/>
435+
<!-- http://usefulinc.com/ns/doap#mailing-list -->
436+
<owl:AnnotationProperty rdf:about="http://usefulinc.com/ns/doap#mailing-list"/>
432437
<!-- http://usefulinc.com/ns/doap#maintainer -->
433438
<owl:AnnotationProperty rdf:about="http://usefulinc.com/ns/doap#maintainer"/>
434439
<!-- http://usefulinc.com/ns/doap#repository -->

0 commit comments

Comments
 (0)