Implemented VC caching & deserialization with string[] and cache option.

Change-Id: I42a7d4211d903587254d6b7fc2d6c242e55a2032
diff --git a/src/main/java/de/ids_mannheim/korap/Krill.java b/src/main/java/de/ids_mannheim/korap/Krill.java
index 46f48cf..d395fec 100644
--- a/src/main/java/de/ids_mannheim/korap/Krill.java
+++ b/src/main/java/de/ids_mannheim/korap/Krill.java
@@ -1,22 +1,19 @@
 package de.ids_mannheim.korap;
 
-import java.io.*;
-import java.util.*;
+import java.io.IOException;
 
 import org.apache.lucene.search.spans.SpanQuery;
-import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
-import de.ids_mannheim.korap.KrillIndex;
-import de.ids_mannheim.korap.response.Result;
-import de.ids_mannheim.korap.util.QueryException;
-import de.ids_mannheim.korap.response.Notifications;
-import de.ids_mannheim.korap.response.Response;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.JsonNode;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import de.ids_mannheim.korap.query.wrap.SpanQueryWrapper;
+import de.ids_mannheim.korap.response.Response;
+import de.ids_mannheim.korap.response.Result;
+import de.ids_mannheim.korap.util.QueryException;
+
 /**
  * <p>Krill is a corpus data retrieval index using Lucene for
  * Look-Ups.</p>
@@ -61,7 +58,6 @@
     private KrillIndex index;
     private SpanQuery spanQuery;
     private JsonNode request;
-    private String spanContext;
 
     private final ObjectMapper mapper = new ObjectMapper();
 
diff --git a/src/main/java/de/ids_mannheim/korap/KrillCollection.java b/src/main/java/de/ids_mannheim/korap/KrillCollection.java
index 8145f86..19f06ae 100644
--- a/src/main/java/de/ids_mannheim/korap/KrillCollection.java
+++ b/src/main/java/de/ids_mannheim/korap/KrillCollection.java
@@ -1,10 +1,10 @@
 package de.ids_mannheim.korap;
 
 import java.io.IOException;
-import java.io.Serializable;
 import java.nio.ByteBuffer;
-import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.lucene.index.DocsAndPositionsEnum;
 import org.apache.lucene.index.LeafReader;
@@ -26,8 +26,9 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
 
-import de.ids_mannheim.korap.collection.CachedCollection;
+import de.ids_mannheim.korap.collection.CachedVCData;
 import de.ids_mannheim.korap.collection.CollectionBuilder;
+import de.ids_mannheim.korap.collection.SerializableDocIdSet;
 import de.ids_mannheim.korap.response.Notifications;
 import de.ids_mannheim.korap.util.QueryException;
 import de.ids_mannheim.korap.util.StatusCodes;
@@ -59,7 +60,7 @@
     private CollectionBuilder cb = new CollectionBuilder();
     private CollectionBuilder.Interface cbi;
     private byte[] pl = new byte[4];
-    private static ByteBuffer bb = ByteBuffer.allocate(4);
+    // private static ByteBuffer bb = ByteBuffer.allocate(4);
 
     // Logger
     private final static Logger log =
@@ -68,10 +69,11 @@
     // This advices the java compiler to ignore all loggings
     public static final boolean DEBUG = false;
 
-    public static Cache cache = CacheManager.newInstance().getCache("named_vc");
-    private boolean isNamedVC = false;
-    private Serializable name;
-    
+    public static CacheManager cacheManager = CacheManager.newInstance();
+    public static Cache cache = cacheManager.getCache("named_vc");
+    private String name;
+    private boolean toCache = false;
+
     /**
      * Construct a new KrillCollection.
      * 
@@ -91,12 +93,31 @@
 
 
     /**
+     * Constructs a KrillCollection according to the given KrillIndex
+     * and KoralQuery.
+     * 
+     * KrillIndex is necessary for caching virtual corpora.
+     * 
+     * @param index
+     * @param jsonString
+     */
+    public KrillCollection (KrillIndex index, String jsonString) {
+        this.index = index;
+        createCollection(jsonString);
+    };
+
+
+    /**
      * Construct a new KrillCollection by passing a KoralQuery.
      * 
      * @param json
      *            The KoralQuery document as a JSON string.
      */
     public KrillCollection (String jsonString) {
+        createCollection(jsonString);
+    }
+
+    public void createCollection (String jsonString) {
         ObjectMapper mapper = new ObjectMapper();
         try {
             JsonNode json = mapper.readTree(jsonString);
@@ -191,12 +212,27 @@
 
         String type = json.get("@type").asText();
 
+        if (json.has("cache")) {
+            setToCache(json.get("cache").asBoolean());
+        }
+
         if (type.equals("koral:doc")) {
 
+            // default key
             String key = "tokens";
             String valtype = "type:string";
             String match = "match:eq";
 
+            if (isToCache()) {
+                if (!json.has("name")) {
+                    throw new QueryException(StatusCodes.MISSING_ID,
+                            "Collection id or name is required for caching.");
+                }
+                else {
+                    setName(json.get("name").asText());
+                }
+            }
+
             if (json.has("key")) key = json.get("key").asText();
 
             if (json.has("type")) valtype = json.get("type").asText();
@@ -291,13 +327,37 @@
 
                 throw new QueryException(841,
                         "Match relation unknown for type");
-            };
+            }
+
+            else if (valtype.equals("type:string[]")) {
+
+                if (json.has("match")) {
+                    match = json.get("match").asText();
+                }
+
+                CollectionBuilder.Group group = null;
+                if (match.equals("match:eq")) {
+                    group = this.cb.orGroup();
+                    for (JsonNode value : json.get("value")) {
+                        group.with(cb.term(key, value.asText()));
+                    }
+                }
+                else if (match.equals("match:ne")) {
+                    group = this.cb.andGroup();
+                    for (JsonNode value : json.get("value")) {
+                        group.with(cb.term(key, value.asText()).not());
+                    }
+                }
+                return group;
+            }
 
             throw new QueryException(843, "Document type is not supported");
         }
 
         // nested group
