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

K-Nearest-Neighbor Queries, Distance Thresholds, Metadata Filters, and Result Ranking

Run deterministic KNN experiments with Euclidean, cosine, and dot-product reasoning, distance thresholds, tenant/category filters, ranking interpretation, and measured filter selectivity.

Advanced · 170–220 minutesKNN · thresholds · metadata filtersFirebase 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: the nearest result changes when the distance and candidate set change

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.

A KNN query is not “semantic search” in the abstract. It is: choose a candidate set, choose a vector field/model version, choose a distance measure, optionally apply a threshold, rank, and return K. AtlasMart must know which of those choices caused a result—not merely display a score.

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

Compute and compare Euclidean, cosine and dot-product rankings on a fixed fixture.

02

Use distance thresholds to reject weak neighbors rather than forcing K results.

03

Apply tenant/category metadata filters before ranking.

04

Measure filter selectivity and distinguish retrieval quality from authorization.

05

Build a small judged ground truth and calculate recall@k.

2. One fixture, three distance functions

compare-distances.mjs
import rows from "./atlasmart-vectors.json" with { type: "json" };import { rank, euclidean, cosineDistance, dot } from "./vector-math.mjs";const q = [0.90,0.06,0.02,0.02,0.24,0.05,0.01,0.13];for (const [name, fn] of [["euclidean",euclidean],["cosine",cosineDistance],["negative-dot",(a,b)=>-dot(a,b)]]) {  const top = rank(rows, q, fn).slice(0,4).map(x=>[x.id,+x.distance.toFixed(6)]);  console.log(name, top);}

3. Distance measure selection is part of model evaluation

Euclidean considers absolute coordinate distance. Cosine normalizes magnitude and compares direction. Dot product can reward magnitude as well as alignment. If the embedding model documentation assumes normalized vectors, dot product and cosine may behave similarly; if not, they can diverge. Do not select a measure because one cherry-picked query “looks better.” Evaluate a judged set representative of production traffic.

4. Thresholds: K is a ceiling, not a promise of relevance

If the nearest item is still far away, forcing five results can manufacture bad recommendations. Current Standard vector search supports a distance threshold. AtlasMart’s local oracle uses the same idea: first rank, then discard candidates beyond a task-specific threshold. Thresholds are model- and measure-specific; they must be calibrated against labeled data and revisited after model changes.

threshold.mjs
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 maxDistance = 0.25; // fixture decision, NOT a universal production valueconst accepted = rank(rows, query).filter(x => x.distance <= maxDistance).slice(0,5);console.table(accepted.map(x => ({ id:x.id, distance:+x.distance.toFixed(6) })));if (accepted.some(x => x.distance > maxDistance)) throw new Error("threshold bug");

5. Metadata prefilters shrink the candidate set before KNN

For tenant-a camera retrieval, candidates from tenants B/C must not be considered merely because they are close. In a trusted server path the authenticated AtlasMart tenant is converted into a mandatory equality filter, not accepted from an arbitrary request body. Category may be a product filter; tenant is an authorization boundary.

local-prefilter.mjs
const candidates = rows.filter(x => x.tenantId === "tenant-a" && x.category === "cameras");const ranked = rank(candidates, query).slice(0, 5);console.log({ total: rows.length, candidates: candidates.length, selectivity: candidates.length / rows.length });if (ranked.some(x => x.tenantId !== "tenant-a")) throw new Error("cross-tenant leak");

6. Managed prefilter query

managed-prefiltered-knn.mjs
import { Firestore, FieldValue } from "@google-cloud/firestore";const db = new Firestore({ projectId: process.env.GCLOUD_PROJECT });const q = [0.90,0.06,0.02,0.02,0.24,0.05,0.01,0.13];const snap = await db.collection("vectorProducts")  .where("tenantId", "==", "tenant-a")  .where("category", "==", "cameras")  .findNearest("embeddingV1", FieldValue.vector(q), {    limit: 5,    distanceMeasure: "EUCLIDEAN",    distanceResultField: "vectorDistance"  })  .get();for (const doc of snap.docs) {  console.log(doc.id, doc.get("vectorDistance"));}

The query requires a matching composite vector index. In Standard pricing, candidate/index work matters: vector search bills returned document reads plus one read for each batch of up to 100 vector index entries read. A selective prefilter can therefore affect both isolation and cost, but do not claim a specific scan reduction until Query Explain/managed evidence measures it.

7. Ground truth and recall@k

AtlasMart’s judged query “outdoor camera similar to Trail Camera” labels p-1001 and p-1005 as relevant. With that tiny ground truth, recall@2 is the fraction of those two relevant IDs returned in the top two. A six-document fixture is not statistically meaningful; its purpose is to make the metric executable before scaling to a real evaluation set.

recall.mjs
export function recallAtK(rankedIds, relevantIds, k) {  const truth = new Set(relevantIds);  const hits = rankedIds.slice(0,k).filter(id => truth.has(id)).length;  return truth.size === 0 ? 1 : hits / truth.size;}const r = recallAtK(["p-1001","p-1005","p-1002"], ["p-1001","p-1005"], 2);console.log({ recallAt2: r });if (r !== 1) throw new Error("expected fixture recall@2 = 1");

8. Wrong approach: distance as a business truth score

A vector distance is not “92% relevant,” not an authorization score, and not a causal explanation. Repair the UI by labeling results as retrieval candidates, keeping model/measure/version in telemetry, evaluating user/task outcomes, and providing fallbacks when no candidate passes the quality threshold.

9. Ties, stability, and ranking contracts

Do not rely on undocumented tie ordering. If two items have effectively equal distance and business UX requires deterministic ordering, apply a documented second-stage ranker in application code using stable business fields after KNN, while keeping the vector distance available for debugging. This post-ranking must not reintroduce unauthorized documents.

10. 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

  • The same fixture is evaluated under at least two distance measures.
  • Threshold is explicitly labeled fixture-specific.
  • Tenant filter is derived from trusted identity/context.
  • Recall@k uses a written judged set, not subjective inspection.
  • Any managed cost statement separates returned documents from vector-index entries scanned.

Production judgment and bridge to Lesson 4

Retrieval quality is now testable, but the vectors still need to be generated, refreshed and governed. Lesson 4 designs that embedding lifecycle and demonstrates why generation belongs outside retryable Firestore transactions.

Knowledge check

  1. What does K control?
  2. Why can a distance threshold be useful?
  3. Is tenantId just a relevance filter?
  4. What does recall@k require?
  5. Why avoid undocumented tie ordering?
Review the answers

1. The maximum number of nearest candidates returned, not a guarantee that all K are relevant.

2. It lets the application reject weak neighbors instead of forcing low-quality results.

3. No. In AtlasMart it is an authorization boundary and must come from trusted context.

4. A judged relevant set and a ranked result list.

5. Because implementation/index changes can reorder equal-distance results; add an explicit post-ranking rule if deterministic UX requires it.

Summary and next step

This lesson established the working contract for K-Nearest-Neighbor Queries, Distance Thresholds, Metadata Filters, and Result Ranking. Keep its edition/mode assumptions, trust boundary, verification evidence, and operational constraints explicit when reusing the pattern.

Next, continue to Firestore Does Not Generate Embeddings: Vertex AI/External Generation Pipelines, Backfills, and Updates.

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.