
prerna.query.interpreters.GremlinInterpreter Maven / Gradle / Ivy
The newest version!
package prerna.query.interpreters;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import org.apache.tinkerpop.gremlin.process.traversal.Order;
import org.apache.tinkerpop.gremlin.process.traversal.P;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import prerna.ds.OwlTemporalEngineMeta;
import prerna.ds.TinkerFrame;
import prerna.engine.api.IDatabaseEngine;
import prerna.query.querystruct.SelectQueryStruct;
import prerna.query.querystruct.filters.GenRowFilters;
import prerna.query.querystruct.filters.IQueryFilter;
import prerna.query.querystruct.filters.SimpleQueryFilter;
import prerna.query.querystruct.joins.BasicRelationship;
import prerna.query.querystruct.joins.IRelation;
import prerna.query.querystruct.selectors.IQuerySelector;
import prerna.query.querystruct.selectors.IQuerySort;
import prerna.query.querystruct.selectors.QueryColumnOrderBySelector;
import prerna.query.querystruct.selectors.QueryColumnOrderBySelector.ORDER_BY_DIRECTION;
import prerna.query.querystruct.selectors.QueryColumnSelector;
import prerna.sablecc2.om.PixelDataType;
import prerna.sablecc2.om.nounmeta.NounMetadata;
public class GremlinInterpreter extends AbstractQueryInterpreter {
protected IDatabaseEngine engine;
// reference for getting actual names for loops within frames
protected OwlTemporalEngineMeta meta;
// all the filters being used
protected GenRowFilters allFilters;
// the gremlin traversal being created
protected GraphTraversalSource g;
protected GraphTraversal gt;
// the list of variables being returned within the traversal
protected List selectors;
// the list of properties for a given vertex
protected Map> propHash;
// identify the name for the type of the name
protected Map typeMap;
// identify the name for the vertex label
protected Map nameMap;
protected boolean useLabel = false;
public GremlinInterpreter(GraphTraversalSource g, Map typeMap, Map nameMap, IDatabaseEngine engine) {
this.g = g;
this.gt = g.V();
this.typeMap = typeMap;
this.nameMap = nameMap;
this.engine = engine;
}
public GremlinInterpreter(GraphTraversalSource g, OwlTemporalEngineMeta meta) {
this.g = g;
this.gt = g.V();
this.meta = meta;
}
public GraphTraversal composeIterator() {
this.allFilters = this.qs.getCombinedFilters();
generateSelectors();
traverseRelations();
addOrderBy();
setSelectors();
if(((SelectQueryStruct) this.qs).isDistinct()) {
this.gt.dedup();
}
long offset = ((SelectQueryStruct) this.qs).getOffset();
long limit = ((SelectQueryStruct) this.qs).getLimit();
if(offset > 0) {
if(limit > 0) {
this.gt = this.gt.range(offset, offset+limit);
} else {
this.gt = this.gt.range(offset, -1);
}
}
if(logger.isDebugEnabled()) {
String query = this.gt.toString();
if(query.length() > 500) {
logger.debug("GREMLIN QUERY.... " + query.substring(0, 500) + "...");
} else {
logger.debug("GREMLIN QUERY.... " + query);
}
}
return this.gt;
}
protected void setSelectors() {
// note, we add all things in the alias map even if they are not returned
// i.e. remember we can skip intermediary nodes
List allAliasSelectors = new Vector();
for(String nodeSelector : this.selectors) {
allAliasSelectors.add(nodeSelector);
}
for(String conceptKey : this.propHash.keySet()) {
List props = this.propHash.get(conceptKey);
for(String propertySelector : props) {
allAliasSelectors.add(conceptKey + "__" + propertySelector);
}
}
if(allAliasSelectors.size() == 1) {
this.gt = this.gt.select(allAliasSelectors.get(0));
} else if(allAliasSelectors.size() == 2) {
this.gt = this.gt.select(allAliasSelectors.get(0), allAliasSelectors.get(1));
} else {
String[] otherSelectors = new String[allAliasSelectors.size() - 2];
for(int i = 2; i < allAliasSelectors.size(); i++) {
otherSelectors[i-2] = allAliasSelectors.get(i);
}
this.gt = this.gt.select(allAliasSelectors.get(0), allAliasSelectors.get(1), otherSelectors);
}
}
/**
* Get the selectors from the QS
* Store both the list of selectors (which includes names of vertices and properties)
* Also maintain a list of vertex to list of properties
*/
protected void generateSelectors() {
if (this.selectors == null) {
// generate the names for each component of the selector
this.selectors = new Vector();
this.propHash = new HashMap>();
Set selectorComps = new HashSet();
List iSelectors = qs.getSelectors();
for(IQuerySelector s : iSelectors) {
selectorComps.addAll(s.getAllQueryColumns());
}
// iterate through the selectors
for (QueryColumnSelector selectorComp : selectorComps) {
String table = selectorComp.getTable();
String column = selectorComp.getColumn();
// are we trying to grab a vertex
// or are we grabbing a property on the vertex
if(column.equals(SelectQueryStruct.PRIM_KEY_PLACEHOLDER)) {
// add the vertex
this.selectors.add(table);
} else {
// add the property
// also store the property in the prop hash
List properties = null;
if(this.propHash.containsKey(table)) {
properties = this.propHash.get(table);
} else {
properties = new ArrayList();
this.propHash.put(table, properties);
}
properties.add(column);
}
}
}
}
protected void traverseRelations() {
Map> edgeMap = generateEdgeMap();
if(edgeMap.isEmpty()) {
// we have only a single selector
// simple traversal
String selector = null;
if(this.selectors.isEmpty()) {
selector = this.propHash.keySet().iterator().next();
} else {
selector = this.selectors.get(0);
}
List props = this.propHash.get(selector);
// but is this traversal, to get a vertex
// or a property on the vertex
if(props != null) {
// this.gt.has(getNodeType(selector), getPhysicalNodeType(selector)).as(selector);
// it is for a property on a vertex
GraphTraversal twoStepT = __.as(selector);
// logic to filter
List startNodeFilters = this.allFilters.getAllSimpleQueryFiltersContainingColumn(selector);
addFiltersToPath(twoStepT, startNodeFilters, getNodeName(selector));
List> propTraversals = getProperties(twoStepT, selector);
if (propTraversals.size() > 0) {
GraphTraversal[] propArray = new GraphTraversal[propTraversals.size()];
twoStepT = twoStepT.match(propTraversals.toArray(propArray));
}
gt = gt.match(twoStepT);
} else {
// it is just the vertex
queryNode(this.gt, selector).as(selector);
// logic to filter
List startNodeFilters = this.allFilters.getAllSimpleQueryFiltersContainingColumn(selector);
addFiltersToPath(this.gt, startNodeFilters, getNodeName(selector));
}
} else {
// we need to go through the traversal
addNodeEdge(edgeMap);
}
}
/**
* Generates the edgeMap to determine what to traverse based on the
* relations Assumes all the joins are inner.joins... at the moment, not
* sure how to/what it would mean to do something like a left join or right
* join since there is only one graph backing a insight If there are no
* relations (like in the case where you want one column to be returned), it
* adds the selectors in the edgeMap
*
* @return
*/
public Map> generateEdgeMap() {
Map> edgeMap = new Hashtable<>();
// add the relationships into the edge map
Set relations = qs.getRelations();
for (IRelation relationship : relations) {
if(relationship.getRelationType() == IRelation.RELATION_TYPE.BASIC) {
BasicRelationship rel = (BasicRelationship) relationship;
String startNode = rel.getFromConcept();
String endNode = rel.getToConcept();
Set joinSet = null;
if (edgeMap.containsKey(startNode)) {
joinSet = edgeMap.get(startNode);
} else {
joinSet = new HashSet<>();
edgeMap.put(startNode, joinSet);
}
joinSet.add(endNode);
} else {
logger.info("Cannot process relationship of type: " + relationship.getRelationType());
}
}
// Map> rels = qs.getRelations();
// // add the relationships into the edge map
// if (!rels.isEmpty()) {
// Set relKeys = rels.keySet();
// // looping through the start node of the relationship
// for (String startNode : relKeys) {
// Map comps = rels.get(startNode);
// // TODO: currently going to not care about the type of join
// // assume everything is an inner join for simplicity
// Set compKeys = comps.keySet();
// for (String comp : compKeys) {
// // this is the end node of the relationship
// List endNodes = comps.get(comp);
//
// Set joinSet = new HashSet();
// for (String node : endNodes) {
// // we may be using joins and not outputting the values
// // so we will add a fake alias so we dont need to check if alias exists
// // when we traverse the map
// joinSet.add(node);
// }
//
// if (edgeMap.containsKey(startNode)) {
// Set currSet = edgeMap.get(startNode);
// currSet.addAll(joinSet);
// } else {
// // need to get rid of "__"
// edgeMap.put(startNode, joinSet);
// }
// }
// }
// }
// else {
// // this occurs when there are no relationships defined...
// // example is when you are only going for one column of data
// }
return edgeMap;
}
/**
* This is the bulk of the class Uses the edgeMap to figure out what things
* are connected
*/
public void addNodeEdge(Map> edgeMap) {
// start traversal if edgeHash is not empty
String startNode = edgeMap.keySet().iterator().next();
// TODO: come back to this to optimize the traversal
// can do this by picking a "better" startNode
this.gt = queryNode(this.gt, startNode).as(startNode);
List startNodeFilters = this.allFilters.getAllSimpleQueryFiltersContainingColumn(startNode);
addFiltersToPath(this.gt, startNodeFilters, getNodeName(startNode));
List travelledEdges = new Vector();
List travelledNodeProperties = new Vector();
List> traversals = new Vector>();
// add the logic to traverse
traversals = visitNode(startNode, edgeMap, travelledEdges, travelledNodeProperties, traversals);
if (traversals.size() > 0) {
GraphTraversal[] array = new GraphTraversal[traversals.size()];
gt = gt.match(traversals.toArray(array));
}
}
/**
* Add the filter object to the current graph traversal
* @param filterVec
*/
protected void addFiltersToPath(GraphTraversal traversalSegment, List filterVec, String filterPropertyName) {
for(SimpleQueryFilter filter : filterVec) {
SimpleQueryFilter.FILTER_TYPE filterType = filter.getSimpleFilterType();
NounMetadata lComp = filter.getLComparison();
NounMetadata rComp = filter.getRComparison();
String comp = filter.getComparator();
if(filterType == SimpleQueryFilter.FILTER_TYPE.COL_TO_VALUES) {
// here, lcomp is the column and rComp is a set of values
processFilterColToValues(traversalSegment, lComp, rComp, comp, filterPropertyName);
} else if(filterType == SimpleQueryFilter.FILTER_TYPE.VALUES_TO_COL) {
// here, lcomp is the values and rComp is a the column
// so same as above, but switch the order
processFilterColToValues(traversalSegment, rComp, lComp, IQueryFilter.getReverseNumericalComparator(comp), filterPropertyName);
}
}
}
/**
* Handle adding a column to set of values filter
* @param traversalSegment
* @param colComp
* @param valuesComp
* @param comparison
*/
protected void processFilterColToValues(GraphTraversal traversalSegment, NounMetadata colComp, NounMetadata valuesComp, String comparison, String filterPropertyName) {
PixelDataType dataType = valuesComp.getNounType();
Object filterObject = valuesComp.getValue();
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy