Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multiple indices in PPL and SQL #408

Merged
merged 1 commit into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions core/src/main/java/org/opensearch/sql/ast/tree/Relation.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
package org.opensearch.sql.ast.tree;

import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,7 +25,18 @@
@EqualsAndHashCode(callSuper = false)
@RequiredArgsConstructor
public class Relation extends UnresolvedPlan {
private final UnresolvedExpression tableName;
private static final String COMMA = ",";

private final List<UnresolvedExpression> tableName;

public Relation(UnresolvedExpression tableName) {
this(tableName, null);
}

public Relation(UnresolvedExpression tableName, String alias) {
this.tableName = Arrays.asList(tableName);
this.alias = alias;
}

/**
* Optional alias name for the relation.
Expand All @@ -36,7 +49,9 @@ public class Relation extends UnresolvedPlan {
* @return table name
*/
public String getTableName() {
return tableName.toString();
return tableName.stream()
.map(UnresolvedExpression::toString)
.collect(Collectors.joining(COMMA));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
* SPDX-License-Identifier: Apache-2.0
*/


package org.opensearch.sql.ast.tree;

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

import java.util.Arrays;
import org.junit.jupiter.api.Test;

class RelationTest {
Expand All @@ -26,4 +26,9 @@ void should_return_alias_if_aliased() {
assertEquals("t", relation.getTableNameOrAlias());
}

@Test
void comma_seperated_index_return_concat_table_names() {
Relation relation = new Relation(Arrays.asList(qualifiedName("test1"), qualifiedName("test2")));
assertEquals("test1,test2", relation.getTableNameOrAlias());
}
}
38 changes: 37 additions & 1 deletion docs/user/general/identifiers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Examples

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

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

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.

Multiple Indices
================

Description
-----------

To query multiple indices, you could

1. Include ``*`` in index name, this is an index pattern for wildcard match.
2. Delimited multiple indices and seperated them by ``,``. Note: no space allowed between each index.


Examples
---------

Query wildcard indices::

os> SELECT count(*) as cnt FROM acc*;
fetched rows / total rows = 1/1
+-------+
| cnt |
|-------|
| 5 |
+-------+


Query delimited multiple indices seperated by ``,``::

os> SELECT count(*) as cnt FROM `accounts,account2`;
fetched rows / total rows = 1/1
+-------+
| cnt |
|-------|
| 5 |
+-------+
49 changes: 48 additions & 1 deletion docs/user/ppl/general/identifiers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,51 @@ Identifiers are treated in case sensitive manner. So it must be exactly same as
Examples
--------

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.
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.

Multiple Indices
================

Description
-----------

To query multiple indices, you could

1. Include ``*`` in index name, this is an index pattern for wildcard match.
2. Include multiple indices and seperated them by ``,``.
3. Delimited multiple indices and seperated them by ``,``. Note: no space allowed between each index.


Examples
---------

Query wildcard indices::

os> source=acc* | stats count();
fetched rows / total rows = 1/1
+-----------+
| count() |
|-----------|
| 5 |
+-----------+

Query multiple indices seperated by ``,``::

os> source=accounts, account2 | stats count();
fetched rows / total rows = 1/1
+-----------+
| count() |
|-----------|
| 5 |
+-----------+

Query delimited multiple indices seperated by ``,``::

os> source=`accounts,account2` | stats count();
fetched rows / total rows = 1/1
+-----------+
| count() |
|-----------|
| 5 |
+-----------+

1 change: 1 addition & 0 deletions doctest/test_data/account2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"account_number":2}
4 changes: 3 additions & 1 deletion doctest/test_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
ACCOUNTS = "accounts"
EMPLOYEES = "employees"
PEOPLE = "people"
ACCOUNT2 = "account2"


class DocTestConnection(OpenSearchConnection):
Expand Down Expand Up @@ -84,6 +85,7 @@ def set_up_test_indices(test):
set_up(test)
load_file("accounts.json", index_name=ACCOUNTS)
load_file("people.json", index_name=PEOPLE)
load_file("account2.json", index_name=ACCOUNT2)


def load_file(filename, index_name):
Expand Down Expand Up @@ -112,7 +114,7 @@ def set_up(test):

def tear_down(test):
# drop leftover tables after each test
test_data_client.indices.delete(index=[ACCOUNTS, EMPLOYEES, PEOPLE], ignore_unavailable=True)
test_data_client.indices.delete(index=[ACCOUNTS, EMPLOYEES, PEOPLE, ACCOUNT2], ignore_unavailable=True)


docsuite = partial(doctest.DocFileSuite,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public interface OpenSearchClient {
* @param indexExpression index expression
* @return index mapping(s) from index name to its mapping
*/
Map<String, IndexMapping> getIndexMappings(String indexExpression);
Map<String, IndexMapping> getIndexMappings(String... indexExpression);

/**
* Perform search query in the search request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,10 @@ public OpenSearchNodeClient(ClusterService clusterService,
* thrown if no index matched.
*/
@Override
public Map<String, IndexMapping> getIndexMappings(String indexExpression) {
public Map<String, IndexMapping> getIndexMappings(String... indexExpression) {
try {
ClusterState state = clusterService.state();
String[] concreteIndices = resolveIndexExpression(state, new String[] {indexExpression});
String[] concreteIndices = resolveIndexExpression(state, indexExpression);

return populateIndexMappings(
state.metadata().findMappings(concreteIndices, ALL_TYPES, ALL_FIELDS));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class OpenSearchRestClient implements OpenSearchClient {
private final RestHighLevelClient client;

@Override
public Map<String, IndexMapping> getIndexMappings(String indexExpression) {
public Map<String, IndexMapping> getIndexMappings(String... indexExpression) {
GetMappingsRequest request = new GetMappingsRequest().indices(indexExpression);
try {
GetMappingsResponse response = client.indices().getMapping(request, RequestOptions.DEFAULT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ public class OpenSearchQueryRequest implements OpenSearchRequest {
public static final TimeValue DEFAULT_QUERY_TIMEOUT = TimeValue.timeValueMinutes(1L);

/**
* Index name.
* {@link OpenSearchRequest.IndexName}.
*/
private final String indexName;
private final IndexName indexName;

/**
* Search request source builder.
Expand All @@ -65,6 +65,14 @@ public class OpenSearchQueryRequest implements OpenSearchRequest {
*/
public OpenSearchQueryRequest(String indexName, int size,
OpenSearchExprValueFactory factory) {
this(new IndexName(indexName), size, factory);
}

/**
* Constructor of ElasticsearchQueryRequest.
*/
public OpenSearchQueryRequest(IndexName indexName, int size,
OpenSearchExprValueFactory factory) {
this.indexName = indexName;
this.sourceBuilder = new SearchSourceBuilder();
sourceBuilder.from(0);
Expand Down Expand Up @@ -97,7 +105,7 @@ public void clean(Consumer<String> cleanAction) {
@VisibleForTesting
protected SearchRequest searchRequest() {
return new SearchRequest()
.indices(indexName)
.indices(indexName.getIndexNames())
.source(sourceBuilder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import java.util.function.Consumer;
import java.util.function.Function;
import lombok.EqualsAndHashCode;
import org.opensearch.action.search.SearchRequest;
import org.opensearch.action.search.SearchResponse;
import org.opensearch.action.search.SearchScrollRequest;
Expand All @@ -19,7 +20,6 @@
* OpenSearch search request.
*/
public interface OpenSearchRequest {

/**
* Apply the search action or scroll action on request based on context.
*
Expand Down Expand Up @@ -49,4 +49,28 @@ OpenSearchResponse search(Function<SearchRequest, SearchResponse> searchAction,
* @return ElasticsearchExprValueFactory.
*/
OpenSearchExprValueFactory getExprValueFactory();

/**
* OpenSearch Index Name.
* Indices are seperated by ",".
*/
@EqualsAndHashCode
class IndexName {
private static final String COMMA = ",";

private final String[] indexNames;

public IndexName(String indexName) {
this.indexNames = indexName.split(COMMA);
}

public String[] getIndexNames() {
return indexNames;
}

@Override
public String toString() {
return String.join(COMMA, indexNames);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,17 @@
* Maintain scroll ID between calls to client search method
*/
@EqualsAndHashCode
@RequiredArgsConstructor
@Getter
@ToString
public class OpenSearchScrollRequest implements OpenSearchRequest {

/** Default scroll context timeout in minutes. */
public static final TimeValue DEFAULT_SCROLL_TIMEOUT = TimeValue.timeValueMinutes(1L);

/** Index name. */
private final String indexName;
/**
* {@link OpenSearchRequest.IndexName}.
*/
private final IndexName indexName;

/** Index name. */
@EqualsAndHashCode.Exclude
Expand All @@ -49,11 +50,20 @@ public class OpenSearchScrollRequest implements OpenSearchRequest {
* Scroll id which is set after first request issued. Because ElasticsearchClient is shared by
* multi-thread so this state has to be maintained here.
*/
@Setter private String scrollId;
@Setter
private String scrollId;

/** Search request source builder. */
private final SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();

public OpenSearchScrollRequest(IndexName indexName, OpenSearchExprValueFactory exprValueFactory) {
this.indexName = indexName;
this.exprValueFactory = exprValueFactory;
}

public OpenSearchScrollRequest(String indexName, OpenSearchExprValueFactory exprValueFactory) {
this(new IndexName(indexName), exprValueFactory);
}

@Override
public OpenSearchResponse search(Function<SearchRequest, SearchResponse> searchAction,
Expand Down Expand Up @@ -87,7 +97,7 @@ public void clean(Consumer<String> cleanAction) {
*/
public SearchRequest searchRequest() {
return new SearchRequest()
.indices(indexName)
.indices(indexName.getIndexNames())
.scroll(DEFAULT_SCROLL_TIMEOUT)
.source(sourceBuilder);
}
Expand Down
Loading