|
19 | 19 | import java.util.List; |
20 | 20 |
|
21 | 21 | import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; |
| 22 | +import static org.elasticsearch.xpack.esql.EsqlTestUtils.getValuesList; |
22 | 23 | import static org.hamcrest.CoreMatchers.containsString; |
| 24 | +import static org.hamcrest.Matchers.equalTo; |
| 25 | +import static org.hamcrest.Matchers.greaterThan; |
| 26 | +import static org.hamcrest.Matchers.lessThan; |
23 | 27 |
|
24 | 28 | //@TestLogging(value = "org.elasticsearch.xpack.esql:TRACE,org.elasticsearch.compute:TRACE", reason = "debug") |
25 | 29 | public class MatchFunctionIT extends AbstractEsqlIntegTestCase { |
@@ -260,20 +264,124 @@ public void testMatchWithinEval() { |
260 | 264 | assertThat(error.getMessage(), containsString("[MATCH] function is only supported in WHERE commands")); |
261 | 265 | } |
262 | 266 |
|
| 267 | + public void testDisjunctionScoring() { |
| 268 | + var query = """ |
| 269 | + FROM test METADATA _score |
| 270 | + | WHERE match(content, "fox") OR length(content) < 20 |
| 271 | + | KEEP id, _score |
| 272 | + | SORT _score DESC, id ASC |
| 273 | + """; |
| 274 | + |
| 275 | + try (var resp = run(query)) { |
| 276 | + assertColumnNames(resp.columns(), List.of("id", "_score")); |
| 277 | + assertColumnTypes(resp.columns(), List.of("integer", "double")); |
| 278 | + List<List<Object>> values = getValuesList(resp); |
| 279 | + assertThat(values.size(), equalTo(3)); |
| 280 | + |
| 281 | + assertThat(values.get(0).get(0), equalTo(1)); |
| 282 | + assertThat(values.get(1).get(0), equalTo(6)); |
| 283 | + assertThat(values.get(2).get(0), equalTo(2)); |
| 284 | + |
| 285 | + // Matches full text query and non pushable query |
| 286 | + assertThat((Double) values.get(0).get(1), greaterThan(1.0)); |
| 287 | + // Matches just non pushable query |
| 288 | + assertThat((Double) values.get(1).get(1), greaterThan(1.0)); |
| 289 | + // Matches just full text query |
| 290 | + assertThat((Double) values.get(2).get(1), equalTo(0.0)); |
| 291 | + } |
| 292 | + } |
| 293 | + |
| 294 | + public void testDisjunctionScoringMultipleNonPushableFunctions() { |
| 295 | + var query = """ |
| 296 | + FROM test METADATA _score |
| 297 | + | WHERE match(content, "fox") OR length(content) < 20 AND id > 2 |
| 298 | + | KEEP id, _score |
| 299 | + | SORT _score DESC |
| 300 | + """; |
| 301 | + |
| 302 | + try (var resp = run(query)) { |
| 303 | + assertColumnNames(resp.columns(), List.of("id", "_score")); |
| 304 | + assertColumnTypes(resp.columns(), List.of("integer", "double")); |
| 305 | + List<List<Object>> values = getValuesList(resp); |
| 306 | + assertThat(values.size(), equalTo(2)); |
| 307 | + |
| 308 | + assertThat(values.get(0).get(0), equalTo(1)); |
| 309 | + assertThat(values.get(1).get(0), equalTo(6)); |
| 310 | + |
| 311 | + // Matches the full text query and a non pushable query |
| 312 | + assertThat((Double) values.get(0).get(1), greaterThan(1.0)); |
| 313 | + assertThat((Double) values.get(0).get(1), lessThan(2.0)); |
| 314 | + // Matches just the match function |
| 315 | + assertThat((Double) values.get(1).get(1), lessThan(1.0)); |
| 316 | + assertThat((Double) values.get(1).get(1), greaterThan(0.0)); |
| 317 | + } |
| 318 | + } |
| 319 | + |
| 320 | + public void testDisjunctionScoringWithNot() { |
| 321 | + var query = """ |
| 322 | + FROM test METADATA _score |
| 323 | + | WHERE NOT(match(content, "dog")) OR length(content) > 50 |
| 324 | + | KEEP id, _score |
| 325 | + | SORT _score DESC, id ASC |
| 326 | + """; |
| 327 | + |
| 328 | + try (var resp = run(query)) { |
| 329 | + assertColumnNames(resp.columns(), List.of("id", "_score")); |
| 330 | + assertColumnTypes(resp.columns(), List.of("integer", "double")); |
| 331 | + List<List<Object>> values = getValuesList(resp); |
| 332 | + assertThat(values.size(), equalTo(3)); |
| 333 | + |
| 334 | + assertThat(values.get(0).get(0), equalTo(1)); |
| 335 | + assertThat(values.get(1).get(0), equalTo(4)); |
| 336 | + assertThat(values.get(2).get(0), equalTo(5)); |
| 337 | + |
| 338 | + // Matches NOT and non pushable query gets score of 0.0 |
| 339 | + assertThat((Double) values.get(0).get(1), equalTo(0.0)); |
| 340 | + assertThat((Double) values.get(1).get(1), equalTo(0.0)); |
| 341 | + assertThat((Double) values.get(2).get(1), equalTo(0.0)); |
| 342 | + } |
| 343 | + } |
| 344 | + |
| 345 | + public void testScoringWithNoFullTextFunction() { |
| 346 | + var query = """ |
| 347 | + FROM test METADATA _score |
| 348 | + | WHERE length(content) > 50 |
| 349 | + | KEEP id, _score |
| 350 | + | SORT _score DESC, id ASC |
| 351 | + """; |
| 352 | + |
| 353 | + try (var resp = run(query)) { |
| 354 | + assertColumnNames(resp.columns(), List.of("id", "_score")); |
| 355 | + assertColumnTypes(resp.columns(), List.of("integer", "double")); |
| 356 | + List<List<Object>> values = getValuesList(resp); |
| 357 | + assertThat(values.size(), equalTo(1)); |
| 358 | + |
| 359 | + assertThat(values.get(0).get(0), equalTo(4)); |
| 360 | + |
| 361 | + // Non pushable query gets score of 0.0, summed with 1.0 coming from Lucene |
| 362 | + assertThat((Double) values.get(0).get(1), equalTo(1.0)); |
| 363 | + } |
| 364 | + } |
| 365 | + |
263 | 366 | private void createAndPopulateIndex() { |
264 | 367 | var indexName = "test"; |
265 | 368 | var client = client().admin().indices(); |
266 | 369 | var CreateRequest = client.prepareCreate(indexName) |
267 | 370 | .setSettings(Settings.builder().put("index.number_of_shards", 1)) |
268 | | - .setMapping("id", "type=integer", "content", "type=text"); |
| 371 | + .setMapping("id", "type=integer", "content", "type=text", "length", "type=integer"); |
269 | 372 | assertAcked(CreateRequest); |
270 | 373 | client().prepareBulk() |
271 | | - .add(new IndexRequest(indexName).id("1").source("id", 1, "content", "This is a brown fox")) |
272 | | - .add(new IndexRequest(indexName).id("2").source("id", 2, "content", "This is a brown dog")) |
273 | | - .add(new IndexRequest(indexName).id("3").source("id", 3, "content", "This dog is really brown")) |
274 | | - .add(new IndexRequest(indexName).id("4").source("id", 4, "content", "The dog is brown but this document is very very long")) |
275 | | - .add(new IndexRequest(indexName).id("5").source("id", 5, "content", "There is also a white cat")) |
276 | | - .add(new IndexRequest(indexName).id("6").source("id", 6, "content", "The quick brown fox jumps over the lazy dog")) |
| 374 | + .add(new IndexRequest(indexName).id("1").source("id", 1, "content", "This is a brown fox", "length", 19)) |
| 375 | + .add(new IndexRequest(indexName).id("2").source("id", 2, "content", "This is a brown dog", "length", 19)) |
| 376 | + .add(new IndexRequest(indexName).id("3").source("id", 3, "content", "This dog is really brown", "length", 25)) |
| 377 | + .add( |
| 378 | + new IndexRequest(indexName).id("4") |
| 379 | + .source("id", 4, "content", "The dog is brown but this document is very very long", "length", 52) |
| 380 | + ) |
| 381 | + .add(new IndexRequest(indexName).id("5").source("id", 5, "content", "There is also a white cat", "length", 25)) |
| 382 | + .add( |
| 383 | + new IndexRequest(indexName).id("6").source("id", 6, "content", "The quick brown fox jumps over the lazy dog", "length", 43) |
| 384 | + ) |
277 | 385 | .setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE) |
278 | 386 | .get(); |
279 | 387 | ensureYellow(indexName); |
|
0 commit comments