Turns each text into one embedding: a vector in which texts with similar
meaning lie close together. Encoding is the step every topic workflow
starts from and by far its most expensive one, so encode once and pass the
matrix to the embeddings argument of topics(), compare_topics(),
topic_corpus(), and the inference verbs. Each text is tokenized with the
model's own tokenizer, truncated to the model's maximum length, run
through the ONNX graph, pooled with pool(), and by default
L2-normalized. The static potion-base-8M model instead averages
looked-up token vectors, with no ONNX Runtime involved.
Usage
encode(
text,
model = NULL,
batch_size = 32L,
normalize = TRUE,
prefix = NULL,
sort_by_length = FALSE,
cache = NULL
)Arguments
- text
Character vector of sentences. Empty strings are supported; missing values are rejected.
- model
A loaded sbert_model, the name of a pinned model from
models(), orNULLfor the defaultall-MiniLM-L6-v2. Names are loaded lazily and kept in a session cache; the first use of a not-yet-installed model offers a one-time verified download (interactive prompt, oroptions(sbert.download = TRUE)in scripts).- batch_size
Positive number of sentences processed per ONNX call.
- normalize
Whether to return row-wise L2-normalized embeddings.
- prefix
Text prepended to every input before tokenization.
NULL(default) uses the model's pinned prefix (for example"query: "for E5 models, which require one);""disables prefixing.- sort_by_length
When
TRUE, group inputs of similar length into the same batch before encoding and restore the original order afterwards. Sequences in a batch are padded to the longest member, so mixed-length input makes the model compute over padding: on clause-level segments 60.1% of token work is padding in input order against 1.6% when sorted, measured at 1.9x faster end to end. Whole documents of similar length gain little (1.1x). Off by default because regrouping changes batch composition, which moves embeddings by around 1e-7 — enough to flip a rare borderline topic assignment, the same trade-off asdedupe_segmentsintopic_gamma(). Row order of the result is unaffected.- cache
Optional path to an embedding cache file. When supplied, every document is looked up by a SHA-256 digest of its own text together with the model identity, revision, dimension, maximum length, pooling method and
normalizesetting; only documents with no matching entry are encoded, and the file is updated with whatever was newly computed. Corpora are usually edited rather than replaced — a few records corrected, a year appended, rows reordered — and encoding is about 97% of the cost of a topic workflow, so reuse dominates. Changing 38 documents of 3,847 cost 0.59 s against 57 s to re-encode the corpus. Repeated documents within a single call are also encoded once (177 of the 3,847 bundledcovidabstracts repeat an earlier one).The key deliberately excludes
batch_sizeandsort_by_length, which shift embeddings by around 1e-7 through batch composition alone. Cached values are therefore stable to whatever computed them first rather than bit-identical to a fresh encode under different batching — the same trade-off assort_by_lengthitself. A cache that cannot be read, or that was written for a different embedding dimension, is discarded with a warning and rebuilt rather than trusted.
Value
A numeric matrix with one row per input, in input order, and one
column per embedding dimension of the model (for example 384 for
all-MiniLM-L6-v2; see models()).
Examples
# Embeddings need a downloaded model, so the full workflow is in the
# interactive block below. Segmenting needs none.
segment("One sentence. Another sentence.", level = "sentence")
#> document_id document_name segment text
#> 1 1 1 One sentence.
#> 2 1 2 Another sentence.
# \donttest{
if (interactive()) {
model <- load_model()
embeddings <- encode(c("A short sentence.", "Another sentence."), model)
# Segment-level work benefits most, because segment lengths vary widely.
segments <- with(head(covid, 50), segment(Abstract, level = "clause"))
embeddings <- with(segments, encode(text, model, sort_by_length = TRUE))
# Encode once, then re-run after editing the corpus: only changed rows cost
# anything the second time.
store <- file.path(tempdir(), "covid-embeddings.rds")
embeddings <- with(covid, encode(Abstract, model, cache = store))
embeddings <- with(covid, encode(Abstract, model, cache = store))
unlink(store)
}
# }
