package esl.cuenet.ranking.network;
import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.util.JSON;
import esl.cuenet.model.Constants;
import esl.cuenet.ranking.SpatioTemporalIndex;
import esl.cuenet.ranking.URINode;
import esl.datastructures.Location;
import org.apache.log4j.Logger;
import org.neo4j.cypher.javacompat.ExecutionEngine;
import org.neo4j.cypher.javacompat.ExecutionResult;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import java.net.UnknownHostException;
import java.util.*;
public class NeoSpatioTemporalIndex implements SpatioTemporalIndex {
private final GraphDatabaseService graphDb;
private final String timestampMillisStart;
private final String timestampMillisEnd;
private final String M_START, M_END, M_ID;
private Logger logger = Logger.getLogger(NeoSpatioTemporalIndex.class);
private DBCollection txColl;
public NeoSpatioTemporalIndex(GraphDatabaseService graphDb) {
this.graphDb = graphDb;
timestampMillisStart = Constants.CuenetNamespace + Constants.TimestampMillisStart;
timestampMillisEnd = Constants.CuenetNamespace + Constants.TimestampMillisEnd;
M_END = "end";
M_START = "start";
M_ID = "id";
openDB("128.195.54.27", "neo4j", "tx");
}
private void openDB(String location, String dbName, String collection) {
try {
Mongo m = new Mongo(location, 27017);
txColl = m.getDB(dbName).getCollection(collection);
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
private long getStartTime(Node node) {
for (Relationship relationship: node.getRelationships(NeoRelationships.BLANK, Direction.OUTGOING)) {
if ( !relationship.hasProperty(OntProperties.ONT_URI) ) continue;
if ( timestampMillisStart.equals(relationship.getProperty(OntProperties.ONT_URI)) )
return (Long) relationship.getEndNode().getProperty(OntProperties.LVALUE);
}
throw new RuntimeException("Couldn't find interval start value " + node);
}
private long getEndTime(Node node) {
for (Relationship relationship: node.getRelationships(NeoRelationships.BLANK, Direction.OUTGOING)) {
if ( !relationship.hasProperty(OntProperties.ONT_URI) ) continue;
if ( timestampMillisEnd.equals(relationship.getProperty(OntProperties.ONT_URI)) )
return (Long) relationship.getEndNode().getProperty(OntProperties.LVALUE);
}
throw new RuntimeException("Couldn't find interval end value " + node);
}
@Override
public void construct() {
logger.info("Constructing Index");
refresh();
final String timeIntervalURI = Constants.CuenetNamespace + Constants.TimeInterval;
String query = "START n=node(*) WHERE has(n.ontURI) AND n.ontURI = '" + timeIntervalURI + "' RETURN n";
ExecutionEngine engine = new ExecutionEngine( graphDb );
ExecutionResult results = engine.execute(query);
for (Map<String, Object> result: results)
for ( Map.Entry<String, Object> column : result.entrySet() ) {
Node n = (Node) column.getValue();
index(n.getId(), getStartTime(n), getEndTime(n));
}
logger.info("-----------");
}
private void index(long id, long startTime, long endTime) {
BasicDBObject o = new BasicDBObject(M_ID, id);
o.put(M_END, endTime);
o.put(M_START, startTime);
txColl.insert(o);
}
private void refresh() {
txColl.remove(new BasicDBObject());
BasicDBObject keys = new BasicDBObject(M_START, 1);
keys.put(M_END, 1);
txColl.ensureIndex(keys);
}
private List<BasicDBObject> execute(String qryString, int limit) {
BasicDBObject query = (BasicDBObject) JSON.parse(qryString);
List<BasicDBObject> results = new ArrayList<BasicDBObject>(25);
for (DBObject o: txColl.find(query, new BasicDBObject("_id", 0)).limit(limit)) {
results.add((BasicDBObject) o);
}
return results;
}
private List<BasicDBObject> execute(String qryString, String sortKey, int sortOrder, int limit) {
BasicDBObject query = (BasicDBObject) JSON.parse(qryString);
List<BasicDBObject> results = new ArrayList<BasicDBObject>(25);
for (DBObject o: txColl.find(query, new BasicDBObject("_id", 0)).sort(new BasicDBObject(sortKey, sortOrder)).limit(limit)) {
results.add((BasicDBObject) o);
}
return results;
}
private List<BasicDBObject> execute(String qryString) {
BasicDBObject query = (BasicDBObject) JSON.parse(qryString);
List<BasicDBObject> results = new ArrayList<BasicDBObject>(25);
for (DBObject o: txColl.find(query, new BasicDBObject("_id", 0))) {
results.add((BasicDBObject) o);
}
return results;
}
@Override
public void overlaps(long start, long end) {
String qryString = String.format("{'start': {'$gt': %d}, 'end': {'$lt': %d} }", start, end);
int ix = 0;
for (BasicDBObject r: execute(qryString)) logger.info((++ix) + ". " + r);
}
@Override
public void before(long moment) {
String qryString = String.format("{'end': {'$lt': %d} }", moment);
execute(qryString);
}
@Override
public void after(long moment) {
String qryString = String.format("{'start': {'$gt': %d} }", moment);
execute(qryString);
}
@Override
public void before(long moment, int limit) {
String qryString = String.format("{'end': {'$lt': %d} }", moment);
execute(qryString, limit);
}
@Override
public void after(long moment, int limit) {
String qryString = String.format("{'end': {'$lt': %d} }", moment);
execute(qryString, limit);
}
@Override
public void previous (long timestamp) {
String qryString = String.format("{'end': {'$lt': %d} }", timestamp);
List<BasicDBObject> results = execute(qryString);
Collections.sort(results, new Comparator<BasicDBObject>() {
@Override
public int compare(BasicDBObject o1, BasicDBObject o2) {
long l1 = o1.getLong(M_END);
long l2 = o2.getLong(M_END);
if (l1 < l2) return 1;
else if (l1 > l2) return -1;
return 0;
}
});
logger.info("I_TS - " + new Date(timestamp));
int ix = 0;
for (BasicDBObject r: results) {
long s = r.getLong(M_START);
logger.info("PREV - " + new Date(s) + " " + r);
ix++;
if (ix == 10) break;
}
results = execute(qryString, "end", -1, 1);
logger.info("* I_TS - " + new Date(timestamp));
ix = 0;
for (BasicDBObject r: results) {
long s = r.getLong(M_START);
logger.info("* PREV - " + new Date(s) + " " + r);
ix++;
if (ix == 10) break;
}
}
@Override
public void next (long timestamp) {
String qryString = String.format("{'start': {'$gt': %d} }", timestamp);
List<BasicDBObject> results = execute(qryString);
Collections.sort(results, new Comparator<BasicDBObject>() {
@Override
public int compare(BasicDBObject o1, BasicDBObject o2) {
long l1 = o1.getLong(M_START);
long l2 = o2.getLong(M_START);
if (l1 > l2) return 1;
else if (l1 < l2) return -1;
return 0;
}
});
logger.info("I_TS - " + new Date(timestamp));
int ix = 0;
for (BasicDBObject r: results) {
long s = r.getLong(M_START);
logger.info("NEXT - " + new Date(s) + " " + r);
ix++;
if (ix == 10) break;
}
results = execute(qryString, 1);
logger.info("* I_TS - " + new Date(timestamp));
ix = 0;
for (BasicDBObject r: results) {
long s = r.getLong(M_START);
logger.info("* NEXT - " + new Date(s) + " " + r);
ix++;
if (ix == 10) break;
}
}
@Override
public Iterator<URINode> lookup(Location location) {
return null;
}
}