-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix : group by on functional expressions in mongo #200
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
[ | ||
{ | ||
"function": 0.0, | ||
"functionCount": 4 | ||
}, | ||
{ | ||
"function": 1.0, | ||
"functionCount": 2 | ||
}, | ||
{ | ||
"function": 3.0, | ||
"functionCount": 2 | ||
} | ||
] |
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -5,15 +5,20 @@ | |||
import static org.hypertrace.core.documentstore.mongo.MongoUtils.encodeKey; | ||||
|
||||
import com.mongodb.BasicDBObject; | ||||
import java.util.ArrayList; | ||||
import java.util.HashMap; | ||||
import java.util.LinkedHashMap; | ||||
import java.util.List; | ||||
import java.util.Map; | ||||
import java.util.Objects; | ||||
import java.util.stream.Collectors; | ||||
import org.apache.commons.collections4.CollectionUtils; | ||||
import org.apache.commons.collections4.MapUtils; | ||||
import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; | ||||
import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; | ||||
import org.hypertrace.core.documentstore.expression.type.GroupTypeExpression; | ||||
import org.hypertrace.core.documentstore.parser.FunctionExpressionChecker; | ||||
import org.hypertrace.core.documentstore.parser.GroupByAliasGetter; | ||||
import org.hypertrace.core.documentstore.parser.GroupTypeExpressionVisitor; | ||||
import org.hypertrace.core.documentstore.parser.SelectTypeExpressionVisitor; | ||||
import org.hypertrace.core.documentstore.query.Query; | ||||
|
@@ -22,6 +27,10 @@ | |||
public final class MongoGroupTypeExpressionParser implements GroupTypeExpressionVisitor { | ||||
|
||||
private static final String GROUP_CLAUSE = "$group"; | ||||
private static final String ADD_FIELDS_CLAUSE = "$addFields"; | ||||
private static final FunctionExpressionChecker FUNCTION_EXPRESSION_CHECKER = | ||||
new FunctionExpressionChecker(); | ||||
private static final GroupByAliasGetter GROUP_BY_ALIAS_GETTER = new GroupByAliasGetter(); | ||||
|
||||
@SuppressWarnings("unchecked") | ||||
@Override | ||||
|
@@ -41,10 +50,32 @@ public Map<String, Object> visit(final IdentifierExpression expression) { | |||
return Map.of(key, PREFIX + identifier); | ||||
} | ||||
|
||||
public static BasicDBObject getGroupClause(final Query query) { | ||||
public static List<BasicDBObject> getGroupClauses(final Query query) { | ||||
final List<SelectionSpec> selectionSpecs = query.getSelections(); | ||||
final List<GroupTypeExpression> expressions = query.getAggregations(); | ||||
|
||||
final List<BasicDBObject> basicDBObjects = new ArrayList<>(); | ||||
|
||||
final List<SelectionSpec> functionExpressionSelectionWithGroupBys = | ||||
getFunctionExpressionSelectionWithGroupBys(selectionSpecs, expressions); | ||||
|
||||
if (!functionExpressionSelectionWithGroupBys.isEmpty()) { | ||||
MongoSelectTypeExpressionParser parser = | ||||
new MongoIdentifierPrefixingParser( | ||||
new MongoIdentifierExpressionParser(new MongoFunctionExpressionParser())); | ||||
Map<String, Object> addFields = | ||||
functionExpressionSelectionWithGroupBys.stream() | ||||
.map(spec -> MongoGroupTypeExpressionParser.parse(parser, spec)) | ||||
.reduce( | ||||
new LinkedHashMap<>(), | ||||
(first, second) -> { | ||||
first.putAll(second); | ||||
return first; | ||||
}); | ||||
|
||||
basicDBObjects.add(new BasicDBObject(ADD_FIELDS_CLAUSE, addFields)); | ||||
} | ||||
|
||||
MongoGroupTypeExpressionParser parser = new MongoGroupTypeExpressionParser(); | ||||
Map<String, Object> groupExp; | ||||
|
||||
|
@@ -82,11 +113,13 @@ public static BasicDBObject getGroupClause(final Query query) { | |||
}); | ||||
|
||||
if (MapUtils.isEmpty(definition) && CollectionUtils.isEmpty(expressions)) { | ||||
return new BasicDBObject(); | ||||
return basicDBObjects; | ||||
} | ||||
|
||||
definition.putAll(groupExp); | ||||
return new BasicDBObject(GROUP_CLAUSE, definition); | ||||
|
||||
basicDBObjects.add(new BasicDBObject(GROUP_CLAUSE, definition)); | ||||
return basicDBObjects; | ||||
} | ||||
|
||||
private static Map<String, Object> parse( | ||||
|
@@ -99,4 +132,29 @@ private Map<String, Object> parse(final GroupTypeExpression expression) { | |||
MongoGroupTypeExpressionParser parser = new MongoGroupTypeExpressionParser(); | ||||
return expression.accept(parser); | ||||
} | ||||
|
||||
private static List<SelectionSpec> getFunctionExpressionSelectionWithGroupBys( | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is this getting used? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Line 56 in 93fdf17
|
||||
final List<SelectionSpec> selectionSpecs, final List<GroupTypeExpression> expressions) { | ||||
List<String> groupByAliases = getGroupByAliases(expressions); | ||||
|
||||
return selectionSpecs.stream() | ||||
.filter( | ||||
selectionSpec -> | ||||
isFunctionExpressionSelectionWithGroupBy(selectionSpec, groupByAliases)) | ||||
.collect(Collectors.toUnmodifiableList()); | ||||
} | ||||
|
||||
public static boolean isFunctionExpressionSelectionWithGroupBy( | ||||
final SelectionSpec selectionSpec, final List<String> groupByAliases) { | ||||
return selectionSpec.getAlias() != null | ||||
&& groupByAliases.contains(selectionSpec.getAlias()) | ||||
&& (Boolean) selectionSpec.getExpression().accept(FUNCTION_EXPRESSION_CHECKER); | ||||
} | ||||
|
||||
public static List<String> getGroupByAliases(final List<GroupTypeExpression> expressions) { | ||||
return expressions.stream() | ||||
.map(expression -> (String) expression.accept(GROUP_BY_ALIAS_GETTER)) | ||||
.filter(Objects::nonNull) | ||||
.collect(Collectors.toUnmodifiableList()); | ||||
} | ||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package org.hypertrace.core.documentstore.parser; | ||
|
||
import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; | ||
import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; | ||
|
||
@SuppressWarnings("unchecked") | ||
public class GroupByAliasGetter implements GroupTypeExpressionVisitor { | ||
|
||
@Override | ||
public String visit(FunctionExpression expression) { | ||
return null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Better to throw exception instead of null. |
||
} | ||
|
||
@Override | ||
public String visit(IdentifierExpression expression) { | ||
return expression.getName(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for a linked hashmap? Is the order important here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no reason, i just copy pasted the reduce used below
don't think the order is important