Keyword search finds "refund" but misses "I want my money back". Embeddings fix that: they turn text, and now images and audio, into lists of numbers where similar meanings sit close together. They power AI search, chatbots that answer from your documents, duplicate detection and clustering. In October Google released EmbeddingGemma 2, a free, open model small enough to run on a laptop or phone. This guide explains the idea and walks through a complete example with tools analysts already use.
Embeddings in one picture
Every document is converted to a vector once and stored. At search time, the question is converted too, and the database returns the stored vectors closest to it, usually measured with cosine similarity, a score from -1 to 1 where higher means more similar.
- Embedding
- A fixed-length list of numbers representing the meaning of an input.
- Dimension
- The length of that list. EmbeddingGemma 2 produces 768 by default.
- Cosine similarity
- How closely two vectors point the same way. 1 means identical meaning.
- Vector index
- A structure such as HNSW that finds near neighbours fast in millions of rows.
- RAG
- Retrieval-augmented generation: find the most relevant documents with embeddings, then give them to a chatbot to answer from.
Step 1: create embeddings in Python
Install the libraries once with pip install -U sentence-transformers transformers. The first run downloads the model from Hugging Face.
from sentence_transformers import SentenceTransformer
# Text only: skip the vision and audio encoders to save memory (270M parameters)
model = SentenceTransformer(
"google/embeddinggemma-2",
config_kwargs={"vision_config": None, "audio_config": None},
)
tickets = [
"I was charged twice for my order",
"Can I get my money back for a broken item?",
"How do I change my delivery address?",
"The app crashes when I open my basket",
]
# Documents use the "Document" prompt; 256 dimensions; unit length for cosine
doc_vecs = model.encode(tickets, prompt_name="Document",
truncate_dim=256, normalize_embeddings=True)
query_vec = model.encode("refund request", prompt_name="SearchQuery",
truncate_dim=256, normalize_embeddings=True)
print(model.similarity(query_vec, doc_vecs)) # highest score = best matchStep 2: store and search
import duckdb
con = duckdb.connect("tickets.duckdb")
con.execute("CREATE OR REPLACE TABLE tickets (id INT, text VARCHAR, emb FLOAT[256])")
con.executemany("INSERT INTO tickets VALUES (?, ?, ?)",
[(i, t, v.tolist()) for i, (t, v) in enumerate(zip(tickets, doc_vecs))])
top = con.execute("""
SELECT text, array_cosine_similarity(emb, ?::FLOAT[256]) AS score
FROM tickets
ORDER BY score DESC
LIMIT 3
""", [query_vec.tolist()]).fetchall()
print(top)CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE tickets (
id bigserial PRIMARY KEY,
text text NOT NULL,
emb vector(256)
);
-- Fast approximate search for large tables
CREATE INDEX ON tickets USING hnsw (emb vector_cosine_ops);
-- $1 is the query vector from Python; <=> is cosine distance (lower = closer)
SELECT text, 1 - (emb <=> $1) AS similarity
FROM tickets
ORDER BY emb <=> $1
LIMIT 5;How many dimensions do you need?
EmbeddingGemma 2 is trained so you can keep only the first part of each vector. Shorter vectors mean less storage and faster search, with a small loss in quality. Google's own benchmark results:
Axis starts at 50 to show the differences. Source: EmbeddingGemma 2 model card. 768 dimensions is the full size; 256 keeps about 98% of the quality at one third of the storage. 128 is best kept for text-only uses.
What analysts can do with this
- 1
Search support tickets by meaning
Find every complaint about late deliveries, however it is worded.
- 2
Group open-text survey answers
Cluster embeddings to discover the themes in thousands of comments in minutes.
- 3
Find duplicates
Spot near-identical products, customers or tickets that exact matching misses.
- 4
Build a "chat with our docs" assistant
Retrieve the right paragraphs with embeddings, then let a language model answer from them.
- 5
Keep it private
Because the model runs locally, sensitive text never leaves your machine.
Check your understanding
1/3What does cosine similarity measure?
Scores near 1 mean very similar meaning, even with different words.
2/3What should you do after shortening (truncating) an embedding?
Truncated vectors are no longer unit length, which distorts cosine scores.
3/3Which pgvector operator gives cosine distance?
<=> is cosine distance; <-> is Euclidean distance and <#> is negative inner product.
You got 0 out of 3.
Working with Python data tools? See Upgrading to pandas 3.0 and DuckDB 2.0. For which AI models to pair with your search, read The best AI models in October 2026.
Sources: the EmbeddingGemma 2 model card on Hugging Face (google/embeddinggemma-2) and Google DeepMind's announcement (6 October 2026); DuckDB array functions documentation; pgvector documentation. Benchmarks are Google's published results.
