Indexing
FAISS-backed vector store for fast similarity search over embeddings.
FAISS
A thin wrapper around a FAISS IndexFlatIP (inner-product) index. Vectors
must be L2-normalised before adding so that inner product equals cosine
similarity. The store does not normalise internally.
Each vector is paired with a metadata dict that can carry any
JSON-serialisable payload (person ID, name, source path, etc.).
Constructor
| Parameter | Type | Default | Description |
|---|---|---|---|
embedding_size |
int |
512 |
Dimension of embedding vectors |
db_path |
str |
"./vector_index" |
Directory for persisting index and metadata |
Methods
add(embedding, metadata)
Add a single embedding with associated metadata.
| Parameter | Type | Description |
|---|---|---|
embedding |
np.ndarray |
L2-normalised embedding vector |
metadata |
dict[str, Any] |
Arbitrary JSON-serialisable key-value pairs |
search(embedding, threshold=0.4)
Find the closest match for a query embedding.
result, similarity = store.search(query_embedding, threshold=0.4)
if result:
print(result["person_id"], similarity)
| Parameter | Type | Default | Description |
|---|---|---|---|
embedding |
np.ndarray |
— | L2-normalised query vector |
threshold |
float |
0.4 |
Minimum cosine similarity to accept a match |
Returns: (metadata, similarity) if a match is found, or (None, similarity) when below threshold or the index is empty.
remove(key, value)
Remove all entries where metadata[key] == value and rebuild the index.
| Parameter | Type | Description |
|---|---|---|
key |
str |
Metadata key to match |
value |
Any |
Value to match |
Returns: Number of entries removed.
save()
Persist the FAISS index and metadata to disk.
Writes two files to db_path:
faiss_index.bin— binary FAISS indexmetadata.json— JSON array of metadata dicts
load()
Load a previously saved index and metadata.
Returns: True if loaded successfully, False if files are missing.
Raises: RuntimeError if files exist but cannot be read.
Properties
| Property | Type | Description |
|---|---|---|
size |
int |
Number of vectors in the index |
len(store) |
int |
Same as size |
Example: End-to-End
import cv2
from uniface.detection import RetinaFace
from uniface.recognition import ArcFace
from uniface.indexing import FAISS
detector = RetinaFace()
recognizer = ArcFace()
# Build
store = FAISS(db_path="./my_index")
image = cv2.imread("alice.jpg")
faces = detector.detect(image)
embedding = recognizer.get_normalized_embedding(image, faces[0].landmarks)
store.add(embedding, {"person_id": "alice"})
store.save()
# Search
store2 = FAISS(db_path="./my_index")
store2.load()
query = cv2.imread("unknown.jpg")
faces = detector.detect(query)
emb = recognizer.get_normalized_embedding(query, faces[0].landmarks)
result, sim = store2.search(emb)
if result:
print(f"Matched: {result['person_id']} (similarity: {sim:.3f})")
else:
print(f"No match (similarity: {sim:.3f})")
See Also
- Face Search Recipe - Building and querying indexes
- Recognition Module - Embedding extraction
- Thresholds Guide - Tuning similarity thresholds