Skip to content

Commit fe20fb1

Browse files
authored
Support multiple indices in PPL and SQL (#408)
Signed-off-by: penghuo <[email protected]>
1 parent f0ff78e commit fe20fb1

File tree

17 files changed

+212
-33
lines changed

17 files changed

+212
-33
lines changed

core/src/main/java/org/opensearch/sql/ast/tree/Relation.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
package org.opensearch.sql.ast.tree;
88

99
import com.google.common.collect.ImmutableList;
10+
import java.util.Arrays;
1011
import java.util.List;
12+
import java.util.stream.Collectors;
1113
import lombok.AllArgsConstructor;
1214
import lombok.EqualsAndHashCode;
1315
import lombok.RequiredArgsConstructor;
@@ -23,7 +25,18 @@
2325
@EqualsAndHashCode(callSuper = false)
2426
@RequiredArgsConstructor
2527
public class Relation extends UnresolvedPlan {
26-
private final UnresolvedExpression tableName;
28+
private static final String COMMA = ",";
29+
30+
private final List<UnresolvedExpression> tableName;
31+
32+
public Relation(UnresolvedExpression tableName) {
33+
this(tableName, null);
34+
}
35+
36+
public Relation(UnresolvedExpression tableName, String alias) {
37+
this.tableName = Arrays.asList(tableName);
38+
this.alias = alias;
39+
}
2740

2841
/**
2942
* Optional alias name for the relation.
@@ -36,7 +49,9 @@ public class Relation extends UnresolvedPlan {
3649
* @return table name
3750
*/
3851
public String getTableName() {
39-
return tableName.toString();
52+
return tableName.stream()
53+
.map(UnresolvedExpression::toString)
54+
.collect(Collectors.joining(COMMA));
4055
}
4156

4257
/**

core/src/test/java/org/opensearch/sql/ast/tree/RelationTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
76
package org.opensearch.sql.ast.tree;
87

98
import static org.junit.jupiter.api.Assertions.assertEquals;
109
import static org.opensearch.sql.ast.dsl.AstDSL.qualifiedName;
1110

11+
import java.util.Arrays;
1212
import org.junit.jupiter.api.Test;
1313

1414
class RelationTest {
@@ -26,4 +26,9 @@ void should_return_alias_if_aliased() {
2626
assertEquals("t", relation.getTableNameOrAlias());
2727
}
2828

29+
@Test
30+
void comma_seperated_index_return_concat_table_names() {
31+
Relation relation = new Relation(Arrays.asList(qualifiedName("test1"), qualifiedName("test2")));
32+
assertEquals("test1,test2", relation.getTableNameOrAlias());
33+
}
2934
}

docs/user/general/identifiers.rst

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ Examples
3838

3939
Here are examples for using index pattern directly without quotes::
4040

41-
os> SELECT * FROM *cc*nt*;
41+
os> SELECT * FROM *cc*nts;
4242
fetched rows / total rows = 4/4
4343
+------------------+-------------+----------------------+-----------+----------+--------+------------+---------+-------+-----------------------+------------+
4444
| account_number | firstname | address | balance | gender | city | employer | state | age | email | lastname |
@@ -140,3 +140,39 @@ The second example is to show a field name qualified by index alias specified. S
140140
+--------+-------+--------------------+
141141

142142
Note that in both examples above, the qualifier is removed in response. This happens only when identifiers selected is a simple field name. In other cases, expressions rather than an atom field, the column name in response is exactly the same as the text in ``SELECT``clause.
143+
144+
Multiple Indices
145+
================
146+
147+
Description
148+
-----------
149+
150+
To query multiple indices, you could
151+
152+
1. Include ``*`` in index name, this is an index pattern for wildcard match.
153+
2. Delimited multiple indices and seperated them by ``,``. Note: no space allowed between each index.
154+
155+
156+
Examples
157+
---------
158+
159+
Query wildcard indices::
160+
161+
os> SELECT count(*) as cnt FROM acc*;
162+
fetched rows / total rows = 1/1
163+
+-------+
164+
| cnt |
165+
|-------|
166+
| 5 |
167+
+-------+
168+
169+
170+
Query delimited multiple indices seperated by ``,``::
171+
172+
os> SELECT count(*) as cnt FROM `accounts,account2`;
173+
fetched rows / total rows = 1/1
174+
+-------+
175+
| cnt |
176+
|-------|
177+
| 5 |
178+
+-------+

docs/user/ppl/general/identifiers.rst

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,4 +94,51 @@ Identifiers are treated in case sensitive manner. So it must be exactly same as
9494
Examples
9595
--------
9696

97-
For example, if you run ``source=Accounts``, it will end up with an index not found exception from our plugin because the actual index name is under lower case.
97+
For example, if you run ``source=Accounts``, it will end up with an index not found exception from our plugin because the actual index name is under lower case.
98+
99+
Multiple Indices
100+
================
101+
102+
Description
103+
-----------
104+
105+
To query multiple indices, you could
106+
107+
1. Include ``*`` in index name, this is an index pattern for wildcard match.
108+
2. Include multiple indices and seperated them by ``,``.
109+
3. Delimited multiple indices and seperated them by ``,``. Note: no space allowed between each index.
110+
111+
112+
Examples
113+
---------
114+
115+
Query wildcard indices::
116+
117+
os> source=acc* | stats count();
118+
fetched rows / total rows = 1/1
119+
+-----------+
120+
| count() |
121+
|-----------|
122+
| 5 |
123+
+-----------+
124+
125+
Query multiple indices seperated by ``,``::
126+
127+
os> source=accounts, account2 | stats count();
128+
fetched rows / total rows = 1/1
129+
+-----------+
130+
| count() |
131+
|-----------|
132+
| 5 |
133+
+-----------+
134+
135+
Query delimited multiple indices seperated by ``,``::
136+
137+
os> source=`accounts,account2` | stats count();
138+
fetched rows / total rows = 1/1
139+
+-----------+
140+
| count() |
141+
|-----------|
142+
| 5 |
143+
+-----------+
144+

doctest/test_data/account2.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"account_number":2}

doctest/test_docs.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
ACCOUNTS = "accounts"
2323
EMPLOYEES = "employees"
2424
PEOPLE = "people"
25+
ACCOUNT2 = "account2"
2526

2627

2728
class DocTestConnection(OpenSearchConnection):
@@ -84,6 +85,7 @@ def set_up_test_indices(test):
8485
set_up(test)
8586
load_file("accounts.json", index_name=ACCOUNTS)
8687
load_file("people.json", index_name=PEOPLE)
88+
load_file("account2.json", index_name=ACCOUNT2)
8789

8890

8991
def load_file(filename, index_name):
@@ -112,7 +114,7 @@ def set_up(test):
112114

113115
def tear_down(test):
114116
# drop leftover tables after each test
115-
test_data_client.indices.delete(index=[ACCOUNTS, EMPLOYEES, PEOPLE], ignore_unavailable=True)
117+
test_data_client.indices.delete(index=[ACCOUNTS, EMPLOYEES, PEOPLE, ACCOUNT2], ignore_unavailable=True)
116118

117119

118120
docsuite = partial(doctest.DocFileSuite,

opensearch/src/main/java/org/opensearch/sql/opensearch/client/OpenSearchClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public interface OpenSearchClient {
2727
* @param indexExpression index expression
2828
* @return index mapping(s) from index name to its mapping
2929
*/
30-
Map<String, IndexMapping> getIndexMappings(String indexExpression);
30+
Map<String, IndexMapping> getIndexMappings(String... indexExpression);
3131

3232
/**
3333
* Perform search query in the search request.

opensearch/src/main/java/org/opensearch/sql/opensearch/client/OpenSearchNodeClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ public OpenSearchNodeClient(ClusterService clusterService,
7777
* thrown if no index matched.
7878
*/
7979
@Override
80-
public Map<String, IndexMapping> getIndexMappings(String indexExpression) {
80+
public Map<String, IndexMapping> getIndexMappings(String... indexExpression) {
8181
try {
8282
ClusterState state = clusterService.state();
83-
String[] concreteIndices = resolveIndexExpression(state, new String[] {indexExpression});
83+
String[] concreteIndices = resolveIndexExpression(state, indexExpression);
8484

8585
return populateIndexMappings(
8686
state.metadata().findMappings(concreteIndices, ALL_TYPES, ALL_FIELDS));

opensearch/src/main/java/org/opensearch/sql/opensearch/client/OpenSearchRestClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class OpenSearchRestClient implements OpenSearchClient {
4242
private final RestHighLevelClient client;
4343

4444
@Override
45-
public Map<String, IndexMapping> getIndexMappings(String indexExpression) {
45+
public Map<String, IndexMapping> getIndexMappings(String... indexExpression) {
4646
GetMappingsRequest request = new GetMappingsRequest().indices(indexExpression);
4747
try {
4848
GetMappingsResponse response = client.indices().getMapping(request, RequestOptions.DEFAULT);

opensearch/src/main/java/org/opensearch/sql/opensearch/request/OpenSearchQueryRequest.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public class OpenSearchQueryRequest implements OpenSearchRequest {
3838
public static final TimeValue DEFAULT_QUERY_TIMEOUT = TimeValue.timeValueMinutes(1L);
3939

4040
/**
41-
* Index name.
41+
* {@link OpenSearchRequest.IndexName}.
4242
*/
43-
private final String indexName;
43+
private final IndexName indexName;
4444

4545
/**
4646
* Search request source builder.
@@ -65,6 +65,14 @@ public class OpenSearchQueryRequest implements OpenSearchRequest {
6565
*/
6666
public OpenSearchQueryRequest(String indexName, int size,
6767
OpenSearchExprValueFactory factory) {
68+
this(new IndexName(indexName), size, factory);
69+
}
70+
71+
/**
72+
* Constructor of ElasticsearchQueryRequest.
73+
*/
74+
public OpenSearchQueryRequest(IndexName indexName, int size,
75+
OpenSearchExprValueFactory factory) {
6876
this.indexName = indexName;
6977
this.sourceBuilder = new SearchSourceBuilder();
7078
sourceBuilder.from(0);
@@ -97,7 +105,7 @@ public void clean(Consumer<String> cleanAction) {
97105
@VisibleForTesting
98106
protected SearchRequest searchRequest() {
99107
return new SearchRequest()
100-
.indices(indexName)
108+
.indices(indexName.getIndexNames())
101109
.source(sourceBuilder);
102110
}
103111
}

0 commit comments

Comments
 (0)