Package org.apache.marmotta.kiwi.caching

Source Code of org.apache.marmotta.kiwi.caching.KiWiQueryCache

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.marmotta.kiwi.caching;

import com.google.common.collect.ImmutableList;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.apache.marmotta.kiwi.model.caching.IntArray;
import org.apache.marmotta.kiwi.model.rdf.KiWiNode;
import org.apache.marmotta.kiwi.model.rdf.KiWiResource;
import org.apache.marmotta.kiwi.model.rdf.KiWiTriple;
import org.apache.marmotta.kiwi.model.rdf.KiWiUriResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.IntBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Add file description here!
* <p/>
* User: sschaffe
*/
public class KiWiQueryCache  {

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

    private Ehcache queryCache;


    public KiWiQueryCache(Ehcache queryCache) {
        this.queryCache = queryCache;
        log.debug("Building up new {}", KiWiQueryCache.class.getSimpleName());
    }


    /**
     * Look up a triple query in the query cache. Returns the result set if the query is found in the cache, returns
     * null if the query is not found.
     *
     * @param subject  the subject of the triples to list or null for wildcard
     * @param property the property of the triples to list or null for wildcard
     * @param object   the object of the triples to list or null for wildcard
     * @param context  the context/knowledge space of the triples to list or null for all spaces
     * @param inferred if true, inferred triples are included in the result; if false not
     * @return the result set if the query is found in the cache, returns null if the query is not found
     */
    @SuppressWarnings("unchecked")
  public List<KiWiTriple> listTriples(KiWiResource subject, KiWiUriResource property, KiWiNode object, KiWiUriResource context, boolean inferred) {
        IntArray key = createCacheKey(subject,property,object,context,inferred);
        if(queryCache.get(key) != null) return (List<KiWiTriple>)queryCache.get(key).getObjectValue();
        else
            return null;
    }


    /**
     * Cache the result of a triple query in the query cache.
     *
     * @param subject  the subject of the triples to list or null for wildcard
     * @param property the property of the triples to list or null for wildcard
     * @param object   the object of the triples to list or null for wildcard
     * @param context  the context/knowledge space of the triples to list or null for all spaces
     * @param inferred if true, inferred triples are included in the result; if false not
     * @param result   the result of the triple query to cache
     */
    public void cacheTriples(KiWiResource subject, KiWiUriResource property, KiWiNode object, KiWiResource context, boolean inferred, List<KiWiTriple> result) {

        // cache the query result
        IntArray key = createCacheKey(subject,property,object,context,inferred);
        queryCache.put(new Element(key,result));

        // cache the nodes of the triples and the triples themselves
        Set<KiWiNode> nodes = new HashSet<KiWiNode>();
        for(KiWiTriple triple : result) {
            Collections.addAll(nodes, new KiWiNode[]{triple.getSubject(), triple.getObject(), triple.getPredicate(), triple.getContext()});
            queryCache.put(new Element(createCacheKey(triple.getSubject(),triple.getPredicate(),triple.getObject(),triple.getContext(),triple.isInferred()), ImmutableList.of(triple)));
        }

        // special optimisation: when only the subject (and optionally context) is given, we also fill the caches for
        // all property values
        if(subject != null && property == null && object == null) {
            HashMap<KiWiUriResource,List<KiWiTriple>> properties = new HashMap<KiWiUriResource, List<KiWiTriple>>();
            for(KiWiTriple triple : result) {
                List<KiWiTriple> values = properties.get(triple.getPredicate());
                if(values == null) {
                    values = new LinkedList<KiWiTriple>();
                    properties.put(triple.getPredicate(),values);
                }
                values.add(triple);
            }
            for(Map.Entry<KiWiUriResource,List<KiWiTriple>> entry : properties.entrySet()) {
                IntArray key2 = createCacheKey(subject,entry.getKey(),null,context,inferred);
                queryCache.put(new Element(key2,entry.getValue()));
            }
        }


    }


    /**
     * Add the triple given as argument to the triple cache. This method ensures that all other cache entries that
     * are affected by the addition of this triple will be expired.
     *
     * @param triple
     */
    public void cacheTriple(KiWiTriple triple) {
        tripleUpdated(triple);
        cacheTriples(triple.getSubject(), triple.getPredicate(), triple.getObject(), triple.getContext(), triple.isInferred(), Collections.singletonList(triple));
    }


    /**
     * Remove the triple given as argument from the triple cache. This method ensures that all other cache entries
     * that are affected by the removal of this triple will be expired.
     * @param triple
     */
    public void removeTriple(KiWiTriple triple) {
        tripleUpdated(triple);
    }


    /**
     * Clear all contents of the query cache.
     */
    public void clearAll() {
        queryCache.removeAll();
    }


    /**
     * Notify the cache that the triple passed as argument has been updated and that all cache entries affected by
     * the triple update need to be cleared.
     *
     * @param triple
     */
    public void tripleUpdated(KiWiTriple triple) {
        queryCache.remove(createCacheKey(null,null,null,null,false));
        queryCache.remove(createCacheKey(null,null,null,null,true));

        // remove all possible combinations of this triple as they may appear in the cache
        queryCache.remove(createCacheKey(triple.getSubject(),null,null,null,false));
        queryCache.remove(createCacheKey(triple.getSubject(),null,null,null,true));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),null,null,false));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),null,null,true));
        queryCache.remove(createCacheKey(null,null,triple.getObject(),null,false));
        queryCache.remove(createCacheKey(null,null,triple.getObject(),null,true));
        queryCache.remove(createCacheKey(null,null,null,triple.getContext(),false));
        queryCache.remove(createCacheKey(null,null,null,triple.getContext(),true));

        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),null,null,false));
        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),null,null,true));
        queryCache.remove(createCacheKey(triple.getSubject(),null,triple.getObject(),null,false));
        queryCache.remove(createCacheKey(triple.getSubject(),null,triple.getObject(),null,true));
        queryCache.remove(createCacheKey(triple.getSubject(),null,null,triple.getContext(),false));
        queryCache.remove(createCacheKey(triple.getSubject(),null,null,triple.getContext(),true));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),triple.getObject(),null,false));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),triple.getObject(),null,true));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),null,triple.getContext(),false));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),null,triple.getContext(),true));
        queryCache.remove(createCacheKey(null,null,triple.getObject(),triple.getContext(),false));
        queryCache.remove(createCacheKey(null,null,triple.getObject(),triple.getContext(),true));


        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),triple.getObject(),null,false));
        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),triple.getObject(),null,true));
        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),null,triple.getContext(),false));
        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),null,triple.getContext(),true));
        queryCache.remove(createCacheKey(triple.getSubject(),null,triple.getObject(),triple.getContext(),false));
        queryCache.remove(createCacheKey(triple.getSubject(),null,triple.getObject(),triple.getContext(),true));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),triple.getObject(),triple.getContext(),false));
        queryCache.remove(createCacheKey(null,triple.getPredicate(),triple.getObject(),triple.getContext(),true));

        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),triple.getObject(),triple.getContext(),false));
        queryCache.remove(createCacheKey(triple.getSubject(),triple.getPredicate(),triple.getObject(),triple.getContext(),true));
    }


    private static IntArray createCacheKey(KiWiResource subject, KiWiUriResource property, KiWiNode object, KiWiResource context, boolean inferred){

        // the cache key is generated by appending the bytes of the hashcodes of subject, property, object, context and inferred and
        // storing them as a BigInteger; generating the cache key should thus be very efficient

        int s = subject != null ? subject.hashCode() : Integer.MIN_VALUE;
        int p = property != null ? property.hashCode() : Integer.MIN_VALUE;
        int o = object != null ? object.hashCode() : Integer.MIN_VALUE;
        int c = context != null ? context.hashCode() : Integer.MIN_VALUE;

        IntBuffer bb = IntBuffer.allocate(5);
        bb.put(s);
        bb.put(p);
        bb.put(o);
        bb.put(c);
        bb.put( (byte) (inferred ? 1 : 0) );

        return new IntArray(bb.array());

    }
}
TOP

Related Classes of org.apache.marmotta.kiwi.caching.KiWiQueryCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.