Skip to Content
We are live but in Staging 🎉

Filtered Search

Vector search answers the question: “Which embeddings are most similar to this embedding?”

In real products, similarity alone is rarely enough. You almost always want to constrain the search to a subset of data:

  • Only documents from a specific tenant / organization
  • Only items that are in_stock = true
  • Only content in a specific language, time window, or category
  • Only records the caller is allowed to see

Filtered search does exactly that: it runs metadata filtering together with ANN (Approximate Nearest Neighbor) search.

What Dodil does

Dodil VBase supports the same idea you may know from Milvus:

  1. Apply a scalar filter (metadata condition) to narrow the candidates.
  2. Run ANN search only within that reduced candidate set.
  3. Return the top‑K matches (optionally including selected metadata fields).

This typically improves:

  • Relevance (you avoid “similar but wrong scope” matches)
  • Performance (search works on fewer candidates)
  • Cost (less compute per query)

Two ways to filter

1) Standard filtering

This is the default model: filter first, then search.

Example mindset:

“Find the top 10 most similar vectors, but only among items where color LIKE "red%" and likes > 50.”

Standard filtering is great when your filter is straightforward and selects a reasonable subset.

2) Iterative filtering

Some filters become expensive when they are very complex or when they match a large portion of the collection.

Iterative filtering is an alternative strategy:

  • VBase searches in iterations (using a search iterator under the hood).
  • Each candidate result is tested against your filter.
  • The process continues until top‑K filtered results are collected.

This can reduce the total amount of scalar filtering work in highly complex cases, but it can also be slower when many candidates must be checked (because results are processed progressively).

If your workload has heavy filters and you see high latency, iterative filtering can be a useful optimization (when supported by your chosen query mode).

Filter expression basics

Filters are written as a string expression against your scalar fields.

Common patterns:

  • Equality / comparison: status == "active", price < 100, likes >= 50
  • Boolean fields: in_stock == true
  • Prefix matching: color like "red%"
  • Membership: category in ["shoes", "bags"]
  • Combine conditions: tenant_id == "org_123" and (lang == "en" or lang == "ar")

Design tip: if you filter by tenant or user ownership on every request, make that field indexed and/or consider partitioning/partition keys (depending on your schema strategy).

Example

Assume your collection has these fields:

  • id (primary key)
  • vector (embedding)
  • color (string)
  • likes (int)

Search with standard filtering

from dodil import Client from dodil.vbase import VBaseConfig # Authorize c = Client( service_account_id="...", service_account_secret="...", ) # Connect to VBase vbase = c.vbase.connect( VBaseConfig( host="vbase-db-<id>.infra.dodil.cloud", port=443, scheme="https", db_name="db_<id>", ) ) query_vector = [ 0.3580376395471989, -0.6023495712049978, 0.18414012509913835, -0.26286205330961354, 0.9029438446296592, ] results = vbase.search( collection_name="my_collection", data=[query_vector], limit=5, filter='color like "red%" and likes > 50', output_fields=["color", "likes"], ) for hit in results[0]: print(hit.id, hit.distance, hit.entity.get("color"), hit.entity.get("likes"))
  • Multi-tenant apps: always filter by tenant_id.
  • RAG: filter by doc_type, source, language, created_at.
  • E‑commerce: filter by in_stock, price, brand, category.
  • Observability / security: filter by service, env, status_code, region.

Filtered search is one of the highest-leverage features in vector applications: it’s the difference between “similar content” and “similar content that is actually usable in my current context.”

Last updated on