diff --git a/traindb-catalog/src/main/java/traindb/catalog/CatalogContext.java b/traindb-catalog/src/main/java/traindb/catalog/CatalogContext.java index 94f1624..61a1823 100644 --- a/traindb-catalog/src/main/java/traindb/catalog/CatalogContext.java +++ b/traindb-catalog/src/main/java/traindb/catalog/CatalogContext.java @@ -51,7 +51,9 @@ MModelInstance trainModelInstance( MSynopsis createSynopsis(String synopsisName, String modeInstanceName) throws CatalogException; - Collection getSynopses() throws CatalogException; + Collection getAllSynopses() throws CatalogException; + + Collection getAllSynopses(String baseSchema, String baseTable) throws CatalogException; boolean synopsisExists(String name) throws CatalogException; diff --git a/traindb-catalog/src/main/java/traindb/catalog/JDOCatalogContext.java b/traindb-catalog/src/main/java/traindb/catalog/JDOCatalogContext.java index 9f9d5b6..894bd6d 100644 --- a/traindb-catalog/src/main/java/traindb/catalog/JDOCatalogContext.java +++ b/traindb-catalog/src/main/java/traindb/catalog/JDOCatalogContext.java @@ -181,7 +181,7 @@ public MSynopsis createSynopsis(String synopsisName, String modelInstanceName) } @Override - public Collection getSynopses() throws CatalogException { + public Collection getAllSynopses() throws CatalogException { try { Query query = pm.newQuery(MSynopsis.class); return (List) query.execute(); @@ -190,6 +190,21 @@ public Collection getSynopses() throws CatalogException { } } + @Override + public Collection getAllSynopses(String baseSchema, String baseTable) + throws CatalogException { + try { + Query query = pm.newQuery(MSynopsis.class); + query.setFilter( + "modelInstance.schemaName == baseSchema && modelInstance.tableName == baseTable"); + query.declareParameters("String baseSchema, String baseTable"); + Collection ret = (List) query.execute(baseSchema, baseTable); + return ret; + } catch (RuntimeException e) { + throw new CatalogException("failed to get synopses", e); + } + } + @Override public boolean synopsisExists(String name) throws CatalogException { return getSynopsis(name) != null; diff --git a/traindb-core/pom.xml b/traindb-core/pom.xml index f5ff8f3..7685e73 100644 --- a/traindb-core/pom.xml +++ b/traindb-core/pom.xml @@ -89,6 +89,10 @@ limitations under the License. org.apache.calcite calcite-testkit + + org.immutables + value + sqlline sqlline @@ -255,25 +259,6 @@ limitations under the License. - - org.apache.maven.plugins - maven-shade-plugin - - - - org.postgresql:postgresql - - - - - - package - - shade - - - - org.apache.maven.plugins maven-surefire-plugin diff --git a/traindb-core/src/main/java/traindb/adapter/jdbc/JdbcTableScan.java b/traindb-core/src/main/java/traindb/adapter/jdbc/JdbcTableScan.java index 3d4977d..32c9040 100644 --- a/traindb-core/src/main/java/traindb/adapter/jdbc/JdbcTableScan.java +++ b/traindb-core/src/main/java/traindb/adapter/jdbc/JdbcTableScan.java @@ -39,7 +39,7 @@ public class JdbcTableScan extends TableScan implements JdbcRel { public final TrainDBJdbcTable jdbcTable; - protected JdbcTableScan( + public JdbcTableScan( RelOptCluster cluster, List hints, RelOptTable table, diff --git a/traindb-core/src/main/java/traindb/engine/TrainDBQueryEngine.java b/traindb-core/src/main/java/traindb/engine/TrainDBQueryEngine.java index 1b60ff2..07c2e54 100644 --- a/traindb-core/src/main/java/traindb/engine/TrainDBQueryEngine.java +++ b/traindb-core/src/main/java/traindb/engine/TrainDBQueryEngine.java @@ -364,7 +364,7 @@ public TrainDBListResultSet showSynopses() throws Exception { List header = Arrays.asList("synopsis", "model_instance", "schema", "table", "columns"); List> synopsisInfo = new ArrayList<>(); - for (MSynopsis mSynopsis : catalogContext.getSynopses()) { + for (MSynopsis mSynopsis : catalogContext.getAllSynopses()) { MModelInstance mModelInstance = mSynopsis.getModelInstance(); synopsisInfo.add(Arrays.asList(mSynopsis.getName(), mModelInstance.getName(), mModelInstance.getSchemaName(), mModelInstance.getTableName(), diff --git a/traindb-core/src/main/java/traindb/jdbc/TrainDBConnectionImpl.java b/traindb-core/src/main/java/traindb/jdbc/TrainDBConnectionImpl.java index 3a99c1c..4e6cef4 100644 --- a/traindb-core/src/main/java/traindb/jdbc/TrainDBConnectionImpl.java +++ b/traindb-core/src/main/java/traindb/jdbc/TrainDBConnectionImpl.java @@ -651,6 +651,10 @@ public static class TrainDBContextImpl implements Context { final boolean enable = config().spark(); return CalcitePrepare.Dummy.getSparkHandler(enable); } + + public CatalogContext getCatalogContext() { + return connection.getCatalogContext(); + } } /** Implementation of {@link CalciteServerStatement}. */ diff --git a/traindb-core/src/main/java/traindb/planner/TrainDBPlanner.java b/traindb-core/src/main/java/traindb/planner/TrainDBPlanner.java index 0b6d9fb..83feeac 100644 --- a/traindb-core/src/main/java/traindb/planner/TrainDBPlanner.java +++ b/traindb-core/src/main/java/traindb/planner/TrainDBPlanner.java @@ -14,39 +14,64 @@ package traindb.planner; +import java.util.Collection; +import java.util.List; import org.apache.calcite.plan.Context; import org.apache.calcite.plan.ConventionTraitDef; import org.apache.calcite.plan.RelOptCostFactory; +import org.apache.calcite.plan.RelOptTable; import org.apache.calcite.plan.RelOptUtil; import org.apache.calcite.plan.volcano.VolcanoPlanner; import org.apache.calcite.rel.RelCollationTraitDef; import org.apache.calcite.runtime.Hook; import org.checkerframework.checker.nullness.qual.Nullable; +import traindb.catalog.CatalogContext; +import traindb.catalog.CatalogException; +import traindb.catalog.pm.MSynopsis; +import traindb.planner.rules.TrainDBRules; +import traindb.prepare.TrainDBCatalogReader; -public class TrainDBPlanner { +public class TrainDBPlanner extends VolcanoPlanner { - private TrainDBPlanner() { - } + private CatalogContext catalogContext; + private TrainDBCatalogReader catalogReader; - public static VolcanoPlanner createPlanner() { - return createPlanner(null, null); + public TrainDBPlanner(CatalogContext catalogContext, TrainDBCatalogReader catalogReader) { + this(catalogContext, catalogReader, null, null); } - public static VolcanoPlanner createPlanner(Context externalContext) { - return createPlanner(null, externalContext); + public TrainDBPlanner(CatalogContext catalogContext, + TrainDBCatalogReader catalogReader, + @Nullable RelOptCostFactory costFactory, + @Nullable Context externalContext) { + super(costFactory, externalContext); + this.catalogContext = catalogContext; + this.catalogReader = catalogReader; + initPlanner(); } - public static VolcanoPlanner createPlanner(@Nullable RelOptCostFactory costFactory, - @Nullable Context externalContext) { - VolcanoPlanner planner = new VolcanoPlanner(costFactory, externalContext); + public void initPlanner() { + // TrainDB rules + addRule(TrainDBRules.APPROX_AGGREGATE_SYNOPSIS); + + RelOptUtil.registerDefaultRules(this, true, Hook.ENABLE_BINDABLE.get(false)); + addRelTraitDef(ConventionTraitDef.INSTANCE); + addRelTraitDef(RelCollationTraitDef.INSTANCE); + setTopDownOpt(false); - RelOptUtil.registerDefaultRules(planner, true, Hook.ENABLE_BINDABLE.get(false)); - planner.addRelTraitDef(ConventionTraitDef.INSTANCE); - planner.addRelTraitDef(RelCollationTraitDef.INSTANCE); - planner.setTopDownOpt(false); + Hook.PLANNER.run(this); // allow test to add or remove rules + } - Hook.PLANNER.run(planner); // allow test to add or remove rules + public Collection getAvailableSynopses(String baseSchema, String baseTable) { + try { + Collection synopses = catalogContext.getAllSynopses(baseSchema, baseTable); + // TODO check columns + return synopses; + } catch (CatalogException e) {} + return null; + } - return planner; + public RelOptTable getTable(List names) { + return catalogReader.getTable(names); } } diff --git a/traindb-core/src/main/java/traindb/planner/rules/ApproxAggregateSynopsisRule.java b/traindb-core/src/main/java/traindb/planner/rules/ApproxAggregateSynopsisRule.java new file mode 100644 index 0000000..909c0a4 --- /dev/null +++ b/traindb-core/src/main/java/traindb/planner/rules/ApproxAggregateSynopsisRule.java @@ -0,0 +1,210 @@ +/* + * 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 traindb.planner.rules; + +import com.google.common.collect.Multimap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import org.apache.calcite.plan.RelOptRuleCall; +import org.apache.calcite.plan.RelRule; +import org.apache.calcite.plan.volcano.RelSubset; +import org.apache.calcite.prepare.RelOptTableImpl; +import org.apache.calcite.rel.RelNode; +import org.apache.calcite.rel.RelVisitor; +import org.apache.calcite.rel.core.Aggregate; +import org.apache.calcite.rel.core.Filter; +import org.apache.calcite.rel.core.Project; +import org.apache.calcite.rel.core.TableScan; +import org.apache.calcite.rel.hint.RelHint; +import org.apache.calcite.rel.logical.LogicalAggregate; +import org.apache.calcite.rel.logical.LogicalProject; +import org.apache.calcite.rel.rules.TransformationRule; +import org.apache.calcite.rex.RexInputRef; +import org.apache.calcite.rex.RexNode; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.immutables.value.Value; +import traindb.adapter.jdbc.JdbcConvention; +import traindb.adapter.jdbc.JdbcTableScan; +import traindb.adapter.jdbc.TrainDBJdbcTable; +import traindb.catalog.pm.MSynopsis; +import traindb.planner.TrainDBPlanner; + +@Value.Enclosing +public class ApproxAggregateSynopsisRule + extends RelRule + implements TransformationRule { + + protected ApproxAggregateSynopsisRule(Config config) { + super(config); + } + + private static boolean isApproximateAggregate(Aggregate aggregate) { + List hints = aggregate.getHints(); + for (RelHint hint : hints) { + if (hint.hintName.equals("APPROXIMATE_AGGR")) { + return true; + } + } + return false; + } + + private static boolean isApproximateTableScan(TableScan scan) { + List hints = scan.getHints(); + for (RelHint hint : hints) { + if (hint.hintName.equals("APPROXIMATE_AGGR_TABLE")) { + return true; + } + } + return false; + } + + /** + * Returns a list of all table scans used by this expression or its children. + */ + private List findAllTableScans(RelNode rel) { + final Multimap, RelNode> nodes = + rel.getCluster().getMetadataQuery().getNodeTypes(rel); + final List usedTableScans = new ArrayList<>(); + if (nodes == null) { + return usedTableScans; + } + for (Map.Entry, Collection> e : nodes.asMap().entrySet()) { + if (TableScan.class.isAssignableFrom(e.getKey())) { + for (RelNode node : e.getValue()) { + usedTableScans.add((TableScan) node); + } + } + } + return usedTableScans; + } + + /** + * Returns the parent of the target node under input ancestor node. + */ + private RelNode getParent(RelNode ancestor, final RelNode target) { + if (ancestor == target) { + return null; + } + final List parentNodes = new ArrayList<>(); + new RelVisitor() { + @Override public void visit(RelNode node, int ordinal, @Nullable RelNode parent) { + if (node == target) { + parentNodes.add(parent); + } + for (RelNode input : node.getInputs()) { + if (input instanceof RelSubset) { + visit(((RelSubset) input).getBestOrOriginal(), ordinal, node); + } + else { + visit(input, ordinal, node); + } + } + } + }.go(ancestor); + if (parentNodes.size() == 1) { + return parentNodes.get(0); + } + return null; + } + + //~ Methods ---------------------------------------------------------------- + @Override public void onMatch(RelOptRuleCall call) { + if (!(call.getPlanner() instanceof TrainDBPlanner)) { + return; + } + final TrainDBPlanner planner = (TrainDBPlanner) call.getPlanner(); + + final Aggregate aggregate = call.rel(0); + List tableScans = findAllTableScans(aggregate); + for (TableScan scan : tableScans) { + // TODO check if the tablescan node includes aggregate columns + // and does not include non-aggregate columns + + if (!isApproximateTableScan(scan)) { + continue; + } + + RelNode parent = getParent(aggregate, scan); + if (parent == null) { + continue; + } + if (!(parent instanceof Filter || parent instanceof Project)) { + continue; + } + List tqn = scan.getTable().getQualifiedName(); + String tableSchema = tqn.get(1); + String tableName = tqn.get(2); + + Collection candidateSynopses = + planner.getAvailableSynopses(tableSchema, tableName); + if (candidateSynopses == null || candidateSynopses.isEmpty()) { + continue; + } + MSynopsis bestSynopsis = null; + for (MSynopsis synopsis : candidateSynopses) { + // TODO choose a synopsis + bestSynopsis = synopsis; + } + + List synopsisNames = new ArrayList<>(); + synopsisNames.add(tqn.get(0)); + synopsisNames.add(tqn.get(1)); + synopsisNames.add(bestSynopsis.getName()); + + RelOptTableImpl synopsisTable = (RelOptTableImpl) planner.getTable(synopsisNames); + JdbcTableScan newScan = new JdbcTableScan(scan.getCluster(), scan.getHints(), synopsisTable, + (TrainDBJdbcTable) synopsisTable.table(), (JdbcConvention) scan.getConvention()); + RelSubset subset = planner.register(newScan, null); + + if (parent instanceof Project) { + List projects = ((Project) parent).getProjects(); + List newProjects = new ArrayList<>(); + for (int i = 0; i < projects.size(); i++) { + RexInputRef inputRef = (RexInputRef) projects.get(i); + int newIndex = bestSynopsis.getModelInstance().getColumnNames() + .indexOf(parent.getRowType().getFieldNames().get(i)); + newProjects.add(new RexInputRef(newIndex, inputRef.getType())); + } + + LogicalProject newProject = new LogicalProject( + parent.getCluster(), parent.getTraitSet(), ((Project) parent).getHints(), + subset, newProjects, parent.getRowType()); + + RelNode grandParent = getParent(aggregate, parent); + RelSubset newSubset = planner.register(newProject, null); + grandParent.replaceInput(0, newSubset); + } + else { + parent.replaceInput(0, subset); + } + } + } + + /** Rule configuration. */ + @Value.Immutable(singleton = true) + public interface Config extends RelRule.Config { + Config DEFAULT = ImmutableApproxAggregateSynopsisRule.Config.of() + .withOperandSupplier(b -> + b.operand(LogicalAggregate.class) + .predicate(ApproxAggregateSynopsisRule::isApproximateAggregate) + .anyInputs()); + + @Override default ApproxAggregateSynopsisRule toRule() { + return new ApproxAggregateSynopsisRule(this); + } + } +} diff --git a/traindb-core/src/main/java/traindb/planner/rules/TrainDBRules.java b/traindb-core/src/main/java/traindb/planner/rules/TrainDBRules.java new file mode 100644 index 0000000..63cddd6 --- /dev/null +++ b/traindb-core/src/main/java/traindb/planner/rules/TrainDBRules.java @@ -0,0 +1,24 @@ +/* + * 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 traindb.planner.rules; + +public class TrainDBRules { + + private TrainDBRules() { + } + + public static final ApproxAggregateSynopsisRule APPROX_AGGREGATE_SYNOPSIS = + ApproxAggregateSynopsisRule.Config.DEFAULT.toRule(); +} diff --git a/traindb-core/src/main/java/traindb/prepare/TrainDBPrepareImpl.java b/traindb-core/src/main/java/traindb/prepare/TrainDBPrepareImpl.java index 099148d..50208c4 100644 --- a/traindb-core/src/main/java/traindb/prepare/TrainDBPrepareImpl.java +++ b/traindb-core/src/main/java/traindb/prepare/TrainDBPrepareImpl.java @@ -124,6 +124,7 @@ import org.apache.calcite.util.Pair; import org.apache.calcite.util.Util; import org.checkerframework.checker.nullness.qual.Nullable; +import traindb.catalog.CatalogContext; import traindb.common.TrainDBLogger; import traindb.engine.TrainDBListResultSet; import traindb.engine.TrainDBQueryEngine; @@ -191,8 +192,11 @@ private ParseResult convert_(Context context, String sql, boolean analyze, final Convention resultConvention = enableBindable ? BindableConvention.INSTANCE : EnumerableConvention.INSTANCE; + // Use the Volcano because it can handle the traits. - final VolcanoPlanner planner = TrainDBPlanner.createPlanner(); + CatalogContext catalogContext = + ((TrainDBConnectionImpl.TrainDBContextImpl) context).getCatalogContext(); + final VolcanoPlanner planner = new TrainDBPlanner(catalogContext, catalogReader); final SqlToRelConverter.Config config = SqlToRelConverter.config().withTrimUnusedFields(true) @@ -414,7 +418,17 @@ protected RelOptPlanner createPlanner( if (externalContext == null) { externalContext = Contexts.of(prepareContext.config()); } - final VolcanoPlanner planner = TrainDBPlanner.createPlanner(costFactory, externalContext); + CatalogContext catalogContext = + ((TrainDBConnectionImpl.TrainDBContextImpl) prepareContext).getCatalogContext(); + + TrainDBCatalogReader catalogReader = + new TrainDBCatalogReader( + prepareContext.getRootSchema(), + prepareContext.getDefaultSchemaPath(), + prepareContext.getTypeFactory(), + prepareContext.config()); + final VolcanoPlanner planner = new TrainDBPlanner( + catalogContext, catalogReader, costFactory, externalContext); return planner; } diff --git a/traindb-core/src/main/java/traindb/sql/calcite/TrainDBHintStrategyTable.java b/traindb-core/src/main/java/traindb/sql/calcite/TrainDBHintStrategyTable.java index f5d7de8..79bab5b 100644 --- a/traindb-core/src/main/java/traindb/sql/calcite/TrainDBHintStrategyTable.java +++ b/traindb-core/src/main/java/traindb/sql/calcite/TrainDBHintStrategyTable.java @@ -27,6 +27,7 @@ private static HintStrategyTable createHintStrategies() { static HintStrategyTable createHintStrategies(HintStrategyTable.Builder builder) { return builder .hintStrategy("APPROXIMATE_AGGR", HintPredicates.AGGREGATE) + .hintStrategy("APPROXIMATE_AGGR_TABLE", HintPredicates.TABLE_SCAN) .build(); } } diff --git a/traindb-core/src/main/java/traindb/sql/calcite/TrainDBSqlSelect.java b/traindb-core/src/main/java/traindb/sql/calcite/TrainDBSqlSelect.java index c41853f..70146c4 100644 --- a/traindb-core/src/main/java/traindb/sql/calcite/TrainDBSqlSelect.java +++ b/traindb-core/src/main/java/traindb/sql/calcite/TrainDBSqlSelect.java @@ -23,7 +23,7 @@ import org.apache.calcite.sql.SqlNodeList; import org.apache.calcite.sql.SqlOperator; import org.apache.calcite.sql.SqlSelect; -import org.apache.calcite.sql.SqlSelectKeyword; +import org.apache.calcite.sql.parser.Span; import org.apache.calcite.sql.parser.SqlParserPos; import org.checkerframework.checker.nullness.qual.Nullable; @@ -57,6 +57,11 @@ public TrainDBSqlSelect(SqlParserPos pos, hintList.add(new SqlHint(pos, new SqlIdentifier("APPROXIMATE_AGGR", pos), SqlNodeList.EMPTY, SqlHint.HintOptionFormat.EMPTY)); setHints(new SqlNodeList(hintList, pos)); + + SqlParserPos fromPos = Span.of(from).end(from); + hintList.add(new SqlHint(fromPos, new SqlIdentifier("APPROXIMATE_AGGR_TABLE", fromPos), + SqlNodeList.EMPTY, SqlHint.HintOptionFormat.EMPTY)); + setHints(new SqlNodeList(hintList, fromPos)); } } diff --git a/traindb-core/src/test/java/traindb/test/JdbcClientTest.java b/traindb-core/src/test/java/traindb/test/JdbcClientTest.java index 4b3ff1c..bbd30a5 100644 --- a/traindb-core/src/test/java/traindb/test/JdbcClientTest.java +++ b/traindb-core/src/test/java/traindb/test/JdbcClientTest.java @@ -184,6 +184,8 @@ public void testJdbcClientTrainModel() throws SQLException { TestUtil.printResultSet(rs); stmt.execute("DROP SYNOPSIS sales_syn"); + stmt.execute("DROP MODEL INSTANCE tgan"); + stmt.execute("DROP MODEL tablegan"); rs.close(); stmt.close(); diff --git a/traindb-core/src/test/resources/sql/basic.iq b/traindb-core/src/test/resources/sql/basic.iq index ca16359..ed409f5 100644 --- a/traindb-core/src/test/resources/sql/basic.iq +++ b/traindb-core/src/test/resources/sql/basic.iq @@ -74,102 +74,4 @@ WHERE a.product_id = b.product_id; +---------+ (1 row) -!ok - -CREATE MODEL tablegan TYPE SYNOPSIS LOCAL AS 'TableGAN' IN 'models/TableGAN.py'; -(0 rows modified) - -!update - -SHOW MODELS; -+----------+----------+----------+----------+--------------------+ -| model | type | location | class | uri | -+----------+----------+----------+----------+--------------------+ -| tablegan | SYNOPSIS | LOCAL | TableGAN | models/TableGAN.py | -+----------+----------+----------+----------+--------------------+ -(1 row) - -!ok - -TRAIN MODEL tablegan INSTANCE tgan ON instacart_small.order_products(product_id, add_to_cart_order); -(0 rows modified) - -!update - -SHOW MODEL INSTANCES; -+----------+----------------+-----------------+----------------+---------------------------------+ -| model | model_instance | schema | table | columns | -+----------+----------------+-----------------+----------------+---------------------------------+ -| tablegan | tgan | instacart_small | order_products | [product_id, add_to_cart_order] | -+----------+----------------+-----------------+----------------+---------------------------------+ -(1 row) - -!ok - -CREATE SYNOPSIS order_products_syn FROM MODEL INSTANCE tgan LIMIT 1000; -(0 rows modified) - -!update - -SHOW SYNOPSES; -+--------------------+----------------+-----------------+----------------+---------------------------------+ -| synopsis | model_instance | schema | table | columns | -+--------------------+----------------+-----------------+----------------+---------------------------------+ -| order_products_syn | tgan | instacart_small | order_products | [product_id, add_to_cart_order] | -+--------------------+----------------+-----------------+----------------+---------------------------------+ -(1 row) - -!ok - -SELECT count(*) as c2 FROM instacart_small.order_products_syn; -+------+ -| c2 | -+------+ -| 1000 | -+------+ -(1 row) - -!ok - -DROP SYNOPSIS order_products_syn; -(0 rows modified) - -!update - -SHOW SYNOPSES; -+ - | -+ -+ -(0 rows) - -!ok - -DROP MODEL INSTANCE tgan; -(0 rows modified) - -!update - -SHOW MODEL INSTANCES; -+ - | -+ -+ -(0 rows) - -!ok - -DROP MODEL tablegan; -(0 rows modified) - -!update - -SHOW MODELS; -+ - | -+ -+ -(0 rows) - -!ok - +!ok \ No newline at end of file diff --git a/traindb-core/src/test/resources/sql/synopsis.iq b/traindb-core/src/test/resources/sql/synopsis.iq new file mode 100644 index 0000000..f115c9f --- /dev/null +++ b/traindb-core/src/test/resources/sql/synopsis.iq @@ -0,0 +1,110 @@ +# synopsis.iq +!use instacart_small +!set outputformat mysql +!set maxwidth 300 + +CREATE MODEL tablegan TYPE SYNOPSIS LOCAL AS 'TableGAN' IN 'models/TableGAN.py'; +(0 rows modified) + +!update + +SHOW MODELS; ++----------+----------+----------+----------+--------------------+ +| model | type | location | class | uri | ++----------+----------+----------+----------+--------------------+ +| tablegan | SYNOPSIS | LOCAL | TableGAN | models/TableGAN.py | ++----------+----------+----------+----------+--------------------+ +(1 row) + +!ok + +TRAIN MODEL tablegan INSTANCE tgan ON instacart_small.order_products(reordered, add_to_cart_order); +(0 rows modified) + +!update + +SHOW MODEL INSTANCES; ++----------+----------------+-----------------+----------------+--------------------------------+ +| model | model_instance | schema | table | columns | ++----------+----------------+-----------------+----------------+--------------------------------+ +| tablegan | tgan | instacart_small | order_products | [reordered, add_to_cart_order] | ++----------+----------------+-----------------+----------------+--------------------------------+ +(1 row) + +!ok + +CREATE SYNOPSIS order_products_syn FROM MODEL INSTANCE tgan LIMIT 1000; +(0 rows modified) + +!update + +SHOW SYNOPSES; ++--------------------+----------------+-----------------+----------------+--------------------------------+ +| synopsis | model_instance | schema | table | columns | ++--------------------+----------------+-----------------+----------------+--------------------------------+ +| order_products_syn | tgan | instacart_small | order_products | [reordered, add_to_cart_order] | ++--------------------+----------------+-----------------+----------------+--------------------------------+ +(1 row) + +!ok + +SELECT count(*) as c2 FROM instacart_small.order_products_syn; ++------+ +| c2 | ++------+ +| 1000 | ++------+ +(1 row) + +!ok + +SELECT APPROXIMATE avg(add_to_cart_order) as average FROM instacart_small.order_products; + +JdbcToEnumerableConverter + JdbcProject(average=[CAST(/(CASE(=($1, 0), null:INTEGER, $0), $1)):INTEGER]) + JdbcAggregate(group=[{}], agg#0=[$SUM0($1)], agg#1=[COUNT()]) + JdbcTableScan(table=[[traindb, instacart_small, order_products_syn]]) +!plan + +DROP SYNOPSIS order_products_syn; +(0 rows modified) + +!update + +SHOW SYNOPSES; ++ + | ++ ++ +(0 rows) + +!ok + +DROP MODEL INSTANCE tgan; +(0 rows modified) + +!update + +SHOW MODEL INSTANCES; ++ + | ++ ++ +(0 rows) + +!ok + +DROP MODEL tablegan; +(0 rows modified) + +!update + +SHOW MODELS; ++ + | ++ ++ +(0 rows) + +!ok + diff --git a/traindb-project/pom.xml b/traindb-project/pom.xml index 6378109..057a148 100644 --- a/traindb-project/pom.xml +++ b/traindb-project/pom.xml @@ -113,6 +113,12 @@ limitations under the License. avatica-core 1.20.0 + + org.immutables + value + 2.9.0 + provided + org.datanucleus