Skip to content
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

ElementMap step support #2942

Merged
merged 2 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion interactive_engine/compiler/src/main/antlr4/GremlinGS.g4
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ traversalMethod
| traversalMethod_inE // inE()[.outV()]
| traversalMethod_bothE // bothE()[.otherV()]
| traversalMethod_limit // limit()
| traversalMethod_valueMap // valueMap()
| traversalMethod_valueMap // valueMap()
| traversalMethod_elementMap // elementMap()
| traversalMethod_order // order()
| traversalMethod_select // select()
| traversalMethod_dedup // dedup()
Expand Down Expand Up @@ -199,6 +200,12 @@ traversalMethod_valueMap
: 'valueMap' LPAREN stringLiteralList RPAREN
;

// elementMap()
// elementMap('s1', ...)
traversalMethod_elementMap
: 'elementMap' LPAREN stringLiteralList RPAREN
;

// order()
// order().by
traversalMethod_order
Expand Down Expand Up @@ -238,12 +245,14 @@ traversalMethod_select
// by()
// by("name")
// by(valueMap())
// by(elementMap())
// by(out().count())
// by(T.label/T.id)
traversalMethod_selectby
: 'by' LPAREN RPAREN
| 'by' LPAREN stringLiteral RPAREN
| 'by' LPAREN (ANON_TRAVERSAL_ROOT DOT)? traversalMethod_valueMap RPAREN
| 'by' LPAREN (ANON_TRAVERSAL_ROOT DOT)? traversalMethod_elementMap RPAREN
| 'by' LPAREN nestedTraversal RPAREN
| 'by' LPAREN traversalToken RPAREN
;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ public InterOpCollection build() throws OpArgIllegalException, UnsupportedStepEx
} else if (Utils.equalClass(step, PropertiesStep.class)
|| Utils.equalClass(step, PropertyMapStep.class)
|| Utils.equalClass(step, LabelStep.class)
|| Utils.equalClass(step, IdStep.class)) {
|| Utils.equalClass(step, IdStep.class)
|| Utils.equalClass(step, ElementMapStep.class)) {
opList.add(StepTransformFactory.VALUES_STEP.apply(step));
} else if (Utils.equalClass(step, IsStep.class)) {
opList.add(StepTransformFactory.IS_STEP.apply(step));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,13 @@ public Traversal visitTraversalMethod_valueMap(
GenericLiteralVisitor.getStringLiteralList(ctx.stringLiteralList()));
}

@Override
public Traversal visitTraversalMethod_elementMap(
GremlinGSParser.TraversalMethod_elementMapContext ctx) {
return graphTraversal.elementMap(
GenericLiteralVisitor.getStringLiteralList(ctx.stringLiteralList()));
}

@Override
public Traversal visitTraversalMethod_select(
GremlinGSParser.TraversalMethod_selectContext ctx) {
Expand Down Expand Up @@ -335,6 +342,15 @@ public Traversal visitTraversalMethod_select(
nestedVisitor.visitTraversalMethod_valueMap(
byCtx.traversalMethod_valueMap());
step.modulateBy(nestedTraversal.asAdmin());
} else if (byCtx.traversalMethod_elementMap()
!= null) { // select(..).by(elementMap('name'))
TraversalMethodVisitor nestedVisitor =
new TraversalMethodVisitor(
gvisitor, GremlinAntlrToJava.getTraversalSupplier().get());
Traversal nestedTraversal =
nestedVisitor.visitTraversalMethod_elementMap(
byCtx.traversalMethod_elementMap());
step.modulateBy(nestedTraversal.asAdmin());
} else if (byChildCount == 4
&& byCtx.nestedTraversal() != null) { // select(..).by(out().count())
Traversal nestedTraversal = visitNestedTraversal(byCtx.nestedTraversal());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1507,6 +1507,14 @@
test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.VertexTest",
method = "g_EX11X",
reason = "unsupported")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementMapTest",
method = "g_EX11X_elementMap",
reason = "cannot get label and id for out and in vertices")
@Graph.OptOut(
test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ElementMapTest",
method = "g_V_elementMap",
reason = "cannot get label and id for out and in vertices")
// @Graph.OptOut(
// test = "org.apache.tinkerpop.gremlin.process.traversal.step.map.ValueMapTest",
// method = "g_V_valueMapXname_ageX",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public class IrGremlinTestSuite extends AbstractGremlinSuite {
VertexTest.Traversals.class,
UnfoldTest.Traversals.class,
ValueMapTest.Traversals.class,
ElementMapTest.Traversals.class,
GroupTest.Traversals.class,
GroupCountTest.Traversals.class,

Expand Down Expand Up @@ -100,6 +101,7 @@ public class IrGremlinTestSuite extends AbstractGremlinSuite {
VertexTest.Traversals.class,
UnfoldTest.Traversals.class,
ValueMapTest.Traversals.class,
ElementMapTest.Traversals.class,
GroupTest.Traversals.class,
GroupCountTest.Traversals.class,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static GremlinResultParser analyze(Traversal traversal) {
|| Utils.equalClass(step, SelectStep.class)
|| Utils.equalClass(step, PropertiesStep.class)
|| Utils.equalClass(step, PropertyMapStep.class)
|| Utils.equalClass(step, ElementMapStep.class)
|| Utils.equalClass(step, TraversalMapStep.class)
|| Utils.equalClass(step, MatchStep.class)
|| Utils.equalClass(step, ExprStep.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,10 @@ public Object parseLabel(Object values, String tag, Object stepOrTraversal, Step
Iterator<Map.Entry> valuesIterator = ((Map) values).entrySet().iterator();
while (valuesIterator.hasNext()) {
Map.Entry valuesEntry = valuesIterator.next();
if (!(stepOrTraversal instanceof ElementMapStep)
|| valuesEntry.getKey().equals(T.label.getAccessor())) {
if (valuesEntry.getValue() instanceof Map) {
parseLabel(valuesEntry.getValue(), tag, stepOrTraversal, parent);
} else if (!(stepOrTraversal instanceof ElementMapStep)
|| valuesEntry.getKey().equals(T.label)) {
valuesEntry.setValue(
parseLabelByType(
valuesEntry.getValue(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import com.alibaba.graphscope.gremlin.transform.alias.AliasManager;

import org.apache.tinkerpop.gremlin.process.traversal.Step;
import org.apache.tinkerpop.gremlin.process.traversal.step.map.PropertyMapStep;
import org.apache.tinkerpop.gremlin.structure.T;

import java.util.*;

Expand All @@ -46,7 +48,7 @@ public static ProjectResultParser create(Step step) {
@Override
public Object parseFrom(IrResult.Results results) {
IrResult.Record record = results.getRecord();
Map<String, Object> projectResult = new LinkedHashMap<>();
Map<Object, Object> projectResult = new LinkedHashMap<>();
record.getColumnsList()
.forEach(
column -> {
Expand All @@ -58,36 +60,8 @@ public Object parseFrom(IrResult.Results results) {
Map tagEntry =
(Map)
projectResult.computeIfAbsent(
tag, k1 -> new HashMap<>());
projectTags.forEach(
(k, v) -> {
if (!(v instanceof EmptyValue)) {
String nameOrId = null;
if (k
instanceof
List) { // valueMap("name") -> Map<["",
// "name"], value>
nameOrId = (String) ((List) k).get(1);
} else if (k
instanceof
String) { // valueMap() -> Map<"name",
// value>
nameOrId = (String) k;
} else if (k
instanceof
Number) { // valueMap() -> Map<1, value>
nameOrId = String.valueOf(k);
}
if (nameOrId == null || nameOrId.isEmpty()) {
throw new GremlinResultParserException(
"map value should have property"
+ " key");
}
String property = getPropertyName(nameOrId);
tagEntry.put(
property, Collections.singletonList(v));
}
});
tag, k1 -> new LinkedHashMap<>());
tagEntry.putAll(flatMap(projectTags));
} else {
if (!(parseEntry instanceof EmptyValue)) {
projectResult.put(tag, parseEntry);
Expand All @@ -104,6 +78,45 @@ public Object parseFrom(IrResult.Results results) {
}
}

// {~label: "person", ~all: {name: "marko"}} -> {~label: "person", name: "marko"}
private Map<Object, Object> flatMap(Map<String, Object> map) {
Map<Object, Object> result = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
Object k = entry.getKey();
Object v = entry.getValue();
if (v instanceof Map) {
result.putAll(flatMap((Map<String, Object>) v));
} else {
if (!(v instanceof EmptyValue)) {
String nameOrId = null;
if (k instanceof List) { // valueMap("name") -> Map<["", "name"], value>
nameOrId = (String) ((List) k).get(1);
} else if (k instanceof String) { // valueMap() -> Map<"name",
// value>
nameOrId = (String) k;
} else if (k instanceof Number) { // valueMap() -> Map<1, value>
nameOrId = String.valueOf(k);
}
if (nameOrId == null || nameOrId.isEmpty()) {
throw new GremlinResultParserException(
"map value should have property" + " key");
}
String property = getPropertyName(nameOrId);
if (step instanceof PropertyMapStep) {
result.put(property, Collections.singletonList(v));
} else if (property.equals(T.id.getAccessor())) {
result.put(T.id, v);
} else if (property.equals(T.label.getAccessor())) {
result.put(T.label, v);
} else {
result.put(property, v);
}
}
}
}
return result;
}

// a_1 -> a, i.e. g.V().as("a").select("a")
// name_1 -> name, i.e. g.V().values("name")
// a_name_1 -> a, i.e. g.V().as("a").select("a").by("name")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,28 @@ default ExprResult getSubTraversalAsExpr(ExprArg exprArg) {
} else if (step instanceof IdStep) {
return (new ExprResult())
.addTagExpr("", Optional.of("@." + T.id.getAccessor())); // @.~id
} else if (step instanceof ElementMapStep) { // elementMap(..)
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("{");
// id
stringBuilder.append("@." + ArgUtils.ID + ",");
// label
stringBuilder.append("@." + ArgUtils.LABEL + ",");
// properties
String[] mapKeys = ((ElementMapStep) step).getPropertyKeys();
if (mapKeys.length > 0) {
for (int i = 0; i < mapKeys.length; ++i) {
if (i > 0) {
stringBuilder.append(",");
}
stringBuilder.append("@." + mapKeys[i]);
}
} else {
// elementMap() -> @.~all
stringBuilder.append("@." + ArgUtils.PROPERTY_ALL);
}
stringBuilder.append("}");
return (new ExprResult()).addTagExpr("", Optional.of(stringBuilder.toString()));
} else if (step instanceof SelectOneStep || step instanceof SelectStep) {
// select('a'), select('a').by()
// select('a').by('name'/values/valueMap)
Expand Down