ExFastembed (ExFastembed v0.1.1)

Copy Markdown View Source

Loads FastEmbed text embedding and reranker models through fastembed-rs.

Use load/1 followed by embed_text/1 to generate vectors, or load_reranker/1 followed by rerank/3 to score documents for a query.

Each BEAM VM shares one embedding model and one independent reranker. Loading a replacement changes the model used by all processes; a failed load preserves the previous model. Loading, inference, and unloading within each family run serially. Applications own their request queues and must stop submitting work before unloading or deleting a model.

Model files are downloaded on first use and cached in .fastembed_cache. Set FASTEMBED_CACHE_DIR before loading a model to use another directory. If HF_HOME is exported when the VM starts, FastEmbed uses that directory instead. Partial downloads reuse the cached revision for consistent model files. Loading and inference block the caller while the native work runs on a dirty scheduler, allowing other BEAM processes to continue running.

All public functions return error tuples for invalid input. Strings must be valid UTF-8. Model names are matched case-insensitively against the bundled FastEmbed catalog, including the legacy aliases.

See the model lifecycle guide for memory, disk usage, cache configuration, and deletion examples.

Summary

Model discovery

Returns the absolute effective cache root without creating it.

Returns text embedding model names accepted by load/1.

Lists the models currently held by the native runtime, with their original cache paths.

Resolves an accepted model name to its variant, metadata, and local cache status.

Lists distinct model variants with their repository, dimension, and cache status.

Returns reranker model names accepted by load_reranker/1.

Model lifecycle

Deletes the downloaded model files from disk, unloading matching native sessions first.

Unloads the shared embedding model while keeping downloaded files.

Unloads the shared reranker while keeping downloaded files and the embedding model.

Embeddings

Embeds a list of strings with the loaded text embedding model.

Loads a text embedding model and returns its embedding dimension.

Reranking

Loads a reranker model.

Reranks documents for a query using the loaded reranker model.

Types

A dense vector with the dimension reported by load/1.

An input, model-loading, or inference failure with a human-readable reason.

A required file, its snapshot path when present, and its non-empty size in bytes.

A model variant with runtime state, local file paths, and disk byte sizes.

The two supported model families.

A zero-based document index, relevance score, and optional document text.

Model discovery

cache_directory()

@spec cache_directory() :: String.t()

Returns the absolute effective cache root without creating it.

Respects HF_HOME from the native process environment at VM startup, otherwise FASTEMBED_CACHE_DIR, with .fastembed_cache as the default. Existing roots are canonicalized, resolving symlinks.

embed_models()

@spec embed_models() :: [String.t()]

Returns text embedding model names accepted by load/1.

Includes repository names, explicit FastEmbed variant names, and legacy aliases. Names are matched case-insensitively.

The list is sorted and contains both full-precision and quantized variants. A repository shared by several variants selects its non-quantized model when available; use an explicit name such as EmbeddingGemma300MQ4 for a specific variant.

Examples

iex> "BGESmallENV15" in ExFastembed.embed_models()
true

loaded_models()

@spec loaded_models() :: {:ok, [model_info()]} | error()

Lists the models currently held by the native runtime, with their original cache paths.

Returns {:ok, []} when nothing is loaded. Unlike models/0, this also finds models loaded from a different FASTEMBED_CACHE_DIR before it was changed. Metadata is a snapshot and can change immediately under concurrent calls.

model_info(name, kind)

@spec model_info(String.t(), model_kind()) :: {:ok, model_info()} | error()

Resolves an accepted model name to its variant, metadata, and local cache status.

kind must be :embedding or :reranker. Resolution follows the same aliases and case-insensitive matching as load/1 and load_reranker/1. See models/0 for the meaning of cached.

Examples

iex> {:ok, info} = ExFastembed.model_info("BAAI/bge-small-en-v1.5", :embedding)
iex> {info.name, info.dimension}
{"BGESmallENV15", 384}

models()

@spec models() :: [model_info()]

Lists distinct model variants with their repository, dimension, and cache status.

Checks the cache locally without network access or loading a model. cached means that the selected ONNX weights, additional data, and four tokenizer/config files are present and non-empty. It does not validate their contents or mean that the model is loaded in the VM. Call load/1 or load_reranker/1 before inference.

Uses FASTEMBED_CACHE_DIR, defaulting to .fastembed_cache. Embedding variants appear first, then rerankers, sorted by name within each family. Rerankers have a nil dimension.

Includes loaded, the absolute cache_dir and repository path, cached revision, relative required files, and per-file file_details with snapshot paths and byte sizes. variant_bytes is the sum of all required non-empty files (nil if incomplete). disk_bytes counts regular file bytes across the entire repository, including other variants, revisions and partial downloads, without following symlinks or counting snapshot links twice (nil on read errors). These are local file sizes, not RAM usage or remote download estimates. Shared repositories repeat disk_bytes; deduplicate by path before summing.

loaded matches the variant and current cache root. Use loaded_models/0 to find sessions loaded from other cache roots. Discovery may wait for active operations while reading runtime state.

Examples

iex> Enum.any?(ExFastembed.models(), &(&1.name == "BGESmallENV15"))
true

reranker_models()

@spec reranker_models() :: [String.t()]

Returns reranker model names accepted by load_reranker/1.

Includes repository names, explicit FastEmbed variant names, and legacy aliases. Names are matched case-insensitively.

