/* * (c) Copyright 2010 Epimorphics Ltd. * All rights reserved. * [See end of file] */ package dev.joinengine; import static java.lang.String.format ; import java.util.ArrayList ; import java.util.Arrays ; import java.util.Iterator ; import java.util.List ; import org.openjena.atlas.iterator.Iter ; import org.openjena.atlas.iterator.NullIterator ; import org.openjena.atlas.iterator.Transform ; import org.openjena.atlas.lib.ColumnMap ; import org.openjena.atlas.lib.Tuple ; import tdb_mem.TupleIndexMem ; import com.hp.hpl.jena.graph.Node ; import com.hp.hpl.jena.graph.Triple ; import com.hp.hpl.jena.query.ARQ ; import com.hp.hpl.jena.sparql.core.BasicPattern ; import com.hp.hpl.jena.sparql.core.Var ; import com.hp.hpl.jena.sparql.engine.ExecutionContext ; import com.hp.hpl.jena.sparql.engine.QueryIterator ; import com.hp.hpl.jena.sparql.engine.binding.Binding ; import com.hp.hpl.jena.sparql.engine.binding.BindingMap ; import com.hp.hpl.jena.sparql.engine.binding.BindingRoot ; import com.hp.hpl.jena.sparql.engine.iterator.QueryIterRoot ; import com.hp.hpl.jena.sparql.engine.main.QC ; import com.hp.hpl.jena.sparql.sse.SSE ; import com.hp.hpl.jena.tdb.TDB ; import com.hp.hpl.jena.tdb.TDBException ; import com.hp.hpl.jena.tdb.TDBFactory ; import com.hp.hpl.jena.tdb.index.TupleIndex ; import com.hp.hpl.jena.tdb.index.TupleTable ; import com.hp.hpl.jena.tdb.nodetable.NodeTable ; import com.hp.hpl.jena.tdb.solver.BindingNodeId ; import com.hp.hpl.jena.tdb.solver.BindingTDB ; import com.hp.hpl.jena.tdb.store.DatasetGraphTDB ; import com.hp.hpl.jena.tdb.store.NodeId ; public class BlockSolver { public static void main(String...rgv) { solver() ; } public static void solver() { // ---- Setup foo DatasetGraphTDB dsg = TDBFactory.createDatasetGraph() ; NodeTable nodeTable = dsg.getTripleTable().getNodeTupleTable().getNodeTable() ; TupleTable tupleTable = dsg.getTripleTable().getNodeTupleTable().getTupleTable() ; // Carefully mess round. 2 index: PSO, POS TupleIndex[] indexes = tupleTable.getIndexes() ; indexes[0] = new TupleIndexMem(3, new ColumnMap("SPO", "PSO")) ; indexes[1] = new TupleIndexMem(3, new ColumnMap("SPO", "POS")) ; indexes[2] = null ; load(dsg) ; ExecutionContext execCxt = new ExecutionContext(TDB.getContext(), dsg.getDefaultGraph(), dsg, QC.getFactory(ARQ.getContext())) ; QueryIterator input = QueryIterRoot.create(execCxt) ; Iterator chain = Iter.map(input, convFromBinding(nodeTable)) ; BasicPattern bgp = SSE.parseBGP("(bgp (?s :p ?o) (?s :q ?v) (?s :q 123) (:s :q ?v))") ; List> bgpTuples = new ArrayList>() ; List> bgpTuplesId = new ArrayList>() ; for ( Triple triple : bgp.getList() ) { Tuple tuple = Tuple.create(triple.getSubject(), triple.getPredicate(), triple.getObject()) ; bgpTuples.add(tuple) ; System.out.println(tuple) ; // Vars and ids. NodeId ids[] = new NodeId[tuple.size()] ; Var[] vars = new Var[tuple.size()] ; BindingNodeId binding = new BindingNodeId(BindingRoot.create()) ; prepare(nodeTable, tuple, binding, ids, vars) ; System.out.print(" ") ; System.out.println(Arrays.asList(ids)) ; System.out.print(" ") ; System.out.println(Arrays.asList(vars)) ; Tuple t = Tuple.create(ids) ; bgpTuplesId.add(t) ; System.out.println() ; } for ( Tuple t : bgpTuplesId ) { TupleIndex tupleIndex = findIndex(tupleTable, t) ; System.out.println(tupleIndex) ; } System.out.println(dsg) ; } private static void load(DatasetGraphTDB dsg) { String[] triples = { "(:s :p 123)", "(:s :p 456)", "(:s :q 'abc')" } ; for ( String x : triples ) { Triple t = SSE.parseTriple(x) ; dsg.getDefaultGraph().add(t) ; } } // ----- Merge back into TupleTable // Change to retuning all possibilities. // Fast track POS, PSO public static TupleIndex findIndex(TupleTable tupleTable, Tuple pattern) { int tupleLen = tupleTable.getTupleLen() ; TupleIndex[] indexes = tupleTable.getIndexes() ; if ( tupleLen != pattern.size() ) throw new TDBException(format("Mismatch: finding tuple of length %d in a table of tuples of length %d", pattern.size(), tupleLen)) ; int numSlots = 0 ; // Canonical form. for ( int i = 0 ; i < tupleLen ; i++ ) { NodeId x = pattern.get(i) ; if ( ! NodeId.isAny(x) ) numSlots++ ; } if ( numSlots == 0 ) return indexes[0] ; int indexNumSlots = 0 ; TupleIndex index = null ; for ( int i = 0 ; i < indexes.length ; i++ ) { TupleIndex idx = indexes[i] ; if ( idx != null ) { int w = idx.weight(pattern) ; if ( w > indexNumSlots ) { indexNumSlots = w ; index = idx ; } } } if ( index == null ) // No index at all. Scan. index = indexes[0] ; return index ; } // ----- SolverLib/StageMatchTuple machinary. public static Binding convToBinding(NodeTable nodeTable, BindingNodeId bindingNodeIds) { if ( true ) return new BindingTDB(bindingNodeIds, nodeTable) ; else { // Makes nodes immediately. Causing unecessary NodeTable accesses (e.g. project) Binding b = new BindingMap() ; for ( Var v : bindingNodeIds ) { //@Override NodeId id = bindingNodeIds.get(v) ; Node n = nodeTable.getNodeForNodeId(id) ; b.add(v, n) ; } return b ; } } // Transform : Binding ==> BindingNodeId private static Transform convFromBinding(final NodeTable nodeTable) { return new Transform() { @Override public BindingNodeId convert(Binding binding) { if ( binding instanceof BindingTDB ) return ((BindingTDB)binding).getBindingId() ; BindingNodeId b = new BindingNodeId(binding) ; // and copy over, getting NodeIds. Iterator vars = binding.vars() ; for ( ; vars.hasNext() ; ) { Var v = vars.next() ; Node n = binding.get(v) ; if ( n == null ) // Variable mentioned in the binding but not actually defined. // Can occur with BindingProject continue ; // Rely on the node table cache for efficency - we will likely be // repeatedly looking up the same node in different bindings. NodeId id = nodeTable.getNodeIdForNode(n) ; // Even put in "does not exist" for a node now known not to be in the DB. // Removed at TDB 0.8.7: if ( ! NodeId.doesNotExist(id) ) b.put(v, id) ; } return b ; } } ; } public static void prepare(NodeTable nodeTable, Tuple patternTuple, BindingNodeId input, NodeId ids[], Var[] var) { // Process the Node to NodeId conversion ourselves because // we wish to abort if an unknown node is seen. for ( int i = 0 ; i < patternTuple.size() ; i++ ) { Node n = patternTuple.get(i) ; // Substitution and turning into NodeIds // Variables unsubstituted are null NodeIds NodeId nId = idFor(nodeTable, input, n) ; if ( NodeId.doesNotExist(nId) ) new NullIterator() ; ids[i] = nId ; if ( nId == null ) var[i] = asVar(n) ; } } private static Var asVar(Node node) { if ( Var.isVar(node) ) return Var.alloc(node) ; return null ; } /** Return null for variables, and for nodes, the node id or NodeDoesNotExist */ private static NodeId idFor(NodeTable nodeTable, BindingNodeId input, Node node) { if ( Var.isVar(node) ) { NodeId n = input.get((Var.alloc(node))) ; // Bound to NodeId or null. return n ; } // May return NodeId.NodeDoesNotExist which must not be null. return nodeTable.getNodeIdForNode(node) ; } } /* * (c) Copyright 2010 Epimorphics Ltd. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */