examples · vector · 7 / 7
7. Filtered top-k
← Vector exampleswhat this does
Pass a filter object to restrict the search to vectors whose stored metadata matches every key. The example above only ranks vectors where category == "shoes". See put-metadata for how to attach the metadata in the first place.
The filter is applied during the search, not after - so a selective filter (say, 2% of the table) stays fast and still returns k hits.
when to use it
- Multi-tenant search where
tenant_idmust match. - Faceted search (category, brand, language, region).
- Soft-delete: filter on
deleted: falseat query time instead of rebuilding the index.
the request
POST /v1/tenants/:t/vector/:table/topk
curl -X POST "https://$OC_HOST/v1/tenants/$OC_TENANT/vector/shop.products/topk" \
-H "Authorization: Bearer $OC_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": [0.0124, -0.0883, 0.0451, /* ... 768 floats ... */],
"k": 10,
"dim": 768,
"metric": "cosine",
"filter": { "category": "shoes" }
}'hits = db.vector.topk(
"shop.products",
query=query_768d,
k=10,
metric="cosine",
filter={"category": "shoes"},
)const hits = await db.vectorTopk("shop.products", {
query: query768d,
k: 10,
dim: 768,
metric: "cosine",
filter: { category: "shoes" },
});hits, err := db.VectorTopK(ctx, "shop.products", originchain.VectorTopKRequest{
Query: query768d,
K: 10,
Dim: 768,
Metric: "cosine",
Filter: map[string]any{"category": "shoes"},
}) what you get back
{
"hits": [
{ "id": "sku-9281", "score": 0.9421 },
{ "id": "sku-1144", "score": 0.9187 }
/* ... only rows whose category == "shoes" ... */
]
}
Same shape as an unfiltered topk. If fewer than k rows match the filter, you get back what exists - no padding.
filter rules
| Rule | Notes |
|---|---|
| Equality only | No $gt, $in, range, or regex. Just key: value pairs. |
| Multiple keys are AND | { "category": "shoes", "in_stock": true } means both must match. |
| Exact match, case-sensitive | "Shoes" does not match "shoes". Normalise on insert. |
| Strings, numbers, booleans | Nested objects and arrays are not filterable. Flatten at put time. |
common mistakes - Range filters. Not supported. If you need
price < 100, bucket the price at insert time (price_band: "under_100") and filter on the bucket. - Case-mismatched values. Filter values must match exactly.
"shoes" and "Shoes" are different. Lowercase on the way in. - Filtering on a field that was never stored. The filter doesn't error - it just matches nothing, and you get an empty hits array. Double-check the metadata was set when you called put.