What you’ll take away
- The best k eligible records and the eligible members of an unfiltered top-k list answer different questions.
- In the original example, changing filter placement returns B and C, B alone, or no records.
- A local unfiltered cutoff can make exact postfiltered results depend on shard grouping.
- A collection-wide matching fraction does not guarantee the same fraction in a ranked candidate prefix.
- For a complete exact ranking, the tight worst-case prefix bound is N − M + k when at least k records qualify.
- Predicate satisfaction, result count, exact-neighbor agreement and source truth require separate checks.
An empty filtered result can hide existing matches
A search asks for the two best documents in a category and returns nothing. It is tempting to conclude that the category has no documents. But the search might first have kept two documents from the whole collection, then rejected both because they belonged to another category. Documents that satisfy the condition could still exist below that earlier cutoff.
Azure AI Search documents several places where a filter can act, including within individual shards and after a global result list has been formed. Its strict global postfiltering mode is marked preview [1]. Elastic likewise distinguishes a filter within the kNN search from a filter applied after it [2]. These are different result-selection questions, not merely different spellings of the same request.
Our original example uses six invented records with fixed scores. Moving one category test changes the returned list from two records to one to none. We calculate those results exactly, without running a vector database or language model. The purpose is to identify what an empty response can actually establish.
A filtered vector query combines an eligibility predicate with a ranking and one or more truncation operators. If truncation removes eligible records before the predicate is applied, the output may contain fewer than k records despite sufficient eligible records in the collection. An empty output then describes the selected candidate path, not necessarily an empty eligible population.
Azure documents shard-local and global filter placement, with strictPostFilter explicitly in preview [1]. Elastic distinguishes a kNN-clause pre-filter from filters elsewhere in the surrounding query tree [2]. The implementation and parameter details belong to their respective systems; the operator definitions below are explicit mathematical constructions.
We assign six distinct, mutually comparable scores and evaluate three exact procedures. There is no approximate graph traversal, embedding, benchmark or downstream answer generation. Holding the records and scores fixed isolates cutoff order as the cause of the different outputs, before considering the separate accuracy limits of an approximate nearest-neighbor engine.
Keep one shared score order across two shards
A shard is one part of a divided search index. Put A, B and C in shard one, with scores 100, 90 and 80. Put D, E and F in shard two, with scores 95, 85 and 70. Higher scores come first. Every number is an invented ordering value on the same scale; none is a probability or a measured level of usefulness.
Mark B, C and F as Red. Mark A, D and E as Blue. Our condition is simply “category is Red,” and we want at most two results. The complete unfiltered order is A, D, B, E, C, F. The complete order among Red records is B, C, F. Therefore an exact search for the best two Red records should return B and C.
These two lists are different reference points. The best two records overall are A and D, both Blue. The best two within Red are B and C. Confusing those questions creates the empty-result surprise before any complicated search algorithm is involved.
Define S₁={A,B,C} and S₂={D,E,F}, with scores s(A)=100, s(B)=90, s(C)=80, s(D)=95, s(E)=85 and s(F)=70. Scores are strict and comparable across shards. Let Filter select the eligible set Eligible={B,C,F}, and use final cutoff k=2.
Write T_k(X) for the first k identities after sorting X by descending score, returning all identities if fewer than k exist. Let Filter(X)=X∩Eligible, retaining the inherited order when applied to an ordered list. The full global order is (A,D,B,E,C,F), while T₂(Eligible)=(B,C). The predicate concerns a stipulated metadata value, not a judgment about document truth.
This exact account deliberately eliminates ties, score normalization and approximate candidate discovery. Azure describes shards as partitions of an index and filters on suitable nonvector fields [1]. Those concepts motivate the setup without asserting that our arbitrary integer scores are actual Azure similarity scores or that a production index has this layout.
Filtering before selection keeps the best eligible pair
Start by applying the Red condition within each shard, then take up to two remaining records from each. Shard one contributes B and C. Shard two contributes F. Merge those contributions in score order and keep the best two: B and C. F is eligible but loses the final ranking comparison because its score is lower.
Notice that shard two supplies only one record. That causes no problem here because the combined eligible population contains three. The final answer still has two entries. The procedure does not require every shard to fill a local two-record allowance; it requires the final selection to consider the relevant eligible candidates.
For this exact construction, taking two eligible records per shard cannot lose a true global top-two eligible record. If a record had two eligible records ahead of it on its own shard, it would already have at least two ahead globally. The argument concerns identities and order. It does not require equal match counts on each shard or require the final pair to come from different shards.
The first procedure is P=T_k(⋃ⱼT_k(Filter(Sⱼ))). For the original partition, local filtered selections are (B,C) and (F), whose globally sorted union is (B,C,F). Applying k=2 produces P=(B,C), equal to T₂(Eligible).
For exact comparable scores and a consistent tie rule if needed, local eligible top-k is sufficient to recover global eligible top-k. Any globally top-k eligible record has fewer than k eligible records preceding it globally, and therefore fewer than k preceding it on its own shard. It survives local eligible selection. Our fixture avoids ties entirely, so no extra tie convention is needed for the demonstrated identities.
The proof explains why a local eligible cutoff of k is sufficient in this exact account. Both final identities can originate on one shard, as B and C do here. A smaller local eligible cutoff would not share that guarantee: keeping only one per shard would leave B and F. Local result cardinality and agreement with the desired global ranking are therefore separate checks.
A cutoff on each shard can remove matches before filtering
Now reverse the local steps. Each shard first keeps its two highest-scoring records without checking the category. Shard one keeps A and B, dropping C. Shard two keeps D and E, dropping F. Apply the Red test to those four survivors. Only B passes, so the final result contains B alone.
The original collection still has three Red records. C and F disappeared because they fell below their shards' unfiltered two-record cutoffs. A later filter can reject candidates, but it cannot recover records that were never passed onward. An unused final slot does not automatically cause this defined procedure to revisit a shard.
This also explains why B can appear even though it is not among the global unfiltered top two. It survived a local cutoff, and the category test removed higher-scoring Blue candidates before the final merge. The missing second result follows from that specific order of operations. It cannot tell us whether the collection has one Red record, three Red records or additional unseen matches below the discarded boundary.
Define local postfiltering as L=T_k(⋃ⱼFilter(T_k(Sⱼ))). Unfiltered local selections are (A,B) and (D,E); after applying Filter they become (B) and the empty list. Thus L=(B). Eligible C and F are irrecoverable within this fixed candidate pool because neither survived local truncation.
The result differs from P even though the predicate, scores, partition and k are unchanged. T_k and Filter do not generally commute. This is an operator-order counterexample, not an approximation error: every local score comparison was exact. No refill or second-pass retrieval is included in L's definition.
B is outside T₂(S₁∪S₂) but inside the larger local candidate union {A,B,D,E}. Filtering that union before its final top-two step can promote B into the final list without restoring either omitted eligible record. Record the intermediate identities as well as the final count: otherwise the same one-entry output could conceal very different reasons for losing its second entry.
Filtering the global top two produces an empty list
The third procedure first forms the two best records across the whole collection: A and D. It then applies the Red condition. Both fail, so nothing remains. The answer is empty even though B, C and F all satisfy the condition.
The result is internally consistent with the question “which of the best two overall records are Red?” It is a different question from “which are the best two Red records?” Knowing which question was implemented matters more than deciding whether the response looks surprising. An application that expects the second question cannot infer it from the first procedure's result.
Its distinguishing property is that every returned record must already belong to the frozen global top-two list. No Red record belongs to that list in this construction, so none can appear afterward. Keeping the intermediate A, D list makes the empty result explainable. Without that list, the response hides the difference between having no matches anywhere and having no matches among the two selected candidates.
Define G=Filter(T_k(⋃ⱼT_k(Sⱼ))). Under exact comparable ranking, merging local unfiltered top-k lists recovers the global unfiltered top-k. Here that list is (A,D). Applying Filter gives G=∅, whereas the eligible universe has size |Eligible|=3.
Equivalently, G is the eligible subset of a fixed unfiltered result list. It does not compute T_k(Filter(S₁∪S₂)). For the declared six records, P=(B,C), L=(B) and G=∅. These outputs isolate the local-versus-global truncation boundary as well as whether filtering precedes truncation.
The empty set proves that no member of the selected global prefix survives Filter. It does not prove that Filter has no matches outside the prefix. The proof of this distinction needs no search failure: A and D were correctly selected under the unfiltered ordering, and both were correctly rejected by the predicate. The mismatch lies between the procedure's question and a request for the best eligible records.
Changing only the shard grouping can change local postfiltering
Keep every score and category unchanged, but regroup the records. Put A, D and E together, and B, C and F together. Local unfiltered selection now keeps A and D from the first shard and B and C from the second. The Red test removes A and D, leaving B and C. The local-postfilter result has grown from one entry to two.
Another grouping puts A, D and B on one shard, with E, C and F on the other. Its local selections are A, D and E, C. After filtering, only C remains. B, the highest-scoring Red record overall, has been lost below a local cutoff.
The filter-first answer stays B and C in all three groupings. The global-cutoff-first answer stays empty. An exhaustive calculation over all twenty labeled ways to split six identities into two groups of three confirms those invariances. This is a controlled mathematical comparison, not a claim that a running database will move records or change answers in this exact way.
For partition ({A,D,E},{B,C,F}), L=(B,C). For partition ({A,D,B},{E,C,F}), L=(C). The original partition gave L=(B). Consequently exact local postfiltering is partition-dependent: both result count and the identity of a retained eligible record can change without changing any score or predicate value.
There are C(6,3)=20 labeled three-plus-three assignments. The original enumeration evaluates every assignment. L is (B) in twelve, (C) in two and (B,C) in six. These counts are exhaustive combinatorial bookkeeping, not probabilities for how a database shards data. Swapping the shard labels leaves each particular computation unchanged.
Across all twenty assignments, P remains (B,C) and G remains empty. Their exact global definitions explain the invariance. This separates a partition effect from an ANN discovery effect; both may matter in an actual system, but this fixture establishes only the former under the explicitly defined procedure. It does not reproduce a vendor's distribution policy or query execution.
Fetching extra candidates helps only when those candidates include matches
Suppose we enlarge a single global candidate prefix before applying the Red filter, then keep at most two survivors. The first two records, A and D, contain no Red record. The first three add B, giving one. The first four add E, still giving one. The first five add C, finally giving the desired B and C. Taking all six adds F, which then loses the final top-two comparison.
Half of the complete collection is Red: three out of six. Dividing the desired two matches by one-half suggests fetching four candidates. Yet the first four contain only B. The fraction for the whole collection does not guarantee the same fraction near the top of this ranking.
Our sequence explains why a larger prefix can help while a simple fraction-based estimate still lacks a guarantee. Each enlargement succeeds only if the added positions include useful candidates. It also separates finding three matching candidates from returning two: the final display limit still applies. The calculation concerns an exact global prefix, not a universal interpretation of every engine's candidate-count parameter.
For an exact global prefix length m, define O_m=T_k(Filter(T_m(U))), where U is the full universe and k=2. For m=2,3,4,5,6, matching-prefix counts are 0,1,1,2,3, while final output counts are 0,1,1,2,2. At m=5 the returned identities first reach (B,C).
The overall eligible share is p=M/N=3/6=0.5. The arithmetic shortcut ceil(k/p)=4 yields only one match here. It is not a worst-case bound because eligibility is not constrained to be evenly distributed within the ranked prefix. We assume no randomized placement or independence between metadata and score.
The relevant observation is the number of eligible identities within the actual candidate prefix. A larger m can expose additional ones, but the last top-k still limits returned count. Increasing m from five to six raises the matching-prefix count without changing the returned pair. Our m is a mathematical prefix length, not a drop-in replacement for HNSW exploration, shard-local candidate budgets or vendor-specific oversampling settings.
A guaranteed prefix needs a worst-case count, not an average fraction
For a finite exact ranking, we can derive a stronger count statement. Suppose there are N records in total and M satisfy the filter. Only N minus M records can fail. Even if every failing record appears first, a prefix of m records must contain at least m minus that failing count, or zero if the subtraction is negative.
Here N is six and M is three. A four-record prefix must contain at least one match; a five-record prefix must contain at least two. To guarantee two matches regardless of where the three Red labels occur, five is the required prefix length. All twenty ways to place three matching labels among six ranked positions confirm this result.
The guarantee needs its assumptions. The total and matching counts must refer to the same complete collection, and the prefix must follow the exact shared ranking. If fewer than two records qualify in the first place, no prefix can manufacture a second one. This is a counting proof, not a recommended production search setting.
For a universe of N identities with M eligible identities, a prefix of size m contains at least max(0,m−(N−M)) eligible identities. At most N−M failures can occupy that prefix. The bound is tight because those failures can be placed first, followed by the eligible identities.
For 1≤k≤M≤N, every arrangement is therefore guaranteed to supply k matches once m≥N−M+k. In our case, 6−3+2=5. At m=4 the minimum is one; at m=5 it is two. Enumerating all C(6,3)=20 eligibility placements reproduces the minima 0,0,0,0,1,2,3 for prefix lengths zero through six.
This finite bound assumes known complete cardinalities and an exact global order. It does not establish an ANN traversal budget, a service latency bound or a practical setting for an unknown corpus. Once an exact prefix contains k eligible identities, its first k eligible members are the global eligible top-k; an approximate candidate set needs its own accuracy assessment.
A stricter filter can introduce different returned identities
First let every category pass. All three exact procedures return A and D. Now tighten the condition to Red. Filtering before selection returns B and C, which were absent from the earlier final list. Local postfiltering returns B, also newly visible. A more restrictive condition has removed eligible choices, yet introduced different identities into the limited display.
There is no contradiction. The final two positions were selected again after removing some candidates. Other records could move into those positions. By contrast, filtering the same frozen global list A, D can only remove entries from that list; it cannot introduce B or C.
To interpret a changing result panel, ask whether the filter acts on a fixed displayed list, a larger candidate pool or the search population before a new ranking cutoff. A promise about subsets applies to a defined pool. It does not automatically describe every limited result list shown by an interface. Keep record membership separate from the number of available display positions.
Let Filter_all admit U and Filter_Red admit Eligible⊂U. Under Filter_all, P=L=G=(A,D). Under Filter_Red, P=(B,C) and L=(B), neither a subset of the earlier final (A,D). Their candidate eligibility shrinks, but a subsequent top-k operation selects different surviving identities.
For a fixed candidate set Pool, Filter_Red(Pool)⊆Filter_all(Pool). That subset relation does not imply T_k(Filter_Red(Pool))⊆T_k(Filter_all(Pool)). The final truncation can remove different identities. The original local candidate pool {A,B,D,E} makes this explicit: B was present in the pool while absent from the broad final top two.
G behaves differently because its truncation precedes the changed predicate and the global prefix remains fixed. Its Red output is a subset of its unfiltered output. That property follows directly from intersecting the fixed prefix with Eligible. Our derivation concerns identity membership under fixed scores and candidates; it does not certify facet counts, cache behavior or a particular search interface's response to changing filters.
Enough returned records does not establish exact nearest-neighbor accuracy
Three questions need separate answers. Does every returned record pass the filter? Did the system return as many qualifying records as the requested limit allows? Are those records the highest-ranked qualifying ones under the intended score? A list can satisfy the first two questions while missing a better eligible record.
Our exact example makes the reference answer known: B and C. A two-entry result containing B and F would have the right category and count, but would miss C. This possible comparison is a definition check, not an observed output from a search product. It shows why counting two Red entries cannot alone verify ranking accuracy.
Qdrant documents both direct scoring of matching points and searching a filterable HNSW graph, and describes comparing ordinary results with exact search when assessing filtered recall [3]. That distinction matters here. A provider's statement about returning a number of matches should be read within its documented conditions, without turning the statement into proof of perfect neighbors or accurate source content.
Predicate satisfaction, result cardinality and agreement with exact eligible top-k are different invariants. For our declared score reference, the exact answer is {B,C}. A hypothetical {B,F} has two eligible identities yet differs from that reference. If measured as set overlap divided by k, its agreement would be 1/2; this is an original counterexample, not a reported engine result.
Qdrant distinguishes planner choices that score matching points directly from approximate filterable-graph search, and its documentation describes an exact-search comparison for filtered recall [3]. A count of two says nothing about whether the second identity was C or F. The comparison needs the actual returned identities and an independently established exact reference.
Even perfect agreement with the declared score would establish only that ranking property. The score may not capture the reader's information need, and an eligible document may be outdated or incorrect. These are downstream evidence questions. Keep the reference population, predicate, scoring rule and candidate accuracy separate before evaluating how a RAG answer uses the retrieved material.
The filter’s meaning and the engine’s execution strategy are different
A label such as prefilter does not describe every internal step across every product. Elastic documents its kNN filter as acting during approximate search; placing a filter elsewhere in the surrounding query tree gives postfiltering behavior [2]. Qdrant's explanation contrasts traditional direct scoring after filtering with its planner's choice between direct scoring and filter-aware graph search [3].
Those descriptions can share an aim—return suitable high-ranking matches—while doing different work. Read the specific product's definition, version and query location before translating the label into a mental picture. Our first procedure filters a complete finite set and sorts exactly. It cannot establish whether an actual service visited every record, used an index or chose another supported plan.
The same care applies to documentation status. Azure marks the strict global variant preview [1]. The retained Elastic reference also contains an explicitly planned strategy, which this article does not treat as a shipped feature [2]. Understanding the current supported contract requires keeping those qualifiers attached instead of combining every documented possibility into one imaginary engine.
Separate logical result semantics from physical execution. Elastic's retrieved reference defines filtering within the kNN clause and distinguishes filters elsewhere in the query tree [2]. Qdrant documents cardinality estimation and a planner that may directly score matching points or search a filterable HNSW graph [3]. The same general eligibility objective does not require an identical execution plan.
Consequently our P, L and G equations are definitions for an exact finite construction, not an API equivalence theorem. Our exact filter-first proof does not require that every production pre-filter materialize all matches, nor does the word postfilter specify whether truncation occurred per shard or globally. The actual candidate boundary must be established from the relevant implementation's documentation.
Version scope also matters. Azure's strictPostFilter remains explicitly preview [1]. A native Elastic filter-definition passage marks an automatic candidate-postfilter/fallback strategy Planned; it is excluded as a current implementation claim here [2]. We execute none of the source queries and prescribe no index or threshold change. The article's conclusions follow from the stated operators rather than an assumed future release.
Record the candidate boundary before explaining a missing match
A useful investigation keeps the predicate, collection snapshot, requested limit, candidate limit and location of filtering together. If shard-local selection matters, preserve the relevant shard memberships or query diagnostics when available. Separate what the record shows from what is merely assumed. An empty final list alone contains too little information to identify which step removed the matches.
There can also be a genuine shortage. If only F qualifies and the requested limit is two, the exact filter-first answer contains just F. One result is then complete for the available eligible population. With our original local cutoffs, however, even F is discarded, so the local and global postfilter procedures return none. Shortage and cutoff loss can coexist.
The six-record example now explains three different outcomes without changing the documents: B and C, B alone, or an empty list. Repartitioning and longer prefixes expose further boundaries. Use that account to ask a precise next question: which candidate set was filtered, and which qualifying identities had already been removed?
Bind the result to a collection snapshot, predicate definition, requested k, relevant candidate limits, shard boundaries where material, score ordering and actual filter placement. Retain version and preview qualifiers for a real implementation. These records support a bounded explanation without assuming that every service exposes full traversal diagnostics.
Distinguish insufficient eligible population from losses introduced by earlier truncation. Under Eligible={F}, the exact filtered population has M=1<k=2, so P=(F) is cardinality-complete. Original local unfiltered selections exclude F, giving L=G=∅. Under Eligible=∅ all three outputs are legitimately empty. These cases show why returned count needs a reference population before it can identify an error.
For the principal Eligible={B,C,F} case, exact computation establishes P=(B,C), L=(B) and G=∅. The partition and prefix extensions preserve the same accounting discipline. No result here validates an access-control implementation, proves source truth or measures a downstream model. It provides an exact explanation of how eligibility and truncation order determine which records remain available for the next stage.
Sources & further reading
Explore the references behind this guide. External pages may change after our review.
- Vector Query Filters - Azure AI Search | Microsoft LearnMicrosoft Learn · Accessed 7 Nov 2026
- Knn query | Elastic DocsElastic · Accessed 7 Nov 2026
- Filtering in Vector Search: When to Use What - QdrantQdrant · Accessed 7 Nov 2026
Article updated 7 Nov 2026.
Found something we should revisit?
Good explanations get better with thoughtful feedback.