/*
* 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.engines.redis;
import notaql.NotaQL;
import notaql.datamodel.*;
import notaql.engines.Engine;
import notaql.engines.EngineEvaluator;
import notaql.engines.mongodb.model.vdata.ListCountFunctionVData;
import notaql.engines.redis.datamodel.ValueConverter;
import notaql.engines.redis.model.vdata.HashMapConstructorVData;
import notaql.engines.redis.parser.path.RedisInputPathParser;
import notaql.engines.redis.parser.path.RedisOutputPathParser;
import notaql.evaluation.SparkTransformationEvaluator;
import notaql.model.EvaluationException;
import notaql.model.Transformation;
import notaql.model.vdata.ConstructorVData;
import notaql.model.vdata.FunctionVData;
import notaql.parser.TransformationParser;
import notaql.parser.path.InputPathParser;
import notaql.parser.path.OutputPathParser;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.ScanResult;
import java.net.ConnectException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
* Created by thomas on 23.02.15.
*/
public class RedisEngineEvaluator implements EngineEvaluator {
private final TransformationParser parser;
private final int databaseId;
private Jedis jedis;
private Engine engine;
private final static Logger logger = Logger.getLogger(RedisEngineEvaluator.class.getName());
public RedisEngineEvaluator(Engine engine, TransformationParser parser, Map<String, AtomValue<?>> params) {
this.engine = engine;
this.parser = parser;
if (!params.keySet().equals(new HashSet<>(engine.getArguments())))
throw new EvaluationException(
"CSV engine expects the following parameters on initialization: " +
engine.getArguments().stream().collect(Collectors.joining(", "))
);
try {
this.databaseId = Integer.parseInt(params.get("database_id").getValue().toString());
} catch(NumberFormatException e) {
throw new EvaluationException("Redis engines expects the database_id to be an integer");
}
}
@Override
public InputPathParser getInputPathParser() {
return new RedisInputPathParser(parser);
}
@Override
public OutputPathParser getOutputPathParser() {
return new RedisOutputPathParser(parser);
}
/**
* TODO: this is really slow and doesn't scale!
* @param transformation
* @return
*/
@Override
public JavaRDD<ObjectValue> evaluate(Transformation transformation) {
try {
connect();
} catch (ConnectException e) {
e.printStackTrace();
throw new EvaluationException(e);
}
final JavaSparkContext sc = NotaQL.SparkFactory.getSparkContext();
final SparkTransformationEvaluator evaluator = new SparkTransformationEvaluator(transformation);
// simply read in all objects
final ListBasedCollectionValue inCollection = new ListBasedCollectionValue();
jedis.select(databaseId);
final Set<String> keys = jedis.keys("*");
final String host = NotaQL.prop.getProperty("redis_host", "localhost");
final ValueConverter converter = new ValueConverter(host, databaseId);
for (String key: keys) {
final Value value = converter.readFromRedis(key);
final ObjectValue objectValue = new ObjectValue();
objectValue.put(new Step<>("_id"), new StringValue(key));
objectValue.put(new Step<>("_v"), value);
inCollection.add(objectValue);
}
disconnect();
final JavaRDD<Value> values = sc.parallelize(inCollection);
final JavaRDD<Value> filtered = values.filter(v -> transformation.satisfiesInPredicate((ObjectValue) v));
return evaluator.process(filtered);
}
/**
* @param result
*/
@Override
public void store(JavaRDD<ObjectValue> result) {
try {
connect();
} catch (ConnectException e) {
e.printStackTrace();
throw new EvaluationException(e);
}
jedis.select(databaseId);
logger.info("Storing objects.");
final String host = NotaQL.prop.getProperty("redis_host", "localhost");
final ValueConverter converter = new ValueConverter(host, databaseId);
result.foreach(
converter::writeToRedis
);
disconnect();
}
private void connect() throws ConnectException {
jedis = new Jedis(NotaQL.prop.getProperty("redis_host", "localhost"));
}
private void disconnect() {
jedis.close();
}
@Override
public ConstructorVData getConstructor(String name) {
if(name.equals("HM"))
return new HashMapConstructorVData();
return null;
}
@Override
public FunctionVData getFunction(String name) {
if(name.equals("LIST_COUNT"))
return new ListCountFunctionVData();
return null;
}
}