Commit dcc137af authored by Georg Fette's avatar Georg Fette
Browse files

added aggregation operators avg and count with test cases

parent 3300400e
......@@ -120,10 +120,10 @@ public class CQL_2_Graph_Mapper {
return prettyTree;
}
private void addOp(OperatorType aType) {
private void addOp(OperatorType aType) {
currentOp = new QueryOperator(currentOp, aType);
}
private cqlParser.QueryExpressionContext parseWithAntlr(String aQueryString) {
ANTLRInputStream stream = new ANTLRInputStream(aQueryString);
cqlLexer lexer = new cqlLexer(stream);
......@@ -141,9 +141,20 @@ public class CQL_2_Graph_Mapper {
QueryExpressionContext qe = parseWithAntlr(aQueryString);
parseQueryExpression(qe);
addLeafsToRootClause();
addDefaultReturnIfNecessary();
return query;
}
private void addDefaultReturnIfNecessary() {
if (query.getReturnedExpressions().size() == 0) {
if (query.rootConcepts.size() > 0) {
query.rootConcepts.get(0).includeInResult = true;
} else {
query.rootClause.getParameters().get(0).includeInResult = true;
}
}
}
private void parseQueryExpression(QueryExpressionContext qe) {
String prettyPrint = prettyPrint(qe);
QueryContext queryContext = qe.query();
......@@ -253,7 +264,7 @@ public class CQL_2_Graph_Mapper {
private void addLeafsToRootClause() {
// add leafs that are not yet part of any operator to the root and
for (QueryConcept aConc : query.getConceptsRecursive()) {
for (QueryConcept aConc : query.rootConcepts) {
for (QueryConcept aLeaf : aConc.getLeafsRecursive()) {
if (aLeaf.parentOps.size() == 0) {
query.rootClause.addParameter(aLeaf);
......@@ -598,6 +609,8 @@ public class CQL_2_Graph_Mapper {
opType = OperatorType.LAST;
} else if (text.equals("Count")) {
opType = OperatorType.COUNT;
} else if (text.equals("Avg")) {
opType = OperatorType.AVG;
} else {
throw new RuntimeException("unexpected");
}
......@@ -608,6 +621,9 @@ public class CQL_2_Graph_Mapper {
// TODO: the contained parameter might as well be an arbitrary expression
setCurrentPath(new GraphPath(newOp.getParameters().get(0).asConcept()));
}
if (opType == OperatorType.COUNT) {
// here should something happen that determines the scope of the aggregation op
}
} else {
throw new RuntimeException("unexpected");
}
......
package de.uniwue.query;
import java.util.List;
import java.util.Set;
public abstract class Expression {
......@@ -28,7 +28,7 @@ public abstract class Expression {
return (QueryOperator) this;
}
public abstract void getReturnedExpressions(List<Expression> results);
public abstract void getReturnedExpressions(Set<Expression> results);
public boolean includeInResult;
......
package de.uniwue.query;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class GraphQuery {
......@@ -31,8 +33,8 @@ public class GraphQuery {
return result;
}
public List<Expression> getReturnedExpressions() {
List<Expression> returns = new ArrayList<Expression>();
public Set<Expression> getReturnedExpressions() {
Set<Expression> returns = new HashSet<Expression>();
for (QueryConcept aConc : getConceptsRecursive()) {
aConc.getReturnedExpressions(returns);
}
......
......@@ -40,6 +40,7 @@ public enum OperatorType {
// aggregation
COUNT,
AVG,
// arithmetics
POWER,
......
package de.uniwue.query;
import java.util.List;
import java.util.Set;
public class Primitive extends Expression {
......@@ -36,7 +36,7 @@ public class Primitive extends Expression {
return result;
}
public void getReturnedExpressions(List<Expression> results) {
public void getReturnedExpressions(Set<Expression> results) {
if (includeInResult) {
results.add(this);
}
......
......@@ -3,6 +3,7 @@ package de.uniwue.query;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import de.uniwue.misc.util.StringUtilsUniWue;
......@@ -140,7 +141,7 @@ public class QueryConcept extends Expression {
return result;
}
public void getReturnedExpressions(List<Expression> results) {
public void getReturnedExpressions(Set<Expression> results) {
if (includeInResult) {
results.add(this);
}
......
......@@ -2,6 +2,7 @@ package de.uniwue.query;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import de.uniwue.misc.util.StringUtilsUniWue;
import de.uniwue.query.Primitive.PrimitiveDataType;
......@@ -179,7 +180,7 @@ public class QueryOperator extends Expression {
return result;
}
public void getReturnedExpressions(List<Expression> results) {
public void getReturnedExpressions(Set<Expression> results) {
if (includeInResult) {
results.add(this);
}
......
......@@ -21,6 +21,7 @@ public class CypherOperatorMapper {
aMap.addOp("OR", OperatorType.OR);
aMap.addOp("count", OperatorType.COUNT);
aMap.addOp("avg", OperatorType.AVG);
aMap.addOp("First", OperatorType.FIRST);
aMap.addOp("Last", OperatorType.LAST);
aMap.addOp("In", OperatorType.IN);
......
......@@ -49,11 +49,20 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
// TODO: fill
@SuppressWarnings("unchecked")
private Set<OperatorType> infixOperators = new HashSet<OperatorType>(
private Set<OperatorType> infixOps = new HashSet<OperatorType>(
Arrays.asList(new OperatorType[] { OperatorType.MORE, OperatorType.LESS, OperatorType.AND,
OperatorType.EQUALS, OperatorType.AFTER, OperatorType.POWER, OperatorType.ADD,
OperatorType.MULTIPLY, OperatorType.DIVIDE, OperatorType.SUBTRACT }));
@SuppressWarnings("unchecked")
private Set<OperatorType> aggrOps = new HashSet<OperatorType>(Arrays.asList(
new OperatorType[] { OperatorType.LAST, OperatorType.FIRST, OperatorType.COUNT }));
@SuppressWarnings("unchecked")
private Set<OperatorType> compOps = new HashSet<OperatorType>(
Arrays.asList(new OperatorType[] { OperatorType.EQUALS, OperatorType.MORE,
OperatorType.MORE_OR_EQUAL, OperatorType.LESS, OperatorType.LESS_OR_EQUAL }));
public Graph_2_Cypher_Mapper() {
super(system);
CypherOperatorMapper.initializeOpMappings(opMap);
......@@ -243,7 +252,7 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
private String writeOperator(QueryOperator anOp) {
String result;
if (infixOperators.contains(anOp.type)) {
if (infixOps.contains(anOp.type)) {
result = writeInfixOperator(anOp);
} else if (anOp.type == OperatorType.LAST) {
result = writeLast(anOp);
......@@ -328,7 +337,19 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
private String writeWhere(GraphQuery aQuery) {
String result = "";
boolean first = true;
boolean containsComparator = false;
for (QueryOperator aClause : aQuery.rootClause.getOperatorsRecursive()) {
if (compOps.contains(aClause.type)) {
containsComparator = true;
}
}
if (!containsComparator) {
return result;
}
for (QueryOperator aClause : aQuery.rootClause.getOperators()) {
if (aClause.includeInResult) {
continue;
}
if (first) {
result = result + " WHERE ";
first = false;
......@@ -344,7 +365,7 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
private String writeReturn(GraphQuery aQuery) {
String result = " RETURN ";
boolean first = true;
List<Expression> returnedExpressions = aQuery.getReturnedExpressions();
Set<Expression> returnedExpressions = aQuery.getReturnedExpressions();
for (Expression anExp : returnedExpressions) {
if (!first) {
result += ", ";
......@@ -355,8 +376,13 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
String alias = aliasesConcs.get(anExp.asConcept());
result += alias;
} else if (anExp.isOperator()) {
String alias = aliasesOps.get(anExp.asOperator());
result += alias;
QueryOperator anOp = anExp.asOperator();
if (aliasesOps.containsKey(anOp)) {
String alias = aliasesOps.get(anOp);
result += alias;
} else {
result += writeOperator(anOp);
}
} else if (anExp.isPrimitive()) {
result += anExp.asPrimitive().toString();
} else {
......@@ -384,7 +410,40 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
return result;
}
private String writeLastWithPart(GraphQuery aQuery, QueryOperator anOp) {
private String writeAggrOpWithPart(GraphQuery aQuery, QueryOperator anOp) {
if (anOp.type == OperatorType.LAST) {
return writeLastOpWithPart(aQuery, anOp);
}
QueryConcept pathEnd = anOp.getParameters().get(0).asConcept();
QueryConcept currentConc = pathEnd;
String path = "";
while (!aliasesConcs.containsKey(currentConc)) {
if (!path.isEmpty()) {
path = "." + path;
}
path = currentConc.code + path;
currentConc = currentConc.parentConcept;
}
String alias = aliasesConcs.get(currentConc);
String opString = opMap.graph_2_system_operatorMap.get(anOp.type);
String fullPath = alias;
if (!path.isEmpty()) {
fullPath += "." + path;
}
String result = opString + "(" + fullPath + ")";
String opAlias = aliasNames[aliasIndex++];
aliasesOps.put(anOp, opAlias);
result += " AS " + opAlias;
for (QueryConcept aConc : aQuery.getConceptsRecursive()) {
if (aliasesConcs.containsKey(aConc)) {
String returnAlias = aliasesConcs.get(aConc);
result += ", " + returnAlias;
}
}
return result;
}
private String writeLastOpWithPart(GraphQuery aQuery, QueryOperator anOp) {
// the max-operator may not group by all intermediate concepts which the last operator is
// traversing during its path to the final member that has to serve as the comparison target
List<QueryConcept> notToAggregateConcets = new ArrayList<QueryConcept>();
......@@ -418,12 +477,12 @@ public class Graph_2_Cypher_Mapper extends Graph_2_System_Mapper {
private String writeWith(GraphQuery aQuery) {
String result = "";
for (QueryOperator anOp : aQuery.rootClause.getOperatorsRecursive()) {
// TODO: change this to an aggregator set check
if (anOp.type == OperatorType.LAST) {
if (aggrOps.contains(anOp.type) && anOp.getParameters().size() > 1) {
// if size > 1 then there is a scope
if (result.isEmpty()) {
result = " WITH ";
}
result += writeLastWithPart(aQuery, anOp);
result += writeAggrOpWithPart(aQuery, anOp);
}
}
return result;
......
......@@ -28,7 +28,7 @@ public class Test_CQL_2_Cypher {
QueryManager queryManager = new QueryManager();
initialize();
for (MultiQuery aMultiQuery : queryManager.queries) {
if (aMultiQuery.name.equals("query_CQL_2_Cypher_Count")) {
if (aMultiQuery.name.equals("query_CQL_2_Cypher_Avg")) {
processQuery(aMultiQuery);
}
}
......
*CQL
[Encounter] A return Avg(A.length.value)
*Cypher
MATCH (A:Encounter)-[:LENGTH]->(B:Duration) RETURN avg(B.value)
\ No newline at end of file
*CQL
[Patient] A where A.name.family = 'smith' return Count(A)
*Cypher
MATCH (A:Patient)-[:NAME]->(B:HumanName) WHERE B.family = 'smith' RETURN count(A)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment