-
Notifications
You must be signed in to change notification settings - Fork 12
Upward extension R2R example
In this example, we will show how to extend the R2R operators to include a simple reasoning step, i.e. an upward extension. We will focus on materializing types assertions based on a simple concept hierarchy, as depicted below:
O3
/ \
O2 O5
/ \ |
O1 O4 O6
This means when we receive the triple <s1> a <O1>
both <s1> a <O2>
and <s1> a <O3>
need to be inferred.
For easy computation, we will store the parents of each concept in a map:
O1: [O2,O3]
O2: [O3]
O3: []
O4: [O2,O3]
O5: [O3]
O6: [O5,O3]
This allows us to efficiently fetch and infer the parent types.
First of all, we need to implement the RelationToRelationOperator
interface, that can access the SDS and the query, as shown below:
public class R2RUpwardExtension implements RelationToRelationOperator<Triple> {
private final SDS sds;
private final ContinuousQuery query;
private final Dataset ds;
private Map<String, Set<String>> extensions;
public R2RUpwardExtension(SDS sds, ContinuousQuery query) {
this.sds = sds;
this.query = query;
this.ds = (Dataset) sds;
this.extensions = new HashMap<String,Set<String>>();
}
@Override
public Stream<SolutionMapping<Triple>> eval(long ts) {
//TODO
}
Before jumping to the implementation of the eval
method where the reasoning takes place, we first need to compute the map that stores the parents of each concept. Lets image that we receive a concept hierarchy as map containing the children for each parent concept, for example:
Map<String,List<String>> schema = new HashMap<>();
schema.put("O2",Arrays.asList("O1","O4"));
schema.put("O3",Arrays.asList("O2","O5"));
schema.put("O5",Arrays.asList("O6"));
This will give us the concept hierarchy depicted above.
To concept map, we first look for the concepts that have no parents, and recursively follow its children to build the structure we introduced before:
public void addSchema(Map<String,List<String>> schema){
// 1 To extract the top parents, we extract all concepts and remove those that have parents:
// 1.1 get all childeren
Set<String> childeren = new HashSet<String>();
for(List<String> childs : schema.values()){
childeren.addAll(childs);
}
// 1.2. get all the types
Set<String> all = new HashSet<String>(childeren);
all.addAll(schema.keySet());
Set<String> tops = new HashSet(all);
// 1.2 remove the childeren from all the types and the parents remain
tops.removeAll(childeren);
// 2 recursively follow the hierarchy from the top parents and build the inference structure
for(String top : tops){
if (!this.extensions.containsKey(top)) {
this.extensions.put(top, new HashSet<>());
}
findSubclasses(top,schema);
}
}
// recursion helper function
private void findSubclasses(String parent,Map<String,List<String>> schema){
if(schema.containsKey(parent) ){
for (String child : schema.get(parent)) {
if (!this.extensions.containsKey(child)) {
this.extensions.put(child, new HashSet<>());
}
// add all the parent concepts of the current parent to the extensions
this.extensions.get(child).addAll(this.extensions.get(parent));
this.extensions.get(child).add(parent);
// recursive step
findSubclasses(child, schema);
}
}
}
This gives us the easy lookup structure introduced before. Now it's time to implement the eval
method. First, we need to extract the data that is relevant at the current time and therefore we consult the SDS. Then we can iterate over all triples and select those that are type assertions (i.e. in the form of <s> a <C>
). For each type assertion, we look up the parents of the asserted type and add the parents as type assertions as well.
@Override
public Stream<SolutionMapping<Triple>> eval(long ts) {
RDF instance = RDFUtils.getInstance();
Set<SolutionMapping<Triple>> sol = new HashSet<SolutionMapping<Triple>>();
// iterate over the triples in the SDS
for(Quad q : ds.iterate()){
Triple t = q.asTriple();
// check if triple is a type assertion
if(t.getPredicate().equals(instance.createIRI("a"))){
//reasoning step
String type = t.getObject().toString();
type = type.substring(1,type.length()-1);
if(this.extensions.containsKey(type)){
// extract the parent concepts
for(String parents:this.extensions.get(type)){
// create a new triple (the materialization)
Triple reasoningResult = instance.createTriple(t.getSubject(),instance.createIRI("a"),instance.createIRI(parents));
// add the materialization to the solution set
sol.add(new SelectInstResponse(query.getID() + "/ans/" + ts, ts, reasoningResult));
}
}
}
//add the triple
sol.add(new SelectInstResponse(query.getID() + "/ans/" + ts, ts, t));
}
return sol.stream();
}
We have implemented an R2R operator that performs a simple reasoning task. You can try out the materialization in the CSPARQL or CQELS example by replacing the `R2RImpl' with the newly created one.