Qdrant answers a filtered search without a payload index by scanning, and it answers correctly, which is
why nobody notices. The query is fine in development over ten thousand points and it is the incident
over ten million. It is the commonest way a Qdrant deployment becomes slow, and the client that built
the filter is the only party that knew every key it named.
Both halves of the check are already here. CollectionInfo.payloadSchema names the indexed fields and
their types. A Filter is a tree this client constructed and can walk. Comparing the two says which
keys in this filter have no index at all, and which have an index whose type cannot answer the condition
being used, which is the subtler and more interesting case: a keyword index does not answer a range, an
integer index configured for lookups does not answer one either, and until Tier 10 lands a keyword index
does not answer a prefix.
The design constraint is that this must not become a cost on every request. Reading the collection's
schema per query is a round trip per query to prevent a mistake that is made once, at the point the
filter was written. So it belongs where mistakes are caught rather than where they are made: an explicit
check callable from a test or from the CLI, and at most an opt-in validation at startup for a caller who
asks for it by name.
The value is that it makes a silent performance failure into a failing test. A consumer who runs it over
their real filters in CI finds the missing index at the point of the change that introduced it, rather
than at the point their collection got large.
Exit criterion: given a collection and a filter, the client names every key with no index and every key
whose index type cannot answer the condition used, proven against a real Qdrant for the missing,
wrong-type and correct cases, and nothing is added to the per-request path.
Qdrant answers a filtered search without a payload index by scanning, and it answers correctly, which is
why nobody notices. The query is fine in development over ten thousand points and it is the incident
over ten million. It is the commonest way a Qdrant deployment becomes slow, and the client that built
the filter is the only party that knew every key it named.
Both halves of the check are already here.
CollectionInfo.payloadSchemanames the indexed fields andtheir types. A
Filteris a tree this client constructed and can walk. Comparing the two says whichkeys in this filter have no index at all, and which have an index whose type cannot answer the condition
being used, which is the subtler and more interesting case: a keyword index does not answer a range, an
integer index configured for lookups does not answer one either, and until Tier 10 lands a keyword index
does not answer a prefix.
The design constraint is that this must not become a cost on every request. Reading the collection's
schema per query is a round trip per query to prevent a mistake that is made once, at the point the
filter was written. So it belongs where mistakes are caught rather than where they are made: an explicit
check callable from a test or from the CLI, and at most an opt-in validation at startup for a caller who
asks for it by name.
The value is that it makes a silent performance failure into a failing test. A consumer who runs it over
their real filters in CI finds the missing index at the point of the change that introduced it, rather
than at the point their collection got large.
Exit criterion: given a collection and a filter, the client names every key with no index and every key
whose index type cannot answer the condition used, proven against a real Qdrant for the missing,
wrong-type and correct cases, and nothing is added to the per-request path.