This is an automated email from the ASF dual-hosted git repository. mcvsubbu pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git
The following commit(s) were added to refs/heads/master by this push: new 7a989f7 Implement QueryOp class. (#6583) 7a989f7 is described below commit 7a989f72d495c4c72904fa3b811259ac6e37043d Author: Liang Mingqiang <mili...@linkedin.com> AuthorDate: Fri Feb 26 11:21:30 2021 -0800 Implement QueryOp class. (#6583) * Implement QueryOp class. Implement QueryOp class, which take a file that has queries, and a file that has results, run the queries through the broker/server and compare the results with the result file. * address comments: reformat code; verify routing table is updated in SegmentOp * address jackjlli's comments * address mcvsubbu's comments * address jackjlli's comments: throwing a generic Exception * use println instead of printf Co-authored-by: Ming Liang <mili...@miliang-mn1.linkedin.biz> --- .../pinot/compat/tests/CompatibilityOpsRunner.java | 11 +- .../org/apache/pinot/compat/tests/QueryOp.java | 95 +++++- .../apache/pinot/compat/tests/QueryProcessor.java | 98 ++++++ .../org/apache/pinot/compat/tests/SegmentOp.java | 26 +- .../pinot/compat/tests/SqlResultComparator.java | 353 +++++++++++++++++++++ .../compat-tests/configs/feature-test-1.json | 11 + .../queries/feature-test-1-sql.queries | 89 ++++++ .../src/test/resources/compat-tests/query-op.yaml | 49 +++ .../query-results/feature-test-1-rest-sql.results | 85 +++++ .../resources/compat-tests/table-segment-op.yaml | 5 + 10 files changed, 812 insertions(+), 10 deletions(-) diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/CompatibilityOpsRunner.java b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/CompatibilityOpsRunner.java index fe9144c..7350cf9 100644 --- a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/CompatibilityOpsRunner.java +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/CompatibilityOpsRunner.java @@ -18,14 +18,10 @@ */ package org.apache.pinot.compat.tests; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; -import java.io.IOException; import java.io.InputStream; -import org.apache.pinot.compat.tests.BaseOp; -import org.apache.pinot.compat.tests.CompatTestOperation; + public class CompatibilityOpsRunner { private static final String ROOT_DIR = "compat-tests"; @@ -36,8 +32,7 @@ public class CompatibilityOpsRunner { _configFileName = configFileName; } - private boolean runOps() - throws IOException, JsonParseException, JsonMappingException { + private boolean runOps() throws Exception { String filePath = ROOT_DIR + "/" + _configFileName; InputStream inputStream = getClass().getClassLoader().getResourceAsStream(filePath); @@ -56,7 +51,7 @@ public class CompatibilityOpsRunner { return passed; } - public static void main(String[] args) throws Exception { + public static void main(String[] args) throws Exception { if (args.length < 1 || args.length > 1) { throw new IllegalArgumentException("Need exactly one file name as argument"); } diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/QueryOp.java b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/QueryOp.java index 48e4ba0..eeafb15 100644 --- a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/QueryOp.java +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/QueryOp.java @@ -19,6 +19,14 @@ package org.apache.pinot.compat.tests; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.JsonNode; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import org.apache.pinot.spi.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** @@ -30,6 +38,11 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; */ @JsonIgnoreProperties(ignoreUnknown = true) public class QueryOp extends BaseOp { + private static final Logger LOGGER = LoggerFactory.getLogger(QueryOp.class); + + private static final String NUM_DOCS_SCANNED_KEY = "numDocsScanned"; + private static final String TIME_USED_MS_KEY = "timeUsedMs"; + private static final String COMMENT_DELIMITER = "#"; private String _queryFileName; private String _expectedResultsFileName; @@ -37,6 +50,11 @@ public class QueryOp extends BaseOp { super(OpType.QUERY_OP); } + private boolean shouldIgnore(String line) { + String trimmedLine = line.trim(); + return trimmedLine.isEmpty() || trimmedLine.startsWith(COMMENT_DELIMITER); + } + public String getQueryFileName() { return _queryFileName; } @@ -56,6 +74,81 @@ public class QueryOp extends BaseOp { @Override boolean runOp() { System.out.println("Verifying queries in " + _queryFileName + " against results in " + _expectedResultsFileName); - return true; + try { + return verifyQueries(); + } catch (Exception e) { + LOGGER.error("FAILED to verify queries in {}: {}", _queryFileName, e); + return false; + } + } + + boolean verifyQueries() + throws Exception { + boolean testPassed = false; + + try (BufferedReader queryReader = new BufferedReader( + new InputStreamReader(new FileInputStream(_queryFileName), StandardCharsets.UTF_8)); + BufferedReader expectedResultReader = new BufferedReader( + new InputStreamReader(new FileInputStream(_expectedResultsFileName), StandardCharsets.UTF_8))) { + + int succeededQueryCount = 0; + int totalQueryCount = 0; + int queryLineNum = 0; + String query; + + while ((query = queryReader.readLine()) != null) { + queryLineNum++; + if (shouldIgnore(query)) { + continue; + } + + JsonNode expectedJson = null; + try { + String expectedResultLine = expectedResultReader.readLine(); + while (shouldIgnore(expectedResultLine)) { + expectedResultLine = expectedResultReader.readLine(); + } + expectedJson = JsonUtils.stringToJsonNode(expectedResultLine); + } catch (Exception e) { + LOGGER.error("Comparison FAILED: Line: {} Exception caught while getting expected response for query: '{}'", + queryLineNum, query, e); + } + + JsonNode actualJson = null; + if (expectedJson != null) { + try { + actualJson = QueryProcessor.postSqlQuery(query); + } catch (Exception e) { + LOGGER.error("Comparison FAILED: Line: {} Exception caught while running query: '{}'", queryLineNum, query, + e); + } + } + + if (expectedJson != null && actualJson != null) { + try { + boolean passed = SqlResultComparator.areEqual(actualJson, expectedJson, query); + if (passed) { + succeededQueryCount++; + LOGGER.debug("Comparison PASSED: Line: {}, query: '{}', actual response: {}, expected response: {}", + queryLineNum, query, actualJson, expectedJson); + } else { + LOGGER.error("Comparison FAILED: Line: {}, query: '{}', actual response: {}, expected response: {}", + queryLineNum, query, actualJson, expectedJson); + } + } catch (Exception e) { + LOGGER.error( + "Comparison FAILED: Line: {} Exception caught while comparing query: '{}' actual response: {}, expected response: {}", + queryLineNum, query, actualJson, expectedJson, e); + } + } + totalQueryCount++; + } + + LOGGER.info("Total {} out of {} queries passed.", succeededQueryCount, totalQueryCount); + if (succeededQueryCount == totalQueryCount) { + testPassed = true; + } + } + return testPassed; } } diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/QueryProcessor.java b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/QueryProcessor.java new file mode 100644 index 0000000..6109134 --- /dev/null +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/QueryProcessor.java @@ -0,0 +1,98 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.pinot.compat.tests; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Map; +import org.apache.pinot.spi.utils.JsonUtils; + + +public class QueryProcessor { + + private static final String BROKER_BASE_API_URL = ClusterDescriptor.CONTROLLER_URL; + + /** + * Queries the broker's sql query endpoint (/sql) + */ + public static JsonNode postSqlQuery(String query) + throws Exception { + return postSqlQuery(query, BROKER_BASE_API_URL); + } + + /** + * Queries the broker's sql query endpoint (/sql) + */ + private static JsonNode postSqlQuery(String query, String brokerBaseApiUrl) + throws Exception { + ObjectNode payload = JsonUtils.newObjectNode(); + payload.put("sql", query); + payload.put("queryOptions", "groupByMode=sql;responseFormat=sql"); + + return JsonUtils.stringToJsonNode(sendPostRequest(brokerBaseApiUrl + "/sql", payload.toString())); + } + + private static String sendPostRequest(String urlString, String payload) + throws IOException { + return sendPostRequest(urlString, payload, Collections.EMPTY_MAP); + } + + private static String sendPostRequest(String urlString, String payload, Map<String, String> headers) + throws IOException { + HttpURLConnection httpConnection = (HttpURLConnection) new URL(urlString).openConnection(); + httpConnection.setRequestMethod("POST"); + if (headers != null) { + for (String key : headers.keySet()) { + httpConnection.setRequestProperty(key, headers.get(key)); + } + } + + if (payload != null && !payload.isEmpty()) { + httpConnection.setDoOutput(true); + try (BufferedWriter writer = new BufferedWriter( + new OutputStreamWriter(httpConnection.getOutputStream(), StandardCharsets.UTF_8))) { + writer.write(payload, 0, payload.length()); + writer.flush(); + } + } + return constructResponse(httpConnection.getInputStream()); + } + + private static String constructResponse(InputStream inputStream) + throws IOException { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + StringBuilder responseBuilder = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + responseBuilder.append(line); + } + return responseBuilder.toString(); + } + } +} diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/SegmentOp.java b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/SegmentOp.java index 7e63212..99e8301 100644 --- a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/SegmentOp.java +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/SegmentOp.java @@ -19,6 +19,7 @@ package org.apache.pinot.compat.tests; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.JsonNode; import java.io.File; import java.io.IOException; import java.net.URI; @@ -154,7 +155,8 @@ public class SegmentOp extends BaseOp { FileUtils.forceMkdir(localOutputTempDir); File segmentTarFile = generateSegment(localOutputTempDir); uploadSegment(segmentTarFile); - return verifySegmentInState(CommonConstants.Helix.StateModel.SegmentStateModel.ONLINE); + return verifySegmentInState(CommonConstants.Helix.StateModel.SegmentStateModel.ONLINE) + && verifyRoutingTableUpdated(); } catch (Exception e) { LOGGER.error("Failed to create and upload segment for input data file {}.", _inputDataFileName, e); return false; @@ -241,6 +243,28 @@ public class SegmentOp extends BaseOp { return true; } + // TODO: verify by getting the number of rows before adding the segment, and the number of rows after adding the + // segment, then make sure that it has increased by the number of rows in the segment. + private boolean verifyRoutingTableUpdated() + throws Exception { + String query = "SELECT count(*) FROM " + _tableName; + JsonNode result = QueryProcessor.postSqlQuery(query); + long startTime = System.currentTimeMillis(); + while (SqlResultComparator.isEmpty(result)) { + if ((System.currentTimeMillis() - startTime) > DEFAULT_MAX_SLEEP_TIME_MS) { + LOGGER + .error("Upload segment verification failed, routing table has not been updated after max wait time {} ms.", + DEFAULT_MAX_SLEEP_TIME_MS); + return false; + } + LOGGER.warn("Routing table has not been updated yet, will retry after {} ms.", DEFAULT_SLEEP_INTERVAL_MS); + Thread.sleep(DEFAULT_SLEEP_INTERVAL_MS); + result = QueryProcessor.postSqlQuery(query); + } + LOGGER.info("Routing table has been updated."); + return true; + } + /** * Deletes the segment for the given segment name and table name. * @return true if delete successful, else false. diff --git a/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/SqlResultComparator.java b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/SqlResultComparator.java new file mode 100644 index 0000000..c117452 --- /dev/null +++ b/pinot-integration-tests/src/test/java/org/apache/pinot/compat/tests/SqlResultComparator.java @@ -0,0 +1,353 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License 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 org.apache.pinot.compat.tests; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import org.apache.calcite.config.Lex; +import org.apache.calcite.sql.SqlKind; +import org.apache.calcite.sql.SqlNode; +import org.apache.calcite.sql.SqlNodeList; +import org.apache.calcite.sql.SqlOrderBy; +import org.apache.calcite.sql.parser.SqlParseException; +import org.apache.calcite.sql.parser.SqlParser; +import org.apache.calcite.sql.parser.babel.SqlBabelParserImpl; +import org.apache.calcite.sql.validate.SqlConformanceEnum; +import org.apache.pinot.spi.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class SqlResultComparator { + + private static final Logger LOGGER = LoggerFactory.getLogger(SqlResultComparator.class); + + private static final String FIELD_RESULT_TABLE = "resultTable"; + private static final String FIELD_DATA_SCHEMA = "dataSchema"; + private static final String FIELD_ROWS = "rows"; + private static final String FIELD_COLUMN_DATA_TYPES = "columnDataTypes"; + private static final String FIELD_IS_SUPERSET = "isSuperset"; + private static final String FIELD_NUM_DOCS_SCANNED = "numDocsScanned"; + private static final String FIELD_EXCEPTIONS = "exceptions"; + private static final String FIELD_NUM_SERVERS_QUERIED = "numServersQueried"; + private static final String FIELD_NUM_SERVERS_RESPONDED = "numServersResponded"; + private static final String FIELD_NUM_SEGMENTS_QUERIED = "numSegmentsQueried"; + private static final String FIELD_NUM_SEGMENTS_PROCESSED = "numSegmentsProcessed"; + private static final String FIELD_NUM_SEGMENTS_MATCHED = "numSegmentsMatched"; + private static final String FIELD_NUM_CONSUMING_SEGMENTS_QUERIED = "numConsumingSegmentsQueried"; + private static final String FIELD_NUM_ENTRIES_SCANNED_IN_FILTER = "numEntriesScannedInFilter"; + private static final String FIELD_NUM_ENTRIES_SCANNED_POST_FILTER = "numEntriesScannedPostFilter"; + private static final String FIELD_NUM_GROUPS_LIMIT_REACHED = "numGroupsLimitReached"; + + private static final String FIELD_TYPE_INT = "INT"; + private static final String FIELD_TYPE_LONG = "LONG"; + private static final String FIELD_TYPE_FLOAT = "FLOAT"; + private static final String FIELD_TYPE_DOUBLE = "DOUBLE"; + private static final String FIELD_TYPE_STRING = "STRING"; + private static final String FIELD_TYPE_BYTES = "BYTES"; + private static final String FIELD_TYPE_INT_ARRAY = "INT_ARRAY"; + private static final String FIELD_TYPE_LONG_ARRAY = "LONG_ARRAY"; + private static final String FIELD_TYPE_FLOAT_ARRAY = "FLOAT_ARRAY"; + private static final String FIELD_TYPE_DOUBLE_ARRAY = "DOUBLE_ARRAY"; + private static final String FIELD_TYPE_STRING_ARRAY = "STRING_ARRAY"; + private static final String FIELD_TYPE_BYTES_ARRRAY = "BYTES_ARRRAY"; + + private static final SqlParser.Config SQL_PARSER_CONFIG = + SqlParser.configBuilder().setLex(Lex.MYSQL_ANSI).setConformance(SqlConformanceEnum.BABEL) + .setParserFactory(SqlBabelParserImpl.FACTORY).build(); + + public static boolean areEqual(JsonNode actual, JsonNode expected, String query) + throws IOException { + if (hasExceptions(actual)) { + return false; + } + + if (areEmpty(actual, expected)) { + return true; + } + + if (!areDataSchemaEqual(actual, expected)) { + return false; + } + + ArrayNode actualRows = (ArrayNode) actual.get(FIELD_RESULT_TABLE).get(FIELD_ROWS); + ArrayNode expectedRows = (ArrayNode) expected.get(FIELD_RESULT_TABLE).get(FIELD_ROWS); + ArrayNode columnDataTypes = (ArrayNode) expected.get(FIELD_RESULT_TABLE).get(FIELD_DATA_SCHEMA). + get(FIELD_COLUMN_DATA_TYPES); + + convertNumbersToString(expectedRows, columnDataTypes); + convertNumbersToString(actualRows, columnDataTypes); + + List<String> actualElementsSerialized = new ArrayList<>(); + List<String> expectedElementsSerialized = new ArrayList<>(); + for (int i = 0; i < actualRows.size(); i++) { + actualElementsSerialized.add(actualRows.get(i).toString()); + } + for (int i = 0; i < expectedRows.size(); i++) { + expectedElementsSerialized.add(expectedRows.get(i).toString()); + } + /* + * If the test compares the returned results to be a subset of total qualified results, ignore the comparison of + * result length and metadata(numDocsScanned, numEntriesScannedInFilter, numEntriesScannedPostFilter, etc). + */ + if (expected.has(FIELD_IS_SUPERSET) && expected.get(FIELD_IS_SUPERSET).asBoolean(false)) { + return areElementsSubset(actualElementsSerialized, expectedElementsSerialized); + } else { + return areLengthsEqual(actual, expected) && areElementsEqual(actualElementsSerialized, expectedElementsSerialized, + query) && areMetadataEqual(actual, expected); + } + } + + public static boolean hasExceptions(JsonNode actual) { + if (actual.get(FIELD_EXCEPTIONS).size() != 0) { + LOGGER.error("Got exception: {} when querying!", actual.get(FIELD_EXCEPTIONS)); + return true; + } + return false; + } + + public static boolean areMetadataEqual(JsonNode actual, JsonNode expected) { + return areNumServersQueriedEqual(actual, expected) && areNumServersRespondedEqual(actual, expected) + && areNumSegmentsQueriedEqual(actual, expected) && areNumSegmentsProcessedEqual(actual, expected) + && areNumSegmentsMatchedEqual(actual, expected) && areNumConsumingSegmentsQueriedEqual(actual, expected) + && areNumDocsScannedEqual(actual, expected) && areNumEntriesScannedInFilterEqual(actual, expected) + && areNumEntriesScannedPostFilterEqual(actual, expected) && areNumGroupsLimitReachedEqual(actual, expected); + } + + private static boolean areNumGroupsLimitReachedEqual(JsonNode actual, JsonNode expected) { + boolean actualNumGroupsLimitReached = actual.get(FIELD_NUM_GROUPS_LIMIT_REACHED).asBoolean(); + boolean expectedNumGroupsLimitReached = expected.get(FIELD_NUM_GROUPS_LIMIT_REACHED).asBoolean(); + if (actualNumGroupsLimitReached != expectedNumGroupsLimitReached) { + LOGGER.error("The numGroupsLimitReached don't match! Actual: {}, Expected: {}", actualNumGroupsLimitReached, + expectedNumGroupsLimitReached); + return false; + } + return true; + } + + private static boolean areNumConsumingSegmentsQueriedEqual(JsonNode actual, JsonNode expected) { + long actualNumConsumingSegmentsQueried = actual.get(FIELD_NUM_CONSUMING_SEGMENTS_QUERIED).asLong(); + long expectedNumConsumingSegmentsQueried = expected.get(FIELD_NUM_CONSUMING_SEGMENTS_QUERIED).asLong(); + if (actualNumConsumingSegmentsQueried != expectedNumConsumingSegmentsQueried) { + LOGGER.error("The numConsumingSegmentsQueried don't match! Actual: {}, Expected: {}", + actualNumConsumingSegmentsQueried, expectedNumConsumingSegmentsQueried); + return false; + } + return true; + } + + private static boolean areNumSegmentsProcessedEqual(JsonNode actual, JsonNode expected) { + long actualNumSegmentsProcessed = actual.get(FIELD_NUM_SEGMENTS_PROCESSED).asLong(); + long expectedNumSegmentsProcessed = expected.get(FIELD_NUM_SEGMENTS_PROCESSED).asLong(); + if (actualNumSegmentsProcessed != expectedNumSegmentsProcessed) { + LOGGER.error("The numSegmentsProcessed don't match! Actual: {}, Expected: {}", actualNumSegmentsProcessed, + expectedNumSegmentsProcessed); + return false; + } + return true; + } + + private static boolean areNumSegmentsQueriedEqual(JsonNode actual, JsonNode expected) { + long actualNumSegmentsQueried = actual.get(FIELD_NUM_SEGMENTS_QUERIED).asLong(); + long expectedNumSegmentsQueried = expected.get(FIELD_NUM_SEGMENTS_QUERIED).asLong(); + if (actualNumSegmentsQueried != expectedNumSegmentsQueried) { + LOGGER.error("The numSegmentsQueried don't match! Actual: {}, Expected: {}", actualNumSegmentsQueried, + expectedNumSegmentsQueried); + return false; + } + return true; + } + + private static boolean areNumSegmentsMatchedEqual(JsonNode actual, JsonNode expected) { + long actualNumSegmentsMatched = actual.get(FIELD_NUM_SEGMENTS_MATCHED).asLong(); + long expectedNumSegmentsMatched = expected.get(FIELD_NUM_SEGMENTS_MATCHED).asLong(); + if (actualNumSegmentsMatched != expectedNumSegmentsMatched) { + LOGGER.error("The numSegmentsMatched don't match! Actual: {}, Expected: {}", actualNumSegmentsMatched, + expectedNumSegmentsMatched); + return false; + } + return true; + } + + private static boolean areNumServersRespondedEqual(JsonNode actual, JsonNode expected) { + long actualNumServersResponded = actual.get(FIELD_NUM_SERVERS_RESPONDED).asLong(); + long expectedNumServersResponded = expected.get(FIELD_NUM_SERVERS_RESPONDED).asLong(); + if (actualNumServersResponded != expectedNumServersResponded) { + LOGGER.error("The numServersResponded don't match! Actual: {}, Expected: {}", actualNumServersResponded, + expectedNumServersResponded); + return false; + } + return true; + } + + private static boolean areNumServersQueriedEqual(JsonNode actual, JsonNode expected) { + long actualNumServersQueried = actual.get(FIELD_NUM_SERVERS_QUERIED).asLong(); + long expectedNumServersQueried = expected.get(FIELD_NUM_SERVERS_QUERIED).asLong(); + if (actualNumServersQueried != expectedNumServersQueried) { + LOGGER.error("The numServersQueried don't match! Actual: {}, Expected: {}", actualNumServersQueried, + expectedNumServersQueried); + return false; + } + return true; + } + + private static boolean areNumEntriesScannedInFilterEqual(JsonNode actual, JsonNode expected) { + long actualNumEntriesScannedInFilter = actual.get(FIELD_NUM_ENTRIES_SCANNED_IN_FILTER).asLong(); + long expectedNumEntriesScannedInFilter = expected.get(FIELD_NUM_ENTRIES_SCANNED_IN_FILTER).asLong(); + if (actualNumEntriesScannedInFilter != expectedNumEntriesScannedInFilter) { + LOGGER + .error("The numEntriesScannedInFilter don't match! Actual: {}, Expected: {}", actualNumEntriesScannedInFilter, + expectedNumEntriesScannedInFilter); + return false; + } + return true; + } + + private static boolean areNumEntriesScannedPostFilterEqual(JsonNode actual, JsonNode expected) { + long actualNumEntriesScannedPostFilter = actual.get(FIELD_NUM_ENTRIES_SCANNED_POST_FILTER).asLong(); + long expectedNumEntriesScannedPostFilter = expected.get(FIELD_NUM_ENTRIES_SCANNED_POST_FILTER).asLong(); + if (actualNumEntriesScannedPostFilter != expectedNumEntriesScannedPostFilter) { + LOGGER.error("The numEntriesScannedPostFilter don't match! Actual: {}, Expected: {}", + actualNumEntriesScannedPostFilter, expectedNumEntriesScannedPostFilter); + return false; + } + return true; + } + + private static boolean areNumDocsScannedEqual(JsonNode actual, JsonNode expected) { + int actualNumDocsScanned = actual.get(FIELD_NUM_DOCS_SCANNED).asInt(); + int expectedNumDocsScanned = expected.get(FIELD_NUM_DOCS_SCANNED).asInt(); + if (actualNumDocsScanned != expectedNumDocsScanned) { + LOGGER.error("The numDocsScanned don't match! Actual: {}, Expected: {}", actualNumDocsScanned, + expectedNumDocsScanned); + return false; + } + return true; + } + + private static boolean areEmpty(JsonNode actual, JsonNode expected) { + if (isEmpty(actual) && isEmpty(expected)) { + LOGGER.debug("Empty results, nothing to compare."); + return true; + } + return false; + } + + public static boolean isEmpty(JsonNode response) { + int numDocsScanned = response.get(FIELD_NUM_DOCS_SCANNED).asInt(); + return numDocsScanned == 0 || !response.has(FIELD_RESULT_TABLE) + || response.get(FIELD_RESULT_TABLE).get(FIELD_ROWS).size() == 0; + } + + private static boolean areLengthsEqual(JsonNode actual, JsonNode expected) { + int actualLength = actual.get(FIELD_RESULT_TABLE).get(FIELD_ROWS).size(); + int expectedLength = expected.get(FIELD_RESULT_TABLE).get(FIELD_ROWS).size(); + if (actualLength != expectedLength) { + LOGGER.error("The length of results don't match! Actual: {}, Expected: {}", actualLength, expectedLength); + return false; + } + return true; + } + + private static boolean areDataSchemaEqual(JsonNode actual, JsonNode expected) { + JsonNode actualDataSchema = actual.get(FIELD_RESULT_TABLE).get(FIELD_DATA_SCHEMA); + JsonNode expecteDataSchema = expected.get(FIELD_RESULT_TABLE).get(FIELD_DATA_SCHEMA); + + String actualDataSchemaStr = actualDataSchema.toString(); + String expecteDataSchemaStr = expecteDataSchema.toString(); + if (!actualDataSchemaStr.equals(expecteDataSchemaStr)) { + LOGGER.error("The dataSchema don't match! Actual: {}, Expected: {}", actualDataSchema, expecteDataSchema); + return false; + } + return true; + } + + private static boolean areElementsSubset(List<String> actualElementsSerialized, + List<String> expectedElementsSerialized) { + boolean result = expectedElementsSerialized.containsAll(actualElementsSerialized); + if (!result) { + LOGGER.error("Actual result '{}' is not a subset of '{}'", actualElementsSerialized, expectedElementsSerialized); + } + return result; + } + + private static boolean areElementsEqual(List<String> actualElementsSerialized, + List<String> expectedElementsSerialized, String query) { + if (isOrdered(query)) { + if (!actualElementsSerialized.equals(expectedElementsSerialized)) { + LOGGER.error("The results of the ordered query don't match! Actual: {}, Expected: {}", actualElementsSerialized, + expectedElementsSerialized); + return false; + } + return true; + } + + // sort elements + actualElementsSerialized.sort(null); + expectedElementsSerialized.sort(null); + if (!actualElementsSerialized.equals(expectedElementsSerialized)) { + LOGGER.error("The results of the non-ordered query don't match. Sorted-expected: '{}', sorted-actual: '{}'", + expectedElementsSerialized, actualElementsSerialized); + return false; + } + return true; + } + + private static void convertNumbersToString(ArrayNode rows, ArrayNode columnDataTypes) + throws IOException { + for (int i = 0; i < rows.size(); i++) { + for (int j = 0; j < columnDataTypes.size(); j++) { + ArrayNode row = (ArrayNode) rows.get(i); + String type = columnDataTypes.get(j).asText(); + if (type.equals(FIELD_TYPE_FLOAT) || type.equals(FIELD_TYPE_DOUBLE)) { + double round = Math.round(Double.valueOf(row.get(j).asText()) * 100) / 100.0; + String str = String.valueOf(round); + row.set(j, JsonUtils.stringToJsonNode(str)); + } else if (type.equals(FIELD_TYPE_FLOAT_ARRAY) || type.equals(FIELD_TYPE_DOUBLE_ARRAY)) { + ArrayNode jsonArray = (ArrayNode) rows.get(i).get(j); + List<String> arrayStr = new ArrayList<>(); + for (int k = 0; k < jsonArray.size(); k++) { + double round = Math.round(Double.valueOf(jsonArray.get(k).asText()) * 100) / 100; + arrayStr.add(String.valueOf(round)); + } + row.set(j, JsonUtils.stringToJsonNode(arrayStr.toString())); + } + } + } + } + + private static boolean isOrdered(String query) { + SqlParser sqlParser = SqlParser.create(query, SQL_PARSER_CONFIG); + try { + SqlNode sqlNode = sqlParser.parseQuery(); + boolean isOrderBy = sqlNode.getKind() == SqlKind.ORDER_BY; + if (!isOrderBy) { + return false; + } + SqlOrderBy sqlOrderBy = (SqlOrderBy) sqlNode; + SqlNodeList orderByColumns = sqlOrderBy.orderList; + return orderByColumns != null && orderByColumns.size() != 0; + } catch (SqlParseException e) { + throw new RuntimeException("Cannot parse query: " + query, e); + } + } +} diff --git a/pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json b/pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json index f9d6ac5..7e6a7cc 100644 --- a/pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json +++ b/pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json @@ -1,4 +1,15 @@ { + "fieldConfigList": [ + { + "encodingType": "RAW", + "indexType": "TEXT", + "name": "textDim1", + "properties": { + "deriveNumDocsPerChunkForRawIndex": "true", + "rawIndexWriterVersion": "3" + } + } + ], "metadata": { "customConfigs": { "d2Name": "" diff --git a/pinot-integration-tests/src/test/resources/compat-tests/queries/feature-test-1-sql.queries b/pinot-integration-tests/src/test/resources/compat-tests/queries/feature-test-1-sql.queries new file mode 100644 index 0000000..f0d63e9 --- /dev/null +++ b/pinot-integration-tests/src/test/resources/compat-tests/queries/feature-test-1-sql.queries @@ -0,0 +1,89 @@ +# Aggregation +SELECT count(*) FROM FeatureTest1 +SELECT sum(intMetric1), sumMV(intDimMV1), min(intMetric1), minMV(intDimMV2), max(longDimSV1), maxMV(intDimMV1) FROM FeatureTest1 +SELECT count(longDimSV1), countMV(intDimMV1), avg(floatMetric1), avgMV(intDimMV2), minMaxRange(doubleMetric1), minMaxRangeMV(intDimMV2) FROM FeatureTest1 +SELECT percentile(longDimSV1, 80), percentileMV(intDimMV1, 90), percentileEst(longDimSV1, 80), percentileEstMV(intDimMV1, 90), percentileTDigest(longDimSV1, 80), percentileTDigestMV(intDimMV1, 90) FROM FeatureTest1 +SELECT distinctCount(longDimSV1), distinctCountMV(intDimMV1), distinctCountHLL(longDimSV1), distinctCountHLLMV(intDimMV1) FROM FeatureTest1 + +# Selection +SELECT longDimSV2, stringDimSV1, textDim1, bytesDimSV1 FROM FeatureTest1 ORDER BY longDimSV2 LIMIT 9 +SELECT longDimSV2, stringDimSV1, textDim1, bytesDimSV1 FROM FeatureTest1 ORDER BY longDimSV2 DESC LIMIT 8 +SELECT longDimSV2, stringDimSV1, textDim1, bytesDimSV1 FROM FeatureTest1 ORDER BY longDimSV2 DESC, stringDimSV1 LIMIT 8 + +# Selection & Filtering +SELECT textDim1, longDimSV2, doubleMetric1 FROM FeatureTest1 WHERE bytesDimSV1 = 'deed0507' +# This is a subset comparison query: there are 4 qualified records in total, the query limit the number of returned records as 2, +# the test compares the returned results to be a subset of total qualified results. +# To generate the result file, use this query instead: SELECT textDim1, longDimSV2, doubleMetric1 FROM FeatureTest1 WHERE bytesDimSV1 = 'deed0507' +SELECT textDim1, longDimSV2, doubleMetric1 FROM FeatureTest1 WHERE bytesDimSV1 = 'deed0507' LIMIT 2 +# This is a query exhausting all records: there are 4 qualified records in total, the query limit the number of returned records as 10 +SELECT textDim1, longDimSV2, doubleMetric1 FROM FeatureTest1 WHERE bytesDimSV1 = 'deed0507' LIMIT 10 +SELECT stringDimSV1, longDimSV1, intDimMV1, intDimMV2, stringDimMV2 FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) ORDER BY longDimSV1 LIMIT 5 +SELECT stringDimSV1, longDimSV1, intDimMV1, intDimMV2, stringDimMV2 FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) ORDER BY longDimSV1 DESC +SELECT stringDimSV1, longDimSV1, intDimMV1, intDimMV2, stringDimMV2 FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) ORDER BY longDimSV1 DESC, stringDimSV1 LIMIT 3 + +# Selection & Grouping on Aggregation +SELECT longDimSV1, intDimMV1, count(*) FROM FeatureTest1 GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, sum(intMetric1), sumMV(intDimMV1), min(intMetric1), minMV(intDimMV2), max(longDimSV1), maxMV(intDimMV1) FROM FeatureTest1 GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, count(longDimSV1), countMV(intDimMV1), avg(floatMetric1), avgMV(intDimMV2), minMaxRange(doubleMetric1), minMaxRangeMV(intDimMV2) FROM FeatureTest1 GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, percentile(longDimSV1, 80), percentileMV(intDimMV1, 90), percentileEst(longDimSV1, 80), percentileEstMV(intDimMV1, 90), percentileTDigest(longDimSV1, 80), percentileTDigestMV(intDimMV1, 90) FROM FeatureTest1 GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, distinctCount(longDimSV1), distinctCountMV(intDimMV1), distinctCountHLL(longDimSV1), distinctCountHLLMV(intDimMV1) FROM FeatureTest1 GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1 LIMIT 5 + +# Selection & Filtering & Grouping on Aggregation +SELECT longDimSV1, intDimMV1, count(*) FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1, intDimMV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, sum(intMetric1), sumMV(intDimMV1), min(intMetric1), minMV(intDimMV2), max(longDimSV1), maxMV(intDimMV1) FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1, intDimMV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, count(longDimSV1), countMV(intDimMV1), avg(floatMetric1), avgMV(intDimMV2), minMaxRange(doubleMetric1), minMaxRangeMV(intDimMV2) FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1, intDimMV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, percentile(longDimSV1, 80), percentileMV(intDimMV1, 90), percentileEst(longDimSV1, 80), percentileEstMV(intDimMV1, 90), percentileTDigest(longDimSV1, 80), percentileTDigestMV(intDimMV1, 90) FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1, intDimMV1 LIMIT 5 +SELECT longDimSV1, intDimMV1, distinctCount(longDimSV1), distinctCountMV(intDimMV1), distinctCountHLL(longDimSV1), distinctCountHLLMV(intDimMV1) FROM FeatureTest1 WHERE stringDimSV1 != 's1-6' AND longDimSV1 BETWEEN 10 AND 1000 OR (intDimMV1 < 42 AND stringDimMV2 IN ('m2-0-0', 'm2-2-0') AND intDimMV2 NOT IN (6,72)) GROUP BY longDimSV1, intDimMV1 ORDER BY longDimSV1, intDimMV1 LIMIT 5 + +# Transformation Functions +SELECT add(longDimSV1, sub(longDimSV2, 3)), mod(intMetric1, 10), div(doubleMetric1, mult(floatMetric1, 5)) FROM FeatureTest1 ORDER BY add(longDimSV1, sub(longDimSV2, 3)) DESC, mod(intMetric1, 10) +SELECT floor(sqrt(doubleMetric1)), ceil(ln(longDimSV1)), exp(mod(abs(longDimSV2), 3)) FROM FeatureTest1 ORDER BY floor(sqrt(doubleMetric1)), ceil(ln(longDimSV1)), exp(mod(abs(longDimSV2), 3)) DESC +SELECT count(*) FROM FeatureTest1 GROUP BY arrayLength(intDimMV1), arrayLength(valueIn(stringDimMV2, 'm2-2-0', 'm2-3-0')) +SELECT valueIn(intDimMV1, 3, 32), count(*) FROM FeatureTest1 GROUP BY valueIn(intDimMV1, 3, 32) +SELECT upper(stringDimSV1), lower(textDim1), reverse(stringDimSV2), ltrim(substr(textDim1, 4, 9)), rtrim(substr(textDim1, 4, 9)) from FeatureTest1 ORDER BY upper(stringDimSV1) LIMIT 10 +SELECT stringDimSV2, replace(stringDimSV2, 'foo', 'bar'), codePoint(stringDimSV2), rpad(stringDimSV2, 11, 'abc'), lpad(stringDimSV2, 11, 'xyz') from FeatureTest1 WHERE strPos(stringDimSV2, '2', 2) > 1 OR startsWith(stringDimSV2, 'foo') = 'true' ORDER BY codePoint(stringDimSV2), replace(stringDimSV2, 'foo', 'bar') LIMIT 10 + +# Groovy Scripts +SELECT longDimSV1, longDimSV2, groovy('{"returnType":"LONG","isSingleValue":true}', 'arg0 + arg1', longDimSV1, longDimSV2) FROM FeatureTest1 ORDER BY longDimSV1, longDimSV2 DESC LIMIT 10 +SELECT count(*), groovy('{"returnType":"STRING", "isSingleValue":true}', 'def result; if (arg0 < 0) { result = "NEGATIVE"; } else if (arg0 < 10) { result = "SMALL";} else if (arg0 < 50) { result = "MEDIUM";} else{result = "LARGE"}; return result', longDimSV1) FROM FeatureTest1 GROUP BY groovy('{"returnType":"STRING", "isSingleValue":true}', 'def result; if (arg0 < 0) { result = "NEGATIVE"; } else if (arg0 < 10) { result = "SMALL";} else if (arg0 < 50) { result = "MEDIUM";} else{result = [...] +SELECT groovy('{"returnType":"INT","isSingleValue":true}', 'arg0.toList().max()', intDimMV1) FROM FeatureTest1 ORDER BY groovy('{"returnType":"INT","isSingleValue":true}', 'arg0.toList().max()', intDimMV1) LIMIT 10 + +# Text Search +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, 'Java') +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, 'Java AND C++') +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, 'Java OR C++') AND longDimSV1 > 20 LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, 'Java C++') AND longDimSV1 > 20 LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, '"Java C++"') LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, '"java c++" "golang python"') LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, '"Java C++" AND (golang python)') LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, '(Java OR C++) AND (golang python)') AND longDimSV1 > 20 LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, 'go*') LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, 'word go*') LIMIT 20 +SELECT stringDimSV1, textDim1 FROM FeatureTest1 WHERE text_match(textDim1, '/go.*g/') LIMIT 20 +SELECT stringDimSV1, count(stringDimSV1) FROM FeatureTest1 WHERE text_match(textDim1, 'Java') GROUP BY stringDimSV1 ORDER BY count(stringDimSV1) DESC LIMIT 20 + +# Map +SELECT stringDimSV1, mapValue(mapDim1__KEYS, 'k1', mapDim1__VALUES), mapValue(mapDim1__KEYS, 'k4', mapDim1__VALUES) FROM FeatureTest1 LIMIT 5 +SELECT stringDimSV1, mapValue(mapDim1__KEYS, 'k1', mapDim1__VALUES), mapValue(mapDim1__KEYS, 'k4', mapDim1__VALUES) FROM FeatureTest1 ORDER BY mapValue(mapDim1__KEYS, 'k1', mapDim1__VALUES) LIMIT 5 +SELECT max(mapValue(mapDim1__KEYS, 'k2', mapDim1__VALUES)), min(mapValue(mapDim1__KEYS, 'k3', mapDim1__VALUES)) FROM FeatureTest1 +SELECT max(mapValue(mapDim1__KEYS, 'k2', mapDim1__VALUES)), min(mapValue(mapDim1__KEYS, 'k3', mapDim1__VALUES)) FROM FeatureTest1 GROUP BY mapValue(mapDim1__KEYS, 'k1', mapDim1__VALUES) ORDER BY max(mapValue(mapDim1__KEYS, 'k2', mapDim1__VALUES)) LIMIT 5 +SELECT mapValue(mapDim1__KEYS, 'k1', mapDim1__VALUES), mapValue(mapDim1__KEYS, 'k2', mapDim1__VALUES) FROM FeatureTest1 WHERE mapValue(mapDim1__KEYS, 'k1', mapDim1__VALUES) <= 4 LIMIT 5 +SELECT mapValue(mapDim1__KEYS, 'k1', mapDim1__VALUES), mapValue(mapDim1__KEYS, 'k2', mapDim1__VALUES) FROM FeatureTest1 WHERE mapValue(mapDim1__KEYS, 'non-existing-key', mapDim1__VALUES) <= 4 +SELECT mapValue(mapDim1__KEYS, 'non-existing-key', mapDim1__VALUES) FROM FeatureTest1 WHERE mapDim1__KEYS = 'non-existing-key' + +# Json Map +SELECT stringDimSV1, jsonExtractScalar(mapDim2json, '$.k1', 'INT'), jsonExtractScalar(mapDim2json, '$.k4', 'INT') FROM FeatureTest1 LIMIT 5 +SELECT stringDimSV1, jsonExtractScalar(mapDim2json, '$.k1', 'INT'), jsonExtractScalar(mapDim2json, '$.k4', 'INT') FROM FeatureTest1 ORDER BY jsonExtractScalar(mapDim2json, '$.k1', 'INT') LIMIT 5 +SELECT max(jsonExtractScalar(mapDim2json, '$.k2', 'INT')), min(jsonExtractScalar(mapDim2json, '$.k3', 'INT')) FROM FeatureTest1 +SELECT max(jsonExtractScalar(mapDim2json, '$.k2', 'INT')), min(jsonExtractScalar(mapDim2json, '$.k3', 'INT')) FROM FeatureTest1 GROUP BY jsonExtractScalar(mapDim2json, '$.k1', 'INT') ORDER BY max(jsonExtractScalar(mapDim2json, '$.k2', 'INT')) LIMIT 5 +SELECT jsonExtractScalar(mapDim2json, '$.k1', 'INT'), jsonExtractScalar(mapDim2json, '$.k2', 'INT') FROM FeatureTest1 WHERE jsonExtractScalar(mapDim2json, '$.k1', 'INT') <= 4 LIMIT 5 +SELECT jsonExtractScalar(mapDim2json, '$.non-existing-key', 'INT', '-1') FROM FeatureTest1 +SELECT jsonExtractScalar(mapDim2json, '$.non-existing-key', 'INT') FROM FeatureTest1 WHERE jsonExtractKey(mapDim2json, '$.*') in ("$['non-existing-key']") + +# Misc +SELECT count(*) FROM FeatureTest1 WHERE regexp_like(textDim1, '^Java.*') GROUP BY longDimSV1 +SELECT count(*) FROM FeatureTest1 WHERE regexp_like(stringDimMV2, 'm2.*0') GROUP BY stringDimMV2 LIMIT 3 +SELECT stringDimSV1, longDimSV1, intDimMV1 FROM FeatureTest1 ORDER BY stringDimSV1 DESC, longDimSV1 LIMIT 3 +SELECT stringDimSV1, longDimSV1, intDimMV1 FROM FeatureTest1 ORDER BY stringDimSV1 DESC, longDimSV1 DESC LIMIT 3 +SELECT * FROM FeatureTest1 ORDER BY longDimSV1 DESC, longMetric1 LIMIT 3 \ No newline at end of file diff --git a/pinot-integration-tests/src/test/resources/compat-tests/query-op.yaml b/pinot-integration-tests/src/test/resources/compat-tests/query-op.yaml new file mode 100644 index 0000000..03b6acf --- /dev/null +++ b/pinot-integration-tests/src/test/resources/compat-tests/query-op.yaml @@ -0,0 +1,49 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License 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. +# + +# Operations to be done. +description: Debug yaml file for query ops +operations: + - type: tableOp + description: Create table feature-test-1.json + op: CREATE + schemaFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/FeatureTest1-schema.json + tableConfigFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json + - type: segmentOp + description: Build and upload segment using FeatureTest1-data-00.csv + op: UPLOAD + inputDataFileName: pinot-integration-tests/src/test/resources/compat-tests/data/FeatureTest1-data-00.csv + schemaFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/FeatureTest1-schema.json + tableConfigFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json + recordReaderConfigFileName: pinot-integration-tests/src/test/resources/compat-tests/data/recordReaderConfig.json + segmentName: FeatureTest1_Segment + - type: queryOp + description: Run query on FeatureTest1 using SQL + queryFileName: pinot-integration-tests/src/test/resources/compat-tests/queries/feature-test-1-sql.queries + expectedResultsFileName: pinot-integration-tests/src/test/resources/compat-tests/query-results/feature-test-1-rest-sql.results + - type: segmentOp + description: Delete segment FeatureTest1_Segment + op: DELETE + tableConfigFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json + segmentName: FeatureTest1_Segment + - type: tableOp + description: Delete table feature-test-1.json + op: DELETE + schemaFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/FeatureTest1-schema.json + tableConfigFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json \ No newline at end of file diff --git a/pinot-integration-tests/src/test/resources/compat-tests/query-results/feature-test-1-rest-sql.results b/pinot-integration-tests/src/test/resources/compat-tests/query-results/feature-test-1-rest-sql.results new file mode 100644 index 0000000..64774c1 --- /dev/null +++ b/pinot-integration-tests/src/test/resources/compat-tests/query-results/feature-test-1-rest-sql.results @@ -0,0 +1,85 @@ +# Aggregation +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG"],"columnNames":["count(*)"]},"rows":[[10]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":0,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":4,"segmentStatistics":[],"traceInfo":{},"minConsumingFreshnessTimeMs":0} +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE","DOUBLE","DOUBLE","DOUBLE","DOUBLE"],"columnNames":["sum(intMetric1)","summv(intDimMV1)","min(intMetric1)","minmv(intDimMV2)","max(longDimSV1)","maxmv(intDimMV1)"]},"rows":[[4.294967536E9,-2.147479976E9,0.0,6.0,7611.0,462.0]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesSc [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","LONG","DOUBLE","DOUBLE","DOUBLE","DOUBLE"],"columnNames":["count(*)","countmv(intDimMV1)","avg(floatMetric1)","avgmv(intDimMV2)","minmaxrange(doubleMetric1)","minmaxrangemv(intDimMV2)"]},"rows":[[10,19,114.09000263214111,1516.9,250.00000000000003,6656.0]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScann [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE","LONG","LONG","DOUBLE","DOUBLE"],"columnNames":["percentile(longDimSV1, 80.0)","percentilemv(intDimMV1, 90.0)","percentileest(longDimSV1, 80.0)","percentileestmv(intDimMV1, 90.0)","percentiletdigest(longDimSV1, 80.0)","percentiletdigestmv(intDimMV1, 90.0)"]},"rows":[[7611.0,462.0,7611,462,7611.0,462.0]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegme [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["INT","INT","LONG","LONG"],"columnNames":["distinctcount(longDimSV1)","distinctcountmv(intDimMV1)","distinctcounthll(longDimSV1)","distinctcounthllmv(intDimMV1)"]},"rows":[[6,8,6,8]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":20,"numGroupsL [...] + +# Selection +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","STRING","STRING","BYTES"],"columnNames":["longDimSV2","stringDimSV1","textDim1","bytesDimSV1"]},"rows":[[2,"s1-0","Java C++ Python","4877625602"],[2,"s1-0","Java C++ Python","01a0bc"],[21,"s1-2","Java C++ golang","13225573e3f5"],[21,"s1-2","Java C++ golang","deadbeef"],[22,"s1-4","Java C++ golang","deed0507"],[32,"s1-5","golang shell bash",""],[6777,"s1-7","golang Java","d54d0507"],[7621,"s1-6","C++ golang python","deed0507"],[7621 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","STRING","STRING","BYTES"],"columnNames":["longDimSV2","stringDimSV1","textDim1","bytesDimSV1"]},"rows":[[7621,"s1-6","C++ golang python","deed0507"],[7621,"s1-6","C++ golang python","deed0507"],[7621,"s1-6","C++ golang python","deed0507"],[6777,"s1-7","golang Java","d54d0507"],[32,"s1-5","golang shell bash",""],[22,"s1-4","Java C++ golang","deed0507"],[21,"s1-2","Java C++ golang","13225573e3f5"],[21,"s1-2","Java C++ golang","deadbe [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","STRING","STRING","BYTES"],"columnNames":["longDimSV2","stringDimSV1","textDim1","bytesDimSV1"]},"rows":[[7621,"s1-6","C++ golang python","deed0507"],[7621,"s1-6","C++ golang python","deed0507"],[7621,"s1-6","C++ golang python","deed0507"],[6777,"s1-7","golang Java","d54d0507"],[32,"s1-5","golang shell bash",""],[22,"s1-4","Java C++ golang","deed0507"],[21,"s1-2","Java C++ golang","13225573e3f5"],[21,"s1-2","Java C++ golang","deadbe [...] + +# Selection & Filtering +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","DOUBLE"],"columnNames":["textDim1","longDimSV2","doubleMetric1"]},"rows":[["Java C++ golang",22,24.1],["C++ golang python",7621,263.1],["C++ golang python",7621,263.1],["C++ golang python",7621,263.1]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":4,"numEntriesScannedInFilter":10,"numEntr [...] +{"isSuperset":true,"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","DOUBLE"],"columnNames":["textDim1","longDimSV2","doubleMetric1"]},"rows":[["Java C++ golang",22,24.1],["C++ golang python",7621,263.1],["C++ golang python",7621,263.1],["C++ golang python",7621,263.1]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":4,"numEntriesScannedInF [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","DOUBLE"],"columnNames":["textDim1","longDimSV2","doubleMetric1"]},"rows":[["Java C++ golang",22,24.1],["C++ golang python",7621,263.1],["C++ golang python",7621,263.1],["C++ golang python",7621,263.1]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":4,"numEntriesScannedInFilter":10,"numEntr [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","INT_ARRAY","INT_ARRAY","STRING_ARRAY"],"columnNames":["stringDimSV1","longDimSV1","intDimMV1","intDimMV2","stringDimMV2"]},"rows":[["s1-5",-9223372036854775808,[-2147483648],[92,22],["m2-2-0"]],["s1-2",11,[32,42],[62,72],["m2-2-0","m2-2-1"]],["s1-2",11,[32,42],[62,72],["m2-3-0","m2-3-1"]],["s1-4",41,[42,52],[72,82],["m2-2-0","m2-2-1"]]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1," [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","INT_ARRAY","INT_ARRAY","STRING_ARRAY"],"columnNames":["stringDimSV1","longDimSV1","intDimMV1","intDimMV2","stringDimMV2"]},"rows":[["s1-4",41,[42,52],[72,82],["m2-2-0","m2-2-1"]],["s1-2",11,[32,42],[62,72],["m2-2-0","m2-2-1"]],["s1-2",11,[32,42],[62,72],["m2-3-0","m2-3-1"]],["s1-5",-9223372036854775808,[-2147483648],[92,22],["m2-2-0"]]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1," [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","INT_ARRAY","INT_ARRAY","STRING_ARRAY"],"columnNames":["stringDimSV1","longDimSV1","intDimMV1","intDimMV2","stringDimMV2"]},"rows":[["s1-4",41,[42,52],[72,82],["m2-2-0","m2-2-1"]],["s1-2",11,[32,42],[62,72],["m2-3-0","m2-3-1"]],["s1-2",11,[32,42],[62,72],["m2-2-0","m2-2-1"]]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSeg [...] + +# Selection & Grouping on Aggregation +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","LONG"],"columnNames":["longDimSV1","intDimMV1","count(*)"]},"rows":[[-9223372036854775808,-2147483648,1],[1,3,2],[1,4,2],[11,42,2],[11,32,2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":20,"numGroupsLimitReached":false,"totalDo [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","DOUBLE","DOUBLE","DOUBLE","DOUBLE","DOUBLE","DOUBLE"],"columnNames":["longDimSV1","intDimMV1","sum(intMetric1)","summv(intDimMV1)","min(intMetric1)","minmv(intDimMV2)","max(longDimSV1)","maxmv(intDimMV1)"]},"rows":[[-9223372036854775808,-2147483648,0.0,-2.147483648E9,0.0,22.0,-9.223372036854776E18,-2.147483648E9],[1,3,20.0,14.0,10.0,6.0,1.0,4.0],[1,4,20.0,14.0,10.0,6.0,1.0,4.0],[11,42,20.0,148.0,10.0,62.0,11.0,42.0],[11,32,20 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","LONG","LONG","DOUBLE","DOUBLE","DOUBLE","DOUBLE"],"columnNames":["longDimSV1","intDimMV1","count(*)","countmv(intDimMV1)","avg(floatMetric1)","avgmv(intDimMV2)","minmaxrange(doubleMetric1)","minmaxrangemv(intDimMV2)"]},"rows":[[-9223372036854775808,-2147483648,1,1,0.0,57.0,0.0,70.0],[1,3,2,4,12.100000381469727,6.5,0.0,1.0],[1,4,2,4,12.100000381469727,6.5,0.0,1.0],[11,42,2,4,22.100000381469727,67.0,0.0,10.0],[11,32,2,4,22.1000 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","DOUBLE","DOUBLE","LONG","LONG","DOUBLE","DOUBLE"],"columnNames":["longDimSV1","intDimMV1","percentile(longDimSV1, 80.0)","percentilemv(intDimMV1, 90.0)","percentileest(longDimSV1, 80.0)","percentileestmv(intDimMV1, 90.0)","percentiletdigest(longDimSV1, 80.0)","percentiletdigestmv(intDimMV1, 90.0)"]},"rows":[[-9223372036854775808,-2147483648,-9.223372036854776E18,-2.147483648E9,-9223372036854775808,-2147483648,-9.2233720368547 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","INT","INT","LONG","LONG"],"columnNames":["longDimSV1","intDimMV1","distinctcount(longDimSV1)","distinctcountmv(intDimMV1)","distinctcounthll(longDimSV1)","distinctcounthllmv(intDimMV1)"]},"rows":[[-9223372036854775808,-2147483648,1,1,1,1],[1,3,1,2,1,2],[1,4,1,2,1,2],[11,42,1,2,1,2],[11,32,1,2,1,2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatche [...] + +# Selection & Filtering & Grouping on Aggregation +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","LONG"],"columnNames":["longDimSV1","intDimMV1","count(*)"]},"rows":[[-9223372036854775808,-2147483648,1],[11,32,2],[11,42,2],[41,42,1],[41,52,1]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":4,"numEntriesScannedInFilter":33,"numEntriesScannedPostFilter":8,"numGroupsLimitReached":false,"tota [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","DOUBLE","DOUBLE","DOUBLE","DOUBLE","DOUBLE","DOUBLE"],"columnNames":["longDimSV1","intDimMV1","sum(intMetric1)","summv(intDimMV1)","min(intMetric1)","minmv(intDimMV2)","max(longDimSV1)","maxmv(intDimMV1)"]},"rows":[[-9223372036854775808,-2147483648,0,-2147483648,0,22,-9223372036854776000,-2147483648],[11,32,20,148,10,62,11,42],[11,42,20,148,10,62,11,42],[41,42,14,94,14,72,41,52],[41,52,14,94,14,72,41,52]]},"exceptions":[],"nu [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","LONG","LONG","DOUBLE","DOUBLE","DOUBLE","DOUBLE"],"columnNames":["longDimSV1","intDimMV1","count(*)","countmv(intDimMV1)","avg(floatMetric1)","avgmv(intDimMV2)","minmaxrange(doubleMetric1)","minmaxrangemv(intDimMV2)"]},"rows":[[-9223372036854775808,-2147483648,1,1,0,57,0,70],[11,32,2,4,22.100000381469727,67,0,10],[11,42,2,4,22.100000381469727,67,0,10],[41,42,1,2,24.100000381469727,77,0,10],[41,52,1,2,24.100000381469727,77,0,1 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","DOUBLE","DOUBLE","LONG","LONG","DOUBLE","DOUBLE"],"columnNames":["longDimSV1","intDimMV1","percentile(longDimSV1, 80.0)","percentilemv(intDimMV1, 90.0)","percentileest(longDimSV1, 80.0)","percentileestmv(intDimMV1, 90.0)","percentiletdigest(longDimSV1, 80.0)","percentiletdigestmv(intDimMV1, 90.0)"]},"rows":[[-9223372036854775808,-2147483648,-9223372036854775808,-2147483648,-9223372036854775808,-2147483648,-9223372036854776000 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","INT","INT","INT","LONG","LONG"],"columnNames":["longDimSV1","intDimMV1","distinctcount(longDimSV1)","distinctcountmv(intDimMV1)","distinctcounthll(longDimSV1)","distinctcounthllmv(intDimMV1)"]},"rows":[[-9223372036854775808,-2147483648,1,1,1,1],[11,32,1,2,1,2],[11,42,1,2,1,2],[41,42,1,2,1,2],[41,52,1,2,1,2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMa [...] + +# Transformation Functions +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE","DOUBLE"],"columnNames":["add(longDimSV1,sub(longDimSV2,'3'))","mod(intMetric1,'10')","div(doubleMetric1,mult(floatMetric1,'5'))"]},"rows":[[15229.0,1.0,0.20076306285631254],[15229.0,7.0,0.20076306285631254],[15229.0,7.0,0.20076306285631254],[13540.0,7.0,0.20076306285631254],[60.0,4.0,0.1999999968342762],[29.0,0.0,0.20904977014723267],[29.0,0.0,0.20904977014723267],[0.0,0.0,0.21652891879345226],[0.0,0.0,0.2165289187934522 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE","DOUBLE"],"columnNames":["floor(sqrt(doubleMetric1))","ceil(ln(longDimSV1))","exp(mod(abs(longDimSV2),'3'))"]},"rows":[[3.0,0.0,7.38905609893065],[3.0,0.0,7.38905609893065],[4.0,3.0,1.0],[4.0,3.0,1.0],[4.0,4.0,2.718281828459045],[4.0,"NaN",7.38905609893065],[16.0,9.0,2.718281828459045],[16.0,9.0,2.718281828459045],[16.0,9.0,2.718281828459045],[16.0,9.0,1.0]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1," [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG"],"columnNames":["count(*)"]},"rows":[[6],[1],[3]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":20,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":9,"segmentStatistics":[],"traceInfo":{},"minConsumingFreshnessTimeMs":0} +{"resultTable":{"dataSchema":{"columnDataTypes":["INT","LONG"],"columnNames":["valuein(intDimMV1,'3','32')","count(*)"]},"rows":[[3,2],[32,2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":10,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":18,"segmentStatistics":[],"traceInfo":{}," [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING","STRING","STRING","STRING"],"columnNames":["upper(stringDimSV1)","lower(textDim1)","reverse(stringDimSV2)","ltrim(substr(textDim1,'4','9'))","rtrim(substr(textDim1,'4','9'))"]},"rows":[["S1-0","java c++ python","0-2s","C++ "," C++"],["S1-0","java c++ python","0-2s","C++ "," C++"],["S1-2","java c++ golang","2-2s","C++ "," C++"],["S1-2","java c++ golang","2-2s","C++ "," C++"],["S1-4","java c++ golang","4-2s","C++ "," C++"], [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING","INT","STRING","STRING"],"columnNames":["stringDimSV2","replace(stringDimSV2,'foo','bar')","codepoint(stringDimSV2)","rpad(stringDimSV2,'11','abc')","lpad(stringDimSV2,'11','xyz')"]},"rows":[["s2-2","s2-2",115,"s2-2abcabca","xyzxyzxs2-2"],["s2-2","s2-2",115,"s2-2abcabca","xyzxyzxs2-2"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"nu [...] + +# Groovy Scripts +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","LONG","LONG"],"columnNames":["longDimSV1","longDimSV2","groovy('{\"returnType\":\"LONG\",\"isSingleValue\":true}','arg0 + arg1',longDimSV1,longDimSV2)"]},"rows":[[-9223372036854775808,32,-9223372036854775776],[1,2,3],[1,2,3],[11,21,32],[11,21,32],[41,22,63],[6766,6777,13543],[7611,7621,15232],[7611,7621,15232],[7611,7621,15232]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProces [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG","STRING"],"columnNames":["count(*)","groovy('{\"returnType\":\"STRING\", \"isSingleValue\":true}','def result; if (arg0 < 0) { result = \"NEGATIVE\"; } else if (arg0 < 10) { result = \"SMALL\";} else if (arg0 < 50) { result = \"MEDIUM\";} else{result = \"LARGE\"}; return result',longDimSV1)"]},"rows":[[4,"LARGE"],[3,"MEDIUM"],[2,"SMALL"],[1,"NEGATIVE"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueri [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["INT"],"columnNames":["groovy('{\"returnType\":\"INT\",\"isSingleValue\":true}','arg0.toList().max()',intDimMV1)"]},"rows":[[-2147483648],[4],[4],[42],[42],[52],[462],[462],[462],[462]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":10,"numGrou [...] + +# Text Search +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-0","Java C++ Python"],["s1-0","Java C++ Python"],["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"],["s1-7","golang Java"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":6,"numEntriesScannedInFilter":0 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-0","Java C++ Python"],["s1-0","Java C++ Python"],["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":0,"numEntriesScannedPost [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-4","Java C++ golang"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-7","golang Java"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":9,"numEntriesScannedPo [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-4","Java C++ golang"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-7","golang Java"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":9,"numEntriesScannedPo [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-0","Java C++ Python"],["s1-0","Java C++ Python"],["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":0,"numEntriesScannedPost [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-0","Java C++ Python"],["s1-0","Java C++ Python"],["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-6","C++ golang python"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSeg [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-0","Java C++ Python"],["s1-0","Java C++ Python"],["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":0,"numEntriesScannedPost [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-4","Java C++ golang"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-7","golang Java"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":9,"numEntriesScannedPo [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"],["s1-5","golang shell bash"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-7","golang Java"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegme [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"],["s1-5","golang shell bash"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-7","golang Java"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegme [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","STRING"],"columnNames":["stringDimSV1","textDim1"]},"rows":[["s1-2","Java C++ golang"],["s1-2","Java C++ golang"],["s1-4","Java C++ golang"],["s1-5","golang shell bash"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-6","C++ golang python"],["s1-7","golang Java"]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegme [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG"],"columnNames":["stringDimSV1","count(*)"]},"rows":[["s1-2",2],["s1-0",2],["s1-7",1],["s1-4",1]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":6,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":6,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":6,"segmentStatistics":[], [...] + +# Map +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","INT","INT"],"columnNames":["stringDimSV1","mapvalue(mapDim1__KEYS,'k1',mapDim1__VALUES)","mapvalue(mapDim1__KEYS,'k4',mapDim1__VALUES)"]},"rows":[["s1-0",1,2],["s1-0",3,3],["s1-2",4,7],["s1-2",7,7],["s1-4",7,8]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":0,"numEn [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","INT","INT"],"columnNames":["stringDimSV1","mapvalue(mapDim1__KEYS,'k1',mapDim1__VALUES)","mapvalue(mapDim1__KEYS,'k4',mapDim1__VALUES)"]},"rows":[["s1-0",1,2],["s1-0",3,3],["s1-2",4,7],["s1-4",7,8],["s1-2",7,7]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numE [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE"],"columnNames":["max(mapvalue(mapDim1__KEYS,'k2',mapDim1__VALUES))","min(mapvalue(mapDim1__KEYS,'k3',mapDim1__VALUES))"]},"rows":[[31,2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":20,"numGroupsLimitReached":false,"totalDo [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE"],"columnNames":["max(mapvalue(mapDim1__KEYS,'k2',mapDim1__VALUES))","min(mapvalue(mapDim1__KEYS,'k3',mapDim1__VALUES))"]},"rows":[[1,2],[3,3],[5,6],[8,7],[31,32]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":20,"numGroupsLim [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["INT","INT"],"columnNames":["mapvalue(mapDim1__KEYS,'k1',mapDim1__VALUES)","mapvalue(mapDim1__KEYS,'k2',mapDim1__VALUES)"]},"rows":[[1,1],[3,3],[4,5]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":3,"numEntriesScannedInFilter":10,"numEntriesScannedPostFilter":6,"numGroupsLimitReached":false,"totalDocs":10 [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["INT","INT"],"columnNames":["mapvalue(mapDim1__KEYS,'k1',mapDim1__VALUES)","mapvalue(mapDim1__KEYS,'k2',mapDim1__VALUES)"]},"rows":[]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":0,"numConsumingSegmentsQueried":0,"numDocsScanned":0,"numEntriesScannedInFilter":10,"numEntriesScannedPostFilter":0,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":12, [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING"],"columnNames":["mapvalue(mapDim1__KEYS,'non-existing-key',mapDim1__VALUES)"]},"rows":[]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":0,"numSegmentsMatched":0,"numConsumingSegmentsQueried":0,"numDocsScanned":0,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":0,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":3,"segmentStatistics":[],"traceInfo":{}, [...] + +# Json Map +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","INT","INT"],"columnNames":["stringDimSV1","jsonextractscalar(mapDim2json,'$.k1','INT')","jsonextractscalar(mapDim2json,'$.k4','INT')"]},"rows":[["s1-0",1,2],["s1-0",3,3],["s1-2",4,7],["s1-2",7,7],["s1-4",7,8]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":0,"numEntr [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","INT","INT"],"columnNames":["stringDimSV1","jsonextractscalar(mapDim2json,'$.k1','INT')","jsonextractscalar(mapDim2json,'$.k4','INT')"]},"rows":[["s1-0",1,2],["s1-0",3,3],["s1-2",4,7],["s1-4",7,8],["s1-2",7,7]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEnt [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE"],"columnNames":["max(jsonextractscalar(mapDim2json,'$.k2','INT'))","min(jsonextractscalar(mapDim2json,'$.k3','INT'))"]},"rows":[[31,2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":10,"numGroupsLimitReached":false,"totalDocs [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["DOUBLE","DOUBLE"],"columnNames":["max(jsonextractscalar(mapDim2json,'$.k2','INT'))","min(jsonextractscalar(mapDim2json,'$.k3','INT'))"]},"rows":[[1,2],[3,3],[5,6],[8,7],[31,32]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":10,"numGroupsLimit [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["INT","INT"],"columnNames":["jsonextractscalar(mapDim2json,'$.k1','INT')","jsonextractscalar(mapDim2json,'$.k2','INT')"]},"rows":[[1,1],[3,3],[4,5]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":3,"numEntriesScannedInFilter":10,"numEntriesScannedPostFilter":3,"numGroupsLimitReached":false,"totalDocs":10," [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["INT"],"columnNames":["jsonextractscalar(mapDim2json,'$.non-existing-key','INT','-1')"]},"rows":[[-1],[-1],[-1],[-1],[-1],[-1],[-1],[-1],[-1],[-1]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":10,"numGroupsLimitReached":false,"totalDocs":10," [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["INT"],"columnNames":["jsonextractscalar(mapDim2json,'$.non-existing-key','INT')"]},"rows":[]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":0,"numConsumingSegmentsQueried":0,"numDocsScanned":0,"numEntriesScannedInFilter":50,"numEntriesScannedPostFilter":0,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":7,"segmentStatistics":[],"traceInfo":{},"mi [...] + +# Misc +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG"],"columnNames":["count(*)"]},"rows":[[2],[1],[2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":5,"numEntriesScannedInFilter":10,"numEntriesScannedPostFilter":5,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":6,"segmentStatistics":[],"traceInfo":{},"minConsumingFreshnessTimeMs":0} +{"resultTable":{"dataSchema":{"columnDataTypes":["LONG"],"columnNames":["count(*)"]},"rows":[[6],[2],[2]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":16,"numEntriesScannedPostFilter":10,"numGroupsLimitReached":false,"totalDocs":10,"timeUsedMs":4,"segmentStatistics":[],"traceInfo":{},"minConsumingFreshnessTimeMs":0} +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","INT_ARRAY"],"columnNames":["stringDimSV1","longDimSV1","intDimMV1"]},"rows":[["s1-7",6766,[392,462]],["s1-6",7611,[392,462]],["s1-6",7611,[392,462]]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":33,"numGroupsLimitReached":fal [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["STRING","LONG","INT_ARRAY"],"columnNames":["stringDimSV1","longDimSV1","intDimMV1"]},"rows":[["s1-7",6766,[392,462]],["s1-6",7611,[392,462]],["s1-6",7611,[392,462]]]},"exceptions":[],"numServersQueried":1,"numServersResponded":1,"numSegmentsQueried":1,"numSegmentsProcessed":1,"numSegmentsMatched":1,"numConsumingSegmentsQueried":0,"numDocsScanned":10,"numEntriesScannedInFilter":0,"numEntriesScannedPostFilter":33,"numGroupsLimitReached":fal [...] +{"resultTable":{"dataSchema":{"columnDataTypes":["BYTES","DOUBLE","FLOAT","INT_ARRAY","INT_ARRAY","INT","LONG","LONG","LONG","STRING_ARRAY","INT_ARRAY","STRING","STRING_ARRAY","STRING_ARRAY","STRING","STRING","STRING"],"columnNames":["bytesDimSV1","doubleMetric1","floatMetric1","intDimMV1","intDimMV2","intMetric1","longDimSV1","longDimSV2","longMetric1","mapDim1__KEYS","mapDim1__VALUES","mapDim2json","stringDimMV1","stringDimMV2","stringDimSV1","stringDimSV2","textDim1"]},"rows":[["deed0 [...] \ No newline at end of file diff --git a/pinot-integration-tests/src/test/resources/compat-tests/table-segment-op.yaml b/pinot-integration-tests/src/test/resources/compat-tests/table-segment-op.yaml index 9379db7..58f7eae 100644 --- a/pinot-integration-tests/src/test/resources/compat-tests/table-segment-op.yaml +++ b/pinot-integration-tests/src/test/resources/compat-tests/table-segment-op.yaml @@ -38,3 +38,8 @@ operations: op: DELETE tableConfigFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json segmentName: FeatureTest1_Segment + - type: tableOp + description: Delete table feature-test-1.json + op: DELETE + schemaFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/FeatureTest1-schema.json + tableConfigFileName: pinot-integration-tests/src/test/resources/compat-tests/configs/feature-test-1.json --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org