Examples

iex> "BAAI/bge-reranker-base" in ExFastembed.reranker_models()
true

Model lifecycle

delete_model(name, kind)

@spec delete_model(String.t(), model_kind()) :: {:ok, true} | error()

Deletes the downloaded model files from disk, unloading matching native sessions first.

The cache directory is the model's on-disk storage: deletion physically removes its repository directory, including ONNX weights, tokenizer/config files, blobs, and partial downloads. To release only RAM and keep these files, use unload/0 or unload_reranker/0.

Accepts the same names and kinds as model_info/2. All cached variants and revisions in the selected repository are removed, including shared tokenizer files and blobs. Both model families are checked before removal. Unrelated repositories and models loaded from a different cache root remain untouched.

Returns {:ok, true} if removed or already absent. Repository symlinks and non-directory entries are rejected. Internal symlinks are removed without following their targets. If file removal fails after unloading, deletion can be partial and the model stays unloaded; correct the error and retry.

Stop submitting work and drain application queues first, as for unload/0. Deletion is serialized with library loads in this VM. Other VMs or external processes sharing the cache must be coordinated by the application.

unload()

@spec unload() :: {:ok, true} | error()

Unloads the shared embedding model while keeping downloaded files.

Waits for an active load or inference, then drops the ONNX session, weights, and its owned native buffers. Returns {:ok, true} even if already unloaded. The reranker is independent and remains available.

Stop submitting model work and drain application queues before calling this function. The library does not manage or cancel jobs; concurrent calls are serialized without an ordering guarantee. A subsequent load can recreate the session. Allocators may retain freed memory, so process RSS need not immediately decrease by the size of the model. Already returned embeddings remain owned by the calling BEAM processes.

unload_reranker()

@spec unload_reranker() :: {:ok, true} | error()

Unloads the shared reranker while keeping downloaded files and the embedding model.

Returns {:ok, true} even if already unloaded. The synchronization, application queue ownership, and memory reclamation behavior described in unload/0 also apply.

Embeddings

embed_text(texts)

@spec embed_text([String.t()]) :: {:ok, [embedding()]} | error()

Embeds a list of strings with the loaded text embedding model.

Call load/1 before calling this function. An empty list returns {:ok, []} without running inference.

Results preserve the input order, with one vector per text. A non-empty input returns an error if no embedding model is loaded. Tokenization and truncation follow the selected model's FastEmbed defaults.

Examples

iex> ExFastembed.embed_text([])
{:ok, []}

iex> ExFastembed.embed_text(["document", 123])
{:error, "Invalid input: texts must be a list of strings"}

load(model_name)

@spec load(String.t()) :: {:ok, pos_integer()} | error()

Loads a text embedding model and returns its embedding dimension.

A successful call replaces the embedding model shared by all processes. A failed download or initialization leaves the previous model available. See embed_models/0 for accepted names. The returned dimension is the length of each vector generated by embed_text/1.

Examples

{:ok, 384} = ExFastembed.load("BAAI/bge-small-en-v1.5")
iex> ExFastembed.load("invalid-model")
{:error, "Model not recognized or not implemented: invalid-model"}

Reranking

load_reranker(model_name)

@spec load_reranker(String.t()) :: {:ok, true} | error()

Loads a reranker model.

A successful call replaces the reranker shared by all processes, independently of the embedding model. A failed load preserves the previous reranker. See reranker_models/0 for accepted names.

Examples

{:ok, true} = ExFastembed.load_reranker("BAAI/bge-reranker-base")
iex> ExFastembed.load_reranker("invalid-reranker")
{:error, "Reranker model not recognized: invalid-reranker"}

rerank(query, documents, return_docs)

@spec rerank(String.t(), [String.t()], boolean()) ::
  {:ok, [rerank_result()]} | error()

Reranks documents for a query using the loaded reranker model.

Call load_reranker/1 before calling this function. An empty document list returns {:ok, []} without running inference.

Results are sorted by descending relevance score. Each result contains the document's zero-based index in the original list, its score, and its text when return_docs is true (nil otherwise). Scores are model-specific and are not necessarily probabilities. A non-empty input requires a loaded reranker.

Examples

iex> ExFastembed.rerank("query", [], false)
{:ok, []}

Types

embedding()

@type embedding() :: [float()]

A dense vector with the dimension reported by load/1.

error()

@type error() :: {:error, String.t()}

An input, model-loading, or inference failure with a human-readable reason.

model_file()

@type model_file() :: %{
  name: String.t(),
  path: String.t() | nil,
  size_bytes: pos_integer() | nil
}

A required file, its snapshot path when present, and its non-empty size in bytes.

model_info()

@type model_info() :: %{
  name: String.t(),
  kind: model_kind(),
  repository: String.t(),
  dimension: pos_integer() | nil,
  cached: boolean(),
  loaded: boolean(),
  cache_dir: String.t(),
  path: String.t(),
  revision: String.t() | nil,
  files: [String.t()],
  file_details: [model_file()],
  variant_bytes: non_neg_integer() | nil,
  disk_bytes: non_neg_integer() | nil
}

A model variant with runtime state, local file paths, and disk byte sizes.

model_kind()

@type model_kind() :: :embedding | :reranker

The two supported model families.

rerank_result()

@type rerank_result() :: {non_neg_integer(), float(), String.t() | nil}

A zero-based document index, relevance score, and optional document text.