!611 Heuristic Index Bitmap Index Operator Functionality Features

Merge pull request !611 from Daniel Zhang/hindex-splits-test
This commit is contained in:
i-robot 2021-02-27 04:10:57 +08:00 committed by Gitee
commit 14eadcdebe
13 changed files with 426 additions and 678 deletions

View File

@ -24,6 +24,12 @@ such as a Gender column.
## Supported operators
= Equality
> Greater than
>= Greater than or equal
< Less than
<= Less than or equal
BETWEEN Between range
IN IN set
## Supported column types
"integer", "smallint", "bigint", "tinyint", "varchar", "char", "boolean", "double", "real", "date"
@ -42,4 +48,10 @@ create index idx using bitmap on hive.hindex.users (gender) where regionkey in (
Using index:
```sql
select name from hive.hindex.users where gender="female"
select * from hive.hindex.users where id>123
select * from hive.hindex.users where id<123
select * from hive.hindex.users where id>=123
select * from hive.hindex.users where id<=123
select * from hive.hindex.users where id between (100, 200)
select * from hive.hindex.users where id in (123, 199)
```

View File

@ -18,7 +18,13 @@ BitMap索引在拥有较少不同值数量的列上比较适用例如
## 支持的运算符
= Equality
= Equality
> Greater than
>= Greater than or equal
< Less than
<= Less than or equal
BETWEEN Between range
IN IN set
## 支持的列类型
"integer", "smallint", "bigint", "tinyint", "varchar", "char", "boolean", "double", "real", "date"
@ -37,4 +43,10 @@ create index idx using bitmap on hive.hindex.users (gender) where regionkey in (
使用:
```sql
select name from hive.hindex.users where gender="female"
select * from hive.hindex.users where id>123
select * from hive.hindex.users where id<123
select * from hive.hindex.users where id>=123
select * from hive.hindex.users where id<=123
select * from hive.hindex.users where id between (100, 200)
select * from hive.hindex.users where id in (123, 199)
```

View File

@ -18,6 +18,25 @@
<org.slf4j.version>1.7.30</org.slf4j.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--disable resusefork so the same JVM is not shared by testcases.
Hindex relies on a static cache in SplitFiltering.java, if multiple
testcases spawn multiple testservers via DistributedQueryRunner
there will be conflicts because all testservers will use the same
cache instance; this is only an issue during unit testing, in production
multiple servers do not share JVMs-->
<forkCount>2</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>

View File

@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableSet;
import io.prestosql.spi.heuristicindex.Index;
import io.prestosql.spi.heuristicindex.Pair;
import io.prestosql.spi.predicate.Domain;
import io.prestosql.spi.predicate.Marker;
import io.prestosql.spi.predicate.Range;
import io.prestosql.spi.predicate.SortedRangeSet;
import org.apache.commons.io.IOUtils;
@ -28,7 +29,6 @@ import org.mapdb.DBMaker;
import org.mapdb.Serializer;
import org.mapdb.serializer.GroupSerializer;
import org.mapdb.serializer.SerializerCompressionWrapper;
import org.roaringbitmap.PeekableIntIterator;
import org.roaringbitmap.RoaringBitmap;
import org.roaringbitmap.buffer.ImmutableRoaringBitmap;
import org.xerial.snappy.SnappyInputStream;
@ -53,6 +53,7 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentNavigableMap;
import java.util.concurrent.atomic.AtomicBoolean;
import static io.hetu.core.heuristicindex.util.TypeUtils.getNativeValue;
@ -184,6 +185,26 @@ public class BitmapIndex
return lookUp(expression).hasNext();
}
private RoaringBitmap lookUpSingle(Object lookupValue)
{
try {
Object objValue = btree.get(lookupValue);
if (objValue == null) {
return null;
}
byte[] value = (byte[]) objValue;
ByteBuffer bb = ByteBuffer.wrap(value);
ImmutableRoaringBitmap bitmap = new ImmutableRoaringBitmap(bb);
RoaringBitmap roaringBitmap = new RoaringBitmap(bitmap);
return roaringBitmap;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public Iterator<Integer> lookUp(Object expression)
{
@ -194,56 +215,74 @@ public class BitmapIndex
List<Range> ranges = ((SortedRangeSet) (predicate.getValues())).getOrderedRanges();
Class<?> javaType = predicate.getValues().getType().getJavaType();
if (ranges.size() != 1) {
throw new UnsupportedOperationException("Bitmap only supports single equality expressions");
}
Object lookupValue = null;
for (Range range : ranges) {
// unique value(for example: id=1, id in (1,2)), bound: EXACTLY
if (range.isSingleValue()) {
lookupValue = getNativeValue(range.getSingleValue());
break;
}
else {
throw new UnsupportedOperationException("Bitmap only supports single equality expressions");
}
}
try {
Object objValue = getBtreeReadOptimized().get(lookupValue);
btree = getBtreeReadOptimized();
ArrayList<RoaringBitmap> allMatches = new ArrayList<>();
for (Range range : ranges) {
if (range.isSingleValue()) {
// unique value(for example: id=1, id in (1,2) (IN operator gives single exact values one by one)), bound: EXACTLY
RoaringBitmap bitmap = lookUpSingle(getNativeValue(range.getSingleValue()));
if (bitmap != null) {
allMatches.add(bitmap);
}
}
else {
// <, <=, >=, >, BETWEEN
boolean highBoundless = range.getHigh().isUpperUnbounded();
boolean lowBoundless = range.getLow().isLowerUnbounded();
ConcurrentNavigableMap<Object, String> concurrentNavigableMap = null;
if (objValue == null) {
return Collections.emptyIterator();
if (highBoundless && !lowBoundless) {
// >= or >
Object low = range.getLow().getValue();
Object high = btree.lastKey();
boolean fromInclusive = range.getLow().getBound().equals(Marker.Bound.EXACTLY);
if (btree.comparator().compare(low, high) > 0) {
Object temp = low;
low = high;
high = temp;
}
concurrentNavigableMap = btree.subMap(low, fromInclusive, high, true);
}
else if (!highBoundless && lowBoundless) {
// <= or <
Object low = btree.firstKey();
Object high = range.getHigh().getValue();
boolean toInclusive = range.getHigh().getBound().equals(Marker.Bound.EXACTLY);
if (btree.comparator().compare(low, high) > 0) {
Object temp = low;
low = high;
high = temp;
}
concurrentNavigableMap = btree.subMap(low, true, high, toInclusive);
}
else if (!highBoundless && !lowBoundless) {
// BETWEEN
Object low = range.getHigh().getValue();
Object high = range.getLow().getValue();
if (btree.comparator().compare(low, high) > 0) {
Object temp = low;
low = high;
high = temp;
}
concurrentNavigableMap = btree.subMap(low, true, high, true);
}
else {
// This case, combined gives a range of boundless for both high and low end
throw new UnsupportedOperationException("No use for bitmap index as all values are matched due to no bounds.");
}
for (Object i : concurrentNavigableMap.keySet()) {
RoaringBitmap bitmap = lookUpSingle(getNativeValue(i));
allMatches.add(bitmap);
}
}
}
byte[] value = (byte[]) objValue;
ByteBuffer bb = ByteBuffer.wrap(value);
ImmutableRoaringBitmap bitmap = new ImmutableRoaringBitmap(bb);
PeekableIntIterator iterator = bitmap.getIntIterator();
if (iterator == null) {
return Collections.emptyIterator();
}
return new Iterator<Integer>()
{
@Override
public boolean hasNext()
{
return iterator.hasNext();
}
@Override
public Integer next()
{
return iterator.next();
}
};
return RoaringBitmap.or(allMatches.iterator()).iterator();
}
catch (Exception e) {
throw new RuntimeException(e);
throw new UnsupportedOperationException("Unsupported expression type.", e);
}
}
else {

View File

@ -250,6 +250,8 @@ public class BTreeIndex
concurrentNavigableMap = dataMap.subMap(key, true, dataMap.lastKey(), true);
result.addAll(concurrentNavigableMap.values().stream().map(this::translateSymbols).flatMap(Collection::stream).collect(Collectors.toList()));
break;
default:
throw new UnsupportedOperationException("Expression not supported");
}
}
}
@ -270,6 +272,8 @@ public class BTreeIndex
}
}
break;
default:
throw new UnsupportedOperationException("Expression not supported");
}
}
else {

View File

@ -129,7 +129,7 @@ public class MinMaxIndex
case GREATER_THAN_OR_EQUAL:
return value.compareTo(max) < 0 || value.compareTo(max) == 0;
default:
throw new IllegalArgumentException("Unsupported operator " + operator);
throw new UnsupportedOperationException("Unsupported operator " + operator);
}
}
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2018-2020. Huawei Technologies Co., Ltd. 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.
* 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 io.hetu.core.heuristicindex;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class HeuristicIndexUtConstants
{
/**
* list of cvs columns data types
*/
public static final List<String> CVS_COLUMNS_DATA_TYPES = Collections.unmodifiableList(new ArrayList<String>() {
{
this.add(Long.class.getName());
this.add(String.class.getName());
}
});
private HeuristicIndexUtConstants()
{
}
}

View File

@ -1,354 +0,0 @@
/*
* Copyright (C) 2018-2020. Huawei Technologies Co., Ltd. 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.
* 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 io.hetu.core.heuristicindex;
//
//import io.hetu.core.common.filesystem.TempFolder;
//import io.hetu.core.filesystem.HetuLocalFileSystemClient;
//import io.hetu.core.filesystem.LocalConfig;
//import io.hetu.core.plugin.heuristicindex.index.bloom.BloomIndex;
//import io.hetu.core.plugin.heuristicindex.index.minmax.MinMaxIndex;
//import io.prestosql.spi.filesystem.HetuFileSystemClient;
//import io.prestosql.spi.heuristicindex.DataSource;
//import io.prestosql.spi.heuristicindex.Index;
//import org.apache.commons.compress.archivers.ArchiveEntry;
//import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.testng.annotations.Test;
//
//import java.io.File;
//import java.io.IOException;
//import java.nio.file.Files;
//import java.nio.file.Path;
//import java.nio.file.Paths;
//import java.util.HashSet;
//import java.util.Properties;
//import java.util.Set;
//import java.util.stream.Collectors;
//
//import static org.mockito.Mockito.mock;
//import static org.testng.Assert.assertEquals;
//import static org.testng.Assert.assertFalse;
//import static org.testng.Assert.assertThrows;
//import static org.testng.Assert.assertTrue;
//
//public class TestHeuristicIndexWriter
//{
// private static final Logger LOG = LoggerFactory.getLogger(TestHeuristicIndexWriter.class);
//
// @Test
// public void testIndexWriterSimple()
// throws IOException
// {
// // Simple workflow without calling readSplit's callback
// DataSource ds = mock(DataSource.class);
// HetuFileSystemClient fs = new HetuLocalFileSystemClient(new LocalConfig(new Properties()), Paths.get("/"));
//
// Set<Index> indices = new HashSet<>();
// indices.add(new BloomIndex());
//
// FileIndexWriter writer = new FileIndexWriter(ds, indices, fs, null);
//
// // Runtime exception will be thrown because the table was empty
// assertThrows(RuntimeException.class, () -> writer.createIndex("catalog.schema.table", new String[] {"test"}, new String[] {}, "bloom"));
//
// // Null check
// assertThrows(RuntimeException.class, () -> new FileIndexWriter(null, null, null, null));
//
// // Invalid table format
// assertThrows(RuntimeException.class,
// () -> writer.createIndex("invalid", new String[] {"test"}, new String[] {}, "bloom"));
// }
//
// @Test
// public void testUnsupportedIndexType()
// throws IOException
// {
// DataSource ds = new TestDataSource();
// try (TempFolder folder = new TempFolder()) {
// folder.create();
//
// HetuFileSystemClient fs = new HetuLocalFileSystemClient(new LocalConfig(new Properties()), folder.getRoot().toPath());
//
// Set<Index> indices = new HashSet<>();
// indices.add(new BloomIndex());
//
// FileIndexWriter writer = new FileIndexWriter(ds, indices, fs, folder.getRoot().toPath());
// String tableName = "catalog.schema.table";
//
// assertThrows(RuntimeException.class,
// () -> writer.createIndex(tableName, new String[] {"test"}, new String[] {}, "Random"));
// assertIndexWriterCleanUp(folder.getRoot().toPath(), tableName);
// }
// }
//
// @Test
// public void testIndexWriterCallback()
// throws IOException
// {
// DataSource ds = new TestDataSource();
// try (TempFolder folder = new TempFolder()) {
// folder.create();
// HetuFileSystemClient fs = new HetuLocalFileSystemClient(new LocalConfig(new Properties()), folder.getRoot().toPath());
//
// Set<Index> indices = new HashSet<>();
// indices.add(new BloomIndex());
//
// FileIndexWriter writer = new FileIndexWriter(ds, indices, fs, folder.getRoot().toPath());
// String tableName = "catalog.schema.table";
//
// writer.createIndex(tableName, new String[] {"test"}, new String[] {}, "bloom");
//
// // Assert index files are created
// File indexFolder = new File(folder.getRoot().getAbsolutePath() + "/" + tableName);
// assertTrue(indexFolder.listFiles().length > 0);
// }
// }
//
// /**
// * create a bloom index followed by a minmax index
// * <p>
// * the lastModifiedTime of the datasource split will change, this means
// * only the latter minmax index should remain
// *
// * @throws IOException
// */
// @Test
// public void testIndexWriterMultipleWritesExpired()
// throws IOException
// {
// DataSource ds = new DataSource()
// {
// @Override
// public String getId()
// {
// return "test";
// }
//
// @Override
// public void readSplits(String schema, String table, String[] columns, String[] partitions, DataSource.Callback callback)
// {
// Object[] values = new Object[] {"test", "dsfdfs", "random"};
// callback.call("UT_test_column", values, "UT_test", 100, System.currentTimeMillis(), 0);
// }
// };
// try (TempFolder folder = new TempFolder()) {
// folder.create();
//
// HetuFileSystemClient fs = new HetuLocalFileSystemClient(new LocalConfig(new Properties()), folder.getRoot().toPath());
//
// Set<Index> indices = new HashSet<>();
// indices.add(new BloomIndex());
// indices.add(new MinMaxIndex());
//
// FileIndexWriter writer = new FileIndexWriter(ds, indices, fs, folder.getRoot().toPath());
// String tableName = "catalog.schema.table";
//
// writer.createIndex(tableName, new String[] {"test"}, new String[] {}, "bloom");
//
// File indexFolder = new File(folder.getRoot().getAbsolutePath() + "/" + tableName);
// LOG.info("Previous files:");
// Set<Path> previousFiles = Files.walk(Paths.get(indexFolder.getAbsolutePath()))
// .filter(Files::isRegularFile).collect(Collectors.toSet());
// previousFiles.forEach(f -> LOG.info(f.toString()));
//
// writer.createIndex(tableName, new String[] {"test"}, new String[] {}, "bloom");
// LOG.info("New files:");
// Set<Path> newFiles = Files.walk(Paths.get(indexFolder.getAbsolutePath()))
// .filter(Files::isRegularFile).collect(Collectors.toSet());
// newFiles.forEach(f -> LOG.info(f.toString()));
//
// // catalog.schema.table/UT_test_column/minmax/UT_test/lastModified=123.tar
// assertEquals(newFiles.size(), 1);
//
// // all files should be different
// for (Path previousFile : previousFiles) {
// assertFalse(newFiles.contains(previousFile), "should not have found " + previousFile);
// }
// }
// }
//
// /**
// * create a bloom index followed by a minmax index
// * <p>
// * the lastModifiedTime of the datasource split will remain the same
// * this means both bloom and minmax index should remain with
// * the same lastModifiedFile
// *
// * @throws IOException
// */
// @Test
// public void testIndexWriterMultipleWrites()
// throws IOException
// {
// DataSource ds = new DataSource()
// {
// @Override
// public String getId()
// {
// return "test";
// }
//
// @Override
// public void readSplits(String schema, String table, String[] columns, String[] partitions, DataSource.Callback
// callback)
// {
// Object[] values = new Object[] {"test", "dsfdfs", "random"};
// callback.call("UT_test_column", values, "UT_test", 100, 123, 0);
// }
// };
//
// try (TempFolder folder = new TempFolder()) {
// folder.create();
//
// HetuFileSystemClient fs = new HetuLocalFileSystemClient(new LocalConfig(new Properties()), folder.getRoot().toPath());
//
// Set<Index> indices = new HashSet<>();
// indices.add(new BloomIndex());
// indices.add(new MinMaxIndex());
//
// FileIndexWriter writer = new FileIndexWriter(ds, indices, fs, folder.getRoot().toPath());
// String tableName = "catalog.schema.table";
//
// writer.createIndex(tableName, new String[] {"test"}, new String[] {}, "bloom");
//
// File indexFolder = new File(folder.getRoot().getAbsolutePath() + "/" + tableName);
// LOG.info("Previous files:");
// Set<Path> previousFiles = Files.walk(Paths.get(indexFolder.getAbsolutePath()))
// .filter(Files::isRegularFile).collect(Collectors.toSet());
// previousFiles.forEach(f -> LOG.info(f.toString()));
//
// writer.createIndex(tableName, new String[] {"test"}, new String[] {}, "minmax");
// LOG.info("New files:");
// Set<Path> newFiles = Files.walk(Paths.get(indexFolder.getAbsolutePath()))
// .filter(Files::isRegularFile).collect(Collectors.toSet());
// newFiles.forEach(f -> LOG.info(f.toString()));
//
// // two files:
// // catalog.schema.table/UT_test_column/minmax/UT_test/lastModified=123.tar
// // catalog.schema.table/UT_test_column/bloom/UT_test/lastModified=123.tar
// assertEquals(newFiles.size(), 2);
// assertTarEntry(newFiles.iterator().next(), 1);
//
// // previous files should still be there
// for (Path previousFile : previousFiles) {
// assertTrue(newFiles.contains(previousFile), "did not find " + previousFile);
// }
// }
// }
//
// /**
// * create a bloom index with debug on, this will also write
// * the data of each split into a file alongside the index file
// *
// * @throws IOException
// */
// @Test
// public void testDebugMode()
// throws IOException
// {
// DataSource ds = new DataSource()
// {
// @Override
// public String getId()
// {
// return "test";
// }
//
// @Override
// public void readSplits(String schema, String table, String[] columns, String[] partitions, DataSource.Callback
// callback)
// {
// Object[] values = new Object[] {"test", "dsfdfs", "random"};
// callback.call("UT_test_column", values, "UT_test", 100, System.currentTimeMillis(), 0);
// }
// };
//
// try (TempFolder folder = new TempFolder()) {
// folder.create();
//
// HetuFileSystemClient fs = new HetuLocalFileSystemClient(new LocalConfig(new Properties()), folder.getRoot().toPath());
//
// Set<Index> indices = new HashSet<>();
// indices.add(new BloomIndex());
//
// FileIndexWriter writer = new FileIndexWriter(ds, indices, fs, folder.getRoot().toPath());
// String tableName = "catalog.schema.table";
//
// writer.createIndex(tableName, new String[] {"test"}, new String[] {}, "bloom", true);
//
// File indexFolder = new File(folder.getRoot().getAbsolutePath() + "/" + tableName);
// LOG.info("Previous files:");
// Set<Path> files = Files.walk(Paths.get(indexFolder.getAbsolutePath()))
// .filter(Files::isRegularFile).collect(Collectors.toSet());
// files.forEach(f -> LOG.info(f.toString()));
//
// assertEquals(files.size(), 1);
// assertTarEntry(files.iterator().next(), 1);
// }
// }
//
// private void assertIndexWriterCleanUp(Path root, String tableName)
// throws IOException
// {
// // TODO: note empty directories may be left behind
// assertTrue(Files.walk(Paths.get(root.toAbsolutePath().toString())).noneMatch(Files::isRegularFile),
// "all part files and lock files has to be deleted upon error");
// }
//
// private static class TestDataSource
// implements DataSource
// {
// @Override
// public String getId()
// {
// return "test";
// }
//
// @Override
// public void readSplits(String schema, String table, String[] columns, String[] partitions, Callback callback)
// throws IOException
// {
// Object[] values = new Object[] {"test", "dsfdfs", "random"};
// callback.call("UT_test_column", values, "UT_test", 100, System.currentTimeMillis(), 0);
// }
// }
//
// private void assertTarEntry(Path pathToTarFile, int expectedEntryCount)
// throws IOException
// {
// int entryCount = 0;
// try (TarArchiveInputStream i = new TarArchiveInputStream(Files.newInputStream(pathToTarFile))) {
// ArchiveEntry entry;
// while ((entry = i.getNextEntry()) != null) {
// entryCount++;
// }
// }
//
// assertEquals(entryCount, expectedEntryCount);
// }
//
// class FilesystemAndRoot
// {
// HetuFileSystemClient fileSystemClient;
// Path root;
//
// FilesystemAndRoot(HetuFileSystemClient fs, Path root)
// {
// this.fileSystemClient = fs;
// this.root = root;
// }
// }
//}

View File

@ -35,9 +35,7 @@ public class TestHindex
{
String tableName = getNewTableName();
String indexName = getNewIndexName();
String[] testerData = createTableDataTypeWithQuery(tableName, dataType);
tableName = testerData[0];
String testerQuery = testerData[1];
String testerQuery = createTableDataTypeWithQuery(tableName, dataType);
// Get splits and result
Pair<Integer, MaterializedResult> resultPairBeforeIndex = getSplitAndMaterializedResult(testerQuery);
@ -101,7 +99,7 @@ public class TestHindex
throws InterruptedException
{
String tableName = getNewTableName();
tableName = createTable1(tableName);
createTable1(tableName);
String testerQuery = "SELECT * FROM " + tableName + " WHERE " + queryVariable + "=" + queryValue;
String indexName = getNewIndexName();
@ -166,7 +164,7 @@ public class TestHindex
throws InterruptedException
{
String tableName = getNewTableName();
tableName = createTable2(tableName);
createTable2(tableName);
String testerQuery = "SELECT * FROM " + tableName + " WHERE " + queryVariable + "=" + queryValue;
String indexName = getNewIndexName();
@ -240,7 +238,7 @@ public class TestHindex
throws InterruptedException
{
String tableName = getNewTableName();
tableName = createTableNullData(tableName);
createTableNullData(tableName);
String testerQuery = "SELECT * FROM " + tableName + " WHERE " + queryVariable + "=" + queryValue;
String indexName = getNewIndexName();
@ -297,7 +295,7 @@ public class TestHindex
{
String tableName = getNewTableName();
String testerQuery = "SELECT * FROM " + tableName + " WHERE id = 2";
tableName = createTable1(tableName);
createTable1(tableName);
// Get splits and result
Pair<Integer, MaterializedResult> resultPairBeforeIndex = getSplitAndMaterializedResult(testerQuery);
@ -345,7 +343,7 @@ public class TestHindex
String tableName = getNewTableName();
String indexName = getNewIndexName();
String testerQuery = "SELECT * FROM " + tableName + " WHERE id = 2";
tableName = createTable1(tableName);
createTable1(tableName);
// Get splits and result
Pair<Integer, MaterializedResult> resultPairBeforeIndex = getSplitAndMaterializedResult(testerQuery);
@ -389,7 +387,7 @@ public class TestHindex
{
String tableName = getNewTableName();
String indexName = getNewIndexName();
tableName = createTable1(tableName);
createTable1(tableName);
// Create index
if (indexType.toLowerCase(Locale.ROOT).equals("btree")) {
@ -480,53 +478,32 @@ public class TestHindex
}
}
@Test
public void testBtreeIndexMultiPartitionedColumn()
@Test(dataProvider = "queryOperatorTest")
public void testQueryOperator(String testerQuery, String indexType)
throws InterruptedException
{
String tableName = getNewTableName();
tableName = createBtreeTableMultiPart1(tableName);
createTable1(tableName);
testerQuery = "SELECT * FROM " + tableName + " WHERE " + testerQuery;
String indexName = getNewIndexName();
String indexName1 = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName1 + " USING btree ON " + tableName +
" (key1) WITH (level=partition) WHERE key3 = 222");
if (indexType.toLowerCase(Locale.ROOT).equals("btree")) {
assertQuerySucceeds("CREATE INDEX " + indexName + " USING " +
indexType + " ON " + tableName + " (id) WITH (level='table')");
}
else {
assertQuerySucceeds("CREATE INDEX " + indexName + " USING " +
indexType + " ON " + tableName + " (id)");
}
String testerQuery1 = "SELECT * FROM " + tableName + " WHERE key1 = 2";
Pair<Integer, MaterializedResult> resultPairLoadingIndex1 = getSplitAndMaterializedResult(testerQuery1);
int splitsLoadingIndex1 = resultPairLoadingIndex1.getFirst();
MaterializedResult resultLoadingIndex1 = resultPairLoadingIndex1.getSecond();
MaterializedResult resultLoadingIndex = computeActual(testerQuery);
// Wait before continuing
Thread.sleep(1000);
Pair<Integer, MaterializedResult> resultPairIndexLoaded1 = getSplitAndMaterializedResult(testerQuery1);
int splitsIndexLoaded1 = resultPairIndexLoaded1.getFirst();
MaterializedResult resultIndexLoaded1 = resultPairIndexLoaded1.getSecond();
MaterializedResult resultIndexLoaded = computeActual(testerQuery);
assertEquals(splitsLoadingIndex1, splitsIndexLoaded1);
assertTrue(verifyEqualResults(resultLoadingIndex1, resultIndexLoaded1), "The results should be equal.");
// Create second index and do query again on different keys
String indexName2 = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName2 + " USING btree ON " + tableName +
" (key2) WITH (level=partition) WHERE key5 = 22222");
String testerQuery2 = "SELECT * FROM " + tableName + " WHERE key2 = 22";
Pair<Integer, MaterializedResult> resultPairLoadingIndex2 = getSplitAndMaterializedResult(testerQuery2);
int splitsLoadingIndex2 = resultPairLoadingIndex2.getFirst();
MaterializedResult resultLoadingIndex2 = resultPairLoadingIndex2.getSecond();
// Wait before continuing
Thread.sleep(1000);
Pair<Integer, MaterializedResult> resultPairIndexLoaded2 = getSplitAndMaterializedResult(testerQuery2);
int splitsIndexLoaded2 = resultPairIndexLoaded2.getFirst();
MaterializedResult resultIndexLoaded2 = resultPairIndexLoaded2.getSecond();
assertEquals(splitsLoadingIndex2, splitsIndexLoaded2);
assertTrue(verifyEqualResults(resultLoadingIndex2, resultIndexLoaded2), "The results should be equal.");
assertTrue(verifyEqualResults(resultLoadingIndex, resultIndexLoaded),
"The results should be equal for " + testerQuery + " " + indexType);
}
}

View File

@ -22,14 +22,14 @@ import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertTrue;
public class TestBTree
public class TestHindexBTreeIndex
extends TestIndexResources
{
@Test
public void testBtreeIndexOnPartitionedColumnCreateAndDelete()
{
String tableName = getNewTableName();
tableName = createBtreeTable1(tableName);
createBtreeTable1(tableName);
String indexName = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName + " USING btree ON " + tableName +
@ -41,7 +41,7 @@ public class TestBTree
public void testBtreeIndexOnNonePartitionedColumnCreateAndDelete()
{
String tableName = getNewTableName();
tableName = createBtreeTable1(tableName);
createBtreeTable1(tableName);
String indexName = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName + " USING btree ON " + tableName +
@ -53,7 +53,7 @@ public class TestBTree
public void testBtreeIndexHasKeyWhereDelete()
{
String tableName = getNewTableName();
tableName = createBtreeTable1(tableName);
createBtreeTable1(tableName);
String indexName = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName + " USING btree ON " + tableName +
@ -65,7 +65,7 @@ public class TestBTree
public void testBtreeIndexInvalidKeyWhereDelete()
{
String tableName = getNewTableName();
tableName = createBtreeTable1(tableName);
createBtreeTable1(tableName);
String indexName = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName + " USING btree ON " + tableName +
@ -83,7 +83,7 @@ public class TestBTree
throws InterruptedException
{
String tableName = getNewTableName();
tableName = createBtreeTable1(tableName);
createBtreeTable1(tableName);
String indexName = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName + " USING btree ON " + tableName +
@ -110,7 +110,7 @@ public class TestBTree
public void testBtreeIndexCreationWhereNonPartitionedColumn()
{
String tableName = getNewTableName();
tableName = createBtreeTable1(tableName);
createBtreeTable1(tableName);
String indexName = getNewIndexName();
assertQueryFails("CREATE INDEX " + indexName + " USING btree ON " + tableName +
@ -123,7 +123,7 @@ public class TestBTree
throws InterruptedException
{
String tableName = getNewTableName();
tableName = createBtreeTableTransact1(tableName);
createBtreeTableTransact1(tableName);
String indexName = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName + " USING btree ON " + tableName +
@ -165,7 +165,7 @@ public class TestBTree
public void testBtreeIndexOperators(String condition)
{
String tableName = getNewTableName();
tableName = createBtreeTable1(tableName);
createBtreeTable1(tableName);
String indexName = getNewIndexName();
try {
@ -178,4 +178,54 @@ public class TestBTree
" Only in-predicate/equality-expressions are supported e.g. partition=1 or partition=2/partition in (1,2)"));
}
}
@Test
public void testBtreeIndexMultiPartitionedColumn()
throws InterruptedException
{
String tableName = getNewTableName();
createBtreeTableMultiPart1(tableName);
String indexName1 = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName1 + " USING btree ON " + tableName +
" (key1) WITH (level=partition) WHERE key3 = 222");
String testerQuery1 = "SELECT * FROM " + tableName + " WHERE key1 = 2";
Pair<Integer, MaterializedResult> resultPairLoadingIndex1 = getSplitAndMaterializedResult(testerQuery1);
int splitsLoadingIndex1 = resultPairLoadingIndex1.getFirst();
MaterializedResult resultLoadingIndex1 = resultPairLoadingIndex1.getSecond();
// Wait before continuing
Thread.sleep(1000);
Pair<Integer, MaterializedResult> resultPairIndexLoaded1 = getSplitAndMaterializedResult(testerQuery1);
int splitsIndexLoaded1 = resultPairIndexLoaded1.getFirst();
MaterializedResult resultIndexLoaded1 = resultPairIndexLoaded1.getSecond();
assertEquals(splitsLoadingIndex1, splitsIndexLoaded1);
assertTrue(verifyEqualResults(resultLoadingIndex1, resultIndexLoaded1), "The results should be equal.");
// Create second index and do query again on different keys
String indexName2 = getNewIndexName();
assertQuerySucceeds("CREATE INDEX " + indexName2 + " USING btree ON " + tableName +
" (key2) WITH (level=partition) WHERE key5 = 22222");
String testerQuery2 = "SELECT * FROM " + tableName + " WHERE key2 = 22";
Pair<Integer, MaterializedResult> resultPairLoadingIndex2 = getSplitAndMaterializedResult(testerQuery2);
int splitsLoadingIndex2 = resultPairLoadingIndex2.getFirst();
MaterializedResult resultLoadingIndex2 = resultPairLoadingIndex2.getSecond();
// Wait before continuing
Thread.sleep(1000);
Pair<Integer, MaterializedResult> resultPairIndexLoaded2 = getSplitAndMaterializedResult(testerQuery2);
int splitsIndexLoaded2 = resultPairIndexLoaded2.getFirst();
MaterializedResult resultIndexLoaded2 = resultPairIndexLoaded2.getSecond();
assertEquals(splitsLoadingIndex2, splitsIndexLoaded2);
assertTrue(verifyEqualResults(resultLoadingIndex2, resultIndexLoaded2), "The results should be equal.");
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2018-2020. Huawei Technologies Co., Ltd. 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.
* 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 io.hetu.core.heuristicindex;
import io.prestosql.testing.MaterializedResult;
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
public class TestHindexBitmapIndex
extends TestIndexResources
{
@Test(dataProvider = "bitmapOperatorInputRowsTest")
public void testBitmapOperatorInputRows(String predicateQuery, String baseQuery)
throws InterruptedException
{
String tableName = getNewTableName();
createTable2(tableName);
String indexName = getNewIndexName();
// baseQuery is the query at which all, most or at least more selected than predicateQuery
// baseQuery does not use indexing, predicateQuery does
// predicateQuery should have less input rows than baseQuery
baseQuery = "SELECT * FROM " + tableName + baseQuery;
predicateQuery = "SELECT * FROM " + tableName + " WHERE " + predicateQuery;
MaterializedResult baseQueryResult = computeActual(baseQuery);
long baseQueryInputRows = getInputRowsOfLastQueryExecution(baseQuery);
assertQuerySucceeds("CREATE INDEX " + indexName + " USING bitmap ON " + tableName + " (key)");
MaterializedResult predicateQueryResultLoadingIndex = computeActual(predicateQuery);
// Wait before continuing
Thread.sleep(1000);
MaterializedResult predicateQueryResultIndexLoaded = computeActual(predicateQuery);
long predicateQueryInputRowsIndexLoaded = getInputRowsOfLastQueryExecution(predicateQuery);
assertTrue(verifyEqualResults(predicateQueryResultLoadingIndex, predicateQueryResultIndexLoaded),
"The results should be equal.");
assertTrue(baseQueryResult.getRowCount() > predicateQueryResultIndexLoaded.getRowCount(),
"Predicate query with index loaded should have less results than base query. " +
"baseQueryResult row count: " + baseQueryResult.getRowCount() +
" predicateQueryResultIndexLoaded row count: " + predicateQueryResultIndexLoaded.getRowCount());
assertTrue(baseQueryInputRows > predicateQueryInputRowsIndexLoaded,
"Predicate query with index loaded should have less input rows than base query. " +
"baseQueryInputRows: " + baseQueryInputRows +
" predicateQueryInputRowsIndexLoaded: " + predicateQueryInputRowsIndexLoaded);
}
}

View File

@ -34,7 +34,7 @@ public class TestHindexFailure
{
String tableName = getNewTableName();
String indexName = getNewIndexName();
tableName = createTable1(tableName);
createTable1(tableName);
// Create index
if (indexType.toLowerCase(Locale.ROOT).equals("btree")) {
@ -47,7 +47,7 @@ public class TestHindexFailure
}
assertQueryFails("DROP INDEX hive", "line 1:1: Index 'hive' does not exist");
assertQueryFails("DROP INDEX HDFS", "line 1:1: Index 'hdfs' does not exist");
assertQueryFails("DROP INDEX test", "line 1:1: Index 'test' does not exist");
assertQueryFails("DROP INDEX TEST", "line 1:1: Index 'test' does not exist");
assertQueryFails("DROP INDEX wrongtest", "line 1:1: Index 'wrongtest' does not exist");
String[] table = tableName.split("\\.");
assertQueryFails("DROP INDEX " + table[2], "line 1:1: Index '" + table[2] + "' does not exist");
@ -63,7 +63,7 @@ public class TestHindexFailure
{
String tableName = getNewTableName();
String indexName = getNewIndexName();
tableName = createTable1(tableName);
createTable1(tableName);
// Create index
if (indexType.toLowerCase(Locale.ROOT).equals("btree")) {
@ -85,7 +85,7 @@ public class TestHindexFailure
public void testMultipleSameIndexCreation(String indexType, String queryVariable)
{
String tableName = getNewTableName();
tableName = createTable1(tableName);
createTable1(tableName);
String indexName1 = getNewIndexName();
if (indexType.toLowerCase(Locale.ROOT).equals("btree")) {
@ -120,7 +120,7 @@ public class TestHindexFailure
throws IllegalStateException
{
String tableName = getNewTableName();
tableName = createEmptyTable(tableName);
createEmptyTable(tableName);
String indexName = getNewIndexName();
if (indexType.toLowerCase(Locale.ROOT).equals("btree")) {
@ -292,7 +292,7 @@ public class TestHindexFailure
public void testIndexWithoutColumnCreation(String indexType)
{
String tableName = getNewTableName();
tableName = createTable1(tableName);
createTable1(tableName);
// Error of "line 1:115: mismatched input ')'. Expecting: <identifier>" exists
// But code style does not allow ) to exist inside a string without having ( before it.
@ -318,7 +318,7 @@ public class TestHindexFailure
throws SemanticException
{
String tableName = getNewTableName();
tableName = createTable1(tableName);
createTable1(tableName);
String indexName = getNewIndexName();
if (indexType.toLowerCase(Locale.ROOT).equals("btree")) {
@ -339,10 +339,10 @@ public class TestHindexFailure
throws ParsingException
{
String tableName = getNewTableName();
tableName = createTable1(tableName);
createTable1(tableName);
String indexName = getNewIndexName();
assertQueryFails("CREATE INDEX " + indexName + " USING wrong_filter ON " + tableName + " (id)",
"line 1:59: mismatched input 'wrong_filter'. Expecting: '.', 'USING'");
"line 1:26: mismatched input 'wrong_filter'. Expecting: '.', 'USING'");
}
}

View File

@ -23,8 +23,9 @@ import org.testng.annotations.DataProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import static org.testng.Assert.assertNotEquals;
import static org.testng.Assert.assertEquals;
public class TestIndexResources
extends AbstractTestQueryFramework
@ -86,46 +87,67 @@ public class TestIndexResources
return new Object[][] {{"BITMAP"}, {"BLOOM"}, {"MINMAX"}, {"BTREE"}};
}
String safeCreateTable(String query, String tableName)
@DataProvider(name = "bitmapOperatorInputRowsTest")
public Object[][] bitmapOperatorInputRowsTest()
{
String newName = tableName;
int max = 1;
for (int i = 0; i < 10; i++) {
try {
assertQuerySucceeds(query);
return newName;
}
catch (AssertionError e) {
max *= 10;
newName = tableName + ((int) (Math.random() * max));
if (newName.length() >= 128) {
throw new RuntimeException("Cannot Create Table: " + tableName + " due to " + e.getCause().toString());
}
query = query.replaceFirst(tableName, newName);
}
}
assertQuerySucceeds(query);
return newName;
return new Object[][] {
{"key = 5", ""}, {"key IN (1, 2)", ""}, {"key BETWEEN 3 AND 7", " WHERE key BETWEEN 2 AND 8"},
{"key < 5", " WHERE key <= 5"}, {"key <= 5", " WHERE key <= 8"},
{"key >= 5", " WHERE key >= 3"}, {"key > 5", " WHERE key >= 5"},
{"key < 0", " WHERE key > -1"}, {"key <= -1", " WHERE key >= 0"},
{"key >= 100", " WHERE key >= 3"}, {"key > 99", " WHERE key >= 5"},
{"key <> 5", ""}, {"key NOT IN (1, 2)", ""}, {"key BETWEEN 7 AND 3", " WHERE key BETWEEN 2 AND 8"},
{"key > 5 AND key < 5", ""}, {"key > 5 OR key < 5", ""}, {"key < 5 AND key > 5", ""}, {"key < 5 OR key > 5", ""},
{"key = 5 AND key IN (5)", ""}, {"key <> 5 AND key IN (5)", ""}, {"key <> 5 OR key NOT IN (5)", ""},
{"key <> 5 AND key NOT IN (5)", ""}, {"key = 5 AND key NOT IN (5)", ""}, {"key = 5 OR key IN (5)", ""},
{"key BETWEEN 3 AND 5 OR key = 6", ""}, {"key BETWEEN 3 AND 5 AND key = 4", ""}};
}
String createEmptyTable(String tableName)
@DataProvider(name = "queryOperatorTest")
public Object[][] queryOperatorTest()
{
return safeCreateTable("CREATE TABLE " + tableName + " (id INTEGER, name VARCHAR(10))", tableName);
return new Object[][] {
{"id = 3", "bitmap"}, {"id = 3", "bloom"}, {"id = 3", "btree"}, {"id = 3", "minmax"},
{"id <> 3", "bitmap"}, {"id <> 3", "bloom"}, {"id <> 3", "btree"}, {"id <> 3", "minmax"},
{"id < 3", "bitmap"}, {"id < 3", "bloom"}, {"id < 3", "btree"}, {"id < 3", "minmax"},
{"id > 3", "bitmap"}, {"id > 3", "bloom"}, {"id > 3", "btree"}, {"id > 3", "minmax"},
{"id <= 3", "bitmap"}, {"id <= 3", "bloom"}, {"id <= 3", "btree"}, {"id <= 3", "minmax"},
{"id >= 3", "bitmap"}, {"id >= 3", "bloom"}, {"id >= 3", "btree"}, {"id >= 3", "minmax"},
{"id IN (1, 2)", "bitmap"}, {"id IN (1, 2)", "bloom"}, {"id IN (1, 2)", "btree"}, {"id IN (1, 2)", "minmax"},
{"id IN (3, 3)", "bitmap"}, {"id IN (3, 3)", "bloom"}, {"id IN (3, 3)", "btree"}, {"id IN (3, 3)", "minmax"},
{"id NOT IN (1, 2)", "bitmap"}, {"id NOT IN (1, 2)", "bloom"}, {"id NOT IN (1, 2)", "btree"}, {"id NOT IN (1, 2)", "minmax"},
{"id BETWEEN 3 AND 5", "bitmap"}, {"id BETWEEN 3 AND 5", "bloom"}, {"id BETWEEN 3 AND 5", "btree"}, {"id BETWEEN 3 AND 5", "minmax"},
{"id BETWEEN 3 AND 3", "bitmap"}, {"id BETWEEN 3 AND 3", "bloom"}, {"id BETWEEN 3 AND 3", "btree"}, {"id BETWEEN 3 AND 3", "minmax"},
{"id > 3 AND id < 3", "bitmap"}, {"id > 3 AND id < 3", "bloom"}, {"id > 3 AND id < 3", "btree"}, {"id > 3 AND id < 3", "minmax"},
{"id > 3 OR id < 3", "bitmap"}, {"id > 3 OR id < 3", "bloom"}, {"id > 3 OR id < 3", "btree"}, {"id > 3 OR id < 3", "minmax"},
{"id < 3 AND id > 3", "bitmap"}, {"id < 3 AND id > 3", "bloom"}, {"id < 3 AND id > 3", "btree"}, {"id < 3 AND id > 3", "minmax"},
{"id < 3 OR id > 3", "bitmap"}, {"id < 3 OR id > 3", "bloom"}, {"id < 3 OR id > 3", "btree"}, {"id < 3 OR id > 3", "minmax"},
{"id <> 3 OR id NOT IN (3)", "bitmap"}, {"id <> 3 OR id NOT IN (3)", "bloom"}, {"id <> 3 OR id NOT IN (3)", "btree"}, {"id <> 3 OR id NOT IN (3)", "minmax"},
{"id <> 3 AND id NOT IN (3)", "bitmap"}, {"id <> 3 AND id NOT IN (3)", "bloom"}, {"id <> 3 AND id NOT IN (3)", "btree"}, {"id <> 3 AND id NOT IN (3)", "minmax"},
{"id = 3 OR id IN (3)", "bitmap"}, {"id = 3 OR id IN (3)", "bloom"}, {"id = 3 OR id IN (3)", "btree"}, {"id = 3 OR id IN (3)", "minmax"},
{"id = 3 AND id NOT IN (3)", "bitmap"}, {"id = 3 AND id NOT IN (3)", "bloom"}, {"id = 3 AND id NOT IN (3)", "btree"}, {"id = 3 AND id NOT IN (3)", "minmax"},
{"id = 3 AND id IN (3)", "bitmap"}, {"id = 3 AND id IN (3)", "bloom"}, {"id = 3 AND id IN (3)", "btree"}, {"id = 3 AND id IN (3)", "minmax"},
{"id <> 3 AND id IN (3)", "bitmap"}, {"id <> 3 AND id IN (3)", "bloom"}, {"id <> 3 AND id IN (3)", "btree"}, {"id <> 3 AND id IN (3)", "minmax"},
{"id BETWEEN 1 AND 3 OR id = 5", "bitmap"}, {"id BETWEEN 1 AND 3 OR id = 5", "bloom"}, {"id BETWEEN 1 AND 3 OR id = 5", "btree"}, {"id BETWEEN 1 AND 3 OR id = 5", "minmax"},
{"id BETWEEN 1 AND 3 AND id = 2", "bitmap"}, {"id BETWEEN 1 AND 3 AND id = 2", "bloom"}, {"id BETWEEN 1 AND 3 AND id = 2", "btree"}, {"id BETWEEN 1 AND 3 AND id = 2", "minmax"}};
}
String createTable1(String tableName)
void createEmptyTable(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName + " (id INTEGER, name VARCHAR(10))", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (id INTEGER, name VARCHAR(10))");
}
void createTable1(String tableName)
{
assertQuerySucceeds("CREATE TABLE " + tableName + " (id INTEGER, name VARCHAR(10))");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(1, 'test')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(2, '123'), (3, 'temp')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(3, 'data'), (9, 'ttt'), (5, 'num')");
return tableName;
}
String createTable2(String tableName)
void createTable2(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (key BIGINT, status VARCHAR(7), price DECIMAL(5,2), date DATE)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (key BIGINT, status VARCHAR(7), price DECIMAL(5,2), date DATE)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(0, 'SUCCESS', 101.12, DATE '2021-01-01')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(1, 'FAILURE', 101.12, DATE '2021-01-01')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(2, 'SUCCESS', 252.36, DATE '2021-01-01')");
@ -142,123 +164,111 @@ public class TestIndexResources
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(6, 'FAILURE', 252.36, DATE '2021-01-03')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(7, 'SUCCESS', 101.12, DATE '2021-01-03')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(8, 'SUCCESS', 101.12, DATE '2021-01-03')");
return tableName;
}
String createTableNullData(String tableName)
void createTableNullData(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName + " (col1 INTEGER, col2 BIGINT, col3 TINYINT)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (col1 INTEGER, col2 BIGINT, col3 TINYINT)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(111, NULL, NULL)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(NULL, BIGINT '222', NULL)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(NULL, NULL, TINYINT '33')");
return tableName;
}
String createBtreeTable1(String tableName)
void createBtreeTable1(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (key1 INT, key2 INT)" +
" WITH (partitioned_by = ARRAY['key2'])", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (key1 INT, key2 INT)" + " WITH (partitioned_by = ARRAY['key2'])");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(0, 10), (1, 11), (2, 12), (1, 11), (3, 13)," +
" (1, 11), (2, 12), (4, 14), (3, 13), (5, 15), (6, 16)");
return tableName;
}
String createBtreeTableTransact1(String tableName)
void createBtreeTableTransact1(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (key1 INT, key2 INT)" +
" WITH (transactional = true, partitioned_by = ARRAY['key2'])", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (key1 INT, key2 INT)" + " WITH (transactional = true, partitioned_by = ARRAY['key2'])");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(0, 10), (1, 11), (2, 12), (1, 11), (3, 13)," +
" (1, 11), (2, 12), (4, 14), (3, 13), (5, 15), (6, 16)");
return tableName;
}
String createBtreeTableMultiPart1(String tableName)
void createBtreeTableMultiPart1(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (key1 INT, key2 INT, key3 INT, key4 INT, key5 INT)" +
" WITH (partitioned_by = ARRAY['key3', 'key4', 'key5'])", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (key1 INT, key2 INT, key3 INT, key4 INT, key5 INT)" +
" WITH (partitioned_by = ARRAY['key3', 'key4', 'key5'])");
assertQuerySucceeds("INSERT INTO " + tableName +
" VALUES(1, 11, 111, 1111, 11111), (2, 22, 222, 2222, 22222), (3, 33, 333, 3333, 33333)," +
" (2, 22, 222, 2222, 22222), (5, 55, 555, 5555, 55555), (1, 11, 111, 1111, 11111)," +
" (6, 66, 666, 6666, 66666), (7, 77, 777, 7777, 77777), (2, 22, 222, 2222, 22222), (2, 22, 222, 2222, 22222)");
return tableName;
}
String[] createTableDataTypeWithQuery(String tableName, String dataType)
String createTableDataTypeWithQuery(String tableName, String dataType)
throws InterruptedException
{
String query = "SELECT * FROM " + tableName + " WHERE data_col2=";
switch (dataType.toLowerCase(Locale.ROOT)) {
case "bigint":
tableName = createTableBigInt(tableName);
createTableBigInt(tableName);
query += "5675354";
break;
case "boolean":
tableName = createTableBoolean(tableName);
createTableBoolean(tableName);
query = query.substring(0, query.length() - 1);
break;
case "char":
tableName = createTableChar(tableName);
createTableChar(tableName);
query += "'z'";
break;
case "date":
tableName = createTableDate(tableName);
createTableDate(tableName);
query += "'2021-12-21'";
break;
case "decimal":
tableName = createTableDecimal(tableName);
createTableDecimal(tableName);
query += "DECIMAL '21.21'";
break;
case "double":
tableName = createTableDouble(tableName);
createTableDouble(tableName);
query += "DOUBLE '21.21'";
break;
case "int":
tableName = createTableInt(tableName);
createTableInt(tableName);
query += "606";
break;
case "real":
tableName = createTableReal(tableName);
createTableReal(tableName);
query += "21.21";
break;
case "smallint":
tableName = createTableSmallInt(tableName);
createTableSmallInt(tableName);
query += "32767";
break;
case "string":
tableName = createTableString(tableName);
createTableString(tableName);
query += "";
break;
case "timestamp":
tableName = createTableTimestamp(tableName);
createTableTimestamp(tableName);
query += "";
break;
case "tinyint":
tableName = createTableTinyInt(tableName);
createTableTinyInt(tableName);
query += "0";
break;
case "varbinary":
tableName = createTableVarBinary(tableName);
createTableVarBinary(tableName);
query += "AAA";
break;
case "varchar":
tableName = createTableVarChar(tableName);
createTableVarChar(tableName);
query += "'tester'";
break;
default:
throw new InterruptedException("Not supported data type.");
}
String[] result = {tableName, query};
return result;
return query;
}
String createTableBigInt(String tableName)
void createTableBigInt(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 BIGINT, data_col2 BIGINT, data_col3 BIGINT)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 BIGINT, data_col2 BIGINT, data_col3 BIGINT)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(1, 1, 1)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(2, 2, 2)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(3, 3, 3)");
@ -267,13 +277,11 @@ public class TestIndexResources
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(2818475983711351641, 2818475983711351641, 2818475983711351641)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(9214215753243532641, 9214215753243532641, 9214215753243532641)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(5675354, 5675354, 5675354)");
return tableName;
}
String createTableBoolean(String tableName)
void createTableBoolean(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 BOOLEAN, data_col2 BOOLEAN, data_col3 BOOLEAN)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 BOOLEAN, data_col2 BOOLEAN, data_col3 BOOLEAN)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(BOOLEAN '0', BOOLEAN '0', BOOLEAN '0')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(BOOLEAN '0', BOOLEAN '0', BOOLEAN '1')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(BOOLEAN '0', BOOLEAN '1', BOOLEAN '0')");
@ -282,59 +290,49 @@ public class TestIndexResources
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(BOOLEAN '1', BOOLEAN '0', BOOLEAN '1')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(BOOLEAN '1', BOOLEAN '1', BOOLEAN '0')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(BOOLEAN '1', BOOLEAN '1', BOOLEAN '1')");
return tableName;
}
String createTableChar(String tableName)
void createTableChar(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 CHAR(1), data_col2 CHAR(1), data_col3 CHAR(1))", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 CHAR(1), data_col2 CHAR(1), data_col3 CHAR(1))");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('a', 'a', 'a')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('b', 'b', 'b')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('c', 'c', 'c')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('d', 'd', 'd')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('e', 'e', 'e')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('z', 'z', 'z')");
return tableName;
}
String createTableDate(String tableName)
void createTableDate(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 DATE, data_col2 DATE, data_col3 DATE)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 DATE, data_col2 DATE, data_col3 DATE)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DATE'1997-01-01', DATE'1997-01-01', DATE'1997-01-01')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DATE'2021-02-09', DATE'2021-02-09', DATE'2021-02-09')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DATE'2020-03-08', DATE'2020-03-08', DATE'2020-03-08')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DATE'2022-04-07', DATE'2022-04-07', DATE'2022-04-07')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DATE'1899-05-06', DATE'1997-05-06', DATE'1899-05-06')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DATE'2021-12-21', DATE'2021-12-21', DATE'2021-12-21')");
return tableName;
}
String createTableDecimal(String tableName)
void createTableDecimal(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 DECIMAL(4,2), data_col2 DECIMAL(4,2), data_col3 DECIMAL(4,2))", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 DECIMAL(4,2), data_col2 DECIMAL(4,2), data_col3 DECIMAL(4,2))");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DECIMAL '11.11', DECIMAL '11.11', DECIMAL '11.11')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DECIMAL '21.21', DECIMAL '21.21', DECIMAL '21.21')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DECIMAL '12.34', DECIMAL '43.21', DECIMAL '88.34')");
return tableName;
}
String createTableDouble(String tableName)
void createTableDouble(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 DOUBLE(4,2), data_col2 DOUBLE(4,2), data_col3 DOUBLE(4,2))", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 DOUBLE(4,2), data_col2 DOUBLE(4,2), data_col3 DOUBLE(4,2))");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DOUBLE '11.11', DOUBLE '11.11', DOUBLE '11.11')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DOUBLE '21.21', DOUBLE '21.21', DOUBLE '21.21')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(DOUBLE '12.34', DOUBLE '43.21', DOUBLE '88.34')");
return tableName;
}
String createTableInt(String tableName)
void createTableInt(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 INT, data_col2 INT, data_col3 INT)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 INT, data_col2 INT, data_col3 INT)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(1, 1, 1)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(2, 2, 2)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(3, 3, 3)");
@ -342,76 +340,62 @@ public class TestIndexResources
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(5, 5, 5)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(606, 606, 606)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(123, 123, 123)");
return tableName;
}
String createTableReal(String tableName)
void createTableReal(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 REAL(4,2), data_col2 REAL(4,2), data_col3 REAL(4,2))", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 REAL(4,2), data_col2 REAL(4,2), data_col3 REAL(4,2))");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(REAL '11.11', REAL '11.11', REAL '11.11')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(REAL '21.21', REAL '21.21', REAL '21.21')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(REAL '12.34', REAL '43.21', REAL '88.34')");
return tableName;
}
String createTableSmallInt(String tableName)
void createTableSmallInt(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 SMALLINT, data_col2 SMALLINT, data_col3 SMALLINT)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 SMALLINT, data_col2 SMALLINT, data_col3 SMALLINT)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(SMALLINT '1', SMALLINT '1', SMALLINT '1')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(SMALLINT '2', SMALLINT '2', SMALLINT '2')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(SMALLINT '3', SMALLINT '3', SMALLINT '3')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(SMALLINT '4', SMALLINT '4', SMALLINT '4')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(SMALLINT '5', SMALLINT '5', SMALLINT '5')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(SMALLINT '-32768', SMALLINT '32767', SMALLINT '0')");
return tableName;
}
String createTableString(String tableName)
void createTableString(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 STRING, data_col2 STRING, data_col3 STRING)", tableName);
return tableName;
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 STRING, data_col2 STRING, data_col3 STRING)");
}
String createTableTimestamp(String tableName)
void createTableTimestamp(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 TIMESTAMP, data_col2 TIMESTAMP, data_col3 TIMESTAMP)", tableName);
return tableName;
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 TIMESTAMP, data_col2 TIMESTAMP, data_col3 TIMESTAMP)");
}
String createTableTinyInt(String tableName)
void createTableTinyInt(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 TINYINT, data_col2 TINYINT, data_col3 TINYINT)", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 TINYINT, data_col2 TINYINT, data_col3 TINYINT)");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(TINYINT '1', TINYINT '1', TINYINT '1')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(TINYINT '2', TINYINT '2', TINYINT '2')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(TINYINT '3', TINYINT '3', TINYINT '3')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(TINYINT '4', TINYINT '4', TINYINT '4')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(TINYINT '5', TINYINT '5', TINYINT '5')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES(TINYINT '-127', TINYINT '0', TINYINT '127')");
return tableName;
}
String createTableVarBinary(String tableName)
void createTableVarBinary(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 VARBINARY(5), data_col2 VARBINARY(5), data_col3 VARBINARY(5))", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 VARBINARY(5), data_col2 VARBINARY(5), data_col3 VARBINARY(5))");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('11111', '11111', '11111')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('22222', '22222', '22222')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('33333', '33333', '33333')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('44444', '44444', '44444')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('55555', '55555', '55555')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('12351', '12341', '15311')");
return tableName;
}
String createTableVarChar(String tableName)
void createTableVarChar(String tableName)
{
tableName = safeCreateTable("CREATE TABLE " + tableName +
" (data_col1 VARCHAR(10), data_col2 VARCHAR(10), data_col3 VARCHAR(10))", tableName);
assertQuerySucceeds("CREATE TABLE " + tableName + " (data_col1 VARCHAR(10), data_col2 VARCHAR(10), data_col3 VARCHAR(10))");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('aaa', 'aaa', 'aaa')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('bbb', 'bbb', 'bbb')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('ccc', 'ccc', 'ccc')");
@ -420,82 +404,42 @@ public class TestIndexResources
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('tester', 'tester', 'tester')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('blah', 'blah', 'blah')");
assertQuerySucceeds("INSERT INTO " + tableName + " VALUES('nothing', 'nothing', 'nothing')");
return tableName;
}
static AtomicInteger count = new AtomicInteger(0);
String getNewTableName()
{
MaterializedResult result = computeActual("SHOW TABLES FROM hive.test");
String tableName = "table" + ((Thread.currentThread().getStackTrace())[2]).getMethodName().toLowerCase(Locale.ROOT);
int newIndex = 1;
ArrayList<String> results = new ArrayList<>();
for (MaterializedRow item : result.getMaterializedRows()) {
results.add(item.getField(0).toString());
}
int size = result.getRowCount();
for (int i = 0; i < size; i++) {
if (results.contains(tableName + newIndex)) {
newIndex++;
}
else {
break;
}
}
return "hive.test." + tableName + newIndex;
return "hive.test.t" + Integer.valueOf(count.getAndIncrement()).toString();
}
String getNewIndexName()
{
MaterializedResult result = computeActual("SHOW INDEX");
String indexName = "index" + ((Thread.currentThread().getStackTrace())[2]).getMethodName().toLowerCase(Locale.ROOT);
int newIndex = 1;
ArrayList<String> results = new ArrayList<>();
for (MaterializedRow item : result.getMaterializedRows()) {
results.add(item.getField(0).toString());
}
int size = result.getRowCount();
for (int i = 0; i < size; i++) {
if (results.contains(indexName + newIndex)) {
newIndex++;
}
else {
break;
}
}
return indexName + newIndex;
return "idx" + Integer.valueOf(count.getAndIncrement()).toString();
}
// Get the split count and MaterializedResult in one pair to return.
Pair<Integer, MaterializedResult> getSplitAndMaterializedResult(String testerQuery)
{
String testerQueryID = "";
int testerSplits = 0;
// Select the entry with specifics
MaterializedResult queryResult = computeActual(testerQuery);
// Get queries executed and query ID
MaterializedResult systemQueriesResult = computeActual("SELECT * FROM system.runtime.queries ORDER BY query_id DESC");
for (MaterializedRow item : systemQueriesResult.getMaterializedRows()) {
// Find query to match and get the query_id of that query for getting sum of splits later
if (testerQueryID.equals("") && item.getField(4).toString().equals(testerQuery)) {
testerQueryID = item.getField(0).toString();
}
}
// Get queries executed and query ID to find the task with sum of splits
String splits = "select sum(splits) from system.runtime.tasks where query_id in " +
"(select query_id from system.runtime.queries " +
"where query='" + testerQuery + "' order by created desc limit 1)";
assertNotEquals(testerQueryID, "");
MaterializedResult rows = computeActual(splits);
// Select entries for tasks done using the previously retrieved query ID amd get sum of splits
MaterializedResult splitsResult = computeActual("SELECT splits " +
"FROM system.runtime.tasks AS t1, system.runtime.queries AS t2 " +
"WHERE t1.query_id = t2.query_id " +
"AND t2.query_id = '" + testerQueryID + "'AND t2.query = '" + testerQuery + "'");
for (MaterializedRow item : splitsResult.getMaterializedRows()) {
// Sum up the splits
testerSplits += Integer.parseInt(item.getField(0).toString());
}
assertEquals(rows.getRowCount(), 1);
return new Pair<>(testerSplits, queryResult);
MaterializedRow materializedRow = rows.getMaterializedRows().get(0);
int fieldCount = materializedRow.getFieldCount();
assertEquals(fieldCount, 1,
"Expected only one column, but got '%d', fiedlCount: " + fieldCount);
Object value = materializedRow.getField(0);
return new Pair<>((int) (long) value, queryResult);
}
// Compare the two results are consistent.
@ -513,4 +457,22 @@ public class TestIndexResources
Collections.sort(data2);
return data1.equals(data2);
}
long getInputRowsOfLastQueryExecution(String sql)
{
String inputRowsSql = "select sum(raw_input_rows) from system.runtime.tasks where query_id in " +
"(select query_id from system.runtime.queries where query='" + sql + "' order by created desc limit 1)";
MaterializedResult rows = computeActual(inputRowsSql);
assertEquals(rows.getRowCount(), 1);
MaterializedRow materializedRow = rows.getMaterializedRows().get(0);
int fieldCount = materializedRow.getFieldCount();
assertEquals(fieldCount, 1,
"Expected only one column, but got '%d', fiedlCount: " + fieldCount);
Object value = materializedRow.getField(0);
return (long) value;
}
}