Skip to content

Commit

Permalink
[GIE Compiler] Parse Label Id to Name in label Operator (#2928)
Browse files Browse the repository at this point in the history
<!--
Thanks for your contribution! please review
https://github.com/alibaba/GraphScope/blob/main/CONTRIBUTING.md before
opening an issue.
-->

## What do these changes do?
as titled.

<!-- 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 #2777

Co-authored-by: Longbin Lai <longbin.lailb@alibaba-inc.com>
  • Loading branch information
shirly121 and longbinlai committed Jun 26, 2023
1 parent 34b3650 commit 96d5093
Show file tree
Hide file tree
Showing 10 changed files with 466 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ public InterOpCollection build() throws OpArgIllegalException, UnsupportedStepEx
|| Utils.equalClass(step, MeanGlobalStep.class)) {
opList.add(StepTransformFactory.AGGREGATE_STEP.apply(step));
} else if (Utils.equalClass(step, PropertiesStep.class)
|| Utils.equalClass(step, PropertyMapStep.class)) {
|| Utils.equalClass(step, PropertyMapStep.class)
|| Utils.equalClass(step, LabelStep.class)
|| Utils.equalClass(step, IdStep.class)) {
opList.add(StepTransformFactory.VALUES_STEP.apply(step));
} else if (Utils.equalClass(step, IsStep.class)) {
opList.add(StepTransformFactory.IS_STEP.apply(step));
Expand Down Expand Up @@ -135,10 +137,6 @@ public InterOpCollection build() throws OpArgIllegalException, UnsupportedStepEx
opList.add(StepTransformFactory.SUBGRAPH_STEP.apply(step));
} else if (Utils.equalClass(step, IdentityStep.class)) {
opList.add(StepTransformFactory.IDENTITY_STEP.apply(step));
} else if (Utils.equalClass(step, IdStep.class)) {
opList.add(StepTransformFactory.ID_STEP.apply(step));
} else if (Utils.equalClass(step, LabelStep.class)) {
opList.add(StepTransformFactory.LABEL_STEP.apply(step));
} else if (Utils.equalClass(step, ConstantStep.class)) {
opList.add(StepTransformFactory.CONSTANT_STEP.apply(step));
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@
import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__;
import org.apache.tinkerpop.gremlin.structure.Column;
import org.apache.tinkerpop.gremlin.structure.Edge;
import org.apache.tinkerpop.gremlin.structure.T;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import org.junit.Assert;
import org.junit.Test;

import java.util.*;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;

public abstract class IrGremlinQueryTest extends AbstractGremlinProcessTest {

Expand All @@ -55,6 +60,16 @@ public abstract class IrGremlinQueryTest extends AbstractGremlinProcessTest {
public abstract Traversal<Vertex, Object>
get_g_V_matchXa_out_b__b_in_cX_select_c_out_dedup_values();

public abstract Traversal<Vertex, String> get_g_V_has_name_marko_label();

public abstract Traversal<Vertex, Object> get_g_V_has_name_marko_select_by_T_label();

public abstract Traversal<Vertex, Object> get_g_V_has_name_marko_select_by_label();

public abstract Traversal<Edge, String> get_g_E_has_weight_0_5_f_label();

public abstract Traversal<Vertex, Map<String, Object>> get_g_V_a_out_b_select_a_b_by_label_id();

@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
@Test
public void g_V_group_by_by_dedup_count_test() {
Expand Down Expand Up @@ -211,6 +226,47 @@ public void g_V_matchXa_out_b__b_in_cX_select_c_out_dedup_values() {
Assert.assertEquals(2, counter);
}

@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
@Test
public void g_V_has_name_marko_label() {
final Traversal<Vertex, String> traversal = get_g_V_has_name_marko_label();
printTraversalForm(traversal);
Assert.assertEquals("person", traversal.next());
}

@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
@Test
public void g_E_has_weight_0_5_f_label() {
final Traversal<Edge, String> traversal = get_g_E_has_weight_0_5_f_label();
printTraversalForm(traversal);
Assert.assertEquals("knows", traversal.next());
}

@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
@Test
public void g_V_has_name_marko_select_by_T_label() {
final Traversal<Vertex, Object> traversal = get_g_V_has_name_marko_select_by_T_label();
printTraversalForm(traversal);
Assert.assertEquals("person", traversal.next());
}

@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
@Test
public void g_V_has_name_marko_select_by_label() {
final Traversal<Vertex, Object> traversal = get_g_V_has_name_marko_select_by_label();
printTraversalForm(traversal);
Assert.assertEquals("person", traversal.next());
}

@LoadGraphWith(LoadGraphWith.GraphData.MODERN)
@Test
public void g_V_a_out_b_select_a_b_by_label_id() {
final Traversal<Vertex, Map<String, Object>> traversal =
get_g_V_a_out_b_select_a_b_by_label_id();
printTraversalForm(traversal);
Assert.assertEquals("{a=person, b=lop}", traversal.next().toString());
}

public static class Traversals extends IrGremlinQueryTest {

@Override
Expand Down Expand Up @@ -271,5 +327,37 @@ public Traversal<Vertex, Object> get_g_V_matchXa_knows_b__b_created_cX_select_c_
.dedup()
.values("name");
}

@Override
public Traversal<Vertex, String> get_g_V_has_name_marko_label() {
return g.V().has("name", "marko").label();
}

@Override
public Traversal<Vertex, Object> get_g_V_has_name_marko_select_by_T_label() {
return g.V().has("name", "marko").as("a").select("a").by(T.label);
}

@Override
public Traversal<Vertex, Object> get_g_V_has_name_marko_select_by_label() {
return g.V().has("name", "marko").as("a").select("a").by(__.label());
}

@Override
public Traversal<Edge, String> get_g_E_has_weight_0_5_f_label() {
return g.E().has("weight", 0.5f).label();
}

@Override
public Traversal<Vertex, Map<String, Object>> get_g_V_a_out_b_select_a_b_by_label_id() {
return g.V().has("name", "marko")
.as("a")
.out()
.has("name", "lop")
.as("b")
.select("a", "b")
.by(label())
.by("name");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ public static GremlinResultParser analyze(Traversal traversal) {
|| Utils.equalClass(step, IdStep.class)
|| Utils.equalClass(step, LabelStep.class)
|| Utils.equalClass(step, ConstantStep.class)) {
parserType = GremlinResultParserFactory.PROJECT_VALUE;
parserType = ProjectResultParser.create(step);
} else if (Utils.equalClass(step, GroupCountStep.class)
|| Utils.equalClass(step, GroupStep.class)) {
parserType = GroupResultParser.create(step);
} else if (Utils.equalClass(step, UnionStep.class)) {
parserType = GremlinResultParserFactory.UNION;
parserType = UnionResultParser.create(step);
} else if (Utils.equalClass(step, SubgraphStep.class)) {
parserType = GremlinResultParserFactory.SUBGRAPH;
} else if (Utils.equalClass(step, HasStep.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,14 @@

package com.alibaba.graphscope.gremlin.result;

import com.alibaba.graphscope.common.jna.type.FfiKeyType;
import com.alibaba.graphscope.gaia.proto.Common;
import com.alibaba.graphscope.gaia.proto.IrResult;
import com.alibaba.graphscope.gremlin.exception.GremlinResultParserException;
import com.alibaba.graphscope.gremlin.transform.alias.AliasManager;

import org.apache.tinkerpop.gremlin.structure.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public enum GremlinResultParserFactory implements GremlinResultParser {
GRAPH_ELEMENT {
Expand All @@ -44,158 +38,15 @@ public Object parseFrom(IrResult.Results results) {
return graphElement;
}
},

SINGLE_VALUE {
@Override
public Object parseFrom(IrResult.Results results) {
IrResult.Entry entry = ParserUtils.getHeadEntry(results);
return ParserUtils.parseEntry(entry);
}
},
PROJECT_VALUE {
// values("name") -> key: head, value: "marko"
// valueMap("name") -> key: head, value: {name, "marko"}
// select("a").by("name") -> key: head, value: "marko"
// select("a", "b").by("name") -> key: a, value: "marko"; key: b, value: "josh"
// select("a", "b").by(valueMap("name")) -> key: a, value: {name, "marko"}; key: b, value:
// {name, "josh"}
@Override
public Object parseFrom(IrResult.Results results) {
logger.debug("{}", results);
IrResult.Record record = results.getRecord();
logger.debug("{}", record);
Map<String, Object> projectResult = new HashMap<>();
record.getColumnsList()
.forEach(
column -> {
String tag = getColumnKeyAsResultKey(column.getNameOrId());
Object parseEntry = ParserUtils.parseEntry(column.getEntry());
if (parseEntry instanceof Map) {
Map projectTags = (Map) parseEntry;
// return empty Map if none properties
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));
}
});
} else {
if (!(parseEntry instanceof EmptyValue)) {
projectResult.put(tag, parseEntry);
}
}
});
if (projectResult.isEmpty()) {
return EmptyValue.INSTANCE;
} else if (projectResult.size() == 1) {
return projectResult.entrySet().iterator().next().getValue();
} else {
return projectResult;
}
}

// 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")
private String getColumnKeyAsResultKey(Common.NameOrId columnKey) {
if (columnKey.getItemCase() == Common.NameOrId.ItemCase.ITEM_NOT_SET) {
return "";
}
switch (columnKey.getItemCase()) {
case ITEM_NOT_SET:
return "";
case NAME:
String key = columnKey.getName();
return AliasManager.getPrefix(key);
case ID:
return String.valueOf(columnKey.getId());
default:
throw new GremlinResultParserException(columnKey.getItemCase() + " is invalid");
}
}

// propertyId is in String format, i.e. "1"
private String getPropertyName(String nameOrId) {
Common.NameOrId.Builder builder = Common.NameOrId.newBuilder();
if (nameOrId.matches("^[0-9]+$")) {
builder.setId(Integer.valueOf(nameOrId));
} else {
builder.setName(nameOrId);
}
return ParserUtils.getKeyName(builder.build(), FfiKeyType.Column);
}
},
UNION {
@Override
public Object parseFrom(IrResult.Results results) {
GremlinResultParser resultParser = inferFromIrResults(results);
return resultParser.parseFrom(results);
}

// try to infer from the results
private GremlinResultParser inferFromIrResults(IrResult.Results results) {
int columns = results.getRecord().getColumnsList().size();
logger.debug("result is {}", results);
if (columns == 1) {
IrResult.Entry entry = ParserUtils.getHeadEntry(results);
switch (entry.getInnerCase()) {
case ELEMENT:
IrResult.Element element = entry.getElement();
if (element.getInnerCase() == IrResult.Element.InnerCase.VERTEX
|| element.getInnerCase() == IrResult.Element.InnerCase.EDGE
|| element.getInnerCase()
== IrResult.Element.InnerCase.GRAPH_PATH) {
return GRAPH_ELEMENT;
} else if (element.getInnerCase() == IrResult.Element.InnerCase.OBJECT) {
Common.Value value = element.getObject();
if (value.getItemCase()
== Common.Value.ItemCase.PAIR_ARRAY) { // project
return PROJECT_VALUE;
} else { // simple type
return SINGLE_VALUE;
}
} else {
throw new GremlinResultParserException(
element.getInnerCase() + " is invalid");
}
case COLLECTION: // path()
default:
throw new GremlinResultParserException(
entry.getInnerCase() + " is unsupported yet");
}
} else if (columns > 1) { // project or group
return PROJECT_VALUE;
} else {
throw new GremlinResultParserException("columns should not be empty");
}
}
},
SUBGRAPH {
@Override
public Object parseFrom(IrResult.Results results) {
Expand Down
Loading

0 comments on commit 96d5093

Please sign in to comment.