Skip to content

Commit 912a86d

Browse files
ES|QL: add tests and fix docs for LOOKUP JOIN with index datemath (#130535)
1 parent 400fda4 commit 912a86d

File tree

2 files changed

+116
-1
lines changed
  • docs/reference/query-languages/esql
  • x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node

2 files changed

+116
-1
lines changed

docs/reference/query-languages/esql/esql-lookup-join.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ The following are the current limitations with `LOOKUP JOIN`:
200200
* Indices in [`lookup` mode](/reference/elasticsearch/index-settings/index-modules.md#index-mode-setting) are always single-sharded.
201201
* Cross cluster search is unsupported initially. Both source and lookup indices must be local.
202202
* Currently, only matching on equality is supported.
203-
* `LOOKUP JOIN` can only use a single match field and a single index. Wildcards, aliases, datemath, and datastreams are not supported.
203+
* `LOOKUP JOIN` can only use a single match field and a single index. Wildcards are not supported.
204+
* Aliases, datemath, and datastreams are supported, as long as the index pattern matches a single concrete index {applies_to}`stack: ga 9.1.0`.
204205
* The name of the match field in `LOOKUP JOIN lu_idx ON match_field` must match an existing field in the query. This may require `RENAME`s or `EVAL`s to achieve.
205206
* The query will circuit break if there are too many matching documents in the lookup index, or if the documents are too large. More precisely, `LOOKUP JOIN` works in batches of, normally, about 10,000 rows; a large amount of heap space is needed if the matching documents from the lookup index for a batch are multiple megabytes or larger. This is roughly the same as for `ENRICH`.

x-pack/plugin/esql/qa/server/single-node/src/javaRestTest/java/org/elasticsearch/xpack/esql/qa/single_node/RestEsqlIT.java

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
import java.io.IOException;
4141
import java.io.InputStream;
4242
import java.nio.charset.StandardCharsets;
43+
import java.time.ZoneOffset;
44+
import java.time.ZonedDateTime;
45+
import java.time.format.DateTimeFormatter;
4346
import java.util.ArrayList;
4447
import java.util.Arrays;
4548
import java.util.Comparator;
@@ -786,6 +789,117 @@ && isMillisOrNanos(listOfTypes.get(j))) {
786789
}
787790
}
788791

792+
public void testDateMathIndexPattern() throws IOException {
793+
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
794+
795+
String[] indices = {
796+
"test-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now),
797+
"test-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now.minusYears(1)),
798+
"test-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now.minusYears(2)) };
799+
800+
int idx = 0;
801+
for (String index : indices) {
802+
createIndex(index);
803+
for (int i = 0; i < 10; i++) {
804+
Request request = new Request("POST", "/" + index + "/_doc/");
805+
request.addParameter("refresh", "true");
806+
request.setJsonEntity("{\"f\":" + idx++ + "}");
807+
assertOK(client().performRequest(request));
808+
}
809+
}
810+
811+
String query = """
812+
{
813+
"query": "from <test-index-{now/d{yyyy}}> | sort f asc | limit 1 | keep f"
814+
}
815+
""";
816+
Request request = new Request("POST", "/_query");
817+
request.setJsonEntity(query);
818+
Response resp = client().performRequest(request);
819+
Map<String, Object> results = entityAsMap(resp);
820+
List<?> values = (List<?>) results.get("values");
821+
assertThat(values.size(), is(1));
822+
List<?> row = (List<?>) values.get(0);
823+
assertThat(row.get(0), is(0));
824+
825+
query = """
826+
{
827+
"query": "from <test-index-{now/d-1y{yyyy}}> | sort f asc | limit 1 | keep f"
828+
}
829+
""";
830+
request = new Request("POST", "/_query");
831+
request.setJsonEntity(query);
832+
resp = client().performRequest(request);
833+
results = entityAsMap(resp);
834+
values = (List<?>) results.get("values");
835+
assertThat(values.size(), is(1));
836+
row = (List<?>) values.get(0);
837+
assertThat(row.get(0), is(10));
838+
839+
for (String index : indices) {
840+
assertThat(deleteIndex(index).isAcknowledged(), is(true)); // clean up
841+
}
842+
}
843+
844+
public void testDateMathInJoin() throws IOException {
845+
ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
846+
847+
createIndex("idx", Settings.EMPTY, """
848+
{
849+
"properties": {
850+
"key": {
851+
"type": "keyword"
852+
}
853+
}
854+
}
855+
""");
856+
857+
Request request = new Request("POST", "/idx/_doc/");
858+
request.addParameter("refresh", "true");
859+
request.setJsonEntity("{\"key\":\"foo\"}");
860+
assertOK(client().performRequest(request));
861+
862+
String[] lookupIndices = {
863+
"lookup-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now),
864+
"lookup-index-" + DateTimeFormatter.ofPattern("yyyy", Locale.ROOT).format(now.minusYears(1)) };
865+
866+
for (String index : lookupIndices) {
867+
createIndex(index, Settings.builder().put("mode", "lookup").build(), """
868+
{
869+
"properties": {
870+
"key": {
871+
"type": "keyword"
872+
}
873+
}
874+
}
875+
""");
876+
request = new Request("POST", "/" + index + "/_doc/");
877+
request.addParameter("refresh", "true");
878+
request.setJsonEntity("{\"key\":\"foo\", \"value\": \"" + index + "\"}");
879+
assertOK(client().performRequest(request));
880+
}
881+
882+
String[] queries = {
883+
"from idx | lookup join <lookup-index-{now/d{yyyy}}> on key | limit 1",
884+
"from idx | lookup join <lookup-index-{now/d-1y{yyyy}}> on key | limit 1" };
885+
for (int i = 0; i < queries.length; i++) {
886+
String queryPayload = "{\"query\": \"" + queries[i] + "\"}";
887+
request = new Request("POST", "/_query");
888+
request.setJsonEntity(queryPayload);
889+
Response resp = client().performRequest(request);
890+
Map<String, Object> results = entityAsMap(resp);
891+
List<?> values = (List<?>) results.get("values");
892+
assertThat(values.size(), is(1));
893+
List<?> row = (List<?>) values.get(0);
894+
assertThat(row.get(1), is(lookupIndices[i]));
895+
}
896+
897+
assertThat(deleteIndex("idx").isAcknowledged(), is(true)); // clean up
898+
for (String index : lookupIndices) {
899+
assertThat(deleteIndex(index).isAcknowledged(), is(true)); // clean up
900+
}
901+
}
902+
789903
static MapMatcher commonProfile() {
790904
return matchesMap() //
791905
.entry("description", any(String.class))

0 commit comments

Comments
 (0)