Files
semantica/docs/reference/embeddings.md
T
Mohd Kaif 5d70d0c10d docs: replace Exported Classes import blocks with summary tables (all 25 modules) (#567)
* docs: replace Exported Classes import blocks with summary tables across all 25 modules

* docs: add method/parameter tables to parse, ingest, ontology, normalize, triplet_store, change_management, conflicts, export, graph_store, provenance, and semantic_extract modules
2026-05-24 15:49:58 +05:30

17 KiB
Raw Blame History

title, description, icon
title description icon
Embeddings Module Text and graph embedding generation — Sentence-Transformers, FastEmbed, OpenAI, BGE, Ollama — with pooling strategies, caching, and GPU acceleration. vector-square

semantica.embeddings converts text and graph structures into dense vectors. These vectors power semantic search, entity resolution, GraphRAG retrieval, and Distance Intelligence across every Semantica module. A single provider-agnostic API abstracts Sentence-Transformers, FastEmbed, OpenAI, BGE, and Ollama behind one interface.

Why Embeddings Matter

Raw text can't be compared mathematically. Embeddings translate meaning into geometry — two semantically similar sentences produce vectors that are close together in high-dimensional space, even when they share no words.

Semantica uses embeddings for:

  • Semantic search — find knowledge graph nodes by meaning, not just keywords
  • Entity resolution — detect that "Apple Inc." and "Apple Computer" refer to the same entity
  • Deduplicationsemantic_v2 strategy measures entity similarity via embedding distance
  • GraphRAG retrieval — hybrid vector + graph traversal for grounded LLM answers
  • Distance Intelligence — N×N semantic distance matrices across entity sets
  • Semantic chunking — detect topic shift boundaries in TextSplitter(method="semantic_transformer")

Exported Classes

Class Role
EmbeddingGenerator Provider-agnostic entry point — handles batching, caching, and provider selection
TextEmbedder Text embedding with disk caching and automatic batch splitting
GraphEmbeddingManager Embed KG nodes and subgraphs for GraphRAG and distance intelligence
OpenAIStore OpenAI text-embedding-3-small / text-embedding-3-large provider
BGEStore BAAI/bge models via sentence-transformers — free, high-quality
FastEmbedStore ONNX-accelerated local embeddings — no CUDA required
LlamaStore Local Ollama embedding models
MeanPooling Default pooling strategy — best for retrieval and clustering

What You Get

Main entry point — provider-agnostic, handles batching automatically across all backends. Text-specific with automatic batching, disk caching, and progress tracking. Node and subgraph embeddings for structural similarity and GraphRAG context assembly. Full lifecycle: embed → store → search in a single coordinated workflow. `OpenAIStore`, `BGEStore`, `FastEmbedStore`, `LlamaStore`, and `ProviderStoreFactory`. Mean, Max, CLS, Attention, and Hierarchical — control token-to-vector aggregation.

Installation

Provider Install Command API Key Required
Sentence-Transformers (default) pip install semantica No
FastEmbed pip install "semantica[fastembed]" No
BGE pip install semantica No (uses sentence-transformers)
OpenAI pip install "semantica[llm-openai]" Yes — OPENAI_API_KEY
Ollama (LlamaStore) pip install "semantica[llm-ollama]" No — local server
All providers pip install "semantica[all]" Varies

Check which providers are available in your environment:

from semantica.embeddings import check_available_providers

providers = check_available_providers()
# → {"sentence_transformers": True, "fastembed": True, "openai": False, "ollama": True}

Quick Start

```python from semantica.embeddings import EmbeddingGenerator
# Default — Sentence-Transformers, free, runs locally
generator = EmbeddingGenerator()

# Custom model via config dict
generator = EmbeddingGenerator(config={"text": {"method": "sentence_transformers", "model_name": "BAAI/bge-large-en-v1.5"}})
```
```python embeddings = generator.generate_embeddings(["Text about AI", "Machine learning concepts"]) ``` ```python # Cosine similarity — 0.0 (unrelated) to 1.0 (identical meaning) score = generator.compare_embeddings(embeddings[0], embeddings[1], method="cosine") print(f"Similarity: {score:.3f}") ``` ```python from semantica.embeddings import VectorEmbeddingManager, TextEmbedder from semantica.vector_store import VectorStore
vector_store = VectorStore(backend="faiss", dimension=384)
manager = VectorEmbeddingManager(
    embedder=TextEmbedder(model="sentence-transformers"),
    vector_store=vector_store,
)
ids = manager.embed_and_store(documents, metadata=metadata_list)

results = manager.search("machine learning algorithms", top_k=10)
for result in results:
    print(f"Score: {result.score:.3f}  —  {result.metadata['title']}")
```

Supported Models

Provider Model Dimension Speed Best For
sentence-transformers all-MiniLM-L6-v2 384 Fast Default — good balance of speed and quality
sentence-transformers all-mpnet-base-v2 768 Medium Higher retrieval quality
bge BAAI/bge-large-en-v1.5 1024 Medium State-of-the-art retrieval accuracy
bge BAAI/bge-small-en-v1.5 384 Fast Lightweight, competitive quality
fastembed BAAI/bge-small-en-v1.5 384 Very fast CPU-optimised, low-latency production
openai text-embedding-3-small 1536 API Cost-effective OpenAI embedding
openai text-embedding-3-large 3072 API Highest quality via OpenAI API
llama (Ollama) Any Ollama model Varies Local Fully local, no API key

EmbeddingGenerator

```python from semantica.embeddings import EmbeddingGenerator
# Default — Sentence-Transformers with all-MiniLM-L6-v2
generator = EmbeddingGenerator()

# Custom model via set_text_model
generator.set_text_model("sentence_transformers", "BAAI/bge-large-en-v1.5")

embeddings = generator.generate_embeddings(texts)
similarity = generator.compare_embeddings(embeddings[0], embeddings[1])
```

Best for: default prototyping, no API key, good quality.
```python from semantica.embeddings import EmbeddingGenerator
generator = EmbeddingGenerator()
generator.set_text_model("fastembed", "BAAI/bge-small-en-v1.5")
embeddings = generator.generate_embeddings(texts)
```

Best for: CPU-only production, lowest latency without GPU.
```python from semantica.embeddings import OpenAIStore import os
store     = OpenAIStore(api_key=os.getenv("OPENAI_API_KEY"), model="text-embedding-3-small")
embedding = store.embed("Hello world")
```

Best for: highest quality (3-large), or matching an OpenAI LLM pipeline.
```python from semantica.embeddings import LlamaStore
store     = LlamaStore(model="llama3.2", base_url="http://localhost:11434")
embedding = store.embed("Hello world")
```

Best for: air-gapped or privacy-sensitive environments — no data leaves your machine.
```python from semantica.embeddings import EmbeddingGenerator
# Set device via text embedder config
generator = EmbeddingGenerator(config={"text": {"device": "cuda"}})

# Apple Silicon (M1/M2/M3)
generator = EmbeddingGenerator(config={"text": {"device": "mps"}})
```

GPU reduces embedding time by 520× depending on batch size and model.

Constructor Parameters

Parameter Type Default Description
config dict None Config dict; config["text"] is passed to TextEmbedder
**kwargs Additional key/value config merged into config

Use generator.set_text_model(method, model_name) to switch the embedding model after construction.

TextEmbedder

Specialised for text workloads — adds automatic batching, progress tracking, and disk caching:

from semantica.embeddings import TextEmbedder

embedder = TextEmbedder(
    model="sentence-transformers",
    cache_dir=".emb_cache",   # persist embeddings to disk
    cache_ttl=86400,          # cache expiry in seconds (24h); None = never expires
    batch_size=128,
    show_progress=True,
)

# Single text
embedding = embedder.embed("A knowledge graph connects entities with typed relationships.")

# Batch — auto-splits into batch_size chunks, shows progress bar
embeddings = embedder.embed_batch(texts, show_progress=True)

Key behaviours:

  • Cache is keyed on text content + model name — identical texts return cached vectors instantly
  • Progress bar uses tqdm in terminal; switches to tqdm.notebook in Jupyter automatically
  • Large batches (> 10k texts) are chunked internally to avoid OOM on GPU

Provider Stores

Use provider stores directly when you need fine-grained control over a single backend:

from semantica.embeddings import (
    OpenAIStore, BGEStore, FastEmbedStore, LlamaStore,
    ProviderStoreFactory,
)
import os

# OpenAI
store     = OpenAIStore(api_key=os.getenv("OPENAI_API_KEY"), model="text-embedding-3-small")
embedding = store.embed("Hello world")

# BGE (Sentence-Transformers wrapper)
store     = BGEStore(model="BAAI/bge-large-en-v1.5", device="cpu")
embedding = store.embed("Hello world")

# FastEmbed — ONNX runtime, no CUDA required
store     = FastEmbedStore(model="BAAI/bge-small-en-v1.5")
embedding = store.embed("Hello world")

# Ollama — fully local
store     = LlamaStore(model="llama3.2", base_url="http://localhost:11434")
embedding = store.embed("Hello world")

# Auto-select from a name string — useful in config-driven pipelines
store = ProviderStoreFactory.create(provider="bge", model="BAAI/bge-large-en-v1.5")

Pooling Strategies

Transformer models produce one embedding per token. Pooling aggregates token embeddings into a single vector:

```python from semantica.embeddings import MeanPooling
pooler = MeanPooling()
pooled = pooler.pool(token_embeddings)   # shape: (hidden_dim,)
```

Best for: retrieval, semantic search, and clustering — averages all token contributions.
```python from semantica.embeddings import MaxPooling
pooler = MaxPooling()
pooled = pooler.pool(token_embeddings)
```

Best for: capturing the presence of any feature — takes the max activation per dimension.
```python from semantica.embeddings import CLSPooling
pooler = CLSPooling()
pooled = pooler.pool(token_embeddings)
```

Best for: classification-style tasks; models explicitly trained with CLS pooling (BERT).
```python from semantica.embeddings import HierarchicalPooling
# Chunk text, mean-pool within chunks, then mean-pool chunks
pooler = HierarchicalPooling(chunk_size=512)
pooled = pooler.pool(token_embeddings)
```

Best for: long documents exceeding the model's max sequence length — reports, papers, contracts.
| Strategy | When to Use |
| -------- | ----------- |
| `mean` | Default for retrieval, semantic search, and clustering |
| `max` | When you want to capture the presence of any feature, not average presence |
| `cls` | Classification-style tasks; models explicitly trained with CLS pooling (BERT) |
| `attention` | When token importance varies significantly; slower but more accurate |
| `hierarchical` | Long documents exceeding model context length; reports, papers, contracts |

```python
from semantica.embeddings import PoolingStrategyFactory

pooler = PoolingStrategyFactory.create(strategy="mean")
```

GraphEmbeddingManager

Embed graph nodes and subgraphs for structural similarity and GraphRAG context assembly:

from semantica.embeddings import GraphEmbeddingManager, TextEmbedder

manager = GraphEmbeddingManager(
    text_embedder=TextEmbedder(model="sentence-transformers"),
    graph_store=graph_store,   # optional — for persistence
)

# Embed all nodes — uses node label + property text
node_embeddings = manager.embed_nodes(kg)

# Embed a subgraph centred on a node (for GraphRAG context)
subgraph_embedding = manager.embed_subgraph(
    kg,
    center_node="Apple Inc.",
    hops=2,   # include neighbours up to 2 hops away
)

# Find semantically similar nodes by ID
similar = manager.find_similar_nodes("apple_inc", top_k=5)
for node_id, score in similar:
    print(f"{node_id}: {score:.3f}")

Key behaviours:

  • Node embedding combines the label, type, and all property values into a single text string before embedding
  • hops=2 captures the local neighbourhood — increase for richer context, decrease for speed
  • Results from find_similar_nodes are sorted by cosine similarity descending

Embedding Cache

The disk cache avoids recomputing embeddings for unchanged text — critical for large corpora and repeated pipeline runs:

from semantica.embeddings import TextEmbedder

embedder = TextEmbedder(
    model="sentence-transformers",
    cache_dir=".embeddings_cache",
    cache_ttl=3600,   # seconds — None means cache never expires
)

# First call: computes and caches
embeddings = embedder.embed_batch(texts)

# Second call (same texts): returns from cache instantly
embeddings = embedder.embed_batch(texts)
The Distance Intelligence module (v0.5.0) uses the same cache to avoid recomputing embeddings during N×N matrix calculations across large entity sets.

Similarity Computation

from semantica.embeddings import calculate_similarity

# Cosine similarity — direction only, not magnitude; most common for text
score = calculate_similarity(embedding_a, embedding_b, method="cosine")
# → 0.0 (orthogonal / unrelated) to 1.0 (identical direction)

# Euclidean distance converted to similarity
score = calculate_similarity(embedding_a, embedding_b, method="euclidean")

# Dot product — use when vectors are already normalised (equivalent to cosine)
score = calculate_similarity(embedding_a, embedding_b, method="dot")

Convenience Functions

from semantica.embeddings import (
    embed_text, generate_embeddings, calculate_similarity,
    pool_embeddings, check_available_providers,
)

# Single text — fastest path
emb = embed_text("Hello world", method="sentence_transformers")

# Batch
embs = generate_embeddings(texts, method="openai")

# Check which providers are installed
providers = check_available_providers()
# → {"sentence_transformers": True, "fastembed": True, "openai": False}

Tips and Common Pitfalls

**Dimension mismatch.** The dimension you pass to `VectorStore(dimension=...)` must exactly match your embedding model's output. `all-MiniLM-L6-v2` → 384, `all-mpnet-base-v2` → 768, `bge-large-en-v1.5` → 1024. Check with `generator.dimension` before creating the store. **Not normalising for cosine similarity.** If you compute cosine similarity directly (dot product), vectors must be L2-normalised first. `EmbeddingGenerator` normalises by default (`normalize=True`). If you disable it, use `calculate_similarity(..., method="cosine")` which normalises internally. **Sequence length limits.** Most models have a 512-token limit. Text beyond that is silently truncated. Use `TextSplitter(method="hierarchical")` + `HierarchicalPooling` for long documents. **Always use the same model for indexing and querying.** Vectors from different models are not comparable — they live in different vector spaces. Switching models requires re-embedding your entire corpus. **Cache invalidation.** The cache key is the text + model name. Switching models requires clearing the cache or using a different `cache_dir` — otherwise you'll get stale vectors silently returned. Store and search the generated embeddings. Chunk text before embedding for better retrieval quality. Distance Intelligence uses graph embeddings for semantic neighbourhoods. Semantic deduplication uses embedding distance for entity resolution.