@@ -164,10 +164,10 @@ public void testExplainRadialMinScoreProducesKnnQuery() throws IOException {
164164 "Radial without WHERE should not embed a filter:\n " + knnJson , knnJson .contains ("filter" ));
165165 }
166166
167- // ── Post -filter DSL shape ──────────────────── ────────────────────────
167+ // ── Default (EFFICIENT) pre -filter DSL shape ────────────────────────
168168
169169 @ Test
170- public void testExplainPostFilterProducesBoolQuery () throws IOException {
170+ public void testExplainDefaultFilterProducesKnnWithFilter () throws IOException {
171171 String explain =
172172 explainQuery (
173173 "SELECT v._id, v._score "
@@ -178,39 +178,32 @@ public void testExplainPostFilterProducesBoolQuery() throws IOException {
178178 + "WHERE v.state = 'TX' "
179179 + "LIMIT 10" );
180180
181- // Post-filter shape: outer bool.must=[knn], bool .filter=[term] — WHERE lives OUTSIDE the knn
182- // payload. Verify by decoding the wrapper and asserting the predicate field is NOT embedded .
181+ // Default (EFFICIENT) shape: WHERE is embedded inside knn .filter, the knn JSON is base64-
182+ // encoded inside a WrapperQueryBuilder, and there is no outer bool/must wrapping .
183183 String sourceBuilderJson = extractSourceBuilderJson (explain );
184- assertTrue (
185- "Explain should contain bool query:\n " + sourceBuilderJson ,
184+ assertFalse (
185+ "Default EFFICIENT mode should not produce bool query:\n " + sourceBuilderJson ,
186186 sourceBuilderJson .contains ("\" bool\" " ));
187- assertTrue (
188- "Explain should contain must clause (knn in scoring context) :\n " + sourceBuilderJson ,
187+ assertFalse (
188+ "Default EFFICIENT mode should not contain must clause:\n " + sourceBuilderJson ,
189189 sourceBuilderJson .contains ("\" must\" " ));
190- assertTrue (
191- "Explain should contain filter clause (WHERE in non-scoring context):\n "
192- + sourceBuilderJson ,
193- sourceBuilderJson .contains ("\" filter\" " ));
194- assertTrue (
195- "Explain should contain the outer state predicate:\n " + sourceBuilderJson ,
196- sourceBuilderJson .contains ("\" state.keyword\" " ));
197190
198191 String knnJson = decodeSoleKnnJson (explain );
199192 assertTrue ("knn JSON should contain knn key:\n " + knnJson , knnJson .contains ("\" knn\" " ));
200193 assertTrue (
201194 "knn JSON should target the embedding field:\n " + knnJson ,
202195 knnJson .contains ("\" embedding\" " ));
203196 assertTrue ("knn JSON should contain k=10:\n " + knnJson , knnJson .contains ("\" k\" :10" ));
204- assertFalse (
205- "Post-filter mode must not embed the WHERE predicate inside knn:\n " + knnJson ,
206- knnJson .contains ("state" ));
207- assertFalse (
208- "Post-filter mode must not embed a filter inside knn:\n " + knnJson ,
197+ assertTrue (
198+ "Default EFFICIENT mode must embed filter inside knn:\n " + knnJson ,
209199 knnJson .contains ("filter" ));
200+ assertTrue (
201+ "Default EFFICIENT mode must embed the WHERE predicate inside knn:\n " + knnJson ,
202+ knnJson .contains ("state" ));
210203 }
211204
212205 @ Test
213- public void testExplainCompoundPredicateProducesBoolQuery () throws IOException {
206+ public void testExplainDefaultCompoundPredicateProducesKnnWithFilter () throws IOException {
214207 String explain =
215208 explainQuery (
216209 "SELECT v._id, v._score "
@@ -221,45 +214,35 @@ public void testExplainCompoundPredicateProducesBoolQuery() throws IOException {
221214 + "WHERE v.state = 'TX' AND v.age > 30 "
222215 + "LIMIT 10" );
223216
224- // Compound post-filter still uses outer bool.must=[ knn]/bool .filter=[predicates]. Both WHERE
225- // predicates must stay outside the knn payload; otherwise efficient mode could false-positive .
217+ // Compound default-mode WHERE must also route through knn.filter: no outer bool/must, and
218+ // both predicate fields embedded inside the knn payload.
226219 String sourceBuilderJson = extractSourceBuilderJson (explain );
227- assertTrue (
228- "Explain should contain bool query:\n " + sourceBuilderJson ,
220+ assertFalse (
221+ "Default EFFICIENT mode should not produce bool query:\n " + sourceBuilderJson ,
229222 sourceBuilderJson .contains ("\" bool\" " ));
230- assertTrue (
231- "Explain should contain must clause (knn in scoring context) :\n " + sourceBuilderJson ,
223+ assertFalse (
224+ "Default EFFICIENT mode should not contain must clause:\n " + sourceBuilderJson ,
232225 sourceBuilderJson .contains ("\" must\" " ));
233- assertTrue (
234- "Explain should contain filter clause (compound WHERE in non-scoring context):\n "
235- + sourceBuilderJson ,
236- sourceBuilderJson .contains ("\" filter\" " ));
237- assertTrue (
238- "Explain should contain the outer state predicate:\n " + sourceBuilderJson ,
239- sourceBuilderJson .contains ("\" state.keyword\" " ));
240- assertTrue (
241- "Explain should contain the outer age predicate:\n " + sourceBuilderJson ,
242- sourceBuilderJson .contains ("\" age\" " ));
243226
244227 String knnJson = decodeSoleKnnJson (explain );
245228 assertTrue ("knn JSON should contain knn key:\n " + knnJson , knnJson .contains ("\" knn\" " ));
246229 assertTrue (
247230 "knn JSON should target the embedding field:\n " + knnJson ,
248231 knnJson .contains ("\" embedding\" " ));
249232 assertTrue ("knn JSON should contain k=10:\n " + knnJson , knnJson .contains ("\" k\" :10" ));
250- assertFalse (
251- "Compound post-filter must not embed the state predicate inside knn:\n " + knnJson ,
233+ assertTrue (
234+ "Compound default EFFICIENT must embed filter inside knn:\n " + knnJson ,
235+ knnJson .contains ("filter" ));
236+ assertTrue (
237+ "Compound default EFFICIENT must embed the state predicate inside knn:\n " + knnJson ,
252238 knnJson .contains ("state" ));
253- assertFalse (
254- "Compound post-filter must not embed the age predicate inside knn:\n " + knnJson ,
239+ assertTrue (
240+ "Compound default EFFICIENT must embed the age predicate inside knn:\n " + knnJson ,
255241 knnJson .contains ("age" ));
256- assertFalse (
257- "Compound post-filter must not embed a filter inside knn:\n " + knnJson ,
258- knnJson .contains ("filter" ));
259242 }
260243
261244 @ Test
262- public void testExplainRadialWithWhereProducesBoolQuery () throws IOException {
245+ public void testExplainDefaultRadialWithWhereProducesKnnWithFilter () throws IOException {
263246 String explain =
264247 explainQuery (
265248 "SELECT v._id, v._score "
@@ -270,22 +253,15 @@ public void testExplainRadialWithWhereProducesBoolQuery() throws IOException {
270253 + "WHERE v.state = 'TX' "
271254 + "LIMIT 100" );
272255
273- // Radial + WHERE should also keep the WHERE predicate in the outer bool.filter rather than
274- // embedding it into the radial knn payload.
256+ // Radial + default WHERE must also use the EFFICIENT shape: no outer bool/must, radial
257+ // parameters preserved inside the knn payload, and the WHERE predicate embedded alongside .
275258 String sourceBuilderJson = extractSourceBuilderJson (explain );
276- assertTrue (
277- "Explain should contain bool query:\n " + sourceBuilderJson ,
259+ assertFalse (
260+ "Default EFFICIENT mode should not produce bool query:\n " + sourceBuilderJson ,
278261 sourceBuilderJson .contains ("\" bool\" " ));
279- assertTrue (
280- "Explain should contain must clause (knn in scoring context) :\n " + sourceBuilderJson ,
262+ assertFalse (
263+ "Default EFFICIENT mode should not contain must clause:\n " + sourceBuilderJson ,
281264 sourceBuilderJson .contains ("\" must\" " ));
282- assertTrue (
283- "Explain should contain filter clause (WHERE in non-scoring context):\n "
284- + sourceBuilderJson ,
285- sourceBuilderJson .contains ("\" filter\" " ));
286- assertTrue (
287- "Explain should contain the outer state predicate:\n " + sourceBuilderJson ,
288- sourceBuilderJson .contains ("\" state.keyword\" " ));
289265
290266 String knnJson = decodeSoleKnnJson (explain );
291267 assertTrue ("knn JSON should contain knn key:\n " + knnJson , knnJson .contains ("\" knn\" " ));
@@ -295,12 +271,12 @@ public void testExplainRadialWithWhereProducesBoolQuery() throws IOException {
295271 assertTrue (
296272 "knn JSON should contain max_distance=10.5:\n " + knnJson ,
297273 knnJson .contains ("\" max_distance\" :10.5" ));
298- assertFalse (
299- "Radial post-filter must not embed the WHERE predicate inside knn:\n " + knnJson ,
300- knnJson .contains ("state" ));
301- assertFalse (
302- "Radial post-filter must not embed a filter inside knn:\n " + knnJson ,
274+ assertTrue (
275+ "Radial default EFFICIENT must embed filter inside knn:\n " + knnJson ,
303276 knnJson .contains ("filter" ));
277+ assertTrue (
278+ "Radial default EFFICIENT must embed the WHERE predicate inside knn:\n " + knnJson ,
279+ knnJson .contains ("state" ));
304280 }
305281
306282 // ── Sort + LIMIT explain ─────────────────────────────────────────────
@@ -456,13 +432,16 @@ public void testEfficientFilterWithOrderByScoreDescSucceeds() throws IOException
456432
457433 @ Test
458434 public void testBetweenPushesAsRange () throws IOException {
435+ // Pin filter_type=post to keep the regression guard aimed at the post-filter serialization
436+ // path: these assertions lock in the outer bool/must/filter shape that only appears when
437+ // WHERE is applied alongside knn rather than embedded under knn.filter.
459438 String explain =
460439 explainQuery (
461440 "SELECT v._id, v._score "
462441 + "FROM vectorSearch(table='"
463442 + TEST_INDEX
464443 + "', field='embedding', "
465- + "vector='[1.0, 2.0, 3.0]', option='k=10') AS v "
444+ + "vector='[1.0, 2.0, 3.0]', option='k=10,filter_type=post ') AS v "
466445 + "WHERE v.balance BETWEEN 50 AND 200 "
467446 + "LIMIT 10" );
468447
@@ -513,13 +492,16 @@ public void testBetweenPushesAsRange() throws IOException {
513492
514493 @ Test
515494 public void testNotInPushesAsMustNotTerms () throws IOException {
495+ // Pin filter_type=post to keep the regression guard aimed at the post-filter serialization
496+ // path: these assertions lock in the outer bool/must/filter shape that only appears when
497+ // WHERE is applied alongside knn rather than embedded under knn.filter.
516498 String explain =
517499 explainQuery (
518500 "SELECT v._id, v._score "
519501 + "FROM vectorSearch(table='"
520502 + TEST_INDEX
521503 + "', field='embedding', "
522- + "vector='[1.0, 2.0, 3.0]', option='k=10') AS v "
504+ + "vector='[1.0, 2.0, 3.0]', option='k=10,filter_type=post ') AS v "
523505 + "WHERE v.gender NOT IN ('M', 'F') "
524506 + "LIMIT 10" );
525507
0 commit comments