This is an automated email from the ASF dual-hosted git repository.

xiangfu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new a4e3adb736 Refactor offline quickstarts to load all the tables by 
default (#9206)
a4e3adb736 is described below

commit a4e3adb7365ef64b02d3fb72505b97474e3d7244
Author: Xiang Fu <xiangfu.1...@gmail.com>
AuthorDate: Mon Aug 15 16:18:43 2022 -0700

    Refactor offline quickstarts to load all the tables by default (#9206)
---
 .../org/apache/pinot/tools/EmptyQuickstart.java    |  47 +-----
 .../org/apache/pinot/tools/GenericQuickstart.java  |  87 +++-------
 .../org/apache/pinot/tools/JoinQuickStart.java     |  75 +--------
 .../apache/pinot/tools/JsonIndexQuickStart.java    |  56 +------
 .../pinot/tools/MultistageEngineQuickStart.java    |  79 +++------
 .../OfflineComplexTypeHandlingQuickStart.java      |  64 +-------
 .../org/apache/pinot/tools/QuickStartBase.java     | 182 ++++++++++++++++++---
 .../java/org/apache/pinot/tools/Quickstart.java    | 119 +++-----------
 .../pinot/tools/TimestampIndexQuickstart.java      |  75 ++-------
 .../tools/admin/command/QuickStartCommand.java     |  33 ++--
 ...hubComplexTypeEvents_offline_table_config.json} |   2 +-
 .../githubComplexTypeEvents_schema.json}           |   2 +-
 .../ingestionJobSpec.yaml}                         |  10 +-
 .../rawdata/githubComplexTypeEvents_data.json}     |   0
 .../batch/githubEvents/ingestionJobSpec.yaml       |   2 +-
 .../githubEvents_data.json                         |   0
 16 files changed, 280 insertions(+), 553 deletions(-)

diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/EmptyQuickstart.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/EmptyQuickstart.java
index 24c3fcc35e..6064a4f1a2 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/EmptyQuickstart.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/EmptyQuickstart.java
@@ -18,61 +18,20 @@
  */
 package org.apache.pinot.tools;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import org.apache.pinot.spi.auth.AuthProvider;
 import org.apache.pinot.tools.admin.PinotAdministrator;
-import org.apache.pinot.tools.admin.command.QuickstartRunner;
 
 
-public class EmptyQuickstart extends QuickStartBase {
+public class EmptyQuickstart extends Quickstart {
   @Override
   public List<String> types() {
     return Arrays.asList("EMPTY", "DEFAULT");
   }
 
-  public AuthProvider getAuthProvider() {
-    return null;
-  }
-
-  public void execute()
-      throws Exception {
-    File quickstartTmpDir = new File(_dataDir.getAbsolutePath());
-    File dataDir = new File(quickstartTmpDir, "rawdata");
-    if (!dataDir.mkdirs()) {
-      printStatus(Quickstart.Color.YELLOW, "***** Bootstrapping data from 
existing directory *****");
-    } else {
-      printStatus(Quickstart.Color.YELLOW, "***** Creating new data directory 
for fresh installation *****");
-    }
-
-    QuickstartRunner runner =
-        new QuickstartRunner(new ArrayList<>(), 1, 1, 1, 1,
-            dataDir, true, getAuthProvider(), getConfigOverrides(), 
_zkExternalAddress, false);
-
-    if (_zkExternalAddress != null) {
-      printStatus(Quickstart.Color.CYAN, "***** Starting controller, broker 
and server *****");
-    } else {
-      printStatus(Quickstart.Color.CYAN, "***** Starting Zookeeper, 
controller, broker and server *****");
-    }
-
-    runner.startAll();
-
-    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-      try {
-        printStatus(Quickstart.Color.GREEN, "***** Shutting down empty quick 
start *****");
-        runner.stop();
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-    }));
-
-    waitForBootstrapToComplete(runner);
-
-    printStatus(Quickstart.Color.YELLOW, "***** Empty quickstart setup 
complete *****");
-    printStatus(Quickstart.Color.GREEN,
-        "You can always go to http://localhost:9000 to play around in the 
query console");
+  public String[] getDefaultBatchTableDirectories() {
+    return new String[]{};
   }
 
   public static void main(String[] args)
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/GenericQuickstart.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/GenericQuickstart.java
index b0e8ac3069..62fc47d6b3 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/GenericQuickstart.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/GenericQuickstart.java
@@ -18,24 +18,16 @@
  */
 package org.apache.pinot.tools;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import java.io.File;
-import java.net.URL;
 import java.util.Arrays;
 import java.util.List;
-import org.apache.commons.io.FileUtils;
 import org.apache.pinot.common.utils.ZkStarter;
 import org.apache.pinot.spi.stream.StreamDataProvider;
 import org.apache.pinot.spi.stream.StreamDataServerStartable;
-import org.apache.pinot.tools.Quickstart.Color;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
 import org.apache.pinot.tools.utils.KafkaStarterUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import static org.apache.pinot.tools.Quickstart.prettyPrintResponse;
-
 
 /**
  * Sets up a demo Pinot cluster with 1 zookeeper, 1 controller, 1 broker and 1 
server
@@ -49,29 +41,12 @@ import static 
org.apache.pinot.tools.Quickstart.prettyPrintResponse;
  *  ingestion_job_spec.json
  *  </code>
  */
-public class GenericQuickstart extends QuickStartBase {
+public class GenericQuickstart extends Quickstart {
   private static final Logger LOGGER = 
LoggerFactory.getLogger(GenericQuickstart.class);
-  private final File _schemaFile;
-  private final File _tableConfigFile;
-  private final File _tableDirectory;
-  private final String _tableName;
   private StreamDataServerStartable _kafkaStarter;
   private ZkStarter.ZookeeperInstance _zookeeperInstance;
 
   public GenericQuickstart() {
-    
this(GenericQuickstart.class.getClassLoader().getResource("examples/batch/starbucksStores").getPath(),
-        "starbucksStores");
-  }
-
-  public GenericQuickstart(String tableDirectoryPath, String tableName) {
-    _tableDirectory = new File(tableDirectoryPath);
-    _tableName = tableName;
-
-    if (!_tableDirectory.exists()) {
-      Preconditions.checkState(_tableDirectory.mkdirs());
-    }
-    _schemaFile = new File(_tableDirectory, "schema.json");
-    _tableConfigFile = new File(_tableDirectory, "table_config.json");
   }
 
   private void startKafka() {
@@ -91,41 +66,9 @@ public class GenericQuickstart extends QuickStartBase {
     return Arrays.asList("GENERIC");
   }
 
-  public void execute()
+  @Override
+  public void runSampleQueries(QuickstartRunner runner)
       throws Exception {
-
-    File tempDir = new File(FileUtils.getTempDirectory(), 
String.valueOf(System.currentTimeMillis()));
-    Preconditions.checkState(tempDir.mkdirs());
-    QuickstartTableRequest request = new 
QuickstartTableRequest(_tableDirectory.getAbsolutePath());
-    final QuickstartRunner runner =
-        new QuickstartRunner(Lists.newArrayList(request), 1, 1, 1, 1, tempDir, 
getConfigOverrides());
-
-    printStatus(Color.CYAN, "***** Starting Kafka *****");
-    startKafka();
-
-    printStatus(Color.CYAN, "***** Starting zookeeper, controller, server and 
broker *****");
-    runner.startAll();
-
-    printStatus(Color.CYAN, "***** Adding table *****");
-    runner.bootstrapTable();
-
-    printStatus(Color.CYAN, "***** Waiting for 10 seconds for a few events to 
get populated *****");
-    Thread.sleep(10000);
-
-    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-      try {
-        printStatus(Color.GREEN, "***** Shutting down QuickStart cluster 
*****");
-        runner.stop();
-        _kafkaStarter.stop();
-        ZkStarter.stopLocalZkServer(_zookeeperInstance);
-        FileUtils.deleteDirectory(_tableDirectory);
-      } catch (Exception e) {
-        LOGGER.error("Caught exception in shutting down QuickStart cluster", 
e);
-      }
-    }));
-
-    printStatus(Color.YELLOW, "***** GenericQuickStart demo quickstart setup 
complete *****");
-
     String q1 = "select count(*) from starbucksStores limit 0";
     printStatus(Color.YELLOW, "Total number of documents in the table");
     printStatus(Color.CYAN, "Query : " + q1);
@@ -145,17 +88,27 @@ public class GenericQuickstart extends QuickStartBase {
     printStatus(Color.CYAN, "Query : " + q3);
     printStatus(Color.YELLOW, prettyPrintResponse(runner.runQuery(q3)));
     printStatus(Color.GREEN, 
"***************************************************");
+  }
+
+  public void execute()
+      throws Exception {
+    printStatus(Color.CYAN, "***** Starting Kafka *****");
+    startKafka();
 
-    printStatus(Color.GREEN, "You can always go to http://localhost:9000 to 
play around in the query console");
+    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+      try {
+        printStatus(Color.GREEN, "***** Shutting down QuickStart cluster 
*****");
+        _kafkaStarter.stop();
+        ZkStarter.stopLocalZkServer(_zookeeperInstance);
+      } catch (Exception e) {
+        LOGGER.error("Caught exception in shutting down QuickStart cluster", 
e);
+      }
+    }));
+    super.execute();
   }
 
   public static void main(String[] args)
       throws Exception {
-    ClassLoader classLoader = GenericQuickstart.class.getClassLoader();
-    URL resource = classLoader.getResource("examples/batch/starbucksStores");
-    String tableDirectoryPath = resource.getPath();
-
-    GenericQuickstart quickstart = new GenericQuickstart(tableDirectoryPath, 
"starbucksStores");
-    quickstart.execute();
+    new GenericQuickstart().execute();
   }
 }
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/JoinQuickStart.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/JoinQuickStart.java
index c6d9c3bdd0..6a22dde415 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/JoinQuickStart.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/JoinQuickStart.java
@@ -18,87 +18,24 @@
  */
 package org.apache.pinot.tools;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import java.io.File;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import org.apache.commons.io.FileUtils;
 import org.apache.pinot.tools.admin.PinotAdministrator;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
 
-import static org.apache.pinot.tools.Quickstart.prettyPrintResponse;
 
-
-public class JoinQuickStart extends QuickStartBase {
+public class JoinQuickStart extends Quickstart {
 
   @Override
   public List<String> types() {
     return Collections.singletonList("JOIN");
   }
 
-  public void execute()
+  @Override
+  public void runSampleQueries(QuickstartRunner runner)
       throws Exception {
-    File quickstartTmpDir = new File(_dataDir, 
String.valueOf(System.currentTimeMillis()));
-
-    // Baseball stat table
-    File baseBallStatsBaseDir = new File(quickstartTmpDir, "baseballStats");
-    File schemaFile = new File(baseBallStatsBaseDir, 
"baseballStats_schema.json");
-    File tableConfigFile = new File(baseBallStatsBaseDir, 
"baseballStats_offline_table_config.json");
-    File ingestionJobSpecFile = new File(baseBallStatsBaseDir, 
"ingestionJobSpec.yaml");
-    ClassLoader classLoader = Quickstart.class.getClassLoader();
-    URL resource = 
classLoader.getResource("examples/batch/baseballStats/baseballStats_schema.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, schemaFile);
-    resource = 
classLoader.getResource("examples/batch/baseballStats/baseballStats_offline_table_config.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, tableConfigFile);
-    resource = 
classLoader.getResource("examples/batch/baseballStats/ingestionJobSpec.yaml");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, ingestionJobSpecFile);
-    QuickstartTableRequest request = new 
QuickstartTableRequest(baseBallStatsBaseDir.getAbsolutePath());
-
-    // Baseball teams dim table
-    File dimBaseballTeamsBaseDir = new File(quickstartTmpDir, 
"dimBaseballTeams");
-    schemaFile = new File(dimBaseballTeamsBaseDir, 
"dimBaseballTeams_schema.json");
-    tableConfigFile = new File(dimBaseballTeamsBaseDir, 
"dimBaseballTeams_offline_table_config.json");
-    ingestionJobSpecFile = new File(dimBaseballTeamsBaseDir, 
"ingestionJobSpec.yaml");
-    classLoader = Quickstart.class.getClassLoader();
-    resource = 
classLoader.getResource("examples/batch/dimBaseballTeams/dimBaseballTeams_schema.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, schemaFile);
-    resource = 
classLoader.getResource("examples/batch/dimBaseballTeams/dimBaseballTeams_offline_table_config.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, tableConfigFile);
-    resource = 
classLoader.getResource("examples/batch/dimBaseballTeams/ingestionJobSpec.yaml");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, ingestionJobSpecFile);
-    QuickstartTableRequest dimTableRequest = new 
QuickstartTableRequest(dimBaseballTeamsBaseDir.getAbsolutePath());
-
-    File tempDir = new File(quickstartTmpDir, "tmp");
-    FileUtils.forceMkdir(tempDir);
-    QuickstartRunner runner =
-        new QuickstartRunner(Lists.newArrayList(request, dimTableRequest), 1, 
1, 3, 1, tempDir, getConfigOverrides());
-
-    printStatus(Quickstart.Color.CYAN, "***** Starting Zookeeper, controller, 
broker and server *****");
-    runner.startAll();
-    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-      try {
-        printStatus(Quickstart.Color.GREEN, "***** Shutting down offline quick 
start *****");
-        runner.stop();
-        FileUtils.deleteDirectory(quickstartTmpDir);
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-    }));
-    printStatus(Quickstart.Color.CYAN, "***** Bootstrap baseballStats table 
*****");
-    runner.bootstrapTable();
-
-    waitForBootstrapToComplete(null);
-
     printStatus(Quickstart.Color.YELLOW, "***** Offline quickstart setup 
complete *****");
 
     String q1 = "select count(*) from baseballStats limit 1";
@@ -120,9 +57,11 @@ public class JoinQuickStart extends QuickStartBase {
     printStatus(Quickstart.Color.CYAN, "Query : " + q3);
     printStatus(Quickstart.Color.YELLOW, 
prettyPrintResponse(runner.runQuery(q3)));
     printStatus(Quickstart.Color.GREEN, 
"***************************************************");
+  }
 
-    printStatus(Quickstart.Color.GREEN,
-        "You can always go to http://localhost:9000 to play around in the 
query console");
+  @Override
+  protected int getNumQuickstartRunnerServers() {
+    return 3;
   }
 
   public static void main(String[] args)
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/JsonIndexQuickStart.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/JsonIndexQuickStart.java
index 035bee90e4..debc15835f 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/JsonIndexQuickStart.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/JsonIndexQuickStart.java
@@ -18,81 +18,31 @@
  */
 package org.apache.pinot.tools;
 
-import com.google.common.base.Preconditions;
-import java.io.File;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.pinot.tools.Quickstart.Color;
 import org.apache.pinot.tools.admin.PinotAdministrator;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
 
-import static org.apache.pinot.tools.Quickstart.prettyPrintResponse;
 
-
-public class JsonIndexQuickStart extends QuickStartBase {
+public class JsonIndexQuickStart extends Quickstart {
 
   @Override
   public List<String> types() {
     return Arrays.asList("OFFLINE_JSON_INDEX", "OFFLINE-JSON-INDEX", 
"BATCH_JSON_INDEX", "BATCH-JSON-INDEX");
   }
 
-  public void execute()
+  @Override
+  public void runSampleQueries(QuickstartRunner runner)
       throws Exception {
-    File quickstartTmpDir = new File(_dataDir, 
String.valueOf(System.currentTimeMillis()));
-    File baseDir = new File(quickstartTmpDir, "githubEvents");
-    File dataDir = new File(quickstartTmpDir, "rawdata");
-    Preconditions.checkState(dataDir.mkdirs());
-
-    File schemaFile = new File(baseDir, "githubEvents_schema.json");
-    File tableConfigFile = new File(baseDir, 
"githubEvents_offline_table_config.json");
-    File ingestionJobSpecFile = new File(baseDir, "ingestionJobSpec.yaml");
-
-    ClassLoader classLoader = JsonIndexQuickStart.class.getClassLoader();
-    URL resource = 
classLoader.getResource("examples/batch/githubEvents/githubEvents_offline_table_config.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, tableConfigFile);
-    resource = 
classLoader.getResource("examples/batch/githubEvents/githubEvents_schema.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, schemaFile);
-    resource = 
classLoader.getResource("examples/batch/githubEvents/ingestionJobSpec.yaml");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, ingestionJobSpecFile);
-
-    QuickstartTableRequest request = new 
QuickstartTableRequest(baseDir.getAbsolutePath());
-    final QuickstartRunner runner =
-        new QuickstartRunner(Collections.singletonList(request), 1, 1, 1, 1, 
dataDir, getConfigOverrides());
-
-    printStatus(Color.CYAN, "***** Starting Zookeeper, controller, broker and 
server *****");
-    runner.startAll();
-    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-      try {
-        printStatus(Color.GREEN, "***** Shutting down offline quick start 
*****");
-        runner.stop();
-        FileUtils.deleteDirectory(quickstartTmpDir);
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-    }));
-    printStatus(Color.CYAN, "***** Bootstrap githubEvents table *****");
-    runner.bootstrapTable();
-
-    waitForBootstrapToComplete(null);
-
     printStatus(Color.YELLOW, "***** Offline json-index quickstart setup 
complete *****");
-
     String q1 =
         "select json_extract_scalar(repo, '$.name', 'STRING'), count(*) from 
githubEvents where json_match(actor, "
             + "'\"$.login\"=''LombiqBot''') group by 1 order by 2 desc limit 
10";
     printStatus(Color.YELLOW, "Most contributed repos by 'LombiqBot'");
     printStatus(Color.CYAN, "Query : " + q1);
     printStatus(Color.YELLOW, prettyPrintResponse(runner.runQuery(q1)));
-
     printStatus(Color.GREEN, 
"***************************************************");
-    printStatus(Color.GREEN, "You can always go to http://localhost:9000 to 
play around in the query console");
   }
 
   public static void main(String[] args)
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/MultistageEngineQuickStart.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/MultistageEngineQuickStart.java
index 1bbb87bca5..2ff4928b03 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/MultistageEngineQuickStart.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/MultistageEngineQuickStart.java
@@ -18,25 +18,18 @@
  */
 package org.apache.pinot.tools;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import java.io.File;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import org.apache.commons.io.FileUtils;
 import org.apache.pinot.spi.utils.CommonConstants;
 import org.apache.pinot.tools.admin.PinotAdministrator;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
 
-import static org.apache.pinot.tools.Quickstart.prettyPrintResponse;
 
-
-public class MultistageEngineQuickStart extends QuickStartBase {
+public class MultistageEngineQuickStart extends Quickstart {
 
   @Override
   public List<String> types() {
@@ -44,59 +37,12 @@ public class MultistageEngineQuickStart extends 
QuickStartBase {
   }
 
   @Override
-  public Map<String, Object> getConfigOverrides() {
-    Map<String, Object> overrides = new HashMap<>(super.getConfigOverrides());
-    overrides.put("pinot.multistage.engine.enabled", "true");
-    overrides.put("pinot.server.instance.currentDataTableVersion", 4);
-    return overrides;
-  }
-
-  public void execute()
+  public void runSampleQueries(QuickstartRunner runner)
       throws Exception {
-    File quickstartTmpDir = new File(_dataDir, 
String.valueOf(System.currentTimeMillis()));
-
-    // Baseball stat table
-    File baseBallStatsBaseDir = new File(quickstartTmpDir, "baseballStats");
-    File schemaFile = new File(baseBallStatsBaseDir, 
"baseballStats_schema.json");
-    File tableConfigFile = new File(baseBallStatsBaseDir, 
"baseballStats_offline_table_config.json");
-    File ingestionJobSpecFile = new File(baseBallStatsBaseDir, 
"ingestionJobSpec.yaml");
-    ClassLoader classLoader = Quickstart.class.getClassLoader();
-    URL resource = 
classLoader.getResource("examples/batch/baseballStats/baseballStats_schema.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, schemaFile);
-    resource = 
classLoader.getResource("examples/batch/baseballStats/baseballStats_offline_table_config.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, tableConfigFile);
-    resource = 
classLoader.getResource("examples/batch/baseballStats/ingestionJobSpec.yaml");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, ingestionJobSpecFile);
-    QuickstartTableRequest request = new 
QuickstartTableRequest(baseBallStatsBaseDir.getAbsolutePath());
-
-    File tempDir = new File(quickstartTmpDir, "tmp");
-    FileUtils.forceMkdir(tempDir);
-    QuickstartRunner runner =
-        new QuickstartRunner(Lists.newArrayList(request), 1, 1, 1, 1, tempDir, 
getConfigOverrides());
-
-    printStatus(Quickstart.Color.CYAN, "***** Starting Zookeeper, controller, 
broker and server *****");
-    runner.startAll();
-    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-      try {
-        printStatus(Quickstart.Color.GREEN, "***** Shutting down offline quick 
start *****");
-        runner.stop();
-        FileUtils.deleteDirectory(quickstartTmpDir);
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-    }));
-    printStatus(Quickstart.Color.CYAN, "***** Bootstrap baseballStats table 
*****");
-    runner.bootstrapTable();
-
-    waitForBootstrapToComplete(null);
 
+    printStatus(Quickstart.Color.YELLOW, "***** Multi-stage engine quickstart 
setup complete *****");
     Map<String, String> queryOptions = Collections.singletonMap("queryOptions",
         CommonConstants.Broker.Request.QueryOptionKey.USE_MULTISTAGE_ENGINE + 
"=true");
-
-    printStatus(Quickstart.Color.YELLOW, "***** Multi-stage engine quickstart 
setup complete *****");
     String q1 = "SELECT count(*) FROM baseballStats_OFFLINE";
     printStatus(Quickstart.Color.YELLOW, "Total number of documents in the 
table");
     printStatus(Quickstart.Color.CYAN, "Query : " + q1);
@@ -112,11 +58,26 @@ public class MultistageEngineQuickStart extends 
QuickStartBase {
     printStatus(Quickstart.Color.YELLOW, 
prettyPrintResponse(runner.runQuery(q2, queryOptions)));
     printStatus(Quickstart.Color.GREEN, 
"***************************************************");
 
+    String q3 = "SELECT a.playerName, a.teamID, b.teamName \n"
+        + "FROM baseballStats_OFFLINE AS a\n"
+        + "JOIN dimBaseballTeams_OFFLINE AS b\n"
+        + "ON a.teamID = b.teamID";
+    printStatus(Quickstart.Color.YELLOW, "Baseball Stats with joined team 
names");
+    printStatus(Quickstart.Color.CYAN, "Query : " + q3);
+    printStatus(Quickstart.Color.YELLOW, 
prettyPrintResponse(runner.runQuery(q3, queryOptions)));
+    printStatus(Quickstart.Color.GREEN, 
"***************************************************");
+
     printStatus(Quickstart.Color.GREEN, 
"***************************************************");
     printStatus(Quickstart.Color.YELLOW, "Example query run completed.");
     printStatus(Quickstart.Color.GREEN, 
"***************************************************");
-    printStatus(Quickstart.Color.GREEN,
-        "You can always go to http://localhost:9000 to play around in the 
query console");
+  }
+
+  @Override
+  public Map<String, Object> getConfigOverrides() {
+    Map<String, Object> overrides = new HashMap<>(super.getConfigOverrides());
+    overrides.put("pinot.multistage.engine.enabled", "true");
+    overrides.put("pinot.server.instance.currentDataTableVersion", 4);
+    return overrides;
   }
 
   public static void main(String[] args)
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/OfflineComplexTypeHandlingQuickStart.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/OfflineComplexTypeHandlingQuickStart.java
index c5cd73c819..168f496067 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/OfflineComplexTypeHandlingQuickStart.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/OfflineComplexTypeHandlingQuickStart.java
@@ -18,81 +18,29 @@
  */
 package org.apache.pinot.tools;
 
-import com.google.common.base.Preconditions;
-import java.io.File;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.pinot.tools.Quickstart.Color;
 import org.apache.pinot.tools.admin.PinotAdministrator;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
 
-import static org.apache.pinot.tools.Quickstart.prettyPrintResponse;
 
-
-public class OfflineComplexTypeHandlingQuickStart extends QuickStartBase {
+public class OfflineComplexTypeHandlingQuickStart extends Quickstart {
   @Override
   public List<String> types() {
-      return Arrays.asList("OFFLINE_COMPLEX_TYPE", "OFFLINE-COMPLEX-TYPE", 
"BATCH_COMPLEX_TYPE", "BATCH-COMPLEX-TYPE");
+    return Arrays.asList("OFFLINE_COMPLEX_TYPE", "OFFLINE-COMPLEX-TYPE", 
"BATCH_COMPLEX_TYPE", "BATCH-COMPLEX-TYPE");
   }
 
-  public void execute()
+  @Override
+  public void runSampleQueries(QuickstartRunner runner)
       throws Exception {
-    File quickstartTmpDir = new File(_dataDir, 
String.valueOf(System.currentTimeMillis()));
-    File baseDir = new File(quickstartTmpDir, "githubEvents");
-    File dataDir = new File(quickstartTmpDir, "rawdata");
-    Preconditions.checkState(dataDir.mkdirs());
-
-    File schemaFile = new File(baseDir, "githubEvents_schema.json");
-    File tableConfigFile = new File(baseDir, 
"githubEvents_offline_table_config.json");
-    File ingestionJobSpecFile = new File(baseDir, "ingestionJobSpec.yaml");
-
-    ClassLoader classLoader = 
OfflineComplexTypeHandlingQuickStart.class.getClassLoader();
-    URL resource = classLoader
-        
.getResource("examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_table_config.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, tableConfigFile);
-    // TODO: add all columns of the flattened fields after the schema inference
-    resource =
-        
classLoader.getResource("examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_schema.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, schemaFile);
-    resource = 
classLoader.getResource("examples/batch/githubEvents/ingestionJobComplexTypeHandlingSpec.yaml");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, ingestionJobSpecFile);
-
-    QuickstartTableRequest request = new 
QuickstartTableRequest(baseDir.getAbsolutePath());
-    final QuickstartRunner runner =
-        new QuickstartRunner(Collections.singletonList(request), 1, 1, 1, 1, 
dataDir, getConfigOverrides());
-
-    printStatus(Color.CYAN, "***** Starting Zookeeper, controller, broker and 
server *****");
-    runner.startAll();
-    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-      try {
-        printStatus(Color.GREEN, "***** Shutting down offline quick start 
*****");
-        runner.stop();
-        FileUtils.deleteDirectory(quickstartTmpDir);
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-    }));
-    printStatus(Color.CYAN, "***** Bootstrap githubEvents table *****");
-    runner.bootstrapTable();
-
-    waitForBootstrapToComplete(null);
-
     printStatus(Color.YELLOW, "***** Offline complex-type-handling quickstart 
setup complete *****");
-
     String q1 =
-        "select id, \"payload.commits.author.name\", 
\"payload.commits.author.email\" from githubEvents limit 10";
+        "select id, \"payload.commits.author.name\", 
\"payload.commits.author.email\" from githubComplexTypeEvents "
+            + "limit 10";
     printStatus(Color.CYAN, "Query : " + q1);
     printStatus(Color.YELLOW, prettyPrintResponse(runner.runQuery(q1)));
-
     printStatus(Color.GREEN, 
"***************************************************");
-    printStatus(Color.GREEN, "You can always go to http://localhost:9000 to 
play around in the query console");
   }
 
   public static void main(String[] args)
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/QuickStartBase.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/QuickStartBase.java
index d58e38bfc8..225aeb40fd 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/QuickStartBase.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/QuickStartBase.java
@@ -18,21 +18,53 @@
  */
 package org.apache.pinot.tools;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import java.io.File;
+import java.io.IOException;
+import java.net.URL;
 import java.nio.file.Paths;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
+import org.apache.pinot.tools.utils.JarUtils;
 import org.apache.pinot.tools.utils.PinotConfigUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 
+/**
+ * Assuming that database name is DBNAME, bootstrap path must have the file 
structure specified below to properly
+ * load the table:
+ *  DBNAME
+ *  ├── ingestionJobSpec.yaml
+ *  ├── rawdata
+ *  │   └── DBNAME_data.csv
+ *  ├── DBNAME_offline_table_config.json
+ *  └── DBNAME_schema.json
+ *
+ */
 public abstract class QuickStartBase {
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(QuickStartBase.class);
+  private static final String TAB = "\t\t";
+  private static final String NEW_LINE = "\n";
+
+  protected static final String[] DEFAULT_OFFLINE_TABLE_DIRECTORIES = new 
String[]{
+      "examples/batch/airlineStats",
+      "examples/minions/batch/baseballStats",
+      "examples/batch/dimBaseballTeams",
+      "examples/batch/starbucksStores",
+      "examples/batch/githubEvents",
+      "examples/batch/githubComplexTypeEvents"
+  };
+
   protected File _dataDir = FileUtils.getTempDirectory();
-  protected String _bootstrapDataDir;
+  protected String[] _bootstrapDataDirs;
   protected String _zkExternalAddress;
   protected String _configFilePath;
 
@@ -41,35 +73,19 @@ public abstract class QuickStartBase {
     return this;
   }
 
-  public QuickStartBase setBootstrapDataDir(String bootstrapDataDir) {
-    _bootstrapDataDir = bootstrapDataDir;
+  public QuickStartBase setBootstrapDataDirs(String[] bootstrapDataDirs) {
+    _bootstrapDataDirs = bootstrapDataDirs;
     return this;
   }
 
-  /**
-   * Assuming that database name is DBNAME, bootstrap path must have the file 
structure specified below to properly
-   * load the table:
-   *  DBNAME
-   *  ├── ingestionJobSpec.yaml
-   *  ├── rawdata
-   *  │   └── DBNAME_data.csv
-   *  ├── DBNAME_offline_table_config.json
-   *  └── DBNAME_schema.json
-   *
-   * @return bootstrap path if specified by command line argument 
-bootstrapTableDir; otherwise, default.
-   */
-  public String getBootstrapDataDir(String bootstrapDataDir) {
-    return _bootstrapDataDir != null ? _bootstrapDataDir : bootstrapDataDir;
-  }
-
   /** @return Table name if specified by command line argument 
-bootstrapTableDir; otherwise, default. */
   public String getTableName(String bootstrapDataDir) {
-    return 
Paths.get(getBootstrapDataDir(bootstrapDataDir)).getFileName().toString();
+    return Paths.get(bootstrapDataDir).getFileName().toString();
   }
 
   /** @return true if bootstrapTableDir is not specified by command line 
argument -bootstrapTableDir, else false.*/
   public boolean useDefaultBootstrapTableDir() {
-    return _bootstrapDataDir == null;
+    return _bootstrapDataDirs == null;
   }
 
   public QuickStartBase setZkExternalAddress(String zkExternalAddress) {
@@ -84,6 +100,10 @@ public abstract class QuickStartBase {
 
   public abstract List<String> types();
 
+  public void runSampleQueries(QuickstartRunner runner)
+      throws Exception {
+  }
+
   protected void waitForBootstrapToComplete(QuickstartRunner runner)
       throws Exception {
     QuickStartBase.printStatus(Quickstart.Color.CYAN,
@@ -98,6 +118,99 @@ public abstract class QuickStartBase {
   public abstract void execute()
       throws Exception;
 
+  protected List<QuickstartTableRequest> bootstrapOfflineTableDirectories(File 
quickstartTmpDir)
+      throws IOException {
+    List<QuickstartTableRequest> quickstartTableRequests = new ArrayList<>();
+    for (String directory : getDefaultBatchTableDirectories()) {
+      String tableName = getTableName(directory);
+      File baseDir = new File(quickstartTmpDir, tableName);
+      File dataDir = new File(baseDir, "rawdata");
+      Preconditions.checkState(dataDir.mkdirs());
+      if (useDefaultBootstrapTableDir()) {
+        copyResourceTableToTmpDirectory(directory, tableName, baseDir, 
dataDir, false);
+      } else {
+        copyFilesystemTableToTmpDirectory(directory, tableName, baseDir);
+      }
+      quickstartTableRequests.add(new 
QuickstartTableRequest(baseDir.getAbsolutePath()));
+    }
+    return quickstartTableRequests;
+  }
+
+  private static void copyResourceTableToTmpDirectory(String sourcePath, 
String tableName, File baseDir, File dataDir,
+      boolean isStreamTable)
+      throws IOException {
+    ClassLoader classLoader = Quickstart.class.getClassLoader();
+    // Copy schema
+    URL resource = classLoader.getResource(sourcePath + File.separator + 
tableName + "_schema.json");
+    Preconditions.checkNotNull(resource, "Missing schema json file for table - 
" + tableName);
+    File schemaFile = new File(baseDir, tableName + "_schema.json");
+    FileUtils.copyURLToFile(resource, schemaFile);
+
+    // Copy table config
+    String tableConfigFileSuffix = isStreamTable ? 
"_realtime_table_config.json" : "_offline_table_config.json";
+    File tableConfigFile = new File(baseDir, tableName + 
tableConfigFileSuffix);
+    String sourceTableConfig = sourcePath + File.separator + tableName + 
tableConfigFileSuffix;
+    resource = classLoader.getResource(sourceTableConfig);
+    Preconditions.checkNotNull(resource, "Missing table config file for table 
- " + tableName);
+    FileUtils.copyURLToFile(resource, tableConfigFile);
+
+    // Copy raw data
+    String sourceRawDataPath = sourcePath + File.separator + "rawdata";
+    resource = classLoader.getResource(sourceRawDataPath);
+    if (resource != null) {
+      File rawDataDir = new File(resource.getFile());
+      if (rawDataDir.isDirectory()) {
+        // Copy the directory from `pinot-tools/src/main/resources/examples` 
directory. This code path is used for
+        // running Quickstart inside IDE, `ClassLoader.getResource()` should 
source it at build directory,
+        // e.g. 
`/pinot-tools/target/classes/examples/batch/airlineStats/rawdata`
+        FileUtils.copyDirectory(rawDataDir, dataDir);
+      } else {
+        // Copy the directory recursively from a jar file. This code path is 
used for running Quickstart using
+        // pinot-admin script. The `ClassLoader.getResource()` should found 
the resources in the jar file then
+        // decompress it, e.g. 
`lib/pinot-all-jar-with-dependencies.jar!/examples/batch/airlineStats/rawdata`
+        String[] jarPathSplits = resource.toString().split("!/", 2);
+        JarUtils.copyResourcesToDirectory(jarPathSplits[0], jarPathSplits[1], 
dataDir.getAbsolutePath());
+      }
+    } else {
+      LOGGER.warn("Not found rawdata directory for table {} from {}", 
tableName, sourceRawDataPath);
+    }
+
+    if (!isStreamTable) {
+      // Copy ingestion job spec file
+      resource = classLoader.getResource(sourcePath + File.separator + 
"ingestionJobSpec.yaml");
+      if (resource != null) {
+        File ingestionJobSpecFile = new File(baseDir, "ingestionJobSpec.yaml");
+        FileUtils.copyURLToFile(resource, ingestionJobSpecFile);
+      }
+    }
+  }
+
+  private static void copyFilesystemTableToTmpDirectory(String sourcePath, 
String tableName, File baseDir)
+      throws IOException {
+    File fileDb = new File(sourcePath);
+
+    if (!fileDb.exists() || !fileDb.isDirectory()) {
+      throw new RuntimeException("Directory " + fileDb.getAbsolutePath() + " 
not found.");
+    }
+
+    File schemaFile = new File(fileDb, tableName + "_schema.json");
+    if (!schemaFile.exists()) {
+      throw new RuntimeException("Schema file " + schemaFile.getAbsolutePath() 
+ " not found.");
+    }
+
+    File tableFile = new File(fileDb, tableName + 
"_offline_table_config.json");
+    if (!tableFile.exists()) {
+      throw new RuntimeException("Table table " + tableFile.getAbsolutePath() 
+ " not found.");
+    }
+
+    File data = new File(fileDb, "rawdata" + File.separator + tableName + 
"_data.csv");
+    if (!data.exists()) {
+      throw new RuntimeException(("Data file " + data.getAbsolutePath() + " 
not found. "));
+    }
+
+    FileUtils.copyDirectory(fileDb, baseDir);
+  }
+
   protected Map<String, Object> getConfigOverrides() {
     try {
       return StringUtils.isEmpty(_configFilePath) ? ImmutableMap.of()
@@ -106,4 +219,31 @@ public abstract class QuickStartBase {
       throw new RuntimeException(e);
     }
   }
+
+  protected String[] getDefaultBatchTableDirectories() {
+    return DEFAULT_OFFLINE_TABLE_DIRECTORIES;
+  }
+
+  public static String prettyPrintResponse(JsonNode response) {
+    StringBuilder responseBuilder = new StringBuilder();
+
+    // Sql Results
+    if (response.has("resultTable")) {
+      JsonNode columns = 
response.get("resultTable").get("dataSchema").get("columnNames");
+      int numColumns = columns.size();
+      for (int i = 0; i < numColumns; i++) {
+        responseBuilder.append(columns.get(i).asText()).append(TAB);
+      }
+      responseBuilder.append(NEW_LINE);
+      JsonNode rows = response.get("resultTable").get("rows");
+      for (int i = 0; i < rows.size(); i++) {
+        JsonNode row = rows.get(i);
+        for (int j = 0; j < numColumns; j++) {
+          responseBuilder.append(row.get(j).asText()).append(TAB);
+        }
+        responseBuilder.append(NEW_LINE);
+      }
+    }
+    return responseBuilder.toString();
+  }
 }
diff --git a/pinot-tools/src/main/java/org/apache/pinot/tools/Quickstart.java 
b/pinot-tools/src/main/java/org/apache/pinot/tools/Quickstart.java
index d55ab66427..9dfa855a79 100644
--- a/pinot-tools/src/main/java/org/apache/pinot/tools/Quickstart.java
+++ b/pinot-tools/src/main/java/org/apache/pinot/tools/Quickstart.java
@@ -18,31 +18,27 @@
  */
 package org.apache.pinot.tools;
 
-import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
 import java.io.File;
-import java.io.IOException;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.io.FileUtils;
 import org.apache.pinot.spi.auth.AuthProvider;
 import org.apache.pinot.tools.admin.PinotAdministrator;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
 
 
+/**
+ * The basic Batch/Offline Quickstart.
+ */
 public class Quickstart extends QuickStartBase {
   @Override
   public List<String> types() {
     return Arrays.asList("OFFLINE", "BATCH");
   }
 
-  private static final String TAB = "\t\t";
-  private static final String NEW_LINE = "\n";
-  private static final String DEFAULT_BOOTSTRAP_DIRECTORY = 
"examples/minions/batch/baseballStats";
-
   public enum Color {
     RESET("\u001B[0m"), GREEN("\u001B[32m"), YELLOW("\u001B[33m"), 
CYAN("\u001B[36m");
 
@@ -61,49 +57,18 @@ public class Quickstart extends QuickStartBase {
     return null;
   }
 
-  public static String prettyPrintResponse(JsonNode response) {
-    StringBuilder responseBuilder = new StringBuilder();
-
-    // Sql Results
-    if (response.has("resultTable")) {
-      JsonNode columns = 
response.get("resultTable").get("dataSchema").get("columnNames");
-      int numColumns = columns.size();
-      for (int i = 0; i < numColumns; i++) {
-        responseBuilder.append(columns.get(i).asText()).append(TAB);
-      }
-      responseBuilder.append(NEW_LINE);
-      JsonNode rows = response.get("resultTable").get("rows");
-      for (int i = 0; i < rows.size(); i++) {
-        JsonNode row = rows.get(i);
-        for (int j = 0; j < numColumns; j++) {
-          responseBuilder.append(row.get(j).asText()).append(TAB);
-        }
-        responseBuilder.append(NEW_LINE);
-      }
-    }
-    return responseBuilder.toString();
-  }
-
   public void execute()
       throws Exception {
-    String tableName = getTableName(DEFAULT_BOOTSTRAP_DIRECTORY);
     File quickstartTmpDir = new File(_dataDir, 
String.valueOf(System.currentTimeMillis()));
-    File baseDir = new File(quickstartTmpDir, tableName);
-    File dataDir = new File(baseDir, "rawdata");
-    Preconditions.checkState(dataDir.mkdirs());
-
-    if (useDefaultBootstrapTableDir()) {
-      
copyResourceTableToTmpDirectory(getBootstrapDataDir(DEFAULT_BOOTSTRAP_DIRECTORY),
 tableName, baseDir, dataDir);
-    } else {
-      
copyFilesystemTableToTmpDirectory(getBootstrapDataDir(DEFAULT_BOOTSTRAP_DIRECTORY),
 tableName, baseDir);
-    }
+    File quickstartRunnerDir = new File(quickstartTmpDir, "quickstart");
+    Preconditions.checkState(quickstartRunnerDir.mkdirs());
+    List<QuickstartTableRequest> quickstartTableRequests = 
bootstrapOfflineTableDirectories(quickstartTmpDir);
 
-    QuickstartTableRequest request = new 
QuickstartTableRequest(baseDir.getAbsolutePath());
     QuickstartRunner runner =
-        new QuickstartRunner(Lists.newArrayList(request), 1, 1, 1, 1, dataDir, 
true, getAuthProvider(),
-            getConfigOverrides(), null, true);
+        new QuickstartRunner(quickstartTableRequests, 1, 1, 
getNumQuickstartRunnerServers(), 1, quickstartRunnerDir,
+            true, getAuthProvider(), getConfigOverrides(), null, true);
 
-    printStatus(Color.CYAN, "***** Starting Zookeeper, controller, broker and 
server *****");
+    printStatus(Color.CYAN, "***** Starting Zookeeper, controller, broker, 
server and minion *****");
     runner.startAll();
     Runtime.getRuntime().addShutdownHook(new Thread(() -> {
       try {
@@ -114,14 +79,16 @@ public class Quickstart extends QuickStartBase {
         e.printStackTrace();
       }
     }));
-    printStatus(Color.CYAN, "***** Bootstrap " + tableName + " table *****");
-    runner.bootstrapTable();
 
-    waitForBootstrapToComplete(runner);
+    if (!CollectionUtils.isEmpty(quickstartTableRequests)) {
+      printStatus(Color.CYAN, "***** Bootstrap tables *****");
+      runner.bootstrapTable();
+      waitForBootstrapToComplete(runner);
+    }
 
     printStatus(Color.YELLOW, "***** Offline quickstart setup complete *****");
 
-    if (useDefaultBootstrapTableDir()) {
+    if (useDefaultBootstrapTableDir() && 
!CollectionUtils.isEmpty(quickstartTableRequests)) {
       // Quickstart is using the default baseballStats sample table, so run 
sample queries.
       runSampleQueries(runner);
     }
@@ -129,58 +96,12 @@ public class Quickstart extends QuickStartBase {
     printStatus(Color.GREEN, "You can always go to http://localhost:9000 to 
play around in the query console");
   }
 
-  private static void copyResourceTableToTmpDirectory(String sourcePath, 
String tableName, File baseDir, File dataDir)
-      throws IOException {
-
-    File schemaFile = new File(baseDir, tableName + "_schema.json");
-    File tableConfigFile = new File(baseDir, tableName + 
"_offline_table_config.json");
-    File ingestionJobSpecFile = new File(baseDir, "ingestionJobSpec.yaml");
-    File dataFile = new File(dataDir, tableName + "_data.csv");
-
-    ClassLoader classLoader = Quickstart.class.getClassLoader();
-    URL resource = classLoader.getResource(sourcePath + File.separator + 
tableName + "_schema.json");
-    com.google.common.base.Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, schemaFile);
-    resource =
-        classLoader.getResource(sourcePath + File.separator + "rawdata" + 
File.separator + tableName + "_data.csv");
-    com.google.common.base.Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, dataFile);
-    resource = classLoader.getResource(sourcePath + File.separator + 
"ingestionJobSpec.yaml");
-    if (resource != null) {
-      FileUtils.copyURLToFile(resource, ingestionJobSpecFile);
-    }
-    resource = classLoader.getResource(sourcePath + File.separator + tableName 
+ "_offline_table_config.json");
-    com.google.common.base.Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, tableConfigFile);
-  }
-
-  private static void copyFilesystemTableToTmpDirectory(String sourcePath, 
String tableName, File baseDir)
-      throws IOException {
-    File fileDb = new File(sourcePath);
-
-    if (!fileDb.exists() || !fileDb.isDirectory()) {
-      throw new RuntimeException("Directory " + fileDb.getAbsolutePath() + " 
not found.");
-    }
-
-    File schemaFile = new File(fileDb, tableName + "_schema.json");
-    if (!schemaFile.exists()) {
-      throw new RuntimeException("Schema file " + schemaFile.getAbsolutePath() 
+ " not found.");
-    }
-
-    File tableFile = new File(fileDb, tableName + 
"_offline_table_config.json");
-    if (!tableFile.exists()) {
-      throw new RuntimeException("Table table " + tableFile.getAbsolutePath() 
+ " not found.");
-    }
-
-    File data = new File(fileDb, "rawdata" + File.separator + tableName + 
"_data.csv");
-    if (!data.exists()) {
-      throw new RuntimeException(("Data file " + data.getAbsolutePath() + " 
not found. "));
-    }
-
-    FileUtils.copyDirectory(fileDb, baseDir);
+  protected int getNumQuickstartRunnerServers() {
+    return 1;
   }
 
-  private static void runSampleQueries(QuickstartRunner runner)
+  @Override
+  public void runSampleQueries(QuickstartRunner runner)
       throws Exception {
     String q1 = "select count(*) from baseballStats limit 1";
     printStatus(Color.YELLOW, "Total number of documents in the table");
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/TimestampIndexQuickstart.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/TimestampIndexQuickstart.java
index a8be24defc..e8af029757 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/TimestampIndexQuickstart.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/TimestampIndexQuickstart.java
@@ -18,84 +18,24 @@
  */
 package org.apache.pinot.tools;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.Lists;
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
-import org.apache.commons.io.FileUtils;
-import org.apache.pinot.tools.Quickstart.Color;
 import org.apache.pinot.tools.admin.PinotAdministrator;
 import org.apache.pinot.tools.admin.command.QuickstartRunner;
 
-import static org.apache.pinot.tools.Quickstart.prettyPrintResponse;
 
-
-public class TimestampIndexQuickstart extends QuickStartBase {
+public class TimestampIndexQuickstart extends Quickstart {
   @Override
   public List<String> types() {
     return Collections.singletonList("TIMESTAMP");
   }
 
-  private File _schemaFile;
-  private File _ingestionJobSpecFile;
-
-  public static void main(String[] args)
-      throws Exception {
-    List<String> arguments = new ArrayList<>();
-    arguments.addAll(Arrays.asList("QuickStart", "-type", "TIMESTAMP"));
-    arguments.addAll(Arrays.asList(args));
-    PinotAdministrator.main(arguments.toArray(new String[arguments.size()]));
-  }
-
-  private QuickstartTableRequest prepareTableRequest(File baseDir)
-      throws IOException {
-    _schemaFile = new File(baseDir, "airlineStats_schema.json");
-    _ingestionJobSpecFile = new File(baseDir, "ingestionJobSpec.yaml");
-    File tableConfigFile = new File(baseDir, 
"airlineStats_offline_table_config.json");
-
-    ClassLoader classLoader = Quickstart.class.getClassLoader();
-    URL resource = 
classLoader.getResource("examples/batch/airlineStats/airlineStats_schema.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, _schemaFile);
-    resource = 
classLoader.getResource("examples/batch/airlineStats/ingestionJobSpec.yaml");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, _ingestionJobSpecFile);
-    resource = 
classLoader.getResource("examples/batch/airlineStats/airlineStats_offline_table_config.json");
-    Preconditions.checkNotNull(resource);
-    FileUtils.copyURLToFile(resource, tableConfigFile);
-    return new QuickstartTableRequest(baseDir.getAbsolutePath());
-  }
-
-  public void execute()
+  @Override
+  public void runSampleQueries(QuickstartRunner runner)
       throws Exception {
-    File quickstartTmpDir = new File(_dataDir, 
String.valueOf(System.currentTimeMillis()));
-    File baseDir = new File(quickstartTmpDir, "airlineStats");
-    File dataDir = new File(baseDir, "data");
-    Preconditions.checkState(dataDir.mkdirs());
-    QuickstartTableRequest bootstrapTableRequest = 
prepareTableRequest(baseDir);
-    final QuickstartRunner runner =
-        new QuickstartRunner(Lists.newArrayList(bootstrapTableRequest), 1, 1, 
1, 1, dataDir, getConfigOverrides());
-    printStatus(Color.YELLOW, "***** Starting Zookeeper, 1 servers, 1 brokers 
and 1 controller *****");
-    runner.startAll();
-    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-      try {
-        printStatus(Color.GREEN, "***** Shutting down timestamp quick start 
*****");
-        runner.stop();
-        FileUtils.deleteDirectory(quickstartTmpDir);
-      } catch (Exception e) {
-        e.printStackTrace();
-      }
-    }));
-    printStatus(Color.YELLOW, "***** Bootstrap airlineStats offline table 
*****");
-    runner.bootstrapTable();
     printStatus(Color.YELLOW, "***** Pinot Timestamp with timestamp table 
setup is complete *****");
-
-
     String q1 = "select ts, $ts$DAY, $ts$WEEK, $ts$MONTH from airlineStats 
limit 1";
     printStatus(Color.YELLOW, "Pick one row with timestamp and different 
granularity using generated column name ");
     printStatus(Color.CYAN, "Query : " + q1);
@@ -115,6 +55,13 @@ public class TimestampIndexQuickstart extends 
QuickStartBase {
     printStatus(Color.CYAN, "Query : " + q3);
     printStatus(Color.YELLOW, prettyPrintResponse(runner.runQuery(q3)));
     printStatus(Color.GREEN, 
"***************************************************");
-    printStatus(Color.GREEN, "You can always go to http://localhost:9000 to 
play around in the query console");
+  }
+
+  public static void main(String[] args)
+      throws Exception {
+    List<String> arguments = new ArrayList<>();
+    arguments.addAll(Arrays.asList("QuickStart", "-type", "TIMESTAMP"));
+    arguments.addAll(Arrays.asList(args));
+    PinotAdministrator.main(arguments.toArray(new String[arguments.size()]));
   }
 }
diff --git 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickStartCommand.java
 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickStartCommand.java
index 96061ed4b7..1578814985 100644
--- 
a/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickStartCommand.java
+++ 
b/pinot-tools/src/main/java/org/apache/pinot/tools/admin/command/QuickStartCommand.java
@@ -39,9 +39,9 @@ public class QuickStartCommand extends 
AbstractBaseAdminCommand implements Comma
       description = "Type of quickstart, supported: STREAM/BATCH/HYBRID")
   private String _type;
 
-  @CommandLine.Option(names = {"-bootstrapTableDir"}, required = false,
-      description = "Directory containing table schema, config, and data.")
-  private String _bootstrapTableDir;
+  @CommandLine.Option(names = {"-bootstrapTableDir"}, required = false, arity 
= "1..*",
+      description = "A list of Directories, each directory containing table 
schema, config, and data.")
+  private String[] _bootstrapTableDirs;
 
   @CommandLine.Option(names = {"-tmpDir", "-quickstartDir", "-dataDir"}, 
required = false,
       description = "Temp Directory to host quickstart data")
@@ -87,11 +87,19 @@ public class QuickStartCommand extends 
AbstractBaseAdminCommand implements Comma
   }
 
   public String getBootstrapDataDir() {
-    return _bootstrapTableDir;
+    return (_bootstrapTableDirs != null && _bootstrapTableDirs.length > 0) ? 
_bootstrapTableDirs[0] : null;
+  }
+
+  public String[] getBootstrapDataDirs() {
+    return _bootstrapTableDirs;
   }
 
   public void setBootstrapTableDir(String bootstrapTableDir) {
-    _bootstrapTableDir = bootstrapTableDir;
+    _bootstrapTableDirs = new String[]{bootstrapTableDir};
+  }
+
+  public void setBootstrapTableDirs(String[] bootstrapTableDirs) {
+    _bootstrapTableDirs = bootstrapTableDirs;
   }
 
   public String getZkExternalAddress() {
@@ -125,7 +133,7 @@ public class QuickStartCommand extends 
AbstractBaseAdminCommand implements Comma
   }
 
   public QuickStartBase selectQuickStart(String type)
-          throws NoSuchMethodException, InvocationTargetException, 
InstantiationException, IllegalAccessException {
+      throws NoSuchMethodException, InvocationTargetException, 
InstantiationException, IllegalAccessException {
     Set<Class<? extends QuickStartBase>> quickStarts = allQuickStarts();
     for (Class<? extends QuickStartBase> quickStart : quickStarts) {
       QuickStartBase quickStartBase = 
quickStart.getDeclaredConstructor().newInstance();
@@ -134,18 +142,19 @@ public class QuickStartCommand extends 
AbstractBaseAdminCommand implements Comma
       }
     }
     throw new UnsupportedOperationException("Unsupported QuickStart type: " + 
type + ". "
-            + "Valid types are: " + errroMessageFor(quickStarts));
+        + "Valid types are: " + errroMessageFor(quickStarts));
   }
 
   @Override
-  public boolean execute() throws Exception {
+  public boolean execute()
+      throws Exception {
     PluginManager.get().init();
 
     if (_type == null) {
       Set<Class<? extends QuickStartBase>> quickStarts = allQuickStarts();
 
       throw new UnsupportedOperationException("No QuickStart type provided. "
-              + "Valid types are: " + errroMessageFor(quickStarts));
+          + "Valid types are: " + errroMessageFor(quickStarts));
     }
 
     QuickStartBase quickstart = selectQuickStart(_type);
@@ -154,8 +163,8 @@ public class QuickStartCommand extends 
AbstractBaseAdminCommand implements Comma
       quickstart.setDataDir(_tmpDir);
     }
 
-    if (_bootstrapTableDir != null) {
-      quickstart.setBootstrapDataDir(_bootstrapTableDir);
+    if (_bootstrapTableDirs != null) {
+      quickstart.setBootstrapDataDirs(_bootstrapTableDirs);
     }
 
     if (_zkExternalAddress != null) {
@@ -171,7 +180,7 @@ public class QuickStartCommand extends 
AbstractBaseAdminCommand implements Comma
   }
 
   private static List<String> errroMessageFor(Set<Class<? extends 
QuickStartBase>> quickStarts)
-          throws InstantiationException, IllegalAccessException, 
InvocationTargetException, NoSuchMethodException {
+      throws InstantiationException, IllegalAccessException, 
InvocationTargetException, NoSuchMethodException {
     List<String> validTypes = new ArrayList<>();
     for (Class<? extends QuickStartBase> quickStart : quickStarts) {
       
validTypes.addAll(quickStart.getDeclaredConstructor().newInstance().types());
diff --git 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_table_config.json
 
b/pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/githubComplexTypeEvents_offline_table_config.json
similarity index 93%
rename from 
pinot-tools/src/main/resources/examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_table_config.json
rename to 
pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/githubComplexTypeEvents_offline_table_config.json
index 154f9dfcdd..d434773aab 100644
--- 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_table_config.json
+++ 
b/pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/githubComplexTypeEvents_offline_table_config.json
@@ -1,5 +1,5 @@
 {
-  "tableName": "githubEvents",
+  "tableName": "githubComplexTypeEvents",
   "tableType": "OFFLINE",
   "tenants": {
   },
diff --git 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_schema.json
 
b/pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/githubComplexTypeEvents_schema.json
similarity index 97%
rename from 
pinot-tools/src/main/resources/examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_schema.json
rename to 
pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/githubComplexTypeEvents_schema.json
index 6b44c9ec65..1c79af79cf 100644
--- 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/githubEvents_offline_complexTypeHandling_schema.json
+++ 
b/pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/githubComplexTypeEvents_schema.json
@@ -71,5 +71,5 @@
       "granularity": "1:SECONDS"
     }
   ],
-  "schemaName": "githubEvents"
+  "schemaName": "githubComplexTypeEvents"
 }
diff --git 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/ingestionJobComplexTypeHandlingSpec.yaml
 
b/pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/ingestionJobSpec.yaml
similarity index 94%
rename from 
pinot-tools/src/main/resources/examples/batch/githubEvents/ingestionJobComplexTypeHandlingSpec.yaml
rename to 
pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/ingestionJobSpec.yaml
index 04b67c4bfa..c2c8e13cd3 100644
--- 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/ingestionJobComplexTypeHandlingSpec.yaml
+++ 
b/pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/ingestionJobSpec.yaml
@@ -41,7 +41,7 @@ executionFrameworkSpec:
 jobType: SegmentCreationAndTarPush
 
 # inputDirURI: Root directory of input data, expected to have scheme 
configured in PinotFS.
-inputDirURI: 'examples/batch/githubEvents/rawdata_complexTypeHandling'
+inputDirURI: 'examples/batch/githubComplexTypeEvents/rawdata'
 
 # includeFileNamePattern: include file name pattern, supported glob pattern.
 # Sample usage:
@@ -56,7 +56,7 @@ includeFileNamePattern: 'glob:**/*.json'
 # _excludeFileNamePattern: ''
 
 # outputDirURI: Root directory of output segments, expected to have scheme 
configured in PinotFS.
-outputDirURI: 'examples/batch/githubEvents/segments'
+outputDirURI: 'examples/batch/githubComplexTypeEvents/segments'
 
 # overwriteOutput: Overwrite output segments if existed.
 overwriteOutput: true
@@ -106,13 +106,13 @@ recordReaderSpec:
 tableSpec:
 
   # tableName: Table name
-  tableName: 'githubEvents'
+  tableName: 'githubComplexTypeEvents'
 
   # schemaURI: defines where to read the table schema, supports PinotFS or 
HTTP.
   # E.g.
   #   hdfs://path/to/table_schema.json
   #   http://localhost:9000/tables/myTable/schema
-  schemaURI: 'http://localhost:9000/tables/githubEvents/schema'
+  schemaURI: 'http://localhost:9000/tables/githubComplexTypeEvents/schema'
 
   # tableConfigURI: defines where to reade the table config.
   # Supports using PinotFS or HTTP.
@@ -121,7 +121,7 @@ tableSpec:
   #   http://localhost:9000/tables/myTable
   # Note that the API to read Pinot table config directly from pinot 
controller contains a JSON wrapper.
   # The real table config is the object under the field 'OFFLINE'.
-  tableConfigURI: 'http://localhost:9000/tables/githubEvents'
+  tableConfigURI: 'http://localhost:9000/tables/githubComplexTypeEvents'
 
 # pinotClusterSpecs: defines the Pinot Cluster Access Point.
 pinotClusterSpecs:
diff --git 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/rawdata_complexTypeHandling/githubEvents_data.json
 
b/pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/rawdata/githubComplexTypeEvents_data.json
similarity index 100%
rename from 
pinot-tools/src/main/resources/examples/batch/githubEvents/rawdata_complexTypeHandling/githubEvents_data.json
rename to 
pinot-tools/src/main/resources/examples/batch/githubComplexTypeEvents/rawdata/githubComplexTypeEvents_data.json
diff --git 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/ingestionJobSpec.yaml
 
b/pinot-tools/src/main/resources/examples/batch/githubEvents/ingestionJobSpec.yaml
index f8216f1bb6..a51bde638f 100644
--- 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/ingestionJobSpec.yaml
+++ 
b/pinot-tools/src/main/resources/examples/batch/githubEvents/ingestionJobSpec.yaml
@@ -41,7 +41,7 @@ executionFrameworkSpec:
 jobType: SegmentCreationAndTarPush
 
 # inputDirURI: Root directory of input data, expected to have scheme 
configured in PinotFS.
-inputDirURI: 'examples/batch/githubEvents/rawdata_json_index'
+inputDirURI: 'examples/batch/githubEvents/rawdata'
 
 # includeFileNamePattern: include file name pattern, supported glob pattern.
 # Sample usage:
diff --git 
a/pinot-tools/src/main/resources/examples/batch/githubEvents/rawdata_json_index/githubEvents_data.json
 
b/pinot-tools/src/main/resources/examples/batch/githubEvents/rawdata/githubEvents_data.json
similarity index 100%
rename from 
pinot-tools/src/main/resources/examples/batch/githubEvents/rawdata_json_index/githubEvents_data.json
rename to 
pinot-tools/src/main/resources/examples/batch/githubEvents/rawdata/githubEvents_data.json


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@pinot.apache.org
For additional commands, e-mail: commits-h...@pinot.apache.org

Reply via email to