Knowledge Check
Work through these before you call the capstone done.
Why does the collection use named vectors instead of one collection per modality?
One signal, one point. A single event can carry text and image evidence at the same time, and named vectors keep all of it on that one point, queryable separately, sharing a single payload for filtering. Splitting by modality would scatter one event across collections, duplicate the filtering logic, and leave you joining results in application code.
A satellite image is ingested with no caption. Which parts of this system stop working for it, and why?
It gets an image vector and nothing else. Image search still finds it, because CLIP matches the query text to the picture. But it has no text_dense vector, so dense_matrix skips it and it can never join a text cluster, and no text query will reach it. That is why the ingestion pipeline captions images rather than treating the caption as optional metadata.
How does CLIP match the query "smoke above factory" to a satellite photo with no text attached?
CLIP is trained on image and caption pairs, which places pictures and text in one shared embedding space. FastEmbed exposes the two halves separately: Qdrant/clip-ViT-B-32-vision embedded the photo, and Qdrant/clip-ViT-B-32-text has to embed the query so it lands in the same space. Using all-MiniLM-L6-v2 instead produces a 384-dimensional vector in an unrelated space, and the query fails on dimension or returns noise.
Why are there three named vectors rather than one per signal source?
Because two of the sources are not new modalities. A transcript is text the moment it has been transcribed, and a video frame is an image the moment it has been sampled, so both reuse spaces that already exist. Adding a separate vector for transcripts would mean two named vectors holding the same 384-dimensional MiniLM embedding of the same words, with no query able to tell them apart.
In a hybrid query, where does the filter belong?
Inside each Prefetch. Each retriever searches only the signals that satisfy the filter, so its 50 candidates are scoped before fusion ranks them.
How would you extend this system to detect a risk theme affecting 15 suppliers at once?
Cluster across suppliers rather than within one: run cluster_and_tag over every signal from the last 24 to 48 hours with no supplier_id filter. A shared theme appears as one tight cluster drawing signals from many suppliers, and its centroid gives you a vector for the emerging narrative, which signals_like_cluster then uses to pull in everything else about it.
The capstone creates every payload index before ingesting anything. Why does the order matter more here than in a single-vector system?
Qdrant adds filter-aware edges to the HNSW graph from indexed payload values, and only for indexes that exist when the graph is built. An index created later still filters correctly, but earning those edges means rebuilding the graph. This collection has two dense graphs, one for text_dense and one for image, so a late index means rebuilding both. On Qdrant Cloud a missing index also fails loudly rather than slowly, since strict mode rejects filters on unindexed fields.