-        else if (type.equals("koral:docGroup")) {
+        else if (type.equals("koral:docGroup"))
+
+        {
 
             if (!json.has("operands") || !json.get("operands").isArray())
                 throw new QueryException(842,
@@ -328,22 +388,22 @@
                 throw new QueryException(StatusCodes.MISSING_VC_REFERENCE,
                         "ref is not found");
             }
-            
+
             String ref = json.get("ref").asText();
-            if (ref.isEmpty()){
+            if (ref.isEmpty()) {
                 throw new QueryException(StatusCodes.MISSING_VC_REFERENCE,
                         "ref is empty");
             }
-            
+
             Element element = cache.get(ref);
-            if (element == null){
+            if (element == null) {
                 this.addError(StatusCodes.MISSING_COLLECTION,
                         "Collection is not found.");
                 return this.build().nothing();
             }
             else {
-               CachedCollection cc = (CachedCollection) element.getObjectValue();
-               return cb.namedVC(cc);
+                CachedVCData cc = (CachedVCData) element.getObjectValue();
+                return cb.namedVC(cc);
             }
         }
 
@@ -471,7 +531,7 @@
      * @throws IOException
      */
     public FixedBitSet bits (LeafReaderContext atomic) throws IOException {
-        
+
         LeafReader r = atomic.reader();
         FixedBitSet bitset = new FixedBitSet(r.maxDoc());
         DocIdSet docids = this.getDocIdSet(atomic, (Bits) r.getLiveDocs());
@@ -662,11 +722,11 @@
                                 4);
 
                         // Add payload as integer
-                        occurrences += bb.wrap(pl).getInt();
+                        occurrences += ByteBuffer.wrap(pl).getInt();
 
                         if (DEBUG) log.debug(
                                 "Value for {} incremented by {} to {} in {}",
-                                term, bb.wrap(pl).getInt(), occurrences,
+                                term, ByteBuffer.wrap(pl).getInt(), occurrences,
                                 docs.docID());
                     };
                 };
@@ -719,20 +779,43 @@
     };
 
 
-    private void createDocVector () {
-        List<FixedBitSet> bitSetList = new ArrayList<>();
-        try {
-            FixedBitSet bitset;
-            for (LeafReaderContext atomic : this.index.reader().leaves()) {
-                if ((bitset = this.bits(atomic)) != null) {
-                    bitSetList.add(bitset);
-                }
-            };
-        }
-        catch (IOException e) {
-            log.warn(e.getLocalizedMessage());
-        };
+    public CachedVCData storeInCache () throws IOException {
+        List<LeafReaderContext> leaves = this.index.reader().leaves();
+        Map<Integer, DocIdSet> docIdMap =
+                new HashMap<Integer, DocIdSet>(leaves.size());
 
+        for (LeafReaderContext context : leaves) {
+            if (docIdMap.get(context.hashCode()) == null) {
+                FixedBitSet bitset = bits(context);
+                docIdMap.put(context.hashCode(),
+                        new SerializableDocIdSet(bitset));
+            }
+        }
+
+        CachedVCData cc = new CachedVCData(docIdMap);
+        cache.put(new Element(getName(), cc));
+
+        this.cbi = cb.namedVC(cc);
+        return cc;
+    }
+
+    public String getName () {
+        return name;
+    }
+
+
+    public void setName (String name) {
+        this.name = name;
+    }
+
+
+    public boolean isToCache () {
+        return toCache;
+    }
+
+
+    public void setToCache (boolean toCache) {
+        this.toCache = toCache;
     }
 
     /*
diff --git a/src/main/java/de/ids_mannheim/korap/KrillIndex.java b/src/main/java/de/ids_mannheim/korap/KrillIndex.java
index b545cad..8aa57c8 100644
--- a/src/main/java/de/ids_mannheim/korap/KrillIndex.java
+++ b/src/main/java/de/ids_mannheim/korap/KrillIndex.java
@@ -1,44 +1,79 @@
 package de.ids_mannheim.korap;
 
-// Krill classes
-import de.ids_mannheim.korap.index.*;
-import de.ids_mannheim.korap.response.*;
-import de.ids_mannheim.korap.query.SpanElementQuery;
-import de.ids_mannheim.korap.util.KrillProperties;
-import de.ids_mannheim.korap.util.QueryException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteBuffer;
+// Java core classes
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.regex.Pattern;
+import java.util.zip.GZIPInputStream;
 
-// Lucene classes
-import org.apache.lucene.search.*;
-import org.apache.lucene.search.spans.*;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.index.*;
-import org.apache.lucene.index.IndexWriterConfig.OpenMode;
-import org.apache.lucene.store.*;
 import org.apache.lucene.analysis.Analyzer;
 /*
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
 import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
 */
 import org.apache.lucene.analysis.miscellaneous.PerFieldAnalyzerWrapper;
-import org.apache.lucene.analysis.util.CharArraySet;
-import org.apache.lucene.util.*;
-import org.apache.lucene.util.automaton.*;
-
-// JSON helper class
-import com.fasterxml.jackson.annotation.*;
-import com.fasterxml.jackson.databind.ObjectMapper;
-
+import org.apache.lucene.document.Document;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.DocsAndPositionsEnum;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.IndexableField;
+import org.apache.lucene.index.LeafReaderContext;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.TermContext;
+import org.apache.lucene.index.Terms;
+import org.apache.lucene.index.TermsEnum;
+// Lucene classes
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.QueryWrapperFilter;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.spans.SpanQuery;
+import org.apache.lucene.search.spans.Spans;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.RAMDirectory;
+import org.apache.lucene.util.Bits;
+import org.apache.lucene.util.BytesRef;
+import org.apache.lucene.util.FixedBitSet;
+import org.apache.lucene.util.automaton.CompiledAutomaton;
+import org.apache.lucene.util.automaton.RegExp;
 // Log4j Logger classes
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-// Java core classes
-import java.util.*;
-import java.util.zip.GZIPInputStream;
-import java.util.regex.Pattern;
-import java.io.*;
-import java.net.URL;
-import java.nio.ByteBuffer;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+// Krill classes
+import de.ids_mannheim.korap.index.FieldDocument;
+import de.ids_mannheim.korap.index.KeywordAnalyzer;
+import de.ids_mannheim.korap.index.PositionsToOffset;
+import de.ids_mannheim.korap.index.SpanInfo;
+import de.ids_mannheim.korap.index.TermInfo;
+import de.ids_mannheim.korap.index.TextAnalyzer;
+import de.ids_mannheim.korap.index.TimeOutThread;
+import de.ids_mannheim.korap.response.Match;
+import de.ids_mannheim.korap.response.MatchCollector;
+import de.ids_mannheim.korap.response.MetaFields;
+import de.ids_mannheim.korap.response.Result;
+import de.ids_mannheim.korap.response.SearchContext;
+import de.ids_mannheim.korap.response.Text;
+import de.ids_mannheim.korap.util.KrillProperties;
+import de.ids_mannheim.korap.util.QueryException;
+import net.sf.ehcache.CacheManager;
 
 /**
  * <p>KrillIndex implements a simple API for searching in and writing
@@ -389,6 +424,7 @@
             log.error("Unable to add document");
         };
 
+        CacheManager.getInstance().clearAll();
         return doc;
     };
 
@@ -419,6 +455,7 @@
             log.error("Unable to delete documents");
         };
 
+        CacheManager.getInstance().clearAll();
         return false;
     };
 
@@ -467,6 +504,7 @@
             fd.setUID(uid);
             fd = this.addDoc(fd);
         };
+        CacheManager.getInstance().clearAll();
         return fd;
     };
 
@@ -522,6 +560,8 @@
             fd.setUID(uid);
             return this.addDoc(fd);
         };
+        
+        CacheManager.getInstance().clearAll();
         return fd;
     };
 
diff --git a/src/main/java/de/ids_mannheim/korap/collection/CachedCollection.java b/src/main/java/de/ids_mannheim/korap/collection/CachedCollection.java
deleted file mode 100644
index 9d393f0..0000000
--- a/src/main/java/de/ids_mannheim/korap/collection/CachedCollection.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package de.ids_mannheim.korap.collection;
-
-import java.util.Map;
-
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.search.DocIdSet;
-
-public class CachedCollection {
-
-    private Map<LeafReaderContext, DocIdSet> docIdMap;
-    
-    public Map<LeafReaderContext, DocIdSet> getDocIdMap () {
-        return docIdMap;
-    }
-
-    public void setDocIdMap (Map<LeafReaderContext, DocIdSet> docIdMap) {
-        this.docIdMap = docIdMap;
-    }
-    
-}
diff --git a/src/main/java/de/ids_mannheim/korap/collection/CachedVCData.java b/src/main/java/de/ids_mannheim/korap/collection/CachedVCData.java
new file mode 100644
index 0000000..d4bae4f
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/collection/CachedVCData.java
@@ -0,0 +1,29 @@
+package de.ids_mannheim.korap.collection;
+
+import java.io.Serializable;
+import java.util.Map;
+
+import org.apache.lucene.search.DocIdSet;
+
+public class CachedVCData implements Serializable{
+
+    /** Auto generated
+     * 
+     */
+    private static final long serialVersionUID = 5635087441839303653L;
+    
+    private Map<Integer, DocIdSet> docIdMap;
+    
+    public CachedVCData (Map<Integer, DocIdSet> docIdMap) {
+        this.docIdMap = docIdMap;
+    }
+    
+    public Map<Integer, DocIdSet> getDocIdMap () {
+        return docIdMap;
+    }
+
+    public void setDocIdMap (Map<Integer, DocIdSet> docIdMap) {
+        this.docIdMap = docIdMap;
+    }
+    
+}
diff --git a/src/main/java/de/ids_mannheim/korap/collection/NamedVCFilter.java b/src/main/java/de/ids_mannheim/korap/collection/CachedVCFilter.java
similarity index 67%
rename from src/main/java/de/ids_mannheim/korap/collection/NamedVCFilter.java
rename to src/main/java/de/ids_mannheim/korap/collection/CachedVCFilter.java
index 63e89e0..39a5d93 100644
--- a/src/main/java/de/ids_mannheim/korap/collection/NamedVCFilter.java
+++ b/src/main/java/de/ids_mannheim/korap/collection/CachedVCFilter.java
@@ -7,11 +7,11 @@
 import org.apache.lucene.search.Filter;
 import org.apache.lucene.util.Bits;
 
-public class NamedVCFilter extends Filter {
+public class CachedVCFilter extends Filter {
 
-    private CachedCollection cachedCollection;
+    private CachedVCData cachedCollection;
     
-    public NamedVCFilter (CachedCollection cachedCollection) {
+    public CachedVCFilter (CachedVCData cachedCollection) {
         this.cachedCollection = cachedCollection;
     }
 
@@ -19,7 +19,7 @@
     public DocIdSet getDocIdSet (LeafReaderContext context, Bits acceptDocs)
             throws IOException {
         
-        return cachedCollection.getDocIdMap().get(context);
+        return cachedCollection.getDocIdMap().get(context.hashCode());
     }
 
 }
diff --git a/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilder.java b/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilder.java
index 3fceebb..b3ee552 100644
--- a/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilder.java
+++ b/src/main/java/de/ids_mannheim/korap/collection/CollectionBuilder.java
@@ -373,18 +373,18 @@
         };
     };
     
-    public class NamedVC implements CollectionBuilder.Interface {
+    public class CachedVC implements CollectionBuilder.Interface {
 
-        private CachedCollection cachedCollection;
+        private CachedVCData cachedCollection;
         private boolean isNegative = false;
 
-        public NamedVC (CachedCollection cc) {
+        public CachedVC (CachedVCData cc) {
             this.cachedCollection = cc;
         }
 
         @Override
         public Filter toFilter () {
-            return new NamedVCFilter(cachedCollection);
+            return new CachedVCFilter(cachedCollection);
         }
 
         @Override
@@ -400,7 +400,7 @@
         
     }
 
-    public Interface namedVC (CachedCollection cc) {
-        return new CollectionBuilder.NamedVC(cc);
+    public Interface namedVC (CachedVCData cc) {
+        return new CollectionBuilder.CachedVC(cc);
     }
 };
diff --git a/src/main/java/de/ids_mannheim/korap/collection/SerializableDocIdSet.java b/src/main/java/de/ids_mannheim/korap/collection/SerializableDocIdSet.java
new file mode 100644
index 0000000..22907fe
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/collection/SerializableDocIdSet.java
@@ -0,0 +1,19 @@
+package de.ids_mannheim.korap.collection;
+
+import java.io.Serializable;
+
+import org.apache.lucene.util.BitDocIdSet;
+import org.apache.lucene.util.BitSet;
+
+public class SerializableDocIdSet extends BitDocIdSet implements Serializable {
+
+    /**
+     * Auto generated
+     * 
+     */
+    private static final long serialVersionUID = 171797306573832807L;
+
+    public SerializableDocIdSet (BitSet set) {
+        super(set);
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/util/StatusCodes.java b/src/main/java/de/ids_mannheim/korap/util/StatusCodes.java
index 9aad2f0..b9067ae 100644
--- a/src/main/java/de/ids_mannheim/korap/util/StatusCodes.java
+++ b/src/main/java/de/ids_mannheim/korap/util/StatusCodes.java
@@ -68,12 +68,14 @@
     public static final int INVALID_REGEX = 807;
     public static final int UNKNOWN_REWRITE_OPERATION = 814;
     public static final int MISSING_SOURCE = 815;
+    public static final int MISSING_ID = 816;
     public static final int MISSING_VALUE = 820;
     public static final int EMPTY_FILTER = 830;
     public static final int UNWRAPPABLE_FILTER = 831;
     public static final int INVALID_FILTER_OPERATION = 832;
     public static final int UNSUPPORTED_TYPE = 843;
     public static final int COLLECTIONS_UNSUPPORTED = 850;
+    public static final int CACHING_COLLECTION_FAILED = 851;
 
     // 900 - 999 - Corpus Data errors 
     public static final int INVALID_OFFSET = 952;
diff --git a/src/test/java/de/ids_mannheim/korap/collection/TestVCCaching.java b/src/test/java/de/ids_mannheim/korap/collection/TestVCCaching.java
new file mode 100644
index 0000000..108c1e2
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/collection/TestVCCaching.java
@@ -0,0 +1,77 @@
+package de.ids_mannheim.korap.collection;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.lucene.store.MMapDirectory;
+import org.junit.Test;
+
+import de.ids_mannheim.korap.Krill;
+import de.ids_mannheim.korap.KrillCollection;
+import de.ids_mannheim.korap.KrillIndex;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+
+public class TestVCCaching {
+
+    private KrillIndex getSampleIndex () throws IOException {
+        return new KrillIndex(new MMapDirectory(
+                Paths.get(getClass().getResource("/sample-index").getFile())));
+
+    }
+
+    private KrillIndex index;
+
+    public TestVCCaching () throws IOException {
+        index = getSampleIndex();
+    }
+
+    @Test
+    public void testCacheVC () throws IOException {
+        InputStream is = getClass().getClassLoader()
+                .getResourceAsStream("named-vc/named-vc-free.jsonld");
+        String json = IOUtils.toString(is);
+
+        KrillCollection kc = new KrillCollection(json);
+        kc.setIndex(index);
+        kc.storeInCache();
+
+        Element element = KrillCollection.cache.get("cache-goe");
+        CachedVCData cc = (CachedVCData) element.getObjectValue();
+
+        assertTrue(cc.getDocIdMap().size() > 0);
+
+        testSearchCachedVC();
+        testClearCache();
+    }
+
+    private void testSearchCachedVC () throws IOException {
+        InputStream is = getClass().getClassLoader()
+                .getResourceAsStream("collection/query-with-vc-ref.jsonld");
+        String json = IOUtils.toString(is);
+
+        String result = new Krill(json).apply(this.index).toJsonString();
+        assertNotNull(result);
+        assertTrue(!result.isEmpty());
+
+        // test with match:eq
+        json.replaceFirst("match:ne", "match:eq");
+        result = new Krill(json).apply(this.index).toJsonString();
+        assertNotNull(result);
+        assertTrue(!result.isEmpty());
+    }
+    
+    public void testClearCache () {
+        CacheManager cacheManager = CacheManager.getInstance();
+        cacheManager.clearAll();
+        
+        Element element = KrillCollection.cache.get("cache-goe");
+        assertNull(element);
+    }
+}
diff --git a/src/test/resources/collection/query-with-vc-ref.jsonld b/src/test/resources/collection/query-with-vc-ref.jsonld
new file mode 100644
index 0000000..d50cd2a
--- /dev/null
+++ b/src/test/resources/collection/query-with-vc-ref.jsonld
@@ -0,0 +1,15 @@
+{"query":{
+    "@type":"koral:token",
+    "wrap":{
+      "@type":"koral:term",
+      "layer":"orth",
+      "key":"der",
+      "match":"match:eq",
+      "foundry":"opennlp"
+    }
+  },
+  "collection": {
+    "@type": "koral:docGroupRef",
+    "ref": "cache-goe"
+  }
+}
diff --git a/src/test/resources/named-vc/named-vc-free.jsonld b/src/test/resources/named-vc/named-vc-free.jsonld
index 4e8cd83..1f90e4c 100644
--- a/src/test/resources/named-vc/named-vc-free.jsonld
+++ b/src/test/resources/named-vc/named-vc-free.jsonld
@@ -2,10 +2,11 @@
     "name" : "cache-goe",
     "@type": "koral:doc",
     "key": "textSigle",
-    "match": "match:eq",
+    "match": "match:ne",
+    "type" : "type:string[]",
     "value": [
         "GOE/AGF/00000",
         "GOE/AGA/01784"
-    ]
-}}
-
+    ],
+    "cache" : "true"
+}}
\ No newline at end of file