Skip to content

Commit e0ae889

Browse files
committed
Add some more tests
1 parent 7f8d663 commit e0ae889

File tree

2 files changed

+341
-0
lines changed

2 files changed

+341
-0
lines changed
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.esql.plugin;
9+
10+
import org.elasticsearch.ElasticsearchException;
11+
import org.elasticsearch.action.index.IndexRequest;
12+
import org.elasticsearch.action.support.WriteRequest;
13+
import org.elasticsearch.common.settings.Settings;
14+
import org.elasticsearch.xpack.esql.VerificationException;
15+
import org.elasticsearch.xpack.esql.action.AbstractEsqlIntegTestCase;
16+
import org.hamcrest.Matchers;
17+
import org.junit.Before;
18+
19+
import java.util.List;
20+
21+
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
22+
import static org.elasticsearch.xpack.esql.EsqlTestUtils.getValuesList;
23+
import static org.hamcrest.CoreMatchers.containsString;
24+
25+
//@TestLogging(value = "org.elasticsearch.xpack.esql:TRACE,org.elasticsearch.compute:TRACE", reason = "debug")
26+
public class MatchPhraseFunctionIT extends AbstractEsqlIntegTestCase {
27+
28+
@Before
29+
public void setupIndex() {
30+
createAndPopulateIndex();
31+
}
32+
33+
public void testSimpleWhereMatchPhrase() {
34+
var query = """
35+
FROM test
36+
| WHERE match_phrase(content, "brown fox")
37+
| KEEP id
38+
| SORT id
39+
""";
40+
41+
try (var resp = run(query)) {
42+
assertColumnNames(resp.columns(), List.of("id"));
43+
assertColumnTypes(resp.columns(), List.of("integer"));
44+
assertValues(resp.values(), List.of(List.of(1), List.of(6)));
45+
}
46+
}
47+
48+
public void testCombinedWhereMatchPhrase() {
49+
var query = """
50+
FROM test
51+
| WHERE match_phrase(content, "brown fox") AND id > 5
52+
| KEEP id
53+
| SORT id
54+
""";
55+
56+
try (var resp = run(query)) {
57+
assertColumnNames(resp.columns(), List.of("id"));
58+
assertColumnTypes(resp.columns(), List.of("integer"));
59+
assertValues(resp.values(), List.of(List.of(6)));
60+
}
61+
}
62+
63+
public void testMultipleMatchPhrase() {
64+
var query = """
65+
FROM test
66+
| WHERE match_phrase(content, "the quick") AND match_phrase(content, "brown fox")
67+
| KEEP id
68+
| SORT id
69+
""";
70+
71+
try (var resp = run(query)) {
72+
assertColumnNames(resp.columns(), List.of("id"));
73+
assertColumnTypes(resp.columns(), List.of("integer"));
74+
assertValues(resp.values(), List.of(List.of(1), List.of(6)));
75+
}
76+
}
77+
78+
public void testMultipleWhereMatchPhrase() {
79+
var query = """
80+
FROM test
81+
| WHERE match_phrase(content, "the quick") AND match_phrase(content, "brown fox")
82+
| EVAL summary = CONCAT("document with id: ", to_str(id), "and content: ", content)
83+
| SORT summary
84+
| LIMIT 4
85+
| WHERE match_phrase(content, "lazy dog")
86+
| KEEP id
87+
""";
88+
89+
var error = expectThrows(ElasticsearchException.class, () -> run(query));
90+
assertThat(error.getMessage(), containsString("[MATCH_PHRASE] function cannot be used after LIMIT"));
91+
}
92+
93+
public void testNotWhereMatchPhrase() {
94+
var query = """
95+
FROM test
96+
| WHERE NOT match_phrase(content, "brown fox")
97+
| KEEP id
98+
| SORT id
99+
""";
100+
101+
try (var resp = run(query)) {
102+
assertColumnNames(resp.columns(), List.of("id"));
103+
assertColumnTypes(resp.columns(), List.of("integer"));
104+
assertValues(resp.values(), List.of(List.of(5)));
105+
}
106+
}
107+
108+
public void testWhereMatchPhraseWithScoring() {
109+
var query = """
110+
FROM test
111+
METADATA _score
112+
| WHERE match_phrase(content, "brown fox")
113+
| KEEP id, _score
114+
| SORT id ASC
115+
""";
116+
117+
try (var resp = run(query)) {
118+
assertColumnNames(resp.columns(), List.of("id", "_score"));
119+
assertColumnTypes(resp.columns(), List.of("integer", "double"));
120+
assertValues(resp.values(), List.of(List.of(1, 1.156558871269226), List.of(6, 0.9114001989364624)));
121+
}
122+
}
123+
124+
public void testWhereMatchPhraseWithScoringDifferentSort() {
125+
126+
var query = """
127+
FROM test
128+
METADATA _score
129+
| WHERE match_phrase(content, "brown fox")
130+
| KEEP id, _score
131+
| SORT id DESC
132+
""";
133+
134+
try (var resp = run(query)) {
135+
assertColumnNames(resp.columns(), List.of("id", "_score"));
136+
assertColumnTypes(resp.columns(), List.of("integer", "double"));
137+
assertValues(resp.values(), List.of(List.of(6, 0.9114001989364624), List.of(1, 1.156558871269226)));
138+
}
139+
}
140+
141+
public void testWhereMatchPhraseWithScoringSortScore() {
142+
var query = """
143+
FROM test
144+
METADATA _score
145+
| WHERE match_phrase(content, "brown fox")
146+
| KEEP id, _score
147+
| SORT _score DESC
148+
""";
149+
150+
try (var resp = run(query)) {
151+
assertColumnNames(resp.columns(), List.of("id", "_score"));
152+
assertColumnTypes(resp.columns(), List.of("integer", "double"));
153+
assertValues(resp.values(), List.of(List.of(1, 1.156558871269226), List.of(6, 0.9114001989364624)));
154+
}
155+
}
156+
157+
public void testWhereMatchPhraseWithScoringNoSort() {
158+
var query = """
159+
FROM test
160+
METADATA _score
161+
| WHERE match_phrase(content, "brown fox")
162+
| KEEP id, _score
163+
""";
164+
165+
try (var resp = run(query)) {
166+
assertColumnNames(resp.columns(), List.of("id", "_score"));
167+
assertColumnTypes(resp.columns(), List.of("integer", "double"));
168+
assertValuesInAnyOrder(resp.values(), List.of(List.of(1, 1.156558871269226), List.of(6, 0.9114001989364624)));
169+
}
170+
}
171+
172+
public void testNonExistingColumn() {
173+
var query = """
174+
FROM test
175+
| WHERE match_phrase(something, "brown fox")
176+
""";
177+
178+
var error = expectThrows(VerificationException.class, () -> run(query));
179+
assertThat(error.getMessage(), containsString("Unknown column [something]"));
180+
}
181+
182+
public void testWhereMatchPhraseEvalColumn() {
183+
var query = """
184+
FROM test
185+
| EVAL upper_content = to_upper(content)
186+
| WHERE match_phrase(upper_content, "BROWN FOX")
187+
| KEEP id
188+
""";
189+
190+
var error = expectThrows(VerificationException.class, () -> run(query));
191+
assertThat(
192+
error.getMessage(),
193+
containsString("[MATCH_PHRASE] function cannot operate on [upper_content], which is not a field from an index mapping")
194+
);
195+
}
196+
197+
public void testWhereMatchPhraseOverWrittenColumn() {
198+
var query = """
199+
FROM test
200+
| DROP content
201+
| EVAL content = CONCAT("document with ID ", to_str(id))
202+
| WHERE match_phrase(content, "document content")
203+
""";
204+
205+
var error = expectThrows(VerificationException.class, () -> run(query));
206+
assertThat(
207+
error.getMessage(),
208+
containsString("[MATCH_PHRASE] function cannot operate on [content], which is not a field from an index mapping")
209+
);
210+
}
211+
212+
public void testWhereMatchPhraseAfterStats() {
213+
var query = """
214+
FROM test
215+
| STATS count(*)
216+
| WHERE match_phrase(content, "brown fox")
217+
""";
218+
219+
var error = expectThrows(VerificationException.class, () -> run(query));
220+
assertThat(error.getMessage(), containsString("Unknown column [content]"));
221+
}
222+
223+
public void testWhereMatchPhraseNotPushedDown() {
224+
var query = """
225+
FROM test
226+
| WHERE match(content, "brown fox") OR length(content) < 20
227+
| KEEP id
228+
| SORT id
229+
""";
230+
231+
try (var resp = run(query)) {
232+
assertColumnNames(resp.columns(), List.of("id"));
233+
assertColumnTypes(resp.columns(), List.of("integer"));
234+
assertValues(resp.values(), List.of(List.of(1), List.of(2), List.of(6)));
235+
}
236+
}
237+
238+
public void testWhereMatchPhraseWithRow() {
239+
var query = """
240+
ROW content = "a brown fox"
241+
| WHERE match(content, "brown fox")
242+
""";
243+
244+
var error = expectThrows(ElasticsearchException.class, () -> run(query));
245+
assertThat(
246+
error.getMessage(),
247+
containsString("line 2:15: [MATCH_PHRASE] function cannot operate on [content], which is not a field from an index mapping")
248+
);
249+
}
250+
251+
public void testMatchPhraseithStats() {
252+
var errorQuery = """
253+
FROM test
254+
| STATS c = count(*) BY match_phrase(content, "brown fox")
255+
""";
256+
257+
var error = expectThrows(ElasticsearchException.class, () -> run(errorQuery));
258+
assertThat(error.getMessage(), containsString("[MATCH_PHRASE] function is only supported in WHERE and STATS commands"));
259+
260+
var query = """
261+
FROM test
262+
| STATS c = count(*) WHERE match_phrase(content, "brown fox"), d = count(*) WHERE match_phrase(content, "lazy dog")
263+
""";
264+
265+
try (var resp = run(query)) {
266+
assertColumnNames(resp.columns(), List.of("c", "d"));
267+
assertColumnTypes(resp.columns(), List.of("long", "long"));
268+
assertValues(resp.values(), List.of(List.of(2L, 4L)));
269+
}
270+
271+
query = """
272+
FROM test METADATA _score
273+
| WHERE match_phrase(content, "brown fox")
274+
| STATS m = max(_score), n = min(_score)
275+
""";
276+
277+
try (var resp = run(query)) {
278+
assertColumnNames(resp.columns(), List.of("m", "n"));
279+
assertColumnTypes(resp.columns(), List.of("double", "double"));
280+
List<List<Object>> valuesList = getValuesList(resp.values());
281+
assertEquals(1, valuesList.size());
282+
assertThat((double) valuesList.get(0).get(0), Matchers.greaterThan(1.0));
283+
assertThat((double) valuesList.get(0).get(1), Matchers.greaterThan(0.0));
284+
}
285+
}
286+
287+
public void testMatchPhraseWithinEval() {
288+
var query = """
289+
FROM test
290+
| EVAL matches_query = match_phrase(content, "brown fox")
291+
""";
292+
293+
var error = expectThrows(VerificationException.class, () -> run(query));
294+
assertThat(error.getMessage(), containsString("[MATCH_PHRASE] function is only supported in WHERE and STATS commands"));
295+
}
296+
297+
private void createAndPopulateIndex() {
298+
var indexName = "test";
299+
var client = client().admin().indices();
300+
var CreateRequest = client.prepareCreate(indexName)
301+
.setSettings(Settings.builder().put("index.number_of_shards", 1))
302+
.setMapping("id", "type=integer", "content", "type=text");
303+
assertAcked(CreateRequest);
304+
client().prepareBulk()
305+
.add(new IndexRequest(indexName).id("1").source("id", 1, "content", "This is a brown fox"))
306+
.add(new IndexRequest(indexName).id("2").source("id", 2, "content", "This is a brown dog"))
307+
.add(new IndexRequest(indexName).id("3").source("id", 3, "content", "This dog is really brown"))
308+
.add(new IndexRequest(indexName).id("4").source("id", 4, "content", "The dog is brown but this document is very very long"))
309+
.add(new IndexRequest(indexName).id("5").source("id", 5, "content", "There is also a white cat"))
310+
.add(new IndexRequest(indexName).id("6").source("id", 6, "content", "The quick brown fox jumps over the lazy dog"))
311+
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
312+
.get();
313+
ensureYellow(indexName);
314+
}
315+
}

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,14 @@ public void testMatchInsideEval() throws Exception {
12151215
);
12161216
}
12171217

1218+
public void testMatchPhraseInsideEval() throws Exception {
1219+
assertEquals(
1220+
"1:36: [:] operator is only supported in WHERE and STATS commands\n"
1221+
+ "line 1:36: [:] operator cannot operate on [title], which is not a field from an index mapping",
1222+
error("row title = \"brown fox\" | eval x = match_phrase(title:\"fox\") ")
1223+
);
1224+
}
1225+
12181226
public void testMatchFunctionNotAllowedAfterCommands() throws Exception {
12191227
assertEquals(
12201228
"1:24: [MATCH] function cannot be used after LIMIT",
@@ -1251,13 +1259,31 @@ public void testMatchWithNonIndexedColumnCurrentlyUnsupported() {
12511259
);
12521260
}
12531261

1262+
public void testMatchPhraseWithNonIndexedColumnCurrentlyUnsupported() {
1263+
assertEquals(
1264+
"1:67: [MATCH_PHRASE] function cannot operate on [initial], which is not a field from an index mapping",
1265+
error("from test | eval initial = substring(first_name, 1) | where match_phrase(initial, \"A\")")
1266+
);
1267+
assertEquals(
1268+
"1:67: [MATCH_PHRASE] function cannot operate on [text], which is not a field from an index mapping",
1269+
error("from test | eval text=concat(first_name, last_name) | where match_phrase(text, \"cat\")")
1270+
);
1271+
}
1272+
12541273
public void testMatchFunctionIsNotNullable() {
12551274
assertEquals(
12561275
"1:48: [MATCH] function cannot operate on [text::keyword], which is not a field from an index mapping",
12571276
error("row n = null | eval text = n + 5 | where match(text::keyword, \"Anna\")")
12581277
);
12591278
}
12601279

1280+
public void testMatchPhraseFunctionIsNotNullable() {
1281+
assertEquals(
1282+
"1:48: [MATCH_PHRASE] function cannot operate on [text::keyword], which is not a field from an index mapping",
1283+
error("row n = null | eval text = n + 5 | where match_phrase(text::keyword, \"Anna\")")
1284+
);
1285+
}
1286+
12611287
public void testQueryStringFunctionsNotAllowedAfterCommands() throws Exception {
12621288
// Source commands
12631289
assertEquals("1:13: [QSTR] function cannot be used after SHOW", error("show info | where qstr(\"8.16.0\")"));

0 commit comments

Comments
 (0)