com.bigdata.rdf.sail.BigdataValueReplacer Maven / Gradle / Ivy
/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
[email protected]
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
* Created on Mar 29, 2011
*/
package com.bigdata.rdf.sail;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.query.Binding;
import org.openrdf.query.BindingSet;
import org.openrdf.query.Dataset;
import org.openrdf.query.impl.BindingImpl;
import org.openrdf.query.impl.DatasetImpl;
import org.openrdf.query.impl.MapBindingSet;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.internal.VTE;
import com.bigdata.rdf.internal.impl.TermId;
import com.bigdata.rdf.model.BigdataValue;
import com.bigdata.rdf.model.BigdataValueFactory;
import com.bigdata.rdf.store.AbstractTripleStore;
import com.bigdata.rdf.store.BigdataOpenRDFBindingSetsResolverator;
/**
* Utility class to manage the efficient translation of openrdf {@link Value}s
* in a {@link BindingSet} into the {@link BigdataValue}s used internally by
* bigdata.
*
* @see BigdataOpenRDFBindingSetsResolverator
*
* @author Bryan Thompson
* @version $Id: BigdataValueReplacer.java 5159 2011-09-08 15:35:15Z thompsonbry
* $
*/
public class BigdataValueReplacer {
private final static Logger log = Logger
.getLogger(BigdataValueReplacer.class);
private final AbstractTripleStore database;
public BigdataValueReplacer(final AbstractTripleStore database) {
if(database == null)
throw new IllegalArgumentException();
this.database = database;
}
/**
* Batch resolve and replace all {@link Value} objects stored in variables
* or in the {@link Dataset} with {@link BigdataValue} objects, which have
* access to the 64-bit internal term identifier associated with each value
* in the database.
*
* Note: The native rule execution must examine the resulting
* {@link BigdataValue}s. If any value does not exist in the lexicon then
* its term identifier will be ZERO (0L). Term identifiers of ZERO (0L) WILL
* NOT match anything in the data and MUST NOT be executed since a ZERO (0L)
* will be interpreted as a variable!
*
* @return yucky hack, need to return a new dataset and a new binding set.
* dataset is [0], binding set is [1]
*/
public Object[] replaceValues(//
final Dataset dataset,//
final BindingSet[] bindingSets//
) {
if(dataset == null && bindingSets == null) {
// At least one argument must be non-null.
throw new IllegalArgumentException();
}
/*
* Resolve the values used by this query.
*
* Note: If any value can not be resolved, then its term identifier
* will remain ZERO (0L) (aka NULL). Except within OPTIONALs, this
* indicates that the query CAN NOT be satisfied by the data since
* one or more required terms are unknown to the database.
*/
final Map values = new LinkedHashMap();
final BigdataValueFactory valueFactory = database.getValueFactory();
if (dataset != null) {
for(URI uri : dataset.getDefaultGraphs())
if (uri != null)
values.put(uri, valueFactory.asValue(uri));
for(URI uri : dataset.getNamedGraphs())
if (uri != null)
values.put(uri, valueFactory.asValue(uri));
}
if (bindingSets != null && bindingSets.length > 0) {
for(BindingSet bindings : bindingSets) {
final Iterator it = bindings.iterator();
while (it.hasNext()) {
final Binding binding = it.next();
final Value val = binding.getValue();
// add BigdataValue variant of the var's Value.
values.put(val, valueFactory.asValue(val));
}
}
}
/*
* Batch resolve term identifiers for those BigdataValues.
*
* Note: If any value does not exist in the lexicon then its term
* identifier will be ZERO (0L).
*/
{
final BigdataValue[] terms = values.values().toArray(
new BigdataValue[] {});
database.getLexiconRelation()
.addTerms(terms, terms.length, true/* readOnly */);
// cache the BigdataValues on the IVs for later
for (BigdataValue term : terms) {
@SuppressWarnings("rawtypes")
final IV iv = term.getIV();
if (iv == null) {
/*
* Since the term identifier is NULL this value is not known
* to the kb.
*/
if (log.isInfoEnabled())
log.info("Not in knowledge base: " + term);
/*
* Create a dummy iv and cache the unknown value on it so
* that it can be used during query evalution.
*/
@SuppressWarnings("rawtypes")
final IV dummy = TermId.mockIV(VTE.valueOf(term));
term.setIV(dummy);
dummy.setValue(term);
} else {
iv.setValue(term);
}
}
}
final BindingSet[] bindingSets2;
if (bindingSets == null) {
bindingSets2 = null;
} else {
// Allocate the output solutions array.
bindingSets2 = new BindingSet[bindingSets.length];
// Generate each output solution from each source solution.
for (int i = 0; i < bindingSets.length; i++) {
/*
* Replace the bindings with one's which have their IV set.
*/
final MapBindingSet bindings2 = new MapBindingSet();
bindingSets2[i] = bindings2; // save off result.
final Iterator it = bindingSets[i].iterator();
while (it.hasNext()) {
final BindingImpl binding = (BindingImpl) it.next();
/*
* Note: We can not do this. The Sesame APIs let bindings
* flow through the query even if they are not projected by
* the query.
*/
// if (!vars.containsKey(binding.getName())) {
//
// // Drop bindings which are not used within the query.
//
// if (log.isInfoEnabled())
// log.info("Dropping unused binding: var=" + binding);
//
// continue;
//
// }
final Value val = binding.getValue();
// Lookup the resolved BigdataValue object.
final BigdataValue val2 = values.get(val);
assert val2 != null : "value not found: "
+ binding.getValue();
if (log.isDebugEnabled())
log.debug("value: " + val + " : " + val2 + " ("
+ val2.getIV() + ")");
// if (val2.getIV() == null) {
//
// /*
// * Since the term identifier is NULL this value is not known
// * to the kb.
// */
//
// if (log.isInfoEnabled())
// log.info("Not in knowledge base: " + val2);
//
// }
/*
* This is no good. We need to create a mock IV and also cache
* the unknown value on it so that it can be used in filter
* evaluation. I took care of this above.
*/
// if(val2.getIV() == null) {
// /*
// * The Value is not in the database, so assign it a mock IV.
// * This IV will not match anything during query. However, we
// * can not simply fail the query since an OPTIONAL or UNION
// * might have solutions even though this Value is not known.
// */
// val2.setIV(TermId.mockIV(VTE.valueOf(val)));
// }
// rewrite the constant in the query.
bindings2.addBinding(binding.getName(), val2);
}
}
}
/*
* Create a new Dataset using the resolved Values.
*/
final DatasetImpl dataset2;
if (dataset == null) {
dataset2 = null;
} else {
dataset2 = new DatasetImpl();
for (URI uri : dataset.getDefaultGraphs())
dataset2.addDefaultGraph((URI) values.get(uri));
for (URI uri : dataset.getNamedGraphs())
dataset2.addNamedGraph((URI) values.get(uri));
}
return new Object[] { dataset2, bindingSets2 };
}
}