Skip to content

Commit 9b50f2b

Browse files
committed
Integration test for LOOKUP JOIN between various types
1 parent 4f019d1 commit 9b50f2b

File tree

1 file changed

+137
-0
lines changed

1 file changed

+137
-0
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
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.action;
9+
10+
import org.elasticsearch.common.settings.Settings;
11+
import org.elasticsearch.plugins.Plugin;
12+
import org.elasticsearch.test.ESIntegTestCase;
13+
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
14+
import org.elasticsearch.xpack.esql.core.type.DataType;
15+
import org.elasticsearch.xpack.esql.plugin.EsqlPlugin;
16+
17+
import java.util.ArrayList;
18+
import java.util.Collection;
19+
import java.util.Iterator;
20+
import java.util.List;
21+
import java.util.Locale;
22+
import java.util.Map;
23+
import java.util.stream.Collectors;
24+
25+
import static org.elasticsearch.test.ESIntegTestCase.Scope.SUITE;
26+
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
27+
import static org.hamcrest.Matchers.equalTo;
28+
29+
@ClusterScope(scope = SUITE, numClientNodes = 1, numDataNodes = 1)
30+
public class LookupJoinTypesIT extends ESIntegTestCase {
31+
32+
private static final Map<DataType, DataType> compatibleJoinTypes = Map.of(
33+
DataType.KEYWORD,
34+
DataType.KEYWORD,
35+
DataType.TEXT,
36+
DataType.KEYWORD,
37+
DataType.INTEGER,
38+
DataType.INTEGER,
39+
DataType.FLOAT,
40+
DataType.FLOAT,
41+
DataType.DOUBLE,
42+
DataType.DOUBLE
43+
);
44+
45+
protected Collection<Class<? extends Plugin>> nodePlugins() {
46+
return List.of(EsqlPlugin.class);
47+
}
48+
49+
public void testLookupJoinTypes() {
50+
initIndexes();
51+
initData();
52+
for (Map.Entry<DataType, DataType> entry : compatibleJoinTypes.entrySet()) {
53+
String query = String.format(
54+
Locale.ROOT,
55+
"FROM index | LOOKUP JOIN %s ON field_%s | KEEP other",
56+
indexName(entry.getKey(), entry.getValue()),
57+
entry.getKey().esType()
58+
);
59+
try (var response = EsqlQueryRequestBuilder.newRequestBuilder(client()).query(query).get()) {
60+
Iterator<Object> results = response.response().column(0).iterator();
61+
assertTrue("Expected at least one result for query: " + query, results.hasNext());
62+
Object indexedResult = response.response().column(0).iterator().next();
63+
assertThat("Expected valid result: " + query, indexedResult, equalTo("value"));
64+
}
65+
}
66+
}
67+
68+
private void initIndexes() {
69+
// The main index will have many fields, one of each type to use in later type specific joins
70+
StringBuilder mainFields = new StringBuilder("{\n \"properties\" : {\n");
71+
mainFields.append(
72+
compatibleJoinTypes.keySet()
73+
.stream()
74+
.map((l) -> "\"field_" + l.esType() + "\": { \"type\" : \"" + l.esType() + "\" }")
75+
.collect(Collectors.joining(",\n "))
76+
);
77+
mainFields.append(" }\n}\n");
78+
assertAcked(prepareCreate("index").setMapping(mainFields.toString()));
79+
80+
Settings.Builder settings = Settings.builder()
81+
.put("index.number_of_shards", 1)
82+
.put("index.number_of_replicas", 0)
83+
.put("index.mode", "lookup");
84+
compatibleJoinTypes.forEach(
85+
// Each lookup index will get a document with a field to join on, and a results field to get back
86+
(l, r) -> { assertAcked(prepareCreate(indexName(l, r)).setSettings(settings.build()).setMapping(String.format(Locale.ROOT, """
87+
{
88+
"properties" : {
89+
"field_%s": { "type" : "%s" },
90+
"other": { "type" : "keyword" }
91+
}
92+
}
93+
""", l.esType(), r.esType()))); }
94+
);
95+
}
96+
97+
private String indexName(DataType mainType, DataType lookupType) {
98+
return "index_" + mainType.esType() + "_" + lookupType.esType();
99+
}
100+
101+
private void initData() {
102+
List<String> mainProperties = new ArrayList<>();
103+
int docId = 0;
104+
for (Map.Entry<DataType, DataType> entry : compatibleJoinTypes.entrySet()) {
105+
DataType mainType = entry.getKey();
106+
DataType lookupType = entry.getValue();
107+
String index = indexName(mainType, lookupType);
108+
String field = "field_" + mainType.esType();
109+
String value = sampleDataFor(lookupType);
110+
String doc = String.format(Locale.ROOT, """
111+
{
112+
"%s": %s,
113+
"other": "value"
114+
}
115+
""", field, value);
116+
mainProperties.add(String.format(Locale.ROOT, "\"%s\": %s", field, value));
117+
index(index, "" + (++docId), doc);
118+
refresh(index);
119+
}
120+
index("index", "1", String.format(Locale.ROOT, """
121+
{
122+
%s
123+
}
124+
""", String.join(",\n", mainProperties)));
125+
refresh("index");
126+
}
127+
128+
private String sampleDataFor(DataType type) {
129+
return switch (type) {
130+
case KEYWORD -> "\"key\"";
131+
case TEXT -> "\"key text\"";
132+
case INTEGER -> "1";
133+
case FLOAT, DOUBLE -> "1.0";
134+
default -> throw new IllegalArgumentException("Unsupported type: " + type);
135+
};
136+
}
137+
}

0 commit comments

Comments
 (0)