Skip to content

Commit

Permalink
implement new Explanations API
Browse files Browse the repository at this point in the history
  • Loading branch information
joshua committed Mar 29, 2021
1 parent 12cc882 commit 945a477
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 51 deletions.
24 changes: 20 additions & 4 deletions api/answer/ConceptMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@
package grakn.client.api.answer;

import grakn.client.api.concept.Concept;
import grakn.client.common.exception.GraknClientException;
import grakn.common.collection.Pair;

import javax.annotation.CheckReturnValue;
import java.util.Collection;
import java.util.Map;
import java.util.Set;

import static grakn.client.common.exception.ErrorMessage.Concept.NONEXISTENT_EXPLAINABLE_CONCEPT;

public interface ConceptMap {

@CheckReturnValue
Expand All @@ -37,13 +41,25 @@ public interface ConceptMap {
@CheckReturnValue
Concept get(String variable);

Set<Explainable> explainables();
Explainables explainables();

interface Explainables {

Explainable concept(String variable);

Explainable ownership(String owner, String attribute);

Map<String, Explainable> explainableConcepts();

Map<Pair<String, String>, Explainable> explainableOwnerships();

interface Explainable {

interface Explainable {
String conjunction();

String conjunction();
long id();

long id();
}

}
}
4 changes: 2 additions & 2 deletions api/query/QueryManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ public interface QueryManager {

Stream<ConceptMap> update(GraqlUpdate query, GraknOptions options);

Stream<Explanation> explain(ConceptMap.Explainable explainable);
Stream<Explanation> explain(ConceptMap.Explainables.Explainable explainable);

Stream<Explanation> explain(ConceptMap.Explainable explainable, GraknOptions options);
Stream<Explanation> explain(ConceptMap.Explainables.Explainable explainable, GraknOptions options);

QueryFuture<Void> define(GraqlDefine query);

Expand Down
4 changes: 4 additions & 0 deletions common/exception/ErrorMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ public static class Concept extends ErrorMessage {
new Concept(6, "The value type '%s' was not recognised.");
public static final Concept BAD_ATTRIBUTE_VALUE =
new Concept(7, "The attribute value '%s' was not recognised.");
public static final Concept NONEXISTENT_EXPLAINABLE_CONCEPT =
new Concept(8, "No explainable concept for '%s' exists.");
public static final Concept NONEXISTENT_EXPLAINABLE_OWNERSHIP =
new Concept(9, "No explainable ownership between owner '%s' and attribute '%s' exists.");

private static final String codePrefix = "CON";
private static final String messagePrefix = "Concept Error";
Expand Down
134 changes: 101 additions & 33 deletions concept/answer/ConceptMapImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,48 +20,57 @@
package grakn.client.concept.answer;

import grakn.client.api.answer.ConceptMap;
import grakn.client.api.answer.ConceptMap.Explainables.Explainable;
import grakn.client.api.concept.Concept;
import grakn.client.common.exception.GraknClientException;
import grakn.client.concept.ConceptImpl;
import grakn.client.concept.thing.ThingImpl;
import grakn.client.concept.type.TypeImpl;
import grakn.common.collection.Pair;
import grakn.protocol.AnswerProto;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Objects;
import java.util.stream.Collectors;

import static grakn.client.common.exception.ErrorMessage.Concept.NONEXISTENT_EXPLAINABLE_CONCEPT;
import static grakn.client.common.exception.ErrorMessage.Concept.NONEXISTENT_EXPLAINABLE_OWNERSHIP;
import static grakn.client.common.exception.ErrorMessage.Query.VARIABLE_DOES_NOT_EXIST;

public class ConceptMapImpl implements ConceptMap {

private final Map<String, Concept> map;
private final Set<Explainable> explainables;
private final Explainables explainables;

public ConceptMapImpl(Map<String, Concept> map, Set<Explainable> explainables) {
public ConceptMapImpl(Map<String, Concept> map) {
this(map, new ExplainablesImpl());
}

public ConceptMapImpl(Map<String, Concept> map, Explainables explainables) {
this.map = Collections.unmodifiableMap(map);
this.explainables = Collections.unmodifiableSet(explainables);
this.explainables = explainables;
}

public static ConceptMap of(AnswerProto.ConceptMap res) {
Map<String, Concept> variableMap = new HashMap<>();
res.getMapMap().forEach((resVar, resConcept) -> {
Concept concept = ConceptImpl.of(resConcept);
variableMap.put(resVar, concept);
});
res.getMapMap().forEach((resVar, resConcept) -> variableMap.put(resVar, ConceptImpl.of(resConcept)));
return new ConceptMapImpl(Collections.unmodifiableMap(variableMap), of(res.getExplainables()));
}

Set<Explainable> explainables = new HashSet<>();
res.getExplainablesList().forEach((explainableProto) -> {
explainables.add(new ExplainableImpl(explainableProto.getConjunction(), explainableProto.getId()));
private static Explainables of(AnswerProto.Explainables explainables) {
Map<String, Explainable> explainableConcepts = new HashMap<>();
explainables.getExplainableConceptsMap().forEach((var, explainable) -> {
explainableConcepts.put(var, ExplainablesImpl.ExplainableImpl.of(explainable));
});

return new ConceptMapImpl(variableMap, explainables);
res.getMapMap().forEach((resVar, resConcept) -> variableMap.put(resVar, ConceptImpl.of(resConcept)));
return new ConceptMapImpl(Collections.unmodifiableMap(variableMap));
Map<Pair<String, String>, Explainable> explainableOwnerships = new HashMap<>();
explainables.getExplainableOwnershipsList().forEach((explainableOwnership) -> {
explainableOwnerships.put(
new Pair<>(explainableOwnership.getOwner(), explainableOwnership.getAttribute()),
ExplainablesImpl.ExplainableImpl.of(explainableOwnership.getExplainable())
);
});
return new ExplainablesImpl(explainableConcepts, explainableOwnerships);
}

@Override
Expand All @@ -82,7 +91,7 @@ public Concept get(String variable) {
}

@Override
public Set<Explainable> explainables() {
public Explainables explainables() {
return explainables;
}

Expand All @@ -104,37 +113,96 @@ public boolean equals(Object obj) {
@Override
public int hashCode() { return map.hashCode();}

static class ExplainableImpl implements Explainable {
public static class ExplainablesImpl implements Explainables {

Map<String, Explainable> explainableConcepts;

private final String conjunction;
private final long id;
Map<Pair<String, String>, Explainable> explainableOwnerships;

ExplainablesImpl() {
this(new HashMap<>(), new HashMap<>());
}

ExplainableImpl(String conjunction, long id) {
this.conjunction = conjunction;
this.id = id;
ExplainablesImpl(Map<String, Explainable> explainableConcepts, Map<Pair<String, String>, Explainable> explainableOwnerships) {
this.explainableConcepts = explainableConcepts;
this.explainableOwnerships = explainableOwnerships;
}

@Override
public Explainable concept(String variable) {
Explainable explainable = explainableConcepts.get(variable);
if (explainable == null) throw new GraknClientException(NONEXISTENT_EXPLAINABLE_CONCEPT, variable);
return explainable;
}

@Override
public String conjunction() {
return conjunction;
public Explainable ownership(String owner, String attribute) {
Explainable explainable = explainableOwnerships.get(new Pair<>(owner, attribute));
if (explainable == null) throw new GraknClientException(NONEXISTENT_EXPLAINABLE_OWNERSHIP, owner, attribute);
return explainable;
}

@Override
public long id() {
return id;
public Map<String, Explainable> explainableConcepts() {
return this.explainableConcepts;
}

@Override
public boolean equals(final Object o) {
public Map<Pair<String, String>, Explainable> explainableOwnerships() {
return this.explainableOwnerships;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ExplainableImpl that = (ExplainableImpl) o;
return id == that.id;
ExplainablesImpl that = (ExplainablesImpl) o;
return explainableConcepts.equals(that.explainableConcepts) &&
explainableOwnerships.equals(that.explainableOwnerships);
}

@Override
public int hashCode() {
return (int)id;
return Objects.hash(explainableConcepts, explainableOwnerships);
}


static class ExplainableImpl implements Explainable {

private final String conjunction;
private final long id;

ExplainableImpl(String conjunction, long id) {
this.conjunction = conjunction;
this.id = id;
}

public static Explainable of(AnswerProto.Explainable explainable) {
return new ExplainableImpl(explainable.getConjunction(), explainable.getId());
}

@Override
public String conjunction() {
return conjunction;
}

@Override
public long id() {
return id;
}

@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final ExplainableImpl that = (ExplainableImpl) o;
return id == that.id;
}

@Override
public int hashCode() {
return (int) id;
}
}
}
}
2 changes: 1 addition & 1 deletion dependencies/graknlabs/artifacts.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def graknlabs_grakn_core_artifact():
artifact_name = "grakn-core-server-{platform}-{version}.{ext}",
tag_source = deployment["artifact.release"],
commit_source = deployment["artifact.snapshot"],
commit = "87677abacaab0813927115135fba51ede262dd22",
commit = "a36868f1e8a34188eb371dee329ed499399cb40f",
)

def graknlabs_grakn_cluster_artifact():
Expand Down
2 changes: 1 addition & 1 deletion dependencies/graknlabs/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def graknlabs_protocol():
git_repository(
name = "graknlabs_protocol",
remote = "https://github.com/flyingsilverfin/protocol",
commit = "1343b1d48086bfa25b6b8374e1de3e4ac648ebe5", # sync-marker: do not remove this comment, this is used for sync-dependencies by @graknlabs_protocol
commit = "14484ab9471a9d4d5b31466621e4b5f1cb37185b", # sync-marker: do not remove this comment, this is used for sync-dependencies by @graknlabs_protocol
)

def graknlabs_behaviour():
Expand Down
4 changes: 2 additions & 2 deletions query/QueryManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,12 @@ public Stream<ConceptMap> update(GraqlUpdate query, GraknOptions options) {
}

@Override
public Stream<Explanation> explain(ConceptMap.Explainable explainable) {
public Stream<Explanation> explain(ConceptMap.Explainables.Explainable explainable) {
return explain(explainable, GraknOptions.core());
}

@Override
public Stream<Explanation> explain(ConceptMap.Explainable explainable, GraknOptions options) {
public Stream<Explanation> explain(ConceptMap.Explainables.Explainable explainable, GraknOptions options) {
return stream(explainReq(explainable.id(), options.proto()))
.flatMap(rp -> rp.getExplainResPart().getExplanationsList().stream())
.map(ExplanationImpl::of);
Expand Down
16 changes: 8 additions & 8 deletions test/integration/ClientQueryTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,17 @@ public class ClientQueryTest {

@BeforeClass
public static void setUpClass() throws InterruptedException, IOException, TimeoutException {
// grakn = new GraknCoreRunner();
// grakn.start();
graknClient = Grakn.coreClient("localhost:1729"); //grakn.address());
grakn = new GraknCoreRunner();
grakn.start();
graknClient = Grakn.coreClient(grakn.address());
if (graknClient.databases().contains("grakn")) graknClient.databases().get("grakn").delete();
graknClient.databases().create("grakn");
}

@AfterClass
public static void closeSession() {
graknClient.close();
// grakn.stop();
grakn.stop();
}

@Test
Expand Down Expand Up @@ -508,11 +508,11 @@ public void testSimpleExplanation() {
"match (friend: $p1, friend: $p2) isa friendship; $p1 has name $na;"
).asMatch()).collect(toList());

assertEquals(1, answers.get(0).explainables().size());
assertEquals(1, answers.get(1).explainables().size());
List<Explanation> explanations = tx.query().explain(answers.get(0).explainables().iterator().next()).collect(Collectors.toList());
assertEquals(1, answers.get(0).explainables().explainableConcepts().size());
assertEquals(1, answers.get(1).explainables().explainableConcepts().size());
List<Explanation> explanations = tx.query().explain(answers.get(0).explainables().explainableConcepts().values().iterator().next()).collect(Collectors.toList());
assertEquals(3, explanations.size());
List<Explanation> explanations2 = tx.query().explain(answers.get(1).explainables().iterator().next()).collect(Collectors.toList());
List<Explanation> explanations2 = tx.query().explain(answers.get(1).explainables().explainableConcepts().values().iterator().next()).collect(Collectors.toList());
assertEquals(3, explanations2.size());
}, READ, GraknOptions.core().explain(true));
}
Expand Down

0 comments on commit 945a477

Please sign in to comment.