/*
* Copyright 2015 by Thomas Lottermann
*
* 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 notaql;
import notaql.datamodel.ObjectValue;
import notaql.engines.Engine;
import notaql.engines.EngineEvaluator;
import notaql.model.NotaQLExpression;
import notaql.model.Transformation;
import notaql.parser.NotaQLExpressionParser;
import org.apache.log4j.BasicConfigurator;
import org.apache.spark.SparkConf;
import org.apache.spark.SparkContext;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import java.io.*;
import java.net.ConnectException;
import java.util.Properties;
/**
* The NotaQL main class. Here is where the magic starts.
*/
public class NotaQL {
public static Properties prop = new Properties();
/**
* This is a simple program which expects a NotaQL query to execute.
* It also allows you to specify a config file.
*
* The config file is sometimes necessary to provide information about the whereabouts of databases.
*
* @param args
* @throws IOException
*/
public static void main(String... args) throws IOException {
BasicConfigurator.configure();
if (args.length < 1)
throw new IllegalArgumentException("The input must be provided as follows: [--config=PATH/TO/settings.config] notaql_query");
int start = 0;
if (args[0].startsWith("--config=")) {
final String path = args[0].substring(args[0].indexOf("=") + 1);
loadConfig(path);
start = 1;
}
final StringBuilder builder = new StringBuilder();
for(int i = start; i < args.length; i++) {
builder.append(args[i]);
if(i < args.length-1)
builder.append(" ");
}
evaluate(builder.toString());
}
/**
* Load the config file and store it in prop
*
* @param path
* @throws IOException
*/
public static void loadConfig(String path) throws IOException {
InputStream stream;
try {
stream = new FileInputStream(new File(path));
} catch(FileNotFoundException e) {
stream = NotaQL.class.getClassLoader().getResourceAsStream(path);
}
if(stream == null) {
throw new FileNotFoundException("Unable to find " + path + " in classpath.");
}
// load a properties file
prop.load(stream);
}
/**
* Evaluates a query, transformation after transformation.
*
* @param query
* @throws ConnectException
*/
public static void evaluate(String query) throws ConnectException {
final NotaQLExpression expression = NotaQLExpressionParser.parse(query);
for (Transformation transformation : expression.getTransformations()) {
final EngineEvaluator inEngineEvaluator = transformation.getInEngineEvaluator();
final EngineEvaluator outEngineEvaluator = transformation.getOutEngineEvaluator();
final JavaRDD<ObjectValue> result = inEngineEvaluator.evaluate(transformation);
outEngineEvaluator.store(result);
}
}
public static class SparkFactory {
private static JavaSparkContext jsc = null;
private SparkFactory(){
}
public static JavaSparkContext getSparkContext() {
if(jsc != null)
return jsc;
SparkConf conf = new SparkConf().setAppName("NotaQL").setMaster(NotaQL.prop.getProperty("spark_master", "local"));
if(NotaQL.prop.getProperty("parallelism") != null)
conf.set("spark.default.parallelism", NotaQL.prop.getProperty("parallelism"));
if(NotaQL.prop.getProperty("kryo") != null && NotaQL.prop.getProperty("kryo").equals("true")) {
conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer");
conf.set("spark.kryoserializer.buffer.mb", "24");
}
final SparkContext sc = new SparkContext(conf);
// TODO: Add progress/timing magic here!
/*sc.addSparkListener(new SparkListener() {
@Override
public void onStageCompleted(SparkListenerStageCompleted sparkListenerStageCompleted) {
System.out.println("Stage completed!");
}
@Override
public void onStageSubmitted(SparkListenerStageSubmitted sparkListenerStageSubmitted) {
System.out.println("Stage submitted!");
}
@Override
public void onTaskStart(SparkListenerTaskStart sparkListenerTaskStart) {
System.out.println("Task started!");
}
@Override
public void onTaskGettingResult(SparkListenerTaskGettingResult sparkListenerTaskGettingResult) {
System.out.println("Task getting Result!");
}
@Override
public void onTaskEnd(SparkListenerTaskEnd sparkListenerTaskEnd) {
System.out.println("Task end!");
}
@Override
public void onJobStart(SparkListenerJobStart sparkListenerJobStart) {
System.out.println("Job start!");
}
@Override
public void onJobEnd(SparkListenerJobEnd sparkListenerJobEnd) {
System.out.println("Job end!");
}
@Override
public void onEnvironmentUpdate(SparkListenerEnvironmentUpdate sparkListenerEnvironmentUpdate) {
System.out.println("Env update!");
}
@Override
public void onBlockManagerAdded(SparkListenerBlockManagerAdded sparkListenerBlockManagerAdded) {
System.out.println("block manager added!");
}
@Override
public void onBlockManagerRemoved(SparkListenerBlockManagerRemoved sparkListenerBlockManagerRemoved) {
System.out.println("block manager removed!");
}
@Override
public void onUnpersistRDD(SparkListenerUnpersistRDD sparkListenerUnpersistRDD) {
System.out.println("unpersist rdd!");
}
@Override
public void onApplicationStart(SparkListenerApplicationStart sparkListenerApplicationStart) {
System.out.println("app start!");
}
@Override
public void onApplicationEnd(SparkListenerApplicationEnd sparkListenerApplicationEnd) {
System.out.println("app end!");
}
@Override
public void onExecutorMetricsUpdate(SparkListenerExecutorMetricsUpdate sparkListenerExecutorMetricsUpdate) {
System.out.println("metrics update!");
}
});*/
jsc = new JavaSparkContext(sc);
final String jarPath = prop.getProperty("dependency_jar");
if(jarPath == null)
return jsc;
final File jar = new File(jarPath);
jsc.addJar(jar.getAbsolutePath());
return jsc;
}
}
}