pymongopredict.embeddings_api
The embeddings API: datasets and a featurizer that turn documents into X for scikit-learn.
This is the scikit-learn workflow underneath $predict (see
pymongopredict.predictions_api): use it to pick your own estimator, cross-validate,
combine features or forecast.
What you use:
MongoDataset: the documents of a collection (with a filter, limit and target) or a list of documents, with the target valuesy. It indexes like an array, so scikit-learn'strain_test_split, cross-validation splitters andcross_val_scorework on it directly.DocumentFeaturizer: an sklearn transformer from documents to chosen columns and embeddings of the documents, for any sklearn estimator orPipeline.MongoSeries: a time series aggregated from documents, for sktime forecasters.SentenceTransformerEmbedder,VoyageEmbedder,HashingEmbedder: embedding models with non-default settings, to pass asembedding_model(a name such as"voyage-4-nano"or"voyage-4-lite"is enough otherwise).
Datasets and splits
MongoDataset(coll, target=...) reads a collection (filter=, projection=, limit= and sort= are passed
to find). dataset.y is a float array for numeric targets, bool for booleans and strings otherwise; documents
without a target value are left out. Split it with scikit-learn: a dataset indexes like an array (ds[indices],
ds.iloc[...], ds.take(...)), so the splitters return train and test datasets that share the same source:
from sklearn.model_selection import GroupShuffleSplit, TimeSeriesSplit, train_test_split ds_train, ds_test = train_test_split(ds, test_size=0.2, stratify=ds.y, random_state=0) # by the target ds_train, ds_test = train_test_split(ds, test_size=0.2, stratify=ds.field_values("address.market")) tr, te = next(GroupShuffleSplit(test_size=0.3).split(ds, groups=ds.field_values("host.host_id"))) ds_train, ds_test = ds[tr], ds[te] # a host on one side ds = MongoDataset(coll, target="y", sort=[("ts", 1)]) # in time order, then ds_train, ds_test = train_test_split(ds, test_size=0.2, shuffle=False) # train on the past for tr, te in TimeSeriesSplit(n_splits=5, gap=24).split(ds): ... # rolling, with a gap
cross_val_score(make_pipeline(DocumentFeaturizer(...), Ridge()), ds, ds.y) cross-validates in the same way.
Featurizing and fitting
DocumentFeaturizer.fit / transform accept a MongoDataset, a pymongo cursor, a generator, a list of documents
or a DataFrame of records, and return a float32 matrix. When fitting on a MongoDataset, its target field is removed
from the embedded JSON (pass exclude= for plain documents), so the answer cannot leak into the features. The
featurizer is an ordinary scikit-learn transformer, so it works with Pipeline, clone and
get_feature_names_out:
from sklearn.linear_model import RidgeClassifierCV from sklearn.pipeline import make_pipeline pipe = make_pipeline(prep, RidgeClassifierCV()) pipe.fit(ds_train, ds_train.y) pipe.score(ds_test, ds_test.y) pipe.predict(coll.find({"address.market": "Porto"}).limit(5)) # predict on any cursor
For cross-validation or model selection, compute X = prep.fit_transform(ds) once and pass X and ds.y to
scikit-learn. Embeddings are cached, so refitting with another estimator does not embed a document again.
Forecasting with sktime
MongoSeries aggregates a time series from a collection, and series.split cuts it in time order (sktime's
temporal_train_test_split(series.series, ...) does the same). The parts are pd.Series with a PeriodIndex
for any sktime forecaster:
from sktime.forecasting.exp_smoothing import ExponentialSmoothing from pymongopredict import MongoSeries series = MongoSeries(coll_weather, time_field="ts", value_field="airTemperature.value", freq="h", agg="mean", valid=lambda v: v < 900) y_train, y_test = series.split(test_size=24) fc = ExponentialSmoothing(trend="add", seasonal="add", sp=24).fit(y_train) fc.predict(fh=range(1, 25))
Streaming large collections
By default a MongoDataset fetches its documents once and keeps them in memory. When documents are much larger than
the features taken from them (for example listings that carry all their reviews), pass streaming=True:
ds = MongoDataset(coll, target="room_type", streaming=True, batch_size=512)
- Loading reads only
_idand the target, andfield_values(for a stratify or group field) fetches only that field. fit/transformfetch documents in batches of_idvalues, with only the fields the featurizer uses whenembed_fieldsis given, and keep only the feature vectors.- The next batch is fetched in a background thread while the current one is embedded (
prefetch=2). - Cursors and generators passed to
fit/transformare also read batch by batch.
The results are the same as in memory (the tests check this). On the Airbnb demo, peak memory drops from about 300 MB to about 215 MB, and the difference grows with the size of the documents.
How documents become features
MongoDataset(collection, target, filter) -> sklearn train_test_split -> ds_train / ds_test | <a href="#DocumentFeaturizer.fit_transform">DocumentFeaturizer.fit_transform</a>(ds_train) / .transform(ds_test) | columns (dotted paths): types inferred embed_fields (or the whole document): (number, bool, date, category, list size), compact JSON -> embedding model missing values filled, scaled, one-hot encoded (voyage-4-nano, Hugging Face, Voyage API) | batch by batch, side by side -> X for any scikit-learn estimator
- Embeddings are cached in a sqlite file (
.mongopredict_cache/), keyed by the model and the text. - Documents are serialised with
orjson.max_json_chars(8000 by default) is applied field by field, so a document with a very long trailing array is not serialised in full only to be cut.max_tokens=32768ormax_tokens="model"measures the budget in tokens with the model's tokenizer instead. - BSON types are converted:
Decimal128to float,ObjectIdto string, dates to ISO strings.
Embedding models
embedding_model= ("embeddingModel" in a prediction model definition) accepts:
| value | embedding model |
|---|---|
"voyage-4-nano" (default) |
runs locally with sentence-transformers, 346M parameters, no API key |
"org/name" or a path containing / |
any sentence-transformers model from Hugging Face or disk |
other "voyage-*" names: "voyage-4-lite", "voyage-4", "voyage-4-large", "voyage-code-4", ... |
the Voyage API (needs VOYAGE_API_KEY) |
"hashing" |
a hashed bag of words without dependencies, for tests and quick baselines |
| an embedder object | used as it is (cached under its name; an object without a name is not cached) |
"voyage-4-nano@512"(orembedding_kwargs={"dimension": 512}) truncates Matryoshka embeddings after the cache, so the full vector is computed once and serves every dimension.- Local models run in bfloat16 on CUDA (float32 elsewhere), with the token limit capped at the model's maximum.
- Voyage API models (
pymongopredict.embeddings_api.embed.VoyageEmbedder) takeoutput_dimension(256, 512, 1024 or 2048),api_key,max_retries(default 5, with exponential backoff on rate limits) andtimeoutthroughembedding_kwargs. Texts go in requests of at most 1,000 texts and within the model's tokens per request. Contextualized and multimodal models (voyage-context-*,voyage-multimodal-*) are not supported. mask_target=Truekeeps the target as the first key with the value<MASK>and putsPredict the value of <MASK>:before the text (mask_tokenandprefixchange them), so the model knows which field is asked for. This is the input format of the voyage-json models, which are trained to predict from whole documents.
Examples
Usage:
from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from pymongopredict import DocumentFeaturizer, MongoDataset ds = MongoDataset(collection, target="room_type") train, test = train_test_split(ds, test_size=0.2, stratify=ds.y, random_state=0) prep = DocumentFeaturizer(columns=[...], embed_fields=[...]) # docs -> X clf = LogisticRegression().fit(prep.fit_transform(train), train.y) clf.score(prep.transform(test), test.y)
Documents of a collection (or an explicit list) together with an optional target.
The query is lazy: nothing is read until the first access to len(), ids,
y, iter_batches() or field_values() (or an explicit load()), and the
result is cached.
Parameters
- collection (pymongo
Collectionor None): Anything with.find(mongomock works).Nonefor in-memory documents (seefrom_documents()). - target (str, optional):
Dotted path of the field to predict (e.g.
"imdb.rating"). Documents without a value are dropped.None(default) for an unlabelled dataset;yis thenNone. - filter, projection, limit, sort (optional):
Forwarded to
collection.find. Theprojectiondefines what a document looks like in both modes; the target field is added to an inclusion projection (or removed from the excluded fields of an exclusion projection) soycan always be read.limitofNoneor 0 means no limit. - streaming (bool, default False):
If
Truethe documents are never held in memory all at once.load()only reads_idand the target; documents are fetched again in_idbatches whenever an estimator iterates over the dataset (with a projection limited to the fields it uses). Use it when documents are much larger than the features derived from them. The collection must not change in between: a document that disappeared raisesKeyError. - batch_size (int, default 512):
Documents per batch in
iter_batches()(and per_idquery in streaming mode). - prefetch (int, default 2): In streaming mode, number of batches fetched ahead in a background thread so the database round trip overlaps with featurisation / embedding (0 disables).
Raises
- ValueError: If
batch_sizeis smaller than 1.
Notes
Each document is identified by its _id. When a document has no _id (in-memory
documents, or an in-memory projection with "_id": 0) its position is used instead.
Examples
>>> ds = MongoDataset(db.movies, target="imdb.rating", projection={"title": 1, "plot": 1})
>>> ds.y.dtype
dtype('float64')
>>> ds.field_values("title")[:2]
In-memory dataset from a list / cursor of documents.
Parameters
- documents (iterable of dict): Documents (a list, a pymongo cursor, a generator). It is read once into a list.
- target (str, optional):
Dotted path of the label inside each document. Documents missing it are dropped.
Ignored for labels when
yis given, but still stored astarget. - y (array-like, optional):
Labels given separately, one per document (no document is dropped). Converted with
_as_target_array().
Returns
- MongoDataset: A dataset with no collection; it cannot be reloaded, and fields left out of the documents cannot be fetched later.
Raises
- ValueError: If
yis not one dimensional or its length differs from the number of documents.
Examples
>>> ds = MongoDataset.from_documents([{"a": 1, "t": "x"}, {"a": 2}], target="t")
>>> len(ds)
1
>>> ds = MongoDataset.from_documents([{"a": 1}, {"a": 2}], y=[0.5, 1.5])
Run the query and cache the result.
In memory, the documents are fetched with the dataset's projection (extended to the
target). When streaming, only _id and the target are fetched. Documents with a
missing target are dropped. A reload clears the cache of field_values().
Parameters
- force (bool, default False): Run the query again even if the dataset is already loaded (e.g. after the collection changed).
Returns
- MongoDataset:
self, so calls can be chained (ds.load().y).
Raises
- ValueError: If the dataset is a subset (from
subset()or a scikit-learn split), which only knows its ids, or if it has no collection and was not built withfrom_documents().
_id of every document, in dataset order (a copy).
Documents without an _id (in-memory documents, or a projection with "_id": 0)
are identified by their position in the query result instead.
Target values aligned with ids (None when the dataset has no target).
Numeric targets come back as a float array, booleans as bool, anything else as strings, so the array can go straight into an sklearn estimator.
All documents as a list, in dataset order (a new list on every access).
In streaming mode this fetches every document (defeating the purpose), so prefer
iter_batches().
Yield lists of at most batch_size documents, in dataset order.
Parameters
- projection (dict, optional):
Fields the consumer needs, used to limit what is fetched in streaming mode. It is
ignored for in-memory documents (already loaded) and for datasets that have their
own
projection, since that projection defines the documents in both modes.
Yields
- list of dict: Consecutive batches. In streaming mode each batch is one
_idquery; withprefetch > 0and more than one batch, the next batches are fetched in a background thread while the current one is processed.
Raises
- KeyError: In streaming mode, if documents were deleted from the collection after loading.
Examples
>>> for batch in ds.iter_batches(projection={"title": 1}):
... texts = [d.get("title") for d in batch]
Values of a dotted field for every document, aligned with ids.
Used for stratify or group values in scikit-learn splits, and by featurizers that
read single columns. Streaming datasets fetch just that field (once, then cached until
the next load()) with a projection, and so do in-memory datasets whose
projection left the field out, so both modes see the same values.
Parameters
- path (str):
Dotted field path, e.g.
"host.host_id"or"scores.0".
Returns
- list: One value per document (a new list). Missing fields give
None; BSON scalars (Decimal128, ObjectId) are converted to plain Python values.
Raises
- ValueError: For an in-memory dataset whose projection leaves out both
pathand_id(or that has no collection), since the field then cannot be fetched by_id.
Dataset restricted to positional indices.
The subset shares the collection, query settings and mode (in memory or streaming),
and copies the matching ids, targets, documents and cached field_values(). It is a
view: it cannot load() its query again.
Parameters
- idx (sequence of int): Positions into this dataset (e.g. from a scikit-learn splitter). Order is kept and repeats are allowed.
Returns
- MongoDataset: A new dataset with
len(idx)documents.
Examples
>>> first_ten = ds.subset(range(10))
The documents at indices as a new dataset (subset()); axis must be 0.
This is what sklearn.model_selection.train_test_split and the other scikit-learn
splitters call, so they split a dataset into datasets:
>>> from sklearn.model_selection import train_test_split
>>> train, test = train_test_split(ds, test_size=0.2, stratify=ds.y, random_state=0)
A univariate time series aggregated from the documents of a collection.
Only the two fields are read, streamed through the cursor. series is a pd.Series
with a PeriodIndex, ready for sktime. The collection is read lazily, on the first
access to series, len() or split(), and the result is cached.
Parameters
- collection (pymongo.collection.Collection): The collection to read.
- time_field (str):
Dotted path of the timestamp field. Accepted values:
datetime/date/pd.Timestamp, ISO 8601 strings, and numbers as epoch seconds (or epoch milliseconds when above 1e11). Timezone-aware times are converted to naive UTC. Documents whose time cannot be parsed are skipped. - value_field (str):
Dotted path of the numeric field to aggregate.
Decimal128values are read as floats; values that are missing,Noneor not convertible tofloatare skipped. - freq (str, default "D"):
pandas offset alias used to bucket timestamps (
"h","D","W","MS"...), with an optional multiple and anchor ("2MS","QS-FEB"). The period-style aliases"M","Q","Y"and"A"are accepted and resampled as"ME","QE"and"YE", which pandas 3 requires. Month, quarter and year aliases (also business ones) map to the matching periods, keeping the multiple ("2MS"gives"2M"periods) and ending start-anchored periods the month before the anchor ("QS-FEB"gives"Q-JAN"). For other aliases the period frequency is inferred from the resampled index. - agg (str, default "mean"):
Aggregation within a bucket, any name pandas
Resampler.aggaccepts ("mean","sum","count","median","max"...). - fill ({"interpolate", "ffill"}, number or None, default "interpolate"):
How to fill empty buckets:
"interpolate"interpolates linearly and extends the first and last values to the ends;"ffill"carries the last value forward (and the first value backward for leading gaps); a number fills with that value;NoneleavesNaN. Aggregations such as"count"and"sum"give 0, notNaN, for empty buckets, so there is nothing to fill. - filter (dict or None, default None):
findfilter;Nonereads every document. - valid (callable or None, default None):
valid(value) -> boolto drop sentinel values (e.g.999.9in the weather sample data). It sees the value before conversion tofloat. - limit (int or None, default None):
Read at most this many documents (in natural order);
Noneor0reads all.
Attributes
- series (pandas.Series):
The aggregated series, named after
value_field.
Examples
>>> ms = MongoSeries(coll, "ts", "airTemperature.value", freq="D") # doctest: +SKIP
>>> train, test = ms.split(0.2) # doctest: +SKIP
Read the collection and build the series (once, unless force).
Parameters
- force (bool, default False): Re-read the collection even if the series is already cached, e.g. after new documents were inserted.
Returns
- MongoSeries:
self, so thatms.load().serieschains.
Raises
- ValueError: If fewer than three documents have a usable (time, value) pair, or fewer than three periods remain after resampling.
Trailing test_size periods (int) or fraction (float) become the test series.
Parameters
- test_size (float or int, default 0.2): An integer of at least 1 is a number of periods; anything else is a fraction of the series length (rounded). The test size is clipped so that the test series has at least one period and the training series at least two.
Returns
- tuple of pandas.Series:
(train, test), contiguous and in time order.
Examples
>>> train, test = ms.split(test_size=12) # last 12 periods # doctest: +SKIP
Turn documents into [tabular columns | embedding of JSON] features.
A scikit-learn transformer. All constructor arguments are stored unchanged (so get_params,
clone and grid search work); everything learned is set by fit in attributes ending
with _, and every fit starts from scratch.
Parameters
columns (list of str or None, default None): Dotted field paths (
"imdb.rating","tags.0") used directly as tabular features.Noneor[]means no tabular block. The kind of each column is inferred from the training documents (see_infer_kind):"size": every value is a list or sub-document; the feature is its length."bool": every value is a boolean; at transform time0/1,"yes"/"no","true"/"false","t"/"f"and"y"/"n"are read too, anything else is missing."datetime": datetime values; the feature is seconds since 1970-01-01 UTC."numeric": a numeric dtype, or at least 95% of the values parse as numbers (numeric strings included). Unparsable values and infinities are missing, values beyond the float32 range are clipped. A column with no values at all is numeric."categorical": anything else. Values become strings (1,1.0and"1"are one category) and missing values the category"<NA>".
Non-categorical columns are imputed with the training median (and standardised when
scale_numeric); categorical columns are one-hot encoded.- embed_fields (list of str, bool or None, default None):
What is serialised to JSON and embedded.
NoneorTrue: the whole document except_idand the excluded paths (thecolumnsstay in the JSON too). A list of dotted paths: only those fields, in document order.Falseor[]: no embedding block. - exclude (sequence of str, default ()):
Dotted paths never embedded. The target of a
MongoDatasetpassed tofitis excluded automatically;exclude_holds the effective list after fitting. - embedding_model (str, BaseEmbedder or None, default
"voyage-4-nano"): Embedding model:"voyage-4-nano"or any"org/name"Hugging Face id (local), other"voyage-*"names (Voyage API),"hashing"(tests), a"@<dim>"suffix for Matryoshka truncation, or an embedder instance. - embedding_kwargs (dict or None, default None):
Forwarded to the embedder constructor (e.g.
{"dimension": 512},{"batch_size": 64}). - cache_dir (str or None, default
".mongopredict_cache"): Directory of the sqlite embedding cache, keyed by the embedder's settings and the text;Nonedisables it. - batch_size (int, default 512):
Documents per batch for cursors, generators and lists. A
MongoDatasetuses its ownbatch_size. - mask_target (bool, default False):
Falseremoves the target field from the embedded JSON.Truekeeps it as the first key, with the valuemask_token, and putsprefixbefore the JSON, so the model sees which field is asked for. The masked key ismask_keyor, failing that, the dataset target; with plain documents (no dataset target) onlymask_keycan be masked, and it is then also excluded from the rest of the JSON. - mask_token (str, default
"<MASK>"): The value shown for the masked field. - mask_key (str or None, default None): The key shown with the mask (default: the dataset target). Useful when the target is a derived field (e.g. a collapsed or logged copy) and the model should see the original field name.
- prefix (str or None, default None):
Text put before the JSON.
Nonemeans"Predict the value of <mask_token>: "when a field is masked and nothing otherwise; any string (""included) is used as is. - max_json_chars (int or None, default 8000):
Character budget for the whole text (prefix included). Fields are added in order and the
first one that does not fit is cut (when more than its key fits), the rest dropped.
Nonemeans unlimited. Ignored whenmax_tokensis set. - max_tokens (int,
"model"or None, default None): Token budget instead of characters, measured withtokenizer."model"uses the tokenizer'smodel_max_length, capped by the model config'smax_position_embeddings(32768 for voyage-4-nano). 16 tokens are kept free for the document prompt and special tokens. For a local embedder the model'smax_seq_lengthis set to this budget too, unlessembedding_kwargssets it. - tokenizer (str, tokenizer object or None, default None):
Used only to measure
max_tokens. A Hugging Face id, or a Hugging Face style tokenizer (callable on a list of texts, returning{"input_ids": ...}, withdecode).None: the embedding model's tokenizer when it is a local model, else voyage-4-nano's. - scale_numeric (bool, default True): Standardise the non-categorical columns after imputation.
- min_frequency (int, default 5): Categories seen fewer times in training go to the one-hot "infrequent" column.
- max_categories (int, default 100):
Upper bound on one-hot columns per categorical column (infrequent bucket included).
The feature matrix is dense float32: its memory is documents x (embedding dimension +
numeric columns + one-hot columns) x 4 bytes, so many categorical columns with a large
max_categoriescost memory on large training sets.
Attributes
- target_ (str or None):
The dataset target seen by the last fit (
Nonefor plain documents). - exclude_ (list of str):
Paths left out of the embedded JSON:
exclude, the target and, for plain documents in mask mode,mask_key. - embedder_ (BaseEmbedder or None):
The embedder built by the last fit (
Nonewhen embeddings are disabled). - tokenizer_ (tokenizer or None):
Tokenizer loaded for
max_tokens; reset by every fit. - column_kinds_ (dict of str to str):
Inferred kind of each column (see
columns). - tabular_ (sklearn ColumnTransformer or None):
Fitted preprocessing of the columns (
Nonewithout columns). - n_tabular_features_, n_embedding_features_ (int): Widths of the two blocks of the output matrix.
Examples
>>> docs = [{"_id": i, "price": 10 + i, "kind": "a" if i % 2 else "b",
... "text": f"item {i}"} for i in range(20)]
>>> prep = DocumentFeaturizer(columns=["price", "kind"], embedding_model="hashing",
... embedding_kwargs={"n_features": 32}, cache_dir=None)
>>> X = prep.fit_transform(docs) # the whole document but ``_id`` is embedded
>>> X.shape, X.dtype
((20, 35), dtype('float32'))
>>> list(prep.get_feature_names_out()[:4])
['num__price', 'cat__kind_a', 'cat__kind_b', 'emb_0']
Effective token budget per text.
Returns
- int or None:
max_tokensas an int; formax_tokens="model"the tokenizer'smodel_max_lengthcapped by the model'smax_position_embeddings.Nonewhenmax_tokensisNone(the character budgetmax_json_charsis used).
Raises
- ValueError: With
max_tokens="model"when the tokenizer reports no usable length.
Fit the featurizer (column kinds, tabular preprocessing, embedder).
Parameters
- X (MongoDataset, cursor, iterable of dict or list of dict):
Training documents. A
MongoDatasetis read in its own batches and itstargetis excluded from (or masked in) the embedded JSON. Other inputs are read in batches ofbatch_size. - y (ignored):
Present for sklearn compatibility; take labels from
MongoDataset.y.
Returns
- DocumentFeaturizer:
self. The documents are embedded during the fit, so with a cache a followingtransformof the same documents is cheap.
Raises
- TypeError: If
columns,embed_fieldsorexcludeis a single string. - ValueError: If there are no documents, or neither columns nor embeddings.
Fit on X and return its feature matrix, reading the documents once.
Parameters
- X (MongoDataset, cursor, iterable of dict or list of dict):
As in
fit(). y (ignored):
**fit_params (ignored):
Returns
- numpy.ndarray of float32, shape (n_documents, n_features):
[tabular columns | embedding]; column names fromget_feature_names_out().
Feature matrix of X with the fitted preprocessing and embedder.
Parameters
- X (MongoDataset, cursor, iterable of dict or list of dict): Documents to featurize. The target is excluded (or masked) as in the fit, so it may be present or absent.
Returns
- numpy.ndarray of float32, shape (n_documents, n_features): An empty
(0, n_features)array whenXhas no documents.
Fit and return the feature matrix, consuming the document batches once.
Only the values of columns and the embeddings are kept per batch, so memory stays
proportional to the features rather than to the raw documents. As in
fit_batches(), no target is known, so it must be in exclude.
Transform an iterable of document batches.
Embeddings are computed batch by batch (so a streaming dataset is never held in memory), while the column values, which are small, are collected and encoded in a single sklearn call at the end: per batch sklearn overhead dominated on collections of small documents.
Parameters
- batches (iterable of list of dict):
Document batches, e.g. from
MongoDataset.iter_batches.
Returns
- numpy.ndarray of float32, shape (n_documents, n_features)
Names of the output columns, in order.
Parameters
- input_features (ignored): Present for sklearn compatibility.
Returns
- numpy.ndarray of str (object dtype): The tabular names from the
ColumnTransformer(e.g."num__year","cat__rated_PG","cat__rated_infrequent_sklearn"), then"emb_0"..."emb_<d-1>"for the embedding dimensions.
Local embeddings through sentence-transformers.
The model is loaded lazily on first use (see model) and is never pickled, so a fitted
featurizer can be saved and loaded on another host.
Parameters
- model_name (str, default
"voyageai/voyage-4-nano"): Hugging Face id, or a key ofLOCAL_ALIASES("voyage-4-nano"). voyage-4-nano is Apache 2.0, 346M parameters. - batch_size (int, default 32): Maximum texts per forward pass.
- max_seq_length (int or None, default 1024):
Token limit per text; longer JSON documents are truncated. Capped at the model's own
limit (e.g. 256 for all-MiniLM-L6-v2).
Nonekeeps the model's limit. - device (str or None, default None):
"cuda","cpu"(or e.g."cuda:1");Nonepicks CUDA when available. - normalize (bool, default True): Return unit-length vectors.
- trust_remote_code (bool, default True):
Forwarded to
SentenceTransformer(needed by models with custom code). - show_progress_bar (bool, default False):
Forwarded to
encode. - dtype (str, default
"auto"):"auto"runs in bfloat16 on CUDA devices that support it and float32 elsewhere; or an explicit torch dtype name such as"float32"/"float16". float16 overflows in voyage-4-nano (Qwen3 backbone) and yields NaN vectors: if any vector of a call comes back non-finite, aRuntimeWarningis issued, the model is switched to float32 for good and those rows are recomputed. - max_batch_tokens (int, default 65536):
Texts are grouped by length so that a batch holds at most about this many tokens
(estimated as characters / 3, capped by
max_seq_length). This keeps long documents from exhausting GPU memory while short ones still go through in batches ofbatch_size. On a CUDA out-of-memory error a group is retried with a quarter of the batch size, down to one text, before the error is raised. - prompt (str or None, default None):
Text put before every document instead of the model's document prompt.
None: the model's own (e.g. voyage-4-nano's"Represent the document for retrieval: ");"": none. - max_seq_length_in_key (bool, default True):
Whether
|len=<max_seq_length>goes intoname(the cache key). The featurizer turns it off when it has already cut every text to the model's length with the model's own tokenizer, so those vectors are the same as untruncated ones.
Attributes
- name (str):
Cache key prefix: the model id, then
|prompt=<prompt>for a custom prompt,|rawwhen not normalised, and|len=<max_seq_length>(seemax_seq_length_in_key). - part (tuple of (int, int) or None):
Set only by
_CachedEmbedderduring one call in part mode. - last_done (numpy.ndarray of bool or None):
Rows the last
embed()call computed (all of them outside part mode).
Notes
Matryoshka truncation is not done here: pass dimension= to _make_embedder(), which
caches the full vectors once and truncates on the way out (see _MatryoshkaTruncate).
The SentenceTransformer, loaded on first access.
Resolves device and dtype="auto" at load time and sets the model's
max_seq_length to min(max_seq_length, native limit).
Assign every length group to one of the K parts of part = (k, K).
Each group goes to the least loaded part, the load being the group's padded tokens
(estimated as characters / 3), in the groups' order (longest first). The assignment is
deterministic and the loads carry over between calls, so the K processes, each
running the same calls, agree on who computes which group.
Parameters
- groups (list of list of int):
Groups from
_token_groups. - texts (list of str): The texts the indices refer to.
Returns
- list of int: The part (
0..K-1) of each group.
Embeddings through the Voyage AI API (the voyageai client is a dependency of the
package; needs an API key in VOYAGE_API_KEY or api_key).
Any text embedding model the API serves works, e.g. "voyage-4-lite", "voyage-4",
"voyage-4-large", "voyage-code-4", "voyage-finance-2" or "voyage-law-2".
voyage-4-nano is an open-weight model and always runs locally (see
SentenceTransformerEmbedder). Texts are sent in requests of at most batch_size
texts (the API takes up to 1,000) and at most the model's tokens per request (1M for
voyage-4-lite, 320K for voyage-4, 120K for voyage-4-large and the others), estimated as
characters / 3. Rate limits and server errors are retried by the client, with exponential
backoff, up to max_retries times.
Parameters
- model (str, default
"voyage-4-lite"): Voyage model name. - output_dimension (int or None, default None):
Dimension requested from the API (256, 512, 1024 or 2048 for the voyage-4 models);
Noneis the model's default (1024). - input_type (str or None, default
"document"): Voyageinput_type("document","query"orNone). - batch_size (int, default 1000): Most texts per API request.
- api_key (str or None, default None):
API key;
NonereadsVOYAGE_API_KEY. - truncation (bool, default True): Let the API truncate texts longer than the model's context (32,000 tokens for the voyage-4 models) instead of failing.
- max_retries (int, default 5):
Retries of a failed request (rate limit, timeout, server error), passed to
voyageai.Client. - timeout (float or None, default None):
Seconds before a request times out;
Noneis the client's default.
Attributes
- name (str):
"voyage-api:<model>@<output_dimension or full>", plus|<input_type>|truncation=...when those differ from the defaults (so default keys stay as they were).
Raises
- ValueError: For a model served by another endpoint (
voyage-context-*,voyage-multimodal-*), and, on the first request, when no API key is set. - ImportError: On the first request, when the
voyageaipackage is not installed.
Hashed word uni- and bigram vectors: fast, deterministic and dependency free.
Not a semantic embedding; use it for tests, CI, quick pipeline checks and as a cheap
bag-of-tokens baseline. analyzer="char_wb" with ngram_range=(3, 5) gives character
n-grams instead (about 10x slower on long JSON documents).
Parameters
- n_features (int, default 256): Output dimension (number of hash buckets).
- ngram_range (tuple of (int, int), default (1, 2)): Range of n-gram lengths.
- analyzer (str, default
"word"):HashingVectorizeranalyzer ("word","char"or"char_wb").
Attributes
- name (str):
"hashing@<n_features>", plus|<analyzer><ngram_range>for non-default analyzers, so different settings never share cache entries.
Examples
>>> HashingEmbedder(n_features=8).embed(['{"a": 1}']).shape
(1, 8)
Interface of all embedders: embed(texts) -> np.ndarray of shape (n_texts, dim).
Subclass it to plug in any model: implement embed() and set name to a string that
identifies the model and every setting that changes its vectors. name is the cache key
prefix of _CachedEmbedder; an embedder that keeps the default "base" is not
cached by _make_embedder().
Attributes
- name (str): Identifier of the model and its settings, used in cache keys.