Chapter 17 · Vector Search: Embeddings, KNN Indexes, Distance Measures, Filters, and Retrieval Design

Embedding Fundamentals, Model Versioning, Dimensions, Similarity / Distance, and Storing Vector Values

Build a precise AtlasMart vector-retrieval data contract: externally generated embeddings, model/version metadata, dimensionality checks, distance semantics, and safe storage boundaries.

Advanced · 170–220 minutesembeddings · model lifecycle · vector valuesFirebase JS 12.19.0 · Admin 14.4.0 · @google-cloud/firestore 9.1.0CLI 15.30.0 lab pin · Standard Native canonical lab · Enterprise differences explicitLast reviewed: 17 September 2026

1. AtlasMart problem: semantic search needs a data contract before it needs a KNN query

Execution and safety note

Use the Emulator Suite, a Firebase demo project, or an isolated test project for destructive, security-sensitive, billing-sensitive, migration, backup/restore, or write-heavy exercises unless the lesson explicitly marks managed verification as required. Treat shown output as expected evidence unless it is explicitly identified as captured output, and re-check current Firebase/Google Cloud edition, mode, quota, pricing, and security documentation before production execution.

AtlasMart wants “products like this camera” and natural-language discovery without copying the entire catalog into a separate system on day one. The dangerous shortcut is to treat an embedding as magic meaning. An embedding is a fixed-length numeric vector produced by an external model; Firestore stores/searches that vector but does not generate it. A model version identifies the generator and configuration that produced the vector. Dimension is the vector length. A distance measure turns two vectors into a numeric proximity score. A K-nearest-neighbor (KNN) query returns the closest indexed vectors according to that chosen measure. Those definitions form the storage/query contract.

Chapter 17 reproducibility baseline · reviewed 17 September 2026

AtlasMart continues the same canonical lab environment used in Chapters 01–16: project ID demo-atlasmart-firestore, Standard edition / Native mode / (default) database, Firestore emulator 127.0.0.1:8080, Authentication emulator 127.0.0.1:9099, Emulator UI 127.0.0.1:4000, Firebase JavaScript SDK 12.19.0, Firebase Admin Node.js SDK 14.4.0 carrying @google-cloud/firestore 9.1.0, @firebase/rules-unit-testing 5.0.2, Firebase CLI 15.30.0, and Node.js 22+. Mandatory work is local/no-cost. Managed vector indexes, managed KNN billing, production latency, Query Explain, Enterprise Pipeline execution, and external embedding services are optional bounded exercises only.

Emulator evidence boundary

The emulator is suitable for AtlasMart documents, Security Rules, deterministic fixture management, and local application tests, but it does not enforce production composite/vector-index requirements and cannot certify managed vector-query latency, index-build status, billing, availability, or Enterprise execution. Therefore the mandatory lab stores deterministic vectors as ordinary numeric arrays and runs an exact local KNN oracle; the lesson also shows the real managed gcloud/@google-cloud/firestore commands, clearly labeled as optional production/demo-project steps.

Learning outcomes

01

Validate vector dimensions and model metadata before a document becomes searchable.

02

Explain Euclidean, cosine and dot-product behavior without treating any distance as semantic truth.

03

Version embeddings so model migrations do not mix incompatible vector spaces.

04

Separate local deterministic retrieval tests from managed vector-index behavior and billing.

05

Identify privacy, tenant-authorization and external-model governance boundaries.

2. Deterministic AtlasMart fixture: eight dimensions, six products, one judged query

The mandatory lab intentionally uses eight-dimensional vectors so every value can be inspected. Eight dimensions are not a production recommendation. They are a deterministic teaching fixture. Production models can emit far larger vectors, but Firestore Native vector indexing currently supports at most 2,048 dimensions. The important contract is that every indexed/query vector for one index has the same dimension and semantic model lineage.

package.json · Chapter 17 deterministic lab
{  "name": "atlasmart-firestore-ch17",  "private": true,  "type": "module",  "engines": { "node": ">=22" },  "dependencies": {    "firebase": "12.19.0",    "firebase-admin": "14.4.0"  },  "devDependencies": { "firebase-tools": "15.30.0" },  "scripts": {    "emulators": "firebase emulators:start --only firestore,auth --project demo-atlasmart-firestore",    "seed": "node seed-ch17.mjs",    "evaluate": "node evaluate-ch17.mjs",    "reset": "node reset-ch17.mjs"  }}
atlasmart-vectors.json · deterministic 8-D fixture
[  {"id":"p-1001","tenantId":"tenant-a","category":"cameras","name":"Trail Camera","embeddingV1":[0.93,0.05,0.02,0.00,0.20,0.06,0.01,0.12]},  {"id":"p-1002","tenantId":"tenant-a","category":"accessories","name":"USB-C Hub","embeddingV1":[0.04,0.91,0.08,0.15,0.01,0.18,0.04,0.02]},  {"id":"p-1003","tenantId":"tenant-b","category":"sensors","name":"Temp Sensor","embeddingV1":[0.09,0.14,0.86,0.05,0.05,0.18,0.02,0.03]},  {"id":"p-1004","tenantId":"tenant-b","category":"gateways","name":"Edge Gateway","embeddingV1":[0.10,0.55,0.31,0.51,0.04,0.28,0.08,0.04]},  {"id":"p-1005","tenantId":"tenant-c","category":"cameras","name":"PoE Camera","embeddingV1":[0.86,0.09,0.02,0.06,0.30,0.07,0.01,0.14]},  {"id":"p-1006","tenantId":"tenant-a","category":"power","name":"Bench PSU","embeddingV1":[0.02,0.22,0.11,0.18,0.01,0.89,0.06,0.02]}]

3. Store vector lineage beside the vector

seed-ch17.mjs · keep the model contract with each document
process.env.FIRESTORE_EMULATOR_HOST = "127.0.0.1:8080";process.env.GCLOUD_PROJECT = "demo-atlasmart-firestore";import { readFile } from "node:fs/promises";import { initializeApp } from "firebase-admin/app";import { getFirestore } from "firebase-admin/firestore";initializeApp({ projectId: "demo-atlasmart-firestore" });const db = getFirestore();const rows = JSON.parse(await readFile("atlasmart-vectors.json", "utf8"));for (const row of rows) {  if (row.embeddingV1.length !== 8) throw new Error(`bad dimension: ${row.id}`);  await db.doc(`vectorProducts/${row.id}`).set({    ...row,    embeddingModel: "atlasmart-local-v1",    embeddingVersion: 1,    embeddingDimension: 8,    embeddingSourceHash: `sha256:${row.id}:fixture-v1`,    searchable: true,    public: true  });}console.log(`seeded ${rows.length} versioned vector products`);

4. Similarity/distance is a measurement, not an explanation

Euclidean distance measures straight-line separation. Cosine distance focuses on angle and is useful when vector magnitude is not intended to carry meaning. Dot product combines direction and magnitude; Firestore Standard documents all three options. For cosine, a zero vector is a special case because normalization is undefined. A smaller Euclidean/cosine distance means nearer; dot-product APIs may expose a score/distance convention that you must read from the SDK documentation before comparing thresholds.

vector-math.mjs · exact local oracle
export function assertVector(v, dim = 8) {  if (!Array.isArray(v) || v.length !== dim || v.some(x => !Number.isFinite(x))) {    throw new TypeError(`expected ${dim} finite numbers`);  }}export function euclidean(a, b) {  assertVector(a, a.length); assertVector(b, a.length);  return Math.sqrt(a.reduce((s,x,i) => s + (x-b[i])**2, 0));}export function dot(a,b) { return a.reduce((s,x,i)=>s+x*b[i],0); }export function norm(a) { return Math.sqrt(dot(a,a)); }export function cosineDistance(a,b) {  const d = norm(a) * norm(b);  if (d === 0) throw new Error('cosine undefined for zero vector');  return 1 - dot(a,b)/d;}export function rank(items, query, distance = euclidean) {  return items.map(x => ({...x, distance: distance(x.embeddingV1, query)}))    .sort((a,b) => a.distance-b.distance || a.id.localeCompare(b.id));}

5. Observable ranking before Firestore is involved

evaluate-ch17.mjs · deterministic Euclidean ground truth
import rows from "./atlasmart-vectors.json" with { type: "json" };import { rank } from "./vector-math.mjs";const query = [0.90,0.06,0.02,0.02,0.24,0.05,0.01,0.13];const ranked = rank(rows, query);console.table(ranked.map(x => ({ id:x.id, tenant:x.tenantId, category:x.category, distance:+x.distance.toFixed(6) })));if (ranked[0].id !== "p-1001" || ranked[1].id !== "p-1005") throw new Error("fixture drifted");console.log("ground-truth top-2 preserved");

6. Model migration: never overwrite lineage invisibly

If AtlasMart changes from atlasmart-local-v1 to another embedding model, vectors from the old and new spaces are not automatically comparable. A safe migration writes embeddingV2 plus explicit embeddingModelV2/embeddingVersion metadata, builds a matching index, evaluates the new retrieval contract, shifts reads, and only then retires v1. An in-place overwrite with no version marker makes rollback and offline quality comparison impossible.

Deliberately wrong approach

“The new model is better, so overwrite embeddingV1 today.” This mixes deployment, index rebuild, quality change and rollback into one irreversible event. Repair it with dual-write/backfill state, explicit version fields, idempotent jobs, and a cutover gate based on judged queries.

7. Managed Firestore vector field: optional cloud step

In managed Standard Native, the server library writes a Firestore vector value and a flat vector index supports KNN. The local mandatory lab does not claim that its array field is a managed vector index; it is a deterministic oracle. When you run the optional managed step, write the same eight values with the server SDK’s vector type and create the matching index.

optional-managed-write.mjs
import { Firestore, FieldValue } from "@google-cloud/firestore";const db = new Firestore({ projectId: process.env.GCLOUD_PROJECT });await db.doc("vectorProducts/p-1001").set({  tenantId: "tenant-a",  category: "cameras",  embeddingModel: "atlasmart-local-v1",  embeddingVersion: 1,  embeddingDimension: 8,  embeddingV1: FieldValue.vector([0.93,0.05,0.02,0.00,0.20,0.06,0.01,0.12])}, { merge: true });

8. Authorization metadata belongs in the retrieval contract

Vector proximity cannot decide whether a caller may see a product. AtlasMart carries tenantId, visibility/category state, and model version as ordinary metadata. A trusted backend that bypasses Security Rules must validate the end-user/tenant and inject the corresponding metadata filter; a broad service-account IAM grant is not tenant authorization. If content is sent to an external embedding service, classify and minimize that content first. Product descriptions may be safe while private support tickets, PII, regulated data, or customer secrets may require a different architecture.

9. Edition/mode/client matrix

Surface Vector capability Important boundary
Standard Native Core Managed nearest-neighbor search through supported server libraries; flat vector indexes; metadata prefilters Maximum 2,048 dimensions; maximum 1,000 returned documents; no realtime snapshot listeners for vector search; current documented client-library support is Python, Node.js, Go, Java
Enterprise Native Core Native Core semantics in Enterprise context Enterprise indexing/billing differ from Standard; do not copy Standard billing equations blindly
Enterprise Native Pipeline findNearest transformation stage with broader Pipeline client surface Pipeline API and supported distance options are distinct; verify current stage and SDK behavior rather than treating it as Standard Core
MongoDB compatibility Separate MongoDB-compatible query/index surface Do not assume Native findNearest, vector-index commands, Rules, or pricing semantics map one-for-one
Emulator Useful for fixture/security/application plumbing; recent emulator versions can store vector values Composite/vector-index enforcement, production latency, billing, index build state, and all service limits are not production evidence

Verification checklist and cleanup

  • Every fixture vector has exactly eight finite numbers and explicit model/version/dimension metadata.
  • The deterministic query returns p-1001 then p-1005 under Euclidean distance.
  • No claim is made that the emulator proves a production vector index or production billing.
  • Changing model/version requires a separate evaluation/cutover path.
  • Tenant/visibility metadata is treated as authorization input, never as semantic relevance alone.
reset-ch17.mjs
process.env.FIRESTORE_EMULATOR_HOST = "127.0.0.1:8080";process.env.GCLOUD_PROJECT = "demo-atlasmart-firestore";import { initializeApp } from "firebase-admin/app";import { getFirestore } from "firebase-admin/firestore";initializeApp({ projectId: "demo-atlasmart-firestore" });await getFirestore().recursiveDelete(getFirestore().collection("vectorProducts"));console.log("Chapter 17 vector fixture removed");

Production judgment and bridge to Lesson 2

Choose an embedding model and distance measure only after defining the retrieval task, privacy boundary, judged queries, model lineage and authorization metadata. Lesson 2 turns that data contract into actual Firestore vector indexes and examines where index configuration, supported SDKs and query limits change the implementation.

Knowledge check

  1. Who generates an AtlasMart embedding in this architecture?
  2. Why record model version beside a vector?
  3. What is the current maximum Firestore embedding dimension for vector indexing?
  4. Is a smaller vector distance proof that an item is semantically correct?
  5. Can a tenant filter be omitted because the nearest vector belongs to another tenant?
Review the answers

1. An external/local embedding generator does; Firestore stores and searches the vector.

2. Vectors from different model spaces may not be comparable; explicit lineage enables evaluation, migration and rollback.

3. 2,048 dimensions.

4. No. It is only proximity under one model and distance function; quality must be judged against task-specific ground truth.

5. No. Relevance never substitutes for authorization. The trusted path must enforce tenant/visibility constraints.

Summary and next step

This lesson established the working contract for Embedding Fundamentals, Model Versioning, Dimensions, Similarity/Distance, and Storing Vector Values. Keep its edition/mode assumptions, trust boundary, verification evidence, and operational constraints explicit when reusing the pattern.

Next, continue to Create/Manage Firestore Vector Indexes and Understand Supported Dimensions/Query Limits.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.