Hi Martynas, Thank you for your input. I don’t know much about SPIN RDF. Just to clarify: my task is not to optimise an original query.
I am working on it using Jena. As soon as I complete the entire algorithm I will publish somewhere and share with all of you (as I am sure it can be optimised). May Thanks, Best Regards, Carlo > On 1 Feb 2016, at 22:55, Martynas Jusevičius <marty...@graphity.org> wrote: > > This thread got me thinking -- couldn't we have reusable, > dereferenceable SPARQL optimizations/rewrites as SPARQL CONSTRUCTs > over SPIN RDF? Which would be mappings between the original syntax > tree and the optimized syntax tree. > > On Mon, Feb 1, 2016 at 8:55 PM, Carlo.Allocca <carlo.allo...@open.ac.uk> > wrote: >> Dear Andy, Lorenz and All, >> >> Thank you very much for your help and support. >> I would like to share the first achievement based on your suggestions. >> >> I have implemented >> >> 1) public Element transform(ElementPathBlock eltPB) >> 2) public Element transform(ElementGroup arg0, List<Element> arg1) >> >> running it over a number of example queries I obtain the expected results. >> For example, for the input query >> >> String qString6 = "prefix >> rdfs:<http://www.w3.org/2000/01/rdf-schema#> " >> + "prefix ex:<http://www.semanticweb.org/dataset1/> " >> + "prefix rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#> " >> + " SELECT DISTINCT ?ind ?boss ?g where " >> + "{ " >> + " {?ind rdf:type ?z. } " >> + "UNION " >> + " {" >> + " { ?boss ex:isBossOf1 ?ind .}" >> + " UNION {?boss ex:isBossOf ?ind ." >> + " Filter(?boss=\"mathieu\") }" >> + "}" >> + "}"; >> >> when removing the triple (?boss ex:isBossOf ?ind .”), I get >> >> SELECT DISTINCT ?ind ?boss ?g >> WHERE >> { { ?ind rdf:type ?z } >> UNION >> { { ?boss ex:isBossOf1 ?ind } >> UNION >> { # Empty BGP >> >> } >> } >> } >> >> which is OK. >> I just need to find out how to remove an ElementGroup which contains only >> one element which is the EMPTY one. >> Of course, I need to do the same for the other case, e.g. OPTION, SUBquery, >> etc. >> >> Many Thanks for your help one again. >> Best Regards, >> Carlo >> >> >> >> == Here the code >> >> >> @Override >> public Element transform(ElementPathBlock eltPB) { >> if (eltPB.isEmpty()) { >> >> System.out.println("[RemoveOpTransform::transform(ElementPathBlock arg0)] >> ElementPathBlock IS EMPTY:: " + eltPB.toString()); >> return eltPB; >> } >> System.out.println("[RemoveOpTransform::transform(ElementPathBlock >> arg0)] ElementPathBlock:: " + eltPB.toString()); >> Iterator<TriplePath> l = eltPB.patternElts(); >> while (l.hasNext()) { >> TriplePath tp = l.next(); >> if (tp.asTriple().matches(this.triple)) { >> l.remove(); >> >> System.out.println("[RemoveOpTransform::transform(ElementPathBlock arg0)] >> ElementPathBlock:: " + tp.toString()+" TRIPLE JUST REMOVED!!!"); >> >> //System.out.println("[RemoveOpTransform::transform(ElementPathBlock arg0)] >> TRIPLE JUST REMOVED!!! "); >> System.out.println(""); >> return this.transform(eltPB);//eltPB; >> } >> } >> return eltPB; >> } >> >> >> @Override >> public Element transform(ElementGroup arg0, List<Element> arg1) { >> //ElementGroup arg0New = new ElementGroup(); >> >> List<Element> elemList = arg0.getElements(); >> Iterator<Element> itr = elemList.iterator(); >> while (itr.hasNext()) { >> Element elem = itr.next(); >> if (elem instanceof ElementGroup) { >> // if(((ElementGroup) elem).isEmpty()){ >> >> System.out.println("[RemoveOpTransform::visit(ElementGroup arg0)] >> ElementGroup IS EMPTY!!! " +((ElementGroup) elem).toString()); >> >> System.out.println("[RemoveOpTransform::visit(ElementGroup arg0)] >> List<Element> arg1 IS EMPTY!!! " +arg1.toString()); >> // } >> } >> >> if (elem instanceof ElementFilter) { >> //... check if this filter is the one that we should remove >> //...get the variables of the triple pattern that we want to >> delete >> Set<Var> tpVars = new HashSet(); >> Node subj = this.triple.getSubject(); >> if (subj.isVariable()) { >> tpVars.add((Var) subj); >> } >> Node pred = this.triple.getPredicate(); >> if (pred.isVariable()) { >> tpVars.add((Var) pred); >> } >> Node obj = this.triple.getObject(); >> if (obj.isVariable()) { >> tpVars.add((Var) obj); >> } >> //...get the variables of the FILTER expression >> Set<Var> expVars = ((ElementFilter) >> elem).getExpr().getVarsMentioned(); >> //...check whether the FILTER expression contains any of the >> triple pattern variable >> for (Var var : expVars) { >> //..if it does then we have to delete the entire FILTER >> expression >> if (tpVars.contains(var)) { >> >> System.out.println("[RemoveOpTransform::visit(ElementGroup arg0)] THE >> "+((ElementFilter) elem).toString() +"IS GOING TO BE REMOVED!!!"); >> //Expr e = new NodeValueBoolean(true); >> //ElementFilter newFilter = new ElementFilter(e); >> itr.remove(); >> return this.transform(arg0, arg1); >> } >> } >> >> } >> } >> // System.out.println("[RemoveOpTransform::transform(ElementGroup >> arg0)] arg1 " + arg1.toString()); >> // System.out.println(""); >> //return arg0New; >> return arg0; >> } >> >> >> >> >>> On 31 Jan 2016, at 15:40, Carlo.Allocca <carlo.allo...@open.ac.uk> wrote: >>> >>> Dear Andy, >>> >>> >>>> On 31 Jan 2016, at 15:25, Andy Seaborne <a...@apache.org> wrote: >>>> >>>> Cleaning up is slightly easier in the syntax because BGPs and filters are >>>> inside a group (nothing to do with GROUP - a syntax group is things >>>> between {}. >>>> >>>> So when you want to delete something, have some custom Element class >>>> 'ElementDeleteMe' to return from the ElementFilter or ElementPathBlock. >>>> Something that can not appear in a legal query. it does not need to >>>> implement anything. >>>> >>>> Then in >>>> transform(ElementGroup el, List<Element> members) ; >>>> >>>> rewrite 'members' to remove any ElementDeleteMe. >>>> >>>> if members.size == 0 >>>> return ElementDeleteMe >>>> >>>> so it recursive works. >>>> >>>> Take care at the top of syntax tree. >>>> >>> Thank you for the details. >>> It seems that I should be using org.apache.jena.sparql.syntax rather than >>> org.apache.jena.sparql.algebra. >>> I will try to implement it as suggested above. >>> >>> Many Thanks, >>> Best Regards, >>> Carlo >>> >>> >>>> Andy >>>> >>>> On 31/01/16 15:11, Carlo.Allocca wrote: >>>>> Hello Lorenz, >>>>> >>>>> >>>>> Sure no problem. >>>>> I can share it here. In case you have suggest any other place I will do >>>>> so. >>>>> >>>>> Please, let me know. >>>>> Many Thanks, >>>>> >>>>> Best Regards, >>>>> Carlo >>>>> >>>>>> On 31 Jan 2016, at 15:07, Lorenz Bühmann >>>>>> <buehm...@informatik.uni-leipzig.de> wrote: >>>>>> >>>>>> Hello Carlo, >>>>>> >>>>>> I'm sure you'll make it, but maybe you should also share the complete >>>>>> code somehow? Maybe this makes it easier for people to help you. >>>>>> >>>>>> Lorenz >>>>>> >>>>>>> Hello Lorenz, >>>>>>> >>>>>>> Thank you very much for your help. >>>>>>> Some comments follow in line. >>>>>>> >>>>>>> >>>>>>>> On 31 Jan 2016, at 13:36, Lorenz Bühmann >>>>>>>> <buehm...@informatik.uni-leipzig.de> wrote: >>>>>>>> >>>>>>>> Hello Carlo, >>>>>>>> >>>>>>>> there is usually no link from a child node to its parent in the JENA >>>>>>>> data structures. >>>>>>> It is very good to confirm it as I don’t spend more time to look for >>>>>>> it. I thought that I was missing some JENA data structure and packages. >>>>>>> >>>>>>>> That means you have to keep track of it when you're processing the >>>>>>>> parents. Why not run some "clean up" after each child has been >>>>>>>> processed? E.g. check if there is no BGP left and thus mark this >>>>>>>> current parent as also "toBeRemoved”. >>>>>>> Sure. I have already started doing it by using some boolean variables. >>>>>>> Let’s see if I can make it. >>>>>>> Otherwise I have to develop a module that transform the Jena Query >>>>>>> Expression into a Tree based representation and then apply the triple >>>>>>> remove operation. >>>>>>> >>>>>>> Thank you again for your support and answers. >>>>>>> >>>>>>> Best Regards, >>>>>>> Carlo >>>>>>> >>>>>>>> Lorenz >>>>>>>> >>>>>>>>> and of course, the below is for processing an BGP: >>>>>>>>> >>>>>>>>> @Override >>>>>>>>> public Op transform(OpBGP opBGP) { >>>>>>>>> >>>>>>>>> System.out.println("[TransformRemoveOp::transform(OpBGP opBGP)] >>>>>>>>> opBGPCounter " + opBGPCounter++); >>>>>>>>> System.out.println("[TransformRemoveOp::transform(OpBGP opBGP)] >>>>>>>>> " + opBGP.toString()); >>>>>>>>> System.out.println(""); >>>>>>>>> Op newOpBGP = opBGP.copy(); >>>>>>>>> BasicPattern newBP = ((OpBGP) newOpBGP).getPattern(); >>>>>>>>> List<Triple> tripleList = newBP.getList(); >>>>>>>>> >>>>>>>>> Iterator<Triple> itr = tripleList.iterator(); >>>>>>>>> while (itr.hasNext()) { >>>>>>>>> Triple tp = itr.next(); >>>>>>>>> if (tp.matches(this.triple)) { >>>>>>>>> itr.remove(); >>>>>>>>> isParent = true; >>>>>>>>> isStarted = true; >>>>>>>>> } >>>>>>>>> } >>>>>>>>> //...it can be empty >>>>>>>>> if (((OpBGP) newOpBGP).getPattern().getList().isEmpty()) { >>>>>>>>> System.out.println("[TransformRemoveOp::transform(OpBGP >>>>>>>>> opBGP)] opBGP is empty " + opBGP.toString()); >>>>>>>>> //return subOp; >>>>>>>>> } >>>>>>>>> return newOpBGP; >>>>>>>>> } >>>>>>>>> >>>>>>>>> >>>>>>>>> Many Thanks, >>>>>>>>> Carlo. >>>>>>>>> >>>>>>>>> >>>>>>>>>> On 31 Jan 2016, at 04:36, Carlo.Allocca <carlo.allo...@open.ac.uk> >>>>>>>>>> wrote: >>>>>>>>>> >>>>>>>>>> Dear Andy, >>>>>>>>>> >>>>>>>>>> Thank you very much one more time. >>>>>>>>>> >>>>>>>>>> Please, some comments follow in line. >>>>>>>>>> >>>>>>>>>> On 30 Jan 2016, at 17:53, Andy Seaborne >>>>>>>>>> <a...@apache.org<mailto:a...@apache.org>> wrote: >>>>>>>>>> >>>>>>>>>> On 30/01/16 15:52, Carlo.Allocca wrote: >>>>>>>>>> Hello Lorenz, >>>>>>>>>> >>>>>>>>>> Thank you for your help. >>>>>>>>>> >>>>>>>>>> It was clear to me that I have to remove from the parent expression >>>>>>>>>> and such is that using a patter-based approach >>>>>>>>>> make it a bit difficult. I tried three of them and I got to the same >>>>>>>>>> results. >>>>>>>>>> >>>>>>>>>> You need to process the parent, not just the ElementFilter. >>>>>>>>>> >>>>>>>>>> How can I process the parent? >>>>>>>>>> My understanding is: >>>>>>>>>> >>>>>>>>>> 1. Building the Abstract Query Tree: Op op = Algebra.compile(q); >>>>>>>>>> >>>>>>>>>> For example, given the query >>>>>>>>>> >>>>>>>>>> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> >>>>>>>>>> PREFIX ex: <http://www.semanticweb.org/dataset1/> >>>>>>>>>> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> >>>>>>>>>> >>>>>>>>>> SELECT DISTINCT ?ind ?boss ?g >>>>>>>>>> WHERE >>>>>>>>>> { { ?ind rdf:type ?z } >>>>>>>>>> UNION >>>>>>>>>> { ?boss ex:isBossOf ?ind >>>>>>>>>> FILTER ( ?boss = "mathieu" ) >>>>>>>>>> } >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> I obtain >>>>>>>>>> >>>>>>>>>> (distinct >>>>>>>>>> (project (?ind ?boss ?g) >>>>>>>>>> (union >>>>>>>>>> (bgp (triple ?ind >>>>>>>>>> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?z)) >>>>>>>>>> (filter (= ?boss "mathieu") >>>>>>>>>> (bgp (triple ?boss >>>>>>>>>> <http://www.semanticweb.org/dataset1/isBossOf> ?ind)))))) >>>>>>>>>> >>>>>>>>>> 2) Travere the tree to modify its internal structure. In terms of >>>>>>>>>> code, I can write: >>>>>>>>>> >>>>>>>>>> (A) Transform transform = new TransformRemoveOp(q,tp) ; >>>>>>>>>> (B) op = Transformer.transform(transform, op); >>>>>>>>>> >>>>>>>>>> where TransformRemoveOp implements Transform interface. >>>>>>>>>> It seems that there is no link between children and parent that can >>>>>>>>>> be used to figure out at which level the process is and modify the >>>>>>>>>> Tree structure, accordingly. Please correct me if I am wrong. >>>>>>>>>> In fact running it over the above example, I got the following: >>>>>>>>>> >>>>>>>>>> =========== DURING >>>>>>>>>> [TransformRemoveOp::transform(OpBGP opBGP)] opBGPCounter 1 >>>>>>>>>> [TransformRemoveOp::transform(OpBGP opBGP)] (bgp (triple ?ind >>>>>>>>>> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?z)) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpBGP opBGP)] opBGPCounter 2 >>>>>>>>>> [TransformRemoveOp::transform(OpBGP opBGP)] (bgp (triple ?boss >>>>>>>>>> <http://www.semanticweb.org/dataset1/isBossOf> ?ind)) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpBGP opBGP)] opBGP is empty (bgp >>>>>>>>>> ) >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpFilter opFilter, Op subOp)] opFilter >>>>>>>>>> (filter (= ?boss "mathieu") >>>>>>>>>> (bgp >>>>>>>>>> )) >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpFilter opFilter, Op subOp)] subOp >>>>>>>>>> Name bgp >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpUnion opUnion, Op left, Op right)] >>>>>>>>>> left: (bgp (triple ?ind >>>>>>>>>> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?z)) >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpUnion opUnion, Op left, Op right)] >>>>>>>>>> right: (filter (exprlist (= ?boss "mathieu") true) >>>>>>>>>> (bgp >>>>>>>>>> )) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpProject opProject, Op subOp)] >>>>>>>>>> (project (?ind ?boss ?g) >>>>>>>>>> (union >>>>>>>>>> (bgp (triple ?ind <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> >>>>>>>>>> ?z)) >>>>>>>>>> (filter (exprlist (= ?boss "mathieu") true) >>>>>>>>>> (bgp >>>>>>>>>> )))) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> [TransformRemoveOp::transform(OpDistinct opDistinct, Op subOp)] >>>>>>>>>> (distinct >>>>>>>>>> (project (?ind ?boss ?g) >>>>>>>>>> (union >>>>>>>>>> (bgp (triple ?ind >>>>>>>>>> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ?z)) >>>>>>>>>> (filter (exprlist (= ?boss "mathieu") true) >>>>>>>>>> (bgp >>>>>>>>>> ))))) >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Moreover, implementing a first version of the OpFilter as reported >>>>>>>>>> below: >>>>>>>>>> >>>>>>>>>> @Override >>>>>>>>>> public Op transform(OpFilter opFilter, Op subOp) { >>>>>>>>>> System.out.println("[TransformRemoveOp::transform(OpFilter >>>>>>>>>> opFilter, Op subOp)] opFilter " + opFilter.toString()); >>>>>>>>>> System.out.println("[TransformRemoveOp::transform(OpFilter >>>>>>>>>> opFilter, Op subOp)] subOp Name " + subOp.getName()); >>>>>>>>>> System.out.println(""); >>>>>>>>>> >>>>>>>>>> if (isParent == false) { >>>>>>>>>> return opFilter; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> //...get the variables of the triple pattern that we want to >>>>>>>>>> delete >>>>>>>>>> Set<Var> tpVars = new HashSet(); >>>>>>>>>> Node subj = this.triple.getSubject(); >>>>>>>>>> if (subj.isVariable()) { >>>>>>>>>> tpVars.add((Var) subj); >>>>>>>>>> } >>>>>>>>>> Node pred = this.triple.getPredicate(); >>>>>>>>>> if (pred.isVariable()) { >>>>>>>>>> tpVars.add((Var) pred); >>>>>>>>>> } >>>>>>>>>> Node obj = this.triple.getObject(); >>>>>>>>>> if (obj.isVariable()) { >>>>>>>>>> tpVars.add((Var) obj); >>>>>>>>>> } >>>>>>>>>> //...get the variables of the FILTER expression >>>>>>>>>> Op opNew = opFilter.copy(subOp); >>>>>>>>>> Set<Var> expVars = ((OpFilter) >>>>>>>>>> opNew).getExprs().getVarsMentioned(); >>>>>>>>>> >>>>>>>>>> //...check whether the FILTER expression contains any of the >>>>>>>>>> triple pattern variable >>>>>>>>>> boolean isContained = false; >>>>>>>>>> for (Var var : expVars) { >>>>>>>>>> //..if it does then we have to delete the entire FILTER >>>>>>>>>> expression >>>>>>>>>> if (tpVars.contains(var)) { >>>>>>>>>> isContained = true; >>>>>>>>>> break; >>>>>>>>>> } >>>>>>>>>> } >>>>>>>>>> //... if the filter contains any variable of the triple that >>>>>>>>>> has been removed, then.... >>>>>>>>>> if (isContained) { >>>>>>>>>> Op newOP; >>>>>>>>>> Expr e; >>>>>>>>>> if (subOp instanceof OpBGP) { >>>>>>>>>> if (((OpBGP) subOp).getPattern().getList().isEmpty()) { >>>>>>>>>> e = new NodeValueBoolean(true); >>>>>>>>>> newOP = OpFilter.filter(e, opFilter);//filter(e, ); >>>>>>>>>> return newOP; >>>>>>>>>> } else { >>>>>>>>>> e = new NodeValueBoolean(false); >>>>>>>>>> newOP = OpFilter.filter(e, opFilter);//filter(e, ); >>>>>>>>>> return newOP; >>>>>>>>>> } >>>>>>>>>> } >>>>>>>>>> } >>>>>>>>>> return opFilter; >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> It produces the following SPARQL query: >>>>>>>>>> >>>>>>>>>> SELECT DISTINCT ?ind ?boss ?g >>>>>>>>>> WHERE >>>>>>>>>> { { ?ind a ?z } >>>>>>>>>> UNION >>>>>>>>>> { # Empty BGP >>>>>>>>>> >>>>>>>>>> FILTER ( ?boss = "mathieu" ) >>>>>>>>>> FILTER ( true ) >>>>>>>>>> } >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> It seems quite challenging even transform the expression of "?boss >>>>>>>>>> = “mathieu” into “true” (as reported above) does not work as It >>>>>>>>>> should. >>>>>>>>>> >>>>>>>>>> If anyone could help me who is more experienced with this kind of >>>>>>>>>> task, I would be very very grateful. >>>>>>>>>> I would like to see something concrete in sense of line of code as I >>>>>>>>>> am using. >>>>>>>>>> >>>>>>>>>> Many Thanks, >>>>>>>>>> Best Regards, >>>>>>>>>> Carlo >>>>>>>>>> On 30 Jan 2016, at 17:53, Andy Seaborne >>>>>>>>>> <a...@apache.org<mailto:a...@apache.org>> wrote: >>>>>>>>>> >>>>>>>>>> element has active parts >>>>>>>>>> >>>>>>>>>> -- The Open University is incorporated by Royal Charter (RC 000391), >>>>>>>>>> an exempt charity in England & Wales and a charity registered in >>>>>>>>>> Scotland (SC 038302). The Open University is authorised and >>>>>>>>>> regulated by the Financial Conduct Authority. >>>>>>>>> >>>>>>>> -- >>>>>>>> Lorenz Bühmann >>>>>>>> AKSW group, University of Leipzig >>>>>>>> Group: http://aksw.org - semantic web research center >>>>>>>> >>>>>>> >>>>>>> >>>>>> -- >>>>>> Lorenz Bühmann >>>>>> AKSW group, University of Leipzig >>>>>> Group: http://aksw.org - semantic web research center >>>>>> >>>>> >>>> >>> >>