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

[GIE Compiler] Parse Label Id to Name in label Operator #2928

Merged
merged 3 commits into from
Jun 26, 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
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