org.openanzo.rdf.MemQuadStore.java Source code

Java tutorial

Introduction

Here is the source code for org.openanzo.rdf.MemQuadStore.java

Source

/*******************************************************************************
 * Copyright (c) 2004, 2007 IBM Corporation and Cambridge Semantics Incorporated.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * File:        $Source: /cvsroot/slrp/boca/com.ibm.adtech.boca.core/src/com/ibm/adtech/boca/model/Attic/QuadStore.java,v $
 * Created by:  Matthew Roy ( <a href="mailto:mroy@us.ibm.com">mroy@us.ibm.com </a>)
 * Created on:  Apr 25, 2007
 * Revision:   $Id: QuadStore.java 168 2007-07-31 14:11:14Z mroy $
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Cambridge Semantics Incorporated - Fork to Anzo
 *******************************************************************************/
package org.openanzo.rdf;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.collections15.MultiMap;
import org.openanzo.exceptions.AnzoException;
import org.openanzo.exceptions.AnzoRuntimeException;
import org.openanzo.exceptions.ExceptionConstants;
import org.openanzo.exceptions.LogUtils;
import org.openanzo.glitter.Engine;
import org.openanzo.glitter.dataset.DefaultQueryDataset;
import org.openanzo.glitter.query.QueryResults;
import org.openanzo.glitter.syntax.concrete.ParseException;
import org.openanzo.rdf.query.CoreEngineConfig;
import org.openanzo.rdf.query.QuadStoreEngineConfig;
import org.openanzo.rdf.utils.MultiTreeArrayMap;
import org.openanzo.rdf.utils.UriGenerator;
import org.openanzo.rdf.vocabulary.Anzo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Core storage of quads with indexes for s,p,o,nguri, po, and sp
 * 
 * @author Matthew Roy ( <a href="mailto:mroy@cambridgesemantics.com">mroy@cambridgesemantics.com </a>)
 * 
 */
public class MemQuadStore extends BaseQuadStore implements IQuadStore {

    private static final Logger log = LoggerFactory.getLogger(MemQuadStore.class);

    //Set of all statements in store
    private final Collection<Statement> statements;

    //Index map of namedGraphUris to statements
    private final MultiMap<URI, Statement> namedGraphMap;

    //Index map of subjects to statements
    private final MultiMap<Resource, Statement> subjectMap;

    //Index map of predicates to statements
    private final MultiMap<URI, Statement> predMap;

    //Index map of object to statements
    private final MultiMap<Value, Statement> objMap;

    //Index map of predicates/object to statements
    private final Map<URI, MultiMap<Value, Statement>> poIndex;

    //Index map of predicate/subject to statements
    private final Map<URI, MultiMap<Resource, Statement>> psIndex;

    private final Engine glitter;

    /**
     * Initialize quadstore's statement set and indexes
     */
    public MemQuadStore() {
        statements = new HashSet<Statement>();
        subjectMap = new MultiTreeArrayMap<Resource, Statement>();
        predMap = new MultiTreeArrayMap<URI, Statement>();
        objMap = new MultiTreeArrayMap<Value, Statement>();
        namedGraphMap = new MultiTreeArrayMap<URI, Statement>();
        poIndex = new TreeMap<URI, MultiMap<Value, Statement>>();
        psIndex = new TreeMap<URI, MultiMap<Resource, Statement>>();

        CoreEngineConfig config = new QuadStoreEngineConfig(this);
        glitter = new Engine(config);
    }

    /**
     * Add statements to store and index them
     * 
     * @param statements
     *            Statements to add
     * @throws AnzoRuntimeException
     *             if the namedGraphURI of a statement is null
     */
    public void add(Statement... statements) {
        synchronized (this.statements) {
            for (Statement stmt : statements) {
                if (stmt.getNamedGraphUri() == null) {
                    throw new AnzoRuntimeException(ExceptionConstants.CLIENT.URI_NOT_NULL);
                }
                if (stmt.getSubject() == null || stmt.getPredicate() == null || stmt.getObject() == null)
                    throw new IllegalStateException("statement cannot contain nulls");
                if (this.statements.add(stmt)) {
                    addMaps(stmt);
                }
            }
        }
    }

    /**
     * Delete statements from store and remove indexes
     * 
     * @param statements
     *            Statements to delete
     * @throws AnzoRuntimeException
     *             if the namedGraphURI of a statement is null
     */
    public void remove(Statement... statements) {
        synchronized (this.statements) {
            for (Statement stmt : statements) {
                if (stmt.getNamedGraphUri() == null) {
                    throw new AnzoRuntimeException(ExceptionConstants.CLIENT.URI_NOT_NULL);
                }
                if (this.statements.remove(stmt)) {
                    removeMaps(stmt);
                }
            }
        }
    }

    /**
     * Index this statement
     * 
     * @param stmt
     *            Statement to index
     */
    private void addMaps(Statement stmt) {
        URI c = stmt.getNamedGraphUri();
        Resource s = stmt.getSubject();
        URI p = stmt.getPredicate();
        Value o = stmt.getObject();
        subjectMap.put(s, stmt);
        predMap.put(p, stmt);
        objMap.put(o, stmt);
        namedGraphMap.put(c, stmt);
        MultiMap<Value, Statement> poIndexMap = poIndex.get(p);
        if (poIndexMap == null) {
            poIndexMap = new MultiTreeArrayMap<Value, Statement>();
            poIndex.put(p, poIndexMap);
        }
        poIndexMap.put(o, stmt);

        MultiMap<Resource, Statement> psIndexMap = psIndex.get(p);
        if (psIndexMap == null) {
            psIndexMap = new MultiTreeArrayMap<Resource, Statement>();
            psIndex.put(p, psIndexMap);
        }
        psIndexMap.put(s, stmt);
    }

    /**
     * Remove indexes for this statement
     * 
     * @param stmt
     *            statement to deindex
     */
    private void removeMaps(Statement stmt) {
        Resource c = stmt.getNamedGraphUri();
        Resource s = stmt.getSubject();
        URI p = stmt.getPredicate();
        Value o = stmt.getObject();
        subjectMap.remove(s, stmt);
        predMap.remove(p, stmt);
        objMap.remove(o, stmt);
        namedGraphMap.remove(c, stmt);
        MultiMap<Value, Statement> poIndexMap = poIndex.get(p);
        if (poIndexMap != null) {
            poIndexMap.remove(o, stmt);
            if (poIndexMap.size() == 0) {
                poIndex.remove(p);
            }
        }
        MultiMap<Resource, Statement> psIndexMap = psIndex.get(p);
        if (psIndexMap != null) {
            psIndexMap.remove(s, stmt);
            if (psIndexMap.size() == 0) {
                psIndex.remove(p);
            }
        }
    }

    public Collection<Statement> find(Resource subj, URI pred, Value obj, URI... namedGraphUris) {
        if (namedGraphUris != null && namedGraphUris.length == 1 && namedGraphUris[0] == null) {
            namedGraphUris = new URI[0];
        }
        return findStatements(subj, pred, obj, namedGraphUris);
    }

    /**
     * Find set of statements that match provided parameters
     * 
     * @param subj
     *            Subject value to match, or wildcard if null
     * @param pred
     *            predicate value to match, or wildcard if null
     * @param obj
     *            Object value to match, or wildcard if null
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return Collection<Statement> of matching statements
     */
    private Collection<Statement> findStatements(Resource subj, URI pred, Value obj, URI... namedGraphUris) {
        //Determine what kind of query this is based on what values are provided
        int type = 0;
        if (subj != null) {
            type |= 1;
        }
        if (pred != null) {
            type |= 2;
        }
        if (obj != null) {
            type |= 4;
        }
        if (namedGraphUris != null && namedGraphUris.length > 0) {
            type |= 8;
        }
        synchronized (statements) {
            switch (type) {
            case 0:
                ArrayList<Statement> results = new ArrayList<Statement>(statements);
                return results;
            case 1:
                Collection<Statement> sSet = subjectMap.get(subj);
                if (sSet == null) {
                    return Collections.<Statement>emptyList();
                } else {
                    return org.openanzo.rdf.utils.Collections.copyCollection(sSet);
                }
            case 2:
                Collection<Statement> pSet = predMap.get(pred);
                if (pSet == null) {
                    return Collections.<Statement>emptyList();
                } else {
                    return org.openanzo.rdf.utils.Collections.copyCollection(pSet);
                }
            case 3:
                return findPS(subj, pred);
            case 4:
                Collection<Statement> oSet = objMap.get(obj);
                if (oSet == null) {
                    return Collections.<Statement>emptyList();
                } else {
                    return org.openanzo.rdf.utils.Collections.copyCollection(oSet);
                }
            case 5:
                return findSOC(subj, obj);
            case 6:
                return findPO(pred, obj);
            case 7:
                return findSPO(subj, pred, obj);
            case 8:
                Collection<Statement> matches = new ArrayList<Statement>();
                if (namedGraphUris != null) {
                    for (Resource namedGraphURI : namedGraphUris) {
                        Collection<Statement> gSet = namedGraphMap.get(namedGraphURI);
                        if (gSet != null) {
                            matches.addAll(gSet);
                        }
                    }
                }
                return matches;
            case 9:
                return findSC(subj, namedGraphUris);
            case 10:
                return findPC(pred, namedGraphUris);
            case 11:
                return findPS(subj, pred, namedGraphUris);
            case 12:
                return findOC(obj, namedGraphUris);
            case 13:
                return findSOC(subj, obj, namedGraphUris);
            case 14:
                return findPO(pred, obj, namedGraphUris);
            case 15:
                matches = new HashSet<Statement>();
                if (namedGraphUris != null) {
                    for (URI namedGraphURI : namedGraphUris) {
                        Statement stmt = new Statement(subj, pred, obj, namedGraphURI);
                        if (statements.contains(stmt)) {
                            matches.add(stmt);
                        }
                    }
                }
                return matches;
            default:
                return Collections.<Statement>emptyList();
            }
        }
    }

    /**
     * Use the predicate/Subject index to find statements
     * 
     * @param subj
     *            Subject value to match
     * @param pred
     *            predicate value to match
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return Collection<Statement> of matching statements
     */
    private Collection<Statement> findPS(Resource subj, URI pred, URI... namedGraphUris) {
        //Lookup predicate/subject index for predicate value provided
        MultiMap<Resource, Statement> psIndexMap = psIndex.get(pred);
        if (psIndexMap != null) {
            //Find subject index for subject provided
            Collection<Statement> map = psIndexMap.get(subj);
            if (map != null && map.size() > 0) {
                //If only 1 namedGraphURI is provided, then get index for that namedGraphURI
                if (namedGraphUris == null || namedGraphUris.length == 0) {
                    return org.openanzo.rdf.utils.Collections.copyCollection(map);
                } else if (namedGraphUris.length == 1) {
                    Collection<Statement> gSet = namedGraphMap.get(namedGraphUris[0]);
                    if (gSet == null) {
                        return Collections.<Statement>emptyList();
                    }
                    Collection<Statement> matches = new ArrayList<Statement>();
                    //Use the smallest set of statements, the ones from the index or set from namedGraphURI index
                    if (gSet.size() < map.size()) {
                        for (Statement stmt : gSet) {
                            if (stmt.getPredicate().equals(pred) && stmt.getSubject().equals(subj)) {
                                matches.add(stmt);
                            }
                        }
                    } else {
                        for (Statement stmt : map) {
                            if (stmt.getNamedGraphUri().equals(namedGraphUris[0])) {
                                matches.add(stmt);
                            }
                        }
                    }
                    return matches;
                } else { //If more than one namedGraphURI compare the namedGraphURI of statement from p/s index to set of namedGraphUris
                    Collection<Statement> matches = new ArrayList<Statement>();
                    HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                    Collections.addAll(namedGraphUriset, namedGraphUris);
                    for (Statement stmt : map) {
                        if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                            matches.add(stmt);
                        }
                    }
                    return matches;
                }
            }
        }
        return Collections.<Statement>emptyList();
    }

    /**
     * Use the predicate/Object index to find statements
     * 
     * @param pred
     *            predicate value to match
     * @param obj
     *            Object value to match
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return Collection<Statement> of matching statements
     */
    private Collection<Statement> findPO(URI pred, Value obj, Resource... namedGraphUris) {
        MultiMap<Value, Statement> poIndexMap = poIndex.get(pred);
        if (poIndexMap != null) {
            Collection<Statement> map = poIndexMap.get(obj);
            if (map != null && map.size() > 0) {
                if (namedGraphUris == null || namedGraphUris.length == 0) {
                    return org.openanzo.rdf.utils.Collections.copyCollection(map);
                } else if (namedGraphUris.length == 1) {
                    Collection<Statement> matches = new ArrayList<Statement>();
                    Collection<Statement> gSet = namedGraphMap.get(namedGraphUris[0]);
                    if (gSet == null) {
                        return Collections.<Statement>emptyList();
                    }
                    if (gSet.size() < map.size()) {
                        for (Statement stmt : gSet) {
                            if (stmt.getPredicate().equals(pred) && stmt.getObject().equals(obj)) {
                                matches.add(stmt);
                            }
                        }
                    } else {
                        for (Statement stmt : map) {
                            if (stmt.getNamedGraphUri().equals(namedGraphUris[0])) {
                                matches.add(stmt);
                            }
                        }
                    }
                    return matches;
                } else {
                    Collection<Statement> matches = new ArrayList<Statement>();
                    HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                    Collections.addAll(namedGraphUriset, namedGraphUris);
                    for (Statement stmt : map) {
                        if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                            matches.add(stmt);
                        }
                    }
                    return matches;
                }
            }
        }
        return Collections.<Statement>emptyList();
    }

    /**
     * Find statements that match Subject,Predicate, and Object values provided
     * 
     * @param subj
     *            Subject value to match
     * @param pred
     *            predicate value to match
     * @param obj
     *            Object value to match
     * @return Collection<Statement> of matching statements
     */
    @SuppressWarnings("unchecked")
    private Collection<Statement> findSPO(Resource subj, URI pred, Value obj) {
        Collection<Statement> sSet = subjectMap.get(subj);
        if (sSet == null) {
            return Collections.<Statement>emptyList();
        }
        Collection<Statement> pSet = predMap.get(pred);
        if (pSet == null) {
            return Collections.<Statement>emptyList();
        }
        Collection<Statement> oSet = objMap.get(obj);
        if (oSet == null) {
            return Collections.<Statement>emptyList();
        }
        Collection<Statement>[] set = new Collection[3];
        set[0] = sSet;
        set[1] = pSet;
        set[2] = oSet;
        Arrays.sort(set, comparator);
        Collection<Statement> matches = new ArrayList<Statement>();
        if (set[0] == sSet) {
            for (Statement stmt : sSet) {
                if (stmt.getObject().equals(obj) && stmt.getPredicate().equals(pred)) {
                    matches.add(stmt);
                }
            }
        } else if (set[0] == oSet) {
            for (Statement stmt : oSet) {
                if (stmt.getSubject().equals(subj) && stmt.getPredicate().equals(pred)) {
                    matches.add(stmt);
                }
            }
        } else {
            for (Statement stmt : pSet) {
                if (stmt.getSubject().equals(subj) && stmt.getObject().equals(obj)) {
                    matches.add(stmt);
                }
            }
        }
        return matches;
    }

    /**
     * Find statements that match Subject and Object values provided
     * 
     * @param subj
     *            Subject value to match
     * @param obj
     *            Object value to match
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return Collection<Statement> of matching statements
     */
    @SuppressWarnings("unchecked")
    private Collection<Statement> findSOC(Resource subj, Value obj, Resource... namedGraphUris) {
        Collection<Statement> sSet = subjectMap.get(subj);
        if (sSet == null || sSet.size() == 0) {
            return Collections.<Statement>emptyList();
        }
        Collection<Statement> oSet = objMap.get(obj);
        if (oSet == null || oSet.size() == 0) {
            return Collections.<Statement>emptyList();
        }
        if (namedGraphUris != null && namedGraphUris.length > 0) {
            if (namedGraphUris.length == 1) {
                Collection<Statement> gSet = namedGraphMap.get(namedGraphUris[0]);
                if (gSet == null || gSet.size() == 0) {
                    return Collections.<Statement>emptyList();
                }
                Collection<Statement>[] set = new Collection[3];
                set[0] = sSet;
                set[1] = gSet;
                set[2] = oSet;
                Arrays.sort(set, comparator);
                Collection<Statement> matches = new ArrayList<Statement>();
                if (set[0] == sSet) {
                    for (Statement stmt : sSet) {
                        if (stmt.getObject().equals(obj) && stmt.getNamedGraphUri().equals(namedGraphUris[0])) {
                            matches.add(stmt);
                        }
                    }
                } else if (set[0] == oSet) {
                    for (Statement stmt : oSet) {
                        if (stmt.getSubject().equals(subj) && stmt.getNamedGraphUri().equals(namedGraphUris[0])) {
                            matches.add(stmt);
                        }
                    }
                } else {
                    for (Statement stmt : gSet) {
                        if (stmt.getSubject().equals(subj) && stmt.getObject().equals(obj)) {
                            matches.add(stmt);
                        }
                    }
                }
                return matches;
            } else {
                Collection<Statement> matches = new ArrayList<Statement>();
                HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                Collections.addAll(namedGraphUriset, namedGraphUris);
                if (sSet.size() < oSet.size()) {
                    for (Statement stmt : sSet) {
                        if (stmt.getObject().equals(obj) && namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                            matches.add(stmt);
                        }
                    }
                } else {
                    for (Statement stmt : oSet) {
                        if (stmt.getSubject().equals(subj) && namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                            matches.add(stmt);
                        }
                    }
                }
                return matches;
            }
        } else {
            Collection<Statement> matches = new ArrayList<Statement>();
            if (sSet.size() < oSet.size()) {
                for (Statement stmt : sSet) {
                    if (stmt.getObject().equals(obj)) {
                        matches.add(stmt);
                    }
                }
            } else {
                for (Statement stmt : oSet) {
                    if (stmt.getSubject().equals(subj)) {
                        matches.add(stmt);
                    }
                }
            }
            return matches;
        }
    }

    /**
     * Find statements that match predicate and namedGraphURI values provided
     * 
     * @param pred
     *            predicate value to match
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return Collection<Statement> of matching statements
     */
    private Collection<Statement> findPC(URI pred, Resource... namedGraphUris) {
        Collection<Statement> pSet = predMap.get(pred);
        if (pSet == null) {
            return Collections.<Statement>emptyList();
        }
        if (namedGraphUris.length == 1) {
            Collection<Statement> gSet = namedGraphMap.get(namedGraphUris[0]);
            if (gSet == null) {
                return Collections.<Statement>emptyList();
            }
            Collection<Statement> matches = new ArrayList<Statement>();
            if (gSet.size() < pSet.size()) {
                for (Statement stmt : gSet) {
                    if (stmt.getPredicate().equals(pred)) {
                        matches.add(stmt);
                    }
                }
            } else {
                for (Statement stmt : pSet) {
                    if (stmt.getNamedGraphUri().equals(namedGraphUris[0])) {
                        matches.add(stmt);
                    }
                }
            }
            return matches;
        } else {
            Collection<Statement> matches = new ArrayList<Statement>();
            HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
            Collections.addAll(namedGraphUriset, namedGraphUris);
            for (Statement stmt : pSet) {
                if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                    matches.add(stmt);
                }
            }
            return matches;
        }
    }

    /**
     * Find statements that match Subject and namedGraphURI values provided
     * 
     * @param subj
     *            Subject value to match
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return Collection<Statement> of matching statements
     */
    private Collection<Statement> findSC(Resource subj, Resource... namedGraphUris) {
        Collection<Statement> sSet = subjectMap.get(subj);
        if (sSet == null) {
            return Collections.<Statement>emptyList();
        }
        if (namedGraphUris.length == 1) {
            Collection<Statement> gSet = namedGraphMap.get(namedGraphUris[0]);
            if (gSet == null) {
                return Collections.<Statement>emptyList();
            }
            Collection<Statement> matches = new ArrayList<Statement>();

            if (gSet.size() < sSet.size()) {
                for (Statement stmt : gSet) {
                    if (stmt.getSubject().equals(subj)) {
                        matches.add(stmt);
                    }
                }
            } else {
                for (Statement stmt : sSet) {
                    if (stmt.getNamedGraphUri().equals(namedGraphUris[0])) {
                        matches.add(stmt);
                    }
                }
            }
            return matches;
        } else {
            Collection<Statement> matches = new ArrayList<Statement>();
            HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
            Collections.addAll(namedGraphUriset, namedGraphUris);
            for (Statement stmt : sSet) {
                if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                    matches.add(stmt);
                }
            }
            return matches;
        }
    }

    /**
     * Find statements that match Subject and namedGraphURI values provided
     * 
     * @param obj
     *            Object value to match
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return Collection<Statement> of matching statements
     */
    private Collection<Statement> findOC(Value obj, Resource... namedGraphUris) {
        Collection<Statement> oSet = objMap.get(obj);
        if (oSet == null) {
            return Collections.<Statement>emptyList();
        }
        if (namedGraphUris.length == 1) {
            Collection<Statement> gSet = namedGraphMap.get(namedGraphUris[0]);
            if (gSet == null) {
                return Collections.<Statement>emptyList();
            }
            Collection<Statement> matches = new ArrayList<Statement>();
            if (gSet.size() < oSet.size()) {
                for (Statement stmt : gSet) {
                    if (stmt.getObject().equals(obj)) {
                        matches.add(stmt);
                    }
                }
            } else {
                for (Statement stmt : oSet) {
                    if (stmt.getNamedGraphUri().equals(namedGraphUris[0])) {
                        matches.add(stmt);
                    }
                }
            }
            return matches;
        } else {
            Collection<Statement> matches = new ArrayList<Statement>();
            HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
            Collections.addAll(namedGraphUriset, namedGraphUris);
            for (Statement stmt : oSet) {
                if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                    matches.add(stmt);
                }
            }
            return matches;
        }
    }

    /**
     * Return all statements in the store
     * 
     * @return Collection<Statement> of statements in store
     */
    public Collection<Statement> getStatements() {
        return new ArrayList<Statement>(statements);
    }

    /**
     * Tests if a statement is contained in the store.
     * 
     * @param match
     *            is the statement to be tested
     * @return boolean result to indicate if the statement was contained in store
     */
    public boolean contains(Statement match) {
        return contains(match.getSubject(), match.getPredicate(), match.getObject(), match.getNamedGraphUri());
    }

    /**
     * Tests if a statement is contained in store that match provided parameters
     * 
     * @param subj
     *            Subject value to match, or wildcard if null
     * @param pred
     *            predicate value to match, or wildcard if null
     * @param obj
     *            Object value to match, or wildcard if null
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return boolean result to indicate if the statement was contained in store
     */
    @SuppressWarnings({ "unchecked" })
    public boolean contains(Resource subj, URI pred, Value obj, URI... namedGraphUris) {
        if ((subj == null && pred == null && obj == null && namedGraphUris == null) || statements.size() == 0) {
            return (statements.size() > 0);
        }
        synchronized (this.statements) {
            if (subj != null && pred != null && obj != null && namedGraphUris != null
                    && namedGraphUris.length == 1) {
                Statement stmt = new Statement(subj, pred, obj, namedGraphUris[0]);
                return statements.contains(stmt);
            }
            if (subj == null && pred != null && obj != null) {
                MultiMap<Value, Statement> poIndexMap = poIndex.get(pred);
                if (poIndexMap != null) {
                    Collection<Statement> map = poIndexMap.get(obj);
                    if (map != null && map.size() > 0) {
                        if (namedGraphUris != null && namedGraphUris.length > 0) {
                            Collection<Statement> gSet = null;
                            HashSet<Resource> namedGraphUriset = null;
                            if (namedGraphUris.length == 1) {
                                gSet = namedGraphMap.get(namedGraphUris[0]);
                            } else {
                                namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                                Collections.addAll(namedGraphUriset, namedGraphUris);
                            }
                            if (gSet != null) {
                                Collection<Statement>[] set = new Collection[2];
                                set[0] = (gSet.size() < map.size()) ? gSet : map;
                                set[1] = (gSet.size() < map.size()) ? map : gSet;
                                for (Statement stmt : set[0]) {
                                    if (set[1].contains(stmt)) {
                                        return true;
                                    }
                                }
                            } else if (namedGraphUriset != null) {
                                for (Statement stmt : map) {
                                    if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                                        return true;
                                    }
                                }
                            }
                        } else {
                            return true;
                        }
                    } else {
                        return false;
                    }
                }
            }
            if (subj != null && pred != null && obj == null) {
                MultiMap<Resource, Statement> psIndexMap = psIndex.get(pred);
                if (psIndexMap != null) {
                    Collection<Statement> map = psIndexMap.get(subj);
                    if (map != null && map.size() > 0) {
                        if (namedGraphUris != null && namedGraphUris.length > 0) {
                            Collection<Statement> gSet = null;
                            HashSet<Resource> namedGraphUriset = null;
                            if (namedGraphUris.length == 1) {
                                gSet = namedGraphMap.get(namedGraphUris[0]);
                            } else {
                                namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                                Collections.addAll(namedGraphUriset, namedGraphUris);
                            }
                            if (gSet != null) {
                                Collection<Statement>[] set = new Collection[2];
                                set[0] = (gSet.size() < map.size()) ? gSet : map;
                                set[1] = (gSet.size() < map.size()) ? map : gSet;
                                for (Statement stmt : set[0]) {
                                    if (set[1].contains(stmt)) {
                                        return true;
                                    }
                                }
                            } else if (namedGraphUriset != null) {
                                for (Statement stmt : map) {
                                    if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                                        return true;
                                    }
                                }
                            }
                        } else {
                            return true;
                        }
                    } else {
                        return false;
                    }
                }
            }
            Collection<Statement> sSet = (subj != null) ? subjectMap.get(subj) : statements;
            Collection<Statement> pSet = (pred != null) ? predMap.get(pred) : statements;
            Collection<Statement> oSet = (obj != null) ? objMap.get(obj) : statements;
            Collection<Statement> gSet = null;
            if (namedGraphUris != null) {
                if (namedGraphUris.length == 1) {
                    gSet = namedGraphMap.get(namedGraphUris[0]);
                    if (gSet == null) {
                        return false;
                    }
                }
            } else {
                gSet = statements;
            }
            if (sSet != null && pSet != null && oSet != null && gSet != null) {
                Collection<Statement>[] set = new Collection[4];
                set[0] = sSet;
                set[1] = pSet;
                set[2] = oSet;
                set[3] = gSet;
                Arrays.sort(set, comparator);
                if (set[0].size() == statements.size()) {
                    return true;
                } else {
                    for (Statement stmt : set[0]) {
                        if ((set[1] == statements || set[1].contains(stmt))
                                && (set[2] == statements || set[2].contains(stmt))
                                && (set[3] == statements || set[3].contains(stmt))) {
                            return true;
                        }
                    }
                }
            } else if (sSet != null && pSet != null && oSet != null && gSet == null) {
                if (namedGraphUris != null) {
                    HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                    Collections.addAll(namedGraphUriset, namedGraphUris);
                    Collection<Statement>[] set = new Collection[3];
                    set[0] = sSet;
                    set[1] = pSet;
                    set[2] = oSet;
                    Arrays.sort(set, comparator);
                    if (set[0].size() == statements.size()) {
                        return true;
                    } else {
                        for (Statement stmt : set[0]) {
                            if ((set[1] == statements || set[1].contains(stmt))
                                    && (set[2] == statements || set[2].contains(stmt))
                                    && namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        return false;
    }

    /**
     * Tests if a statement is contained in store that match provided parameters
     * 
     * @param subj
     *            Subject value to match, or wildcard if null
     * @param pred
     *            predicate value to match, or wildcard if null
     * @param obj
     *            Object value to match, or wildcard if null
     * @param namedGraphUris
     *            namedGraphURI value to match, or wildcard if null
     * @return boolean result to indicate if the statement was contained in store
     */
    @SuppressWarnings({ "unchecked" })
    public long count(Resource subj, URI pred, Value obj, URI... namedGraphUris) {
        if ((subj == null && pred == null && obj == null && namedGraphUris == null) || statements.size() == 0) {
            return statements.size();
        }
        synchronized (this.statements) {
            if (subj != null && pred != null && obj != null && namedGraphUris != null
                    && namedGraphUris.length == 1) {
                Statement stmt = new Statement(subj, pred, obj, namedGraphUris[0]);
                return statements.contains(stmt) ? 1 : 0;
            }
            long count = 0;
            if (subj == null && pred != null && obj != null) {
                MultiMap<Value, Statement> poIndexMap = poIndex.get(pred);
                if (poIndexMap != null) {
                    Collection<Statement> map = poIndexMap.get(obj);
                    if (map != null && map.size() > 0) {
                        if (namedGraphUris != null && namedGraphUris.length > 0) {
                            Collection<Statement> gSet = null;
                            HashSet<Resource> namedGraphUriset = null;
                            if (namedGraphUris.length == 1) {
                                gSet = namedGraphMap.get(namedGraphUris[0]);
                            } else {
                                namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                                Collections.addAll(namedGraphUriset, namedGraphUris);
                            }
                            if (gSet != null) {
                                Collection<Statement>[] set = new Collection[2];
                                set[0] = (gSet.size() < map.size()) ? gSet : map;
                                set[1] = (gSet.size() < map.size()) ? map : gSet;
                                for (Statement stmt : set[0]) {
                                    if (set[1].contains(stmt)) {
                                        count++;
                                    }
                                }
                            } else if (namedGraphUriset != null) {
                                for (Statement stmt : map) {
                                    if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                                        count++;
                                    }
                                }
                            }
                        } else {
                            return map.size();
                        }
                    } else {
                        return 0;
                    }
                }
            }
            if (subj != null && pred != null && obj == null) {
                MultiMap<Resource, Statement> psIndexMap = psIndex.get(pred);
                if (psIndexMap != null) {
                    Collection<Statement> map = psIndexMap.get(subj);
                    if (map != null && map.size() > 0) {
                        if (namedGraphUris != null && namedGraphUris.length > 0) {
                            Collection<Statement> gSet = null;
                            HashSet<Resource> namedGraphUriset = null;
                            if (namedGraphUris.length == 1) {
                                gSet = namedGraphMap.get(namedGraphUris[0]);
                            } else {
                                namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                                Collections.addAll(namedGraphUriset, namedGraphUris);
                            }
                            if (gSet != null) {
                                Collection<Statement>[] set = new Collection[2];
                                set[0] = (gSet.size() < map.size()) ? gSet : map;
                                set[1] = (gSet.size() < map.size()) ? map : gSet;
                                for (Statement stmt : set[0]) {
                                    if (set[1].contains(stmt)) {
                                        return count++;
                                    }
                                }
                            } else if (namedGraphUriset != null) {
                                for (Statement stmt : map) {
                                    if (namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                                        return count++;
                                    }
                                }
                            }
                        } else {
                            return map.size();
                        }
                    } else {
                        return 0;
                    }
                }
            }
            Collection<Statement> sSet = (subj != null) ? subjectMap.get(subj) : statements;
            Collection<Statement> pSet = (pred != null) ? predMap.get(pred) : statements;
            Collection<Statement> oSet = (obj != null) ? objMap.get(obj) : statements;
            Collection<Statement> gSet = null;
            if (namedGraphUris != null) {
                if (namedGraphUris.length == 1) {
                    gSet = namedGraphMap.get(namedGraphUris[0]);
                    if (gSet == null) {
                        return 0;
                    }
                }
            } else {
                gSet = statements;
            }
            if (sSet != null && pSet != null && oSet != null && gSet != null) {
                Collection<Statement>[] set = new Collection[4];
                set[0] = sSet;
                set[1] = pSet;
                set[2] = oSet;
                set[3] = gSet;
                Arrays.sort(set, comparator);
                if (set[0].size() == statements.size()) {
                    return statements.size();
                } else {
                    for (Statement stmt : set[0]) {
                        if ((set[1] == statements || set[1].contains(stmt))
                                && (set[2] == statements || set[2].contains(stmt))
                                && (set[3] == statements || set[3].contains(stmt))) {
                            return count++;
                        }
                    }
                }
            } else if (sSet != null && pSet != null && oSet != null && gSet == null) {
                if (namedGraphUris != null) {
                    HashSet<Resource> namedGraphUriset = new HashSet<Resource>(namedGraphUris.length);
                    Collections.addAll(namedGraphUriset, namedGraphUris);
                    Collection<Statement>[] set = new Collection[3];
                    set[0] = sSet;
                    set[1] = pSet;
                    set[2] = oSet;
                    Arrays.sort(set, comparator);
                    if (set[0].size() == statements.size()) {
                        return statements.size();
                    } else {
                        for (Statement stmt : set[0]) {
                            if ((set[1] == statements || set[1].contains(stmt))
                                    && (set[2] == statements || set[2].contains(stmt))
                                    && namedGraphUriset.contains(stmt.getNamedGraphUri())) {
                                return count++;
                            }
                        }
                    }
                }
            }
            return count;
        }

    }

    /**
     * Simple comparator to sort arrays by size
     */
    private final static StmtSetComp comparator = new StmtSetComp();

    static private class StmtSetComp implements Comparator<Collection<?>> {

        public int compare(Collection<?> o1, Collection<?> o2) {
            int result = 0;
            if (o1.size() == o2.size()) {
                return result;
            }
            return (o1.size() < o2.size()) ? -1 : 1;
        }
    }

    /**
     * Clear statements and indexes from memory
     */
    public void clear() {
        synchronized (this.statements) {
            statements.clear();
            subjectMap.clear();
            predMap.clear();
            objMap.clear();
            namedGraphMap.clear();
            poIndex.clear();
            psIndex.clear();
        }
    }

    /**
     * Return the number of statements in the store
     * 
     * @return the number of statements in the store
     */
    public int size() {
        return statements.size();
    }

    /**
     * Return if store is empty
     * 
     * @return if store is empty
     */
    public boolean isEmpty() {
        return statements.isEmpty();
    }

    /* Return the number of statements in the store for given namedGraphUris
     * @param namedGraphUris to determine size of in container
     * @return the number of statements in the store for given namedGraphUris
     */
    public int size(URI... namedGraphUris) {
        int size = 0;
        for (Resource namedGraphURI : namedGraphUris) {
            Collection<Statement> stmts = namedGraphMap.get(namedGraphURI);
            if (stmts != null) {
                size += stmts.size();
            }
        }
        return size;
    }

    /**
     * Return the set of namedGraphUris contained within store
     * 
     * @return collection of namedGraphUris contained within store
     */
    public Collection<URI> getNamedGraphUris() {
        return new HashSet<URI>(namedGraphMap.keySet());
    }

    public QueryResults executeQuery(Set<URI> defaultNamedGraphsIn, Set<URI> namedGraphsIn, Set<URI> namedDatasets,
            String query, URI baseUri) throws AnzoException {
        try {
            HashSet<URI> defaultNamedGraphs = new HashSet<URI>(defaultNamedGraphsIn);
            HashSet<URI> namedGraphs = new HashSet<URI>(namedGraphsIn);
            if (namedDatasets != null) {
                for (URI uri : namedDatasets) {
                    for (Statement s : find(uri, Anzo.DEFAULTGRAPH, null, uri)) {
                        defaultNamedGraphs.add((URI) s.getObject());
                    }
                    for (Statement s : find(uri, Anzo.NAMEDGRAPH, null, uri)) {
                        namedGraphs.add((URI) s.getObject());
                    }
                }
            }
            // copy these since we then modify them
            UriGenerator.handleSpecialGraphUris(defaultNamedGraphs, this);
            UriGenerator.handleSpecialGraphUris(namedGraphs, this);

            return glitter.executeQuery(null, query, new DefaultQueryDataset(defaultNamedGraphs, namedGraphs),
                    baseUri);
        } catch (ParseException e) {
            log.error(LogUtils.GLITTER_MARKER, "Error parsing query:" + query, e);
            throw new AnzoException(ExceptionConstants.CLIENT.ERROR_PARSING_QUERY, e, query);
        }
    }
}