|
14 | 14 | import org.opensearch.sql.legacy.TestsConstants; |
15 | 15 |
|
16 | 16 | /** |
17 | | - * Integration tests for vectorSearch SQL table function. These tests verify DSL push-down shape via |
18 | | - * _explain and validation error paths. They do NOT require the k-NN plugin since _explain only |
19 | | - * parses and plans the query without executing it against a knn index. |
| 17 | + * Integration tests for vectorSearch SQL table function — validation and error paths. These tests |
| 18 | + * verify that invalid inputs are rejected with clear error messages. Explain-plan DSL shape tests |
| 19 | + * live in {@link VectorSearchExplainIT}. |
20 | 20 | */ |
21 | 21 | public class VectorSearchIT extends SQLIntegTestCase { |
22 | 22 |
|
23 | 23 | @Override |
24 | 24 | protected void init() throws Exception { |
25 | | - // _explain needs the index to exist for field resolution. |
26 | 25 | loadIndex(Index.ACCOUNT); |
27 | 26 | } |
28 | 27 |
|
29 | 28 | private static final String TEST_INDEX = TestsConstants.TEST_INDEX_ACCOUNT; |
30 | 29 |
|
31 | | - // ── DSL shape verification via _explain ─────────────────────────────── |
32 | | - |
33 | | - @Test |
34 | | - public void testExplainTopKProducesKnnQuery() throws IOException { |
35 | | - String explain = |
36 | | - explainQuery( |
37 | | - "SELECT v._id, v._score " |
38 | | - + "FROM vectorSearch(table='" |
39 | | - + TEST_INDEX |
40 | | - + "', field='embedding', " |
41 | | - + "vector='[1.0, 2.0, 3.0]', option='k=5') AS v " |
42 | | - + "LIMIT 5"); |
43 | | - |
44 | | - // WrapperQueryBuilder wraps the knn JSON — verify the wrapper is present |
45 | | - // and track_scores is enabled for score preservation. |
46 | | - assertTrue("Explain should contain wrapper query:\n" + explain, explain.contains("wrapper")); |
47 | | - assertTrue( |
48 | | - "Explain should contain track_scores:\n" + explain, explain.contains("track_scores")); |
49 | | - } |
50 | | - |
51 | | - @Test |
52 | | - public void testExplainRadialMaxDistanceProducesKnnQuery() throws IOException { |
53 | | - String explain = |
54 | | - explainQuery( |
55 | | - "SELECT v._id, v._score " |
56 | | - + "FROM vectorSearch(table='" |
57 | | - + TEST_INDEX |
58 | | - + "', field='embedding', " |
59 | | - + "vector='[1.0, 2.0]', option='max_distance=10.5') AS v " |
60 | | - + "LIMIT 100"); |
61 | | - |
62 | | - assertTrue("Explain should contain wrapper query:\n" + explain, explain.contains("wrapper")); |
63 | | - } |
64 | | - |
65 | | - @Test |
66 | | - public void testExplainRadialMinScoreProducesKnnQuery() throws IOException { |
67 | | - String explain = |
68 | | - explainQuery( |
69 | | - "SELECT v._id, v._score " |
70 | | - + "FROM vectorSearch(table='" |
71 | | - + TEST_INDEX |
72 | | - + "', field='embedding', " |
73 | | - + "vector='[1.0, 2.0]', option='min_score=0.8') AS v " |
74 | | - + "LIMIT 100"); |
75 | | - |
76 | | - assertTrue("Explain should contain wrapper query:\n" + explain, explain.contains("wrapper")); |
77 | | - } |
78 | | - |
79 | | - @Test |
80 | | - public void testExplainPostFilterProducesBoolQuery() throws IOException { |
81 | | - String explain = |
82 | | - explainQuery( |
83 | | - "SELECT v._id, v._score " |
84 | | - + "FROM vectorSearch(table='" |
85 | | - + TEST_INDEX |
86 | | - + "', field='embedding', " |
87 | | - + "vector='[1.0, 2.0, 3.0]', option='k=10') AS v " |
88 | | - + "WHERE v.state = 'TX' " |
89 | | - + "LIMIT 10"); |
90 | | - |
91 | | - assertTrue("Explain should contain bool query:\n" + explain, explain.contains("bool")); |
92 | | - assertTrue( |
93 | | - "Explain should contain must clause (knn in scoring context):\n" + explain, |
94 | | - explain.contains("must")); |
95 | | - assertTrue( |
96 | | - "Explain should contain filter clause (WHERE in non-scoring context):\n" + explain, |
97 | | - explain.contains("filter")); |
98 | | - } |
99 | | - |
100 | 30 | // ── Validation error paths ──────────────────────────────────────────── |
101 | 31 |
|
102 | 32 | @Test |
@@ -205,23 +135,6 @@ public void testMissingRequiredOptionRejects() throws IOException { |
205 | 135 |
|
206 | 136 | // ── Sort restriction validation ───────────────────────────────────────── |
207 | 137 |
|
208 | | - @Test |
209 | | - public void testOrderByScoreDescExplainSucceeds() throws IOException { |
210 | | - String explain = |
211 | | - explainQuery( |
212 | | - "SELECT v._id, v._score " |
213 | | - + "FROM vectorSearch(table='" |
214 | | - + TEST_INDEX |
215 | | - + "', field='embedding', " |
216 | | - + "vector='[1.0, 2.0]', option='k=5') AS v " |
217 | | - + "ORDER BY v._score DESC " |
218 | | - + "LIMIT 5"); |
219 | | - |
220 | | - assertTrue( |
221 | | - "Explain should succeed with ORDER BY _score DESC:\n" + explain, |
222 | | - explain.contains("wrapper")); |
223 | | - } |
224 | | - |
225 | 138 | @Test |
226 | 139 | public void testOrderByNonScoreFieldRejects() throws IOException { |
227 | 140 | ResponseException ex = |
@@ -255,64 +168,4 @@ public void testOrderByScoreAscRejects() throws IOException { |
255 | 168 |
|
256 | 169 | assertThat(ex.getMessage(), containsString("_score ASC is not supported")); |
257 | 170 | } |
258 | | - |
259 | | - // ── Compound predicate and radial + WHERE ─────────────────────────────── |
260 | | - |
261 | | - @Test |
262 | | - public void testExplainCompoundPredicateProducesBoolQuery() throws IOException { |
263 | | - String explain = |
264 | | - explainQuery( |
265 | | - "SELECT v._id, v._score " |
266 | | - + "FROM vectorSearch(table='" |
267 | | - + TEST_INDEX |
268 | | - + "', field='embedding', " |
269 | | - + "vector='[1.0, 2.0, 3.0]', option='k=10') AS v " |
270 | | - + "WHERE v.state = 'TX' AND v.age > 30 " |
271 | | - + "LIMIT 10"); |
272 | | - |
273 | | - assertTrue("Explain should contain bool query:\n" + explain, explain.contains("bool")); |
274 | | - assertTrue( |
275 | | - "Explain should contain must clause (knn in scoring context):\n" + explain, |
276 | | - explain.contains("must")); |
277 | | - assertTrue( |
278 | | - "Explain should contain filter clause (compound WHERE in non-scoring context):\n" + explain, |
279 | | - explain.contains("filter")); |
280 | | - } |
281 | | - |
282 | | - @Test |
283 | | - public void testExplainRadialWithWhereProducesBoolQuery() throws IOException { |
284 | | - String explain = |
285 | | - explainQuery( |
286 | | - "SELECT v._id, v._score " |
287 | | - + "FROM vectorSearch(table='" |
288 | | - + TEST_INDEX |
289 | | - + "', field='embedding', " |
290 | | - + "vector='[1.0, 2.0]', option='max_distance=10.5') AS v " |
291 | | - + "WHERE v.state = 'TX' " |
292 | | - + "LIMIT 100"); |
293 | | - |
294 | | - assertTrue("Explain should contain bool query:\n" + explain, explain.contains("bool")); |
295 | | - assertTrue( |
296 | | - "Explain should contain must clause (knn in scoring context):\n" + explain, |
297 | | - explain.contains("must")); |
298 | | - assertTrue( |
299 | | - "Explain should contain filter clause (WHERE in non-scoring context):\n" + explain, |
300 | | - explain.contains("filter")); |
301 | | - } |
302 | | - |
303 | | - // ── LIMIT validation ─────────────────────────────────────────────────── |
304 | | - |
305 | | - @Test |
306 | | - public void testExplainLimitWithinKSucceeds() throws IOException { |
307 | | - String explain = |
308 | | - explainQuery( |
309 | | - "SELECT v._id, v._score " |
310 | | - + "FROM vectorSearch(table='" |
311 | | - + TEST_INDEX |
312 | | - + "', field='embedding', " |
313 | | - + "vector='[1.0, 2.0]', option='k=10') AS v " |
314 | | - + "LIMIT 5"); |
315 | | - |
316 | | - assertTrue("Explain should succeed with LIMIT <= k:\n" + explain, explain.contains("wrapper")); |
317 | | - } |
318 | 171 | } |
0 commit comments