Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Support describe index alias #775

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
2 changes: 1 addition & 1 deletion docs/user/dql/metadata.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Result set:
Example 2: Show Specific Index Information
------------------------------------------

Here is an example that searches metadata for index name prefixed by 'acc'
Here is an example that searches metadata for index name prefixed by 'acc'. Besides index name and pattern with wildcard characters, searching by index alias is also supported. So you can ``SHOW`` or ``DESCRIBE`` an index alias which gives you same result as doing this with an index name.

SQL query::

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.not;

import com.amazon.opendistroforelasticsearch.sql.legacy.utils.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -299,6 +300,54 @@ public void describeSingleIndex() throws IOException {
assertThat(row.get(5), not(equalTo(JSONObject.NULL)));
}

@Test
public void showSingleIndexAlias() throws IOException {
client().performRequest(new Request("PUT",
TestsConstants.TEST_INDEX_ACCOUNT + "/_alias/acc"));

JSONObject expected = executeQuery("SHOW TABLES LIKE " + TestsConstants.TEST_INDEX_ACCOUNT);
JSONObject actual = executeQuery("SHOW TABLES LIKE acc");

assertThat(getDataRows(actual).length(), equalTo(1));
assertTrue(StringUtils.format("Expected: %s, actual: %s", expected, actual),
expected.similar(actual));
}

@Test
public void describeSingleIndexAlias() throws IOException {
client().performRequest(new Request("PUT",
TestsConstants.TEST_INDEX_ACCOUNT + "/_alias/acc"));

JSONObject expected = executeQuery("DESCRIBE TABLES LIKE " + TestsConstants.TEST_INDEX_ACCOUNT);
JSONObject actual = executeQuery("DESCRIBE TABLES LIKE acc");

assertThat(getDataRows(actual).length(), greaterThan(0));
assertTrue(StringUtils.format("Expected: %s, actual: %s", expected, actual),
expected.similar(actual));
}

@Test
public void showSingleIndexNameWithDot() throws IOException {
Request request = new Request("POST", "/index.date1/_doc");
request.setJsonEntity("{ \"test\": 123 }");
client().performRequest(request);

JSONObject response = executeQuery("SHOW TABLES LIKE index.date1");
JSONArray dataRows = getDataRows(response);
assertThat(dataRows.length(), equalTo(1));
}

@Test
public void describeSingleIndexNameWithDot() throws IOException {
Request request = new Request("POST", "/index.date2/_doc");
request.setJsonEntity("{ \"test\": 123 }");
client().performRequest(request);

JSONObject response = executeQuery("DESCRIBE TABLES LIKE index.date2");
JSONArray dataRows = getDataRows(response);
assertThat(dataRows.length(), equalTo(1));
}

@Test
public void describeSingleIndexWithObjectFieldShouldPass() throws IOException {
JSONObject response =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,7 @@ private List<Row> loadRows() {
for (ObjectObjectCursor<String, ImmutableOpenMap<String, MappingMetadata>> indexCursor : indexMappings) {
String index = indexCursor.key;

// Check to see if index matches given pattern
if (matchesPattern(index, statement.getIndexPattern())) {
if (matchesPatternIfRegex(index, statement.getIndexPattern())) {
ImmutableOpenMap<String, MappingMetadata> typeMapping = indexCursor.value;
// Assuming ES 6.x, iterate through the only type of the index to get mapping data
for (ObjectObjectCursor<String, MappingMetadata> typeCursor : typeMapping) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,26 @@ protected String getClusterName() {
.getClusterName();
}

/**
* Check if given string matches the pattern. Do this check only if the pattern is a regex.
* Otherwise skip the matching process and consider it's a match.
* This is a quick fix to support SHOW/DESCRIBE alias by skip mismatch between actual index name
* and pattern (alias).
* @param string string to match
* @param pattern pattern
* @return true if match or pattern is not regular expression. otherwise false.
*/
protected boolean matchesPatternIfRegex(String string, String pattern) {
return isNotRegexPattern(pattern) || matchesPattern(string, pattern);
}

protected boolean matchesPattern(String string, String pattern) {
Pattern p = Pattern.compile(pattern);
Matcher matcher = p.matcher(string);
return matcher.find();
}

private boolean isNotRegexPattern(String pattern) {
return !pattern.contains(".") && !pattern.contains("*");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private List<String> extractIndices() {
String[] indices = ((GetIndexResponse) queryResult).getIndices();

return Arrays.stream(indices)
.filter(index -> matchesPattern(index, indexPattern))
.filter(index -> matchesPatternIfRegex(index, indexPattern))
.collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/

package com.amazon.opendistroforelasticsearch.sql.legacy.executor.format;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Test;

public class ResultSetTest {

private final ResultSet resultSet = new ResultSet() {
@Override
public Schema getSchema() {
return super.getSchema();
}
};

/**
* Case #1:
* LIKE 'test%' is converted to:
* 1. Regex pattern: test.*
* 2. ES search pattern: test*
* In this case, what ES returns is the final result.
*/
@Test
public void testWildcardForZeroOrMoreCharacters() {
assertTrue(resultSet.matchesPatternIfRegex("test123", "test.*"));
}

/**
* Case #2:
* LIKE 'test_123' is converted to:
* 1. Regex pattern: test.123
* 2. ES search pattern: (all)
* Because ES doesn't support single wildcard character, in this case, none is passed
* as ES search pattern. So all index names are returned and need to be filtered by
* regex pattern again.
*/
@Test
public void testWildcardForSingleCharacter() {
assertFalse(resultSet.matchesPatternIfRegex("accounts", "test.23"));
assertFalse(resultSet.matchesPatternIfRegex(".kibana", "test.23"));
assertTrue(resultSet.matchesPatternIfRegex("test123", "test.23"));
}

/**
* Case #3:
* LIKE 'acc' has same regex and ES pattern.
* In this case, only index name(s) aliased by 'acc' is returned.
* So regex match is skipped to avoid wrong empty result.
* The assumption here is ES won't return unrelated index names if
* LIKE pattern doesn't include any wildcard.
*/
@Test
public void testIndexAlias() {
assertTrue(resultSet.matchesPatternIfRegex("accounts", "acc"));
}

/**
* Case #4:
* LIKE 'test.2020.10' has same regex pattern. Because it includes dot (wildcard),
* ES search pattern is all.
* In this case, all index names are returned. Because the pattern includes dot,
* it's treated as regex and regex match won't be skipped.
*/
@Test
public void testIndexNameWithDot() {
assertFalse(resultSet.matchesPatternIfRegex("accounts", "test.2020.10"));
assertFalse(resultSet.matchesPatternIfRegex(".kibana", "test.2020.10"));
assertTrue(resultSet.matchesPatternIfRegex("test.2020.10", "test.2020.10"));
}

}