![JAR search and dependency download from the Maven repository](/logo.png)
com.bigdata.rdf.internal.encoder.IVBindingSetEncoder 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 Feb 15, 2012
*/
package com.bigdata.rdf.internal.encoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import com.bigdata.bop.Constant;
import com.bigdata.bop.IBindingSet;
import com.bigdata.bop.IConstant;
import com.bigdata.bop.IVariable;
import com.bigdata.bop.bindingSet.ListBindingSet;
import com.bigdata.btree.keys.ASCIIKeyBuilderFactory;
import com.bigdata.btree.keys.IKeyBuilder;
import com.bigdata.htree.HTree;
import com.bigdata.rdf.internal.IV;
import com.bigdata.rdf.internal.IVCache;
import com.bigdata.rdf.internal.IVUtility;
import com.bigdata.rdf.internal.VTE;
import com.bigdata.rdf.internal.impl.BlobIV;
import com.bigdata.rdf.internal.impl.TermId;
import com.bigdata.rdf.internal.impl.bnode.FullyInlineUnicodeBNodeIV;
import com.bigdata.rdf.internal.impl.literal.FullyInlineTypedLiteralIV;
import com.bigdata.rdf.internal.impl.literal.MockedValueIV;
import com.bigdata.rdf.internal.impl.uri.FullyInlineURIIV;
import com.bigdata.rdf.model.BigdataBNodeImpl;
import com.bigdata.rdf.model.BigdataLiteralImpl;
import com.bigdata.rdf.model.BigdataURIImpl;
import com.bigdata.rdf.model.BigdataValue;
import com.bigdata.rdf.model.BigdataValueFactory;
/**
* A utility class for generating and processing compact representations of
* {@link IBindingSet}s whose {@link IConstant}s are bound to {@link IV}s.
* Individual {@link IV}s may be associated with a cached RDF {@link Value}.
*
* Note: This implementation does NOT maintain the {@link IVCache} associations.
*
* @author Bryan Thompson
* @version $Id: IVBindingSetEncoder.java 6032 2012-02-16 12:48:04Z thompsonbry
* $
*/
public class IVBindingSetEncoder implements IBindingSetEncoder,
IBindingSetDecoder {
/**
* Value factory
*/
protected final BigdataValueFactory vf;
/**
* true
iff this is in support of a DISTINCT filter.
*
* Note: we do not maintain the {@link #ivCacheSchema} for a DISTINCT filter
* since the original solutions flow through the filter.
*/
protected final boolean filter;
/**
* The schema provides the order in which the {@link IV}[] for solutions
* stored in the hash index are encoded in the {@link HTree}. {@link IV}
* s which are not bound are modeled by a {@link TermId#NullIV}.
*
* Note: In order to be able to encode/decode the schema based on the
* lazy identification of the variables which appear in solutions the
* {@link HTree} must store variable length {@link IV}[]s since new
* variables may be discovered at any point.
*/
private final LinkedHashSet> schema;
/**
* The set of variables for which materialized {@link IV}s have been
* observed.
*/
final protected LinkedHashSet> ivCacheSchema;
/**
* A cache mapping from non-inline {@link IV}s ({@link TermId}s and
* {@link BlobIV}s) whose {@link IVCache} association was set to the
* corresponding {@link BigdataValue}.
*/
final Map, BigdataValue> cache;
/**
* Used to encode the {@link IV}s.
*/
private final IKeyBuilder keyBuilder;
/**
* @param store the backing store
* @param filter
* true
iff this is in support of a DISTINCT filter.
*
* Note: we do not maintain the {@link #ivCacheSchema} for a
* DISTINCT filter since the original solutions flow through the
* filter.
*/
public IVBindingSetEncoder(final BigdataValueFactory vf, final boolean filter) {
this.vf = vf;
this.filter = filter;
this.schema = new LinkedHashSet>();
// The set of variables for which materialized values are observed.
this.ivCacheSchema = filter ? null : new LinkedHashSet>();
this.keyBuilder = new ASCIIKeyBuilderFactory(128).getKeyBuilder();
// Used to batch updates into the ID2TERM and BLOBS indices.
this.cache = filter ? null : new HashMap, BigdataValue>();
}
/**
* {@inheritDoc}
*
* This implementation does not maintain the {@link IVCache} associations.
*/
@Override
public boolean isValueCache() {
return false;
}
/**
* Build up the schema based on variables that are actually bound in the
* observed bindings.
*
* @param bset
* An observed binding set.
*/
private void updateSchema(final IBindingSet bset) {
@SuppressWarnings("rawtypes")
final Iterator vitr = bset.vars();
while (vitr.hasNext()) {
schema.add(vitr.next());
}
}
@Override
public byte[] encodeSolution(final IBindingSet bset) {
return encodeSolution(bset, true/* updateCache */);
}
@Override
public byte[] encodeSolution(final IBindingSet bset,
final boolean updateCache) {
if(bset == null)
throw new IllegalArgumentException();
final Map, BigdataValue> cache = updateCache ? this.cache
: null;
/*
* Before we can encode the binding set, we need to update the schema
* such that it captures any variables used in the binding set (plus
* any variables which have been observed in previous binding sets).
*/
updateSchema(bset);
/*
* Encode the binding set. Bindings will appear in the same order that
* they were added to the schema. Unbound variables are represented by a
* NullIV.
*/
keyBuilder.reset();
final Iterator> vitr = schema.iterator();
while (vitr.hasNext()) {
final IVariable> v = vitr.next();
@SuppressWarnings("unchecked")
final IConstant> c = bset.get(v);
if (c == null) {
IVUtility.encode(keyBuilder, TermId.NullIV);
} else {
final IV, ?> iv = c.get();
if (iv.isNullIV()) {
/**
* BLZG-611 (https://jira.blazegraph.com/browse/BLZG-611):
* we need to properly encode (and later on, decode)
* mocked IVs, which have either been constructed at runtime or
* represent values that are not present in the database. We do
* this by wrapping fully inlined IV types (for URIs, literals,
* or blank nodes) into MockedValueIV, which will be properly
* decoded as a mocked IV later on.
*/
final Object val = iv.getValue();
final IV,?> ivToEncode;
if (val instanceof BigdataURIImpl) {
// create fully inlined URI IV
ivToEncode = new FullyInlineURIIV<>((BigdataURIImpl)val);
} else if (val instanceof BigdataLiteralImpl) {
// create fully inlined literal IV
final BigdataLiteralImpl valAsLiteral = (BigdataLiteralImpl)val;
ivToEncode =
new FullyInlineTypedLiteralIV<>(
valAsLiteral.getLabel(),
((BigdataLiteralImpl) val).getLanguage(),
((BigdataLiteralImpl) val).getDatatype());
} else if (val instanceof BigdataBNodeImpl) {
// create fully inlined blank node IV
final BigdataBNodeImpl valAsBNode = (BigdataBNodeImpl)val;
ivToEncode = new FullyInlineUnicodeBNodeIV<>(valAsBNode.getID());
} else {
// unreachable code, just in case...
throw new IllegalArgumentException("Uncovered iv.getValue() type in encode.");
}
IVUtility.encode(keyBuilder, new MockedValueIV(ivToEncode));
} else {
IVUtility.encode(keyBuilder, iv);
if (!iv.isInline() && iv.hasValue() && !filter) {
ivCacheSchema.add(v);
if (cache != null)
cache.put(iv, iv.getValue());
}
}
}
}
return keyBuilder.getKey();
}
@Override
public void flush() {
if (cache != null)
cache.clear();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public IBindingSet decodeSolution(final byte[] val, final int off,
final int len, final boolean resolveCachedValues) {
final IBindingSet bset = new ListBindingSet();
final IV, ?>[] ivs = IVUtility.decodeAll(val, off, len);
int i = 0;
for (IVariable> v : schema) {
if (i == ivs.length) {
/*
* This solution does not include all variables which were
* eventually discovered to be part of the schema.
*/
break;
}
final IV, ?> iv = ivs[i++];
if (iv == null) {
// Not bound.
continue;
}
/**
* BLZG-611 (https://jira.blazegraph.com/browse/BLZG-611):
* decoding of MockeedValueIV, see encodeSolution() for more information.
*/
if (iv instanceof MockedValueIV) {
final MockedValueIV mvIv = (MockedValueIV)iv;
final IV,?> innerIv = mvIv.getIV();
final BigdataValue value; // set inside subsequent if block
final TermId mockIv; // populated subsequently
if (innerIv instanceof FullyInlineURIIV) {
final FullyInlineURIIV innerIvAsUri = (FullyInlineURIIV)innerIv;
final URI inlineUri = innerIvAsUri.getInlineValue();
value = vf.createURI(inlineUri.stringValue());
mockIv = TermId.mockIV(VTE.URI);
} else if (innerIv instanceof FullyInlineTypedLiteralIV) {
final FullyInlineTypedLiteralIV innerIvAsLiteral =
(FullyInlineTypedLiteralIV)innerIv;
value = vf.createLiteral(
innerIvAsLiteral.getLabel(),
innerIvAsLiteral.getDatatype(),
innerIvAsLiteral.getLanguage());
mockIv = TermId.mockIV(VTE.LITERAL);
} else if (innerIv instanceof FullyInlineUnicodeBNodeIV) {
final FullyInlineUnicodeBNodeIV innerIvAsBNode =
(FullyInlineUnicodeBNodeIV)innerIv;
value = vf.createBNode(innerIvAsBNode.getID());
mockIv = TermId.mockIV(VTE.BNODE);
} else {
// unreachable code, just in case...
throw new IllegalArgumentException("Uncovered inner IV type in decode");
}
// re-construct original mock IV
mockIv.setValue(value);
value.setIV(mockIv);
bset.set(v, new Constant>(mockIv));
} else {
bset.set(v, new Constant>(iv));
}
}
if(resolveCachedValues)
resolveCachedValues(bset);
return bset;
}
/**
* {@inheritDoc}
*
* Note: This implementation is a NOP as the {@link IVCache} association
* is NOT maintained by this class.
*/
@Override
public void resolveCachedValues(final IBindingSet bset) {
// NOP
}
@Override
public void release() {
schema.clear();
if (ivCacheSchema != null) {
ivCacheSchema.clear();
}
}
}