Skip to content

Commit

Permalink
ElementMap step support (#2942)
Browse files Browse the repository at this point in the history
## What do these changes do?

```gremlin
gremlin> g.V(1,2,4).elementMap()
==>{label=person, id=1, name=marko, id=1, age=29}
==>{label=person, id=2, name=vadas, id=2, age=27}
==>{label=person, id=4, name=josh, id=4, age=32}

gremlin> g.V(1,2,4).elementMap("name", "age")
==>{age=27, label=person, id=2, name=vadas}
==>{age=32, label=person, id=4, name=josh}
==>{age=29, label=person, id=1, name=marko}

gremlin> g.V().elementMap()
==>{label=person, id=2, name=vadas, id=2, age=27}
==>{label=software, id=72057594037927941, name=ripple, id=5, lang=java}
==>{label=person, id=1, name=marko, id=1, age=29}
==>{label=software, id=72057594037927939, name=lop, id=3, lang=java}
==>{label=person, id=4, name=josh, id=4, age=32}
==>{label=person, id=6, name=peter, id=6, age=35}
```

Compare to the official result, now **g.E().elementMap()** lack the
information of in(out)'s vertices

```
# our result
gremlin> g.E().elementMap()
==>{label=knows, id=0, start_id=0.5, end_id=0.5, weight=0.5}

# official result
gremlin> g.E().elementMap()
==>{label=knows, id=0, start_id=0.5, end_id=0.5, weight=0.5, IN=[label=person, id=0], OUT=[label=person, id=1]}

```

<!-- Please give a short brief about these changes. -->

## Related issue number

<!-- Are there any issues opened that will be resolved by merging this
change? -->

Fixes #2778

---------

Co-authored-by: shirly121 <[email protected]>
  • Loading branch information
lidongze0629 and shirly121 authored Jun 28, 2023
1 parent b6402e7 commit 7035c0a
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 35 deletions.
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

0 comments on commit 7035c0a

Please sign in to comment.