http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/analysis/LongAnalyzerReal.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/analysis/LongAnalyzerReal.java 
b/src/blur-core/src/main/java/org/apache/blur/analysis/LongAnalyzerReal.java
new file mode 100644
index 0000000..5eb4c7e
--- /dev/null
+++ b/src/blur-core/src/main/java/org/apache/blur/analysis/LongAnalyzerReal.java
@@ -0,0 +1,77 @@
+package org.apache.blur.analysis;
+/**
+ * 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.
+ */
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.NumericTokenStream;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.util.NumericUtils;
+
+public class LongAnalyzerReal extends Analyzer {
+
+  private static final String TYPE = "long";
+  private int precisionStepDefault = NumericUtils.PRECISION_STEP_DEFAULT;
+  private int radix = 10;
+
+  public LongAnalyzerReal(String typeStr) {
+    if (typeStr.startsWith(TYPE)) {
+      int index = typeStr.indexOf(',');
+      if (index > 0) {
+        String[] s = typeStr.split(",");
+        if (s.length > 1) {
+          try {
+            precisionStepDefault = Integer.parseInt(s[1]);
+          } catch (NumberFormatException e) {
+            throw new RuntimeException("Can not parser [" + s[1] + "] into an 
integer for the precisionStepDefault.");
+          }
+        }
+        if (s.length > 2) {
+          try {
+            precisionStepDefault = Integer.parseInt(s[2]);
+          } catch (NumberFormatException e) {
+            throw new RuntimeException("Can not parser [" + s[2] + "] into an 
integer for the radix.");
+          }
+        }
+      }
+    } else {
+      throw new RuntimeException("Long type can not parser [" + typeStr + "]");
+    }
+  }
+
+  @Override
+  public TokenStream tokenStream(String fieldName, Reader reader) {
+    NumericTokenStream numericTokenStream = new 
NumericTokenStream(precisionStepDefault);
+    try {
+      numericTokenStream.setLongValue(toLong(reader));
+    } catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+    return numericTokenStream;
+  }
+
+  private long toLong(Reader reader) throws IOException {
+    StringBuilder builder = new StringBuilder(20);
+    int read;
+    while ((read = reader.read()) != -1) {
+      builder.append((char) read);
+    }
+    return Long.parseLong(builder.toString(), radix);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/AbstractWrapperQuery.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/AbstractWrapperQuery.java
 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/AbstractWrapperQuery.java
new file mode 100644
index 0000000..5fa4116
--- /dev/null
+++ 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/AbstractWrapperQuery.java
@@ -0,0 +1,82 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import java.io.IOException;
+import java.util.Set;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Similarity;
+import org.apache.lucene.search.Weight;
+
+@SuppressWarnings("deprecation")
+public abstract class AbstractWrapperQuery extends Query {
+  private static final long serialVersionUID = -4512813621542220044L;
+  protected Query _query;
+  protected boolean _rewritten;
+
+  public AbstractWrapperQuery(Query query) {
+    this(query, false);
+  }
+
+  public AbstractWrapperQuery(Query query, boolean rewritten) {
+    this._query = query;
+    this._rewritten = rewritten;
+  }
+
+  public abstract Object clone();
+
+  public Query combine(Query[] queries) {
+    return _query.combine(queries);
+  }
+
+  public abstract Weight createWeight(Searcher searcher) throws IOException;
+
+  public boolean equals(Object obj) {
+    return _query.equals(obj);
+  }
+
+  public void extractTerms(Set<Term> terms) {
+    _query.extractTerms(terms);
+  }
+
+  public float getBoost() {
+    return _query.getBoost();
+  }
+
+  public Similarity getSimilarity(Searcher searcher) {
+    return _query.getSimilarity(searcher);
+  }
+
+  public int hashCode() {
+    return _query.hashCode();
+  }
+
+  public abstract Query rewrite(IndexReader reader) throws IOException;
+
+  public void setBoost(float b) {
+    _query.setBoost(b);
+  }
+
+  public abstract String toString();
+
+  public abstract String toString(String field);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/FacetQuery.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/FacetQuery.java 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/FacetQuery.java
new file mode 100644
index 0000000..980493c
--- /dev/null
+++ b/src/blur-core/src/main/java/org/apache/blur/lucene/search/FacetQuery.java
@@ -0,0 +1,201 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicLongArray;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Weight;
+
+@SuppressWarnings("deprecation")
+public class FacetQuery extends AbstractWrapperQuery {
+
+  private static final long serialVersionUID = -9131606859383383004L;
+  private Query[] facets;
+  private AtomicLongArray counts;
+
+  public FacetQuery(Query query, Query[] facets, AtomicLongArray counts) {
+    super(query, false);
+    this.facets = facets;
+    this.counts = counts;
+  }
+
+  public FacetQuery(Query query, Query[] facets, AtomicLongArray counts, 
boolean rewritten) {
+    super(query, rewritten);
+    this.facets = facets;
+    this.counts = counts;
+  }
+
+  public String toString() {
+    return "facet:{" + _query.toString() + "}";
+  }
+
+  public String toString(String field) {
+    return "facet:{" + _query.toString(field) + "}";
+  }
+
+  @Override
+  public Object clone() {
+    return new FacetQuery((Query) _query.clone(), facets, counts, _rewritten);
+  }
+
+  @Override
+  public Query rewrite(IndexReader reader) throws IOException {
+    if (_rewritten) {
+      return this;
+    }
+    for (int i = 0; i < facets.length; i++) {
+      facets[i] = facets[i].rewrite(reader);
+    }
+    return new FacetQuery(_query.rewrite(reader), facets, counts, true);
+  }
+
+  @Override
+  public Weight createWeight(Searcher searcher) throws IOException {
+    Weight weight = _query.createWeight(searcher);
+    return new FacetWeight(weight, getWeights(searcher), counts);
+  }
+
+  private Weight[] getWeights(Searcher searcher) throws IOException {
+    Weight[] weights = new Weight[facets.length];
+    for (int i = 0; i < weights.length; i++) {
+      weights[i] = facets[i].createWeight(searcher);
+    }
+    return weights;
+  }
+
+  public static class FacetWeight extends Weight {
+
+    private static final long serialVersionUID = -5649908738708119094L;
+    private Weight weight;
+    private Weight[] facets;
+    private AtomicLongArray counts;
+
+    public FacetWeight(Weight weight, Weight[] facets, AtomicLongArray counts) 
{
+      this.weight = weight;
+      this.facets = facets;
+      this.counts = counts;
+    }
+
+    @Override
+    public Explanation explain(IndexReader reader, int doc) throws IOException 
{
+      return weight.explain(reader, doc);
+    }
+
+    @Override
+    public Query getQuery() {
+      return weight.getQuery();
+    }
+
+    @Override
+    public float getValue() {
+      return weight.getValue();
+    }
+
+    @Override
+    public void normalize(float norm) {
+      weight.normalize(norm);
+    }
+
+    @Override
+    public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean 
topScorer) throws IOException {
+      Scorer scorer = weight.scorer(reader, true, topScorer);
+      if (scorer == null) {
+        return null;
+      }
+      return new FacetScorer(scorer, getScorers(reader, true, topScorer), 
counts);
+    }
+
+    private Scorer[] getScorers(IndexReader reader, boolean scoreDocsInOrder, 
boolean topScorer) throws IOException {
+      Scorer[] scorers = new Scorer[facets.length];
+      for (int i = 0; i < scorers.length; i++) {
+        scorers[i] = facets[i].scorer(reader, scoreDocsInOrder, topScorer);
+      }
+      return scorers;
+    }
+
+    @Override
+    public float sumOfSquaredWeights() throws IOException {
+      return weight.sumOfSquaredWeights();
+    }
+  }
+
+  public static class FacetScorer extends Scorer {
+
+    private Scorer baseScorer;
+    private Scorer[] facets;
+    private AtomicLongArray counts;
+    private int facetLength;
+
+    public FacetScorer(Scorer scorer, Scorer[] facets, AtomicLongArray counts) 
{
+      super(scorer.getSimilarity());
+      this.baseScorer = scorer;
+      this.facets = facets;
+      this.counts = counts;
+      this.facetLength = facets.length;
+    }
+
+    private int processFacets(int doc) throws IOException {
+      if (doc == NO_MORE_DOCS) {
+        return doc;
+      }
+      for (int i = 0; i < facetLength; i++) {
+        Scorer facet = facets[i];
+        if (facet == null) {
+          continue;
+        }
+        int docID = facet.docID();
+        if (docID == NO_MORE_DOCS) {
+          continue;
+        }
+        if (docID == doc) {
+          counts.incrementAndGet(i);
+        } else if (docID < doc) {
+          if (facet.advance(doc) == doc) {
+            counts.incrementAndGet(i);
+          }
+        }
+      }
+      return doc;
+    }
+
+    @Override
+    public float score() throws IOException {
+      return baseScorer.score();
+    }
+
+    @Override
+    public int advance(int target) throws IOException {
+      return processFacets(baseScorer.advance(target));
+    }
+
+    @Override
+    public int docID() {
+      return baseScorer.docID();
+    }
+
+    @Override
+    public int nextDoc() throws IOException {
+      return processFacets(baseScorer.nextDoc());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/FairSimilarity.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/FairSimilarity.java 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/FairSimilarity.java
new file mode 100644
index 0000000..f0203d1
--- /dev/null
+++ 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/FairSimilarity.java
@@ -0,0 +1,56 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import org.apache.lucene.index.FieldInvertState;
+import org.apache.lucene.search.Similarity;
+
+public class FairSimilarity extends Similarity {
+
+  private static final long serialVersionUID = 8819964136561756067L;
+
+  @Override
+  public float coord(int overlap, int maxOverlap) {
+    return 1;
+  }
+
+  @Override
+  public float idf(int docFreq, int numDocs) {
+    return 1;
+  }
+
+  @Override
+  public float queryNorm(float sumOfSquaredWeights) {
+    return 1;
+  }
+
+  @Override
+  public float sloppyFreq(int distance) {
+    return 1;
+  }
+
+  @Override
+  public float tf(float freq) {
+    return 1;
+  }
+
+  @Override
+  public float computeNorm(String field, FieldInvertState state) {
+    return 1;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/IterablePaging.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/IterablePaging.java 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/IterablePaging.java
new file mode 100644
index 0000000..06a106b
--- /dev/null
+++ 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/IterablePaging.java
@@ -0,0 +1,232 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+
+/**
+ * The {@link IterablePaging} class allows for easy paging through lucene hits.
+ */
+public class IterablePaging implements Iterable<ScoreDoc> {
+
+  private static int DEFAULT_NUMBER_OF_HITS_TO_COLLECT = 1000;
+  private IndexSearcher searcher;
+  private Query query;
+  private TotalHitsRef totalHitsRef = new TotalHitsRef();
+  private ProgressRef progressRef = new ProgressRef();
+  private int skipTo;
+  private int numHitsToCollect = DEFAULT_NUMBER_OF_HITS_TO_COLLECT;
+  private int gather = -1;
+  private AtomicBoolean running;
+
+  public IterablePaging(AtomicBoolean running, IndexSearcher searcher, Query 
query) throws IOException {
+    this(running, searcher, query, DEFAULT_NUMBER_OF_HITS_TO_COLLECT, null, 
null);
+  }
+
+  public IterablePaging(AtomicBoolean running, IndexSearcher searcher, Query 
query, int numHitsToCollect) throws IOException {
+    this(running, searcher, query, numHitsToCollect, null, null);
+  }
+
+  public IterablePaging(AtomicBoolean running, IndexSearcher searcher, Query 
query, int numHitsToCollect, TotalHitsRef totalHitsRef, ProgressRef 
progressRef) throws IOException {
+    this.running = running;
+    this.query = searcher.rewrite(query);
+    this.searcher = searcher;
+    this.numHitsToCollect = numHitsToCollect;
+    this.totalHitsRef = totalHitsRef == null ? this.totalHitsRef : 
totalHitsRef;
+    this.progressRef = progressRef == null ? this.progressRef : progressRef;
+  }
+
+  public static class TotalHitsRef {
+    // This is an atomic integer because more than likely if there is
+    // any status sent to the user, it will be done in another thread.
+    protected AtomicInteger totalHits = new AtomicInteger(0);
+
+    public int totalHits() {
+      return totalHits.get();
+    }
+  }
+
+  public static class ProgressRef {
+    // These are atomic integers because more than likely if there is
+    // any status sent to the user, it will be done in another thread.
+    protected AtomicInteger skipTo = new AtomicInteger(0);
+    protected AtomicInteger currentHitPosition = new AtomicInteger(0);
+    protected AtomicInteger searchesPerformed = new AtomicInteger(0);
+    protected AtomicLong queryTime = new AtomicLong(0);
+
+    public int skipTo() {
+      return skipTo.get();
+    }
+
+    public int currentHitPosition() {
+      return currentHitPosition.get();
+    }
+
+    public int searchesPerformed() {
+      return searchesPerformed.get();
+    }
+
+    public long queryTime() {
+      return queryTime.get();
+    }
+  }
+
+  /**
+   * Gets the total hits of the search.
+   * 
+   * @return the total hits.
+   */
+  public int getTotalHits() {
+    return totalHitsRef.totalHits();
+  }
+
+  /**
+   * Allows for gathering of the total hits of this search.
+   * 
+   * @param ref
+   *          {@link TotalHitsRef}.
+   * @return this.
+   */
+  public IterablePaging totalHits(TotalHitsRef ref) {
+    totalHitsRef = ref;
+    return this;
+  }
+
+  /**
+   * Skips the first x number of hits.
+   * 
+   * @param skipTo
+   *          the number hits to skip.
+   * @return this.
+   */
+  public IterablePaging skipTo(int skipTo) {
+    this.skipTo = skipTo;
+    return this;
+  }
+
+  /**
+   * Only gather up to x number of hits.
+   * 
+   * @param gather
+   *          the number of hits to gather.
+   * @return this.
+   */
+  public IterablePaging gather(int gather) {
+    this.gather = gather;
+    return this;
+  }
+
+  /**
+   * Allows for gathering the progress of the paging.
+   * 
+   * @param ref
+   *          the {@link ProgressRef}.
+   * @return this.
+   */
+  public IterablePaging progress(ProgressRef ref) {
+    this.progressRef = ref;
+    return this;
+  }
+
+  /**
+   * The {@link ScoreDoc} iterator.
+   */
+  @Override
+  public Iterator<ScoreDoc> iterator() {
+    return skipHits(new PagingIterator());
+  }
+
+  class PagingIterator implements Iterator<ScoreDoc> {
+    private PagingCollector collector;
+    private ScoreDoc[] scoreDocs;
+    private int counter = 0;
+    private int offset = 0;
+    private int endPosition = gather == -1 ? Integer.MAX_VALUE : skipTo + 
gather;
+
+    PagingIterator() {
+      search();
+    }
+
+    void search() {
+      long s = System.currentTimeMillis();
+      progressRef.searchesPerformed.incrementAndGet();
+      if (collector == null) {
+        collector = new PagingCollector(numHitsToCollect);
+      } else {
+        collector = new PagingCollector(numHitsToCollect, 
scoreDocs[scoreDocs.length - 1]);
+      }
+      try {
+        StopExecutionCollector stopExecutionCollector = new 
StopExecutionCollector(collector, running);
+        searcher.search(query, stopExecutionCollector);
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+
+      totalHitsRef.totalHits.set(collector.getTotalHits());
+      scoreDocs = collector.topDocs().scoreDocs;
+      long e = System.currentTimeMillis();
+      progressRef.queryTime.addAndGet(e - s);
+    }
+
+    @Override
+    public boolean hasNext() {
+      return counter < totalHitsRef.totalHits() && counter < endPosition ? 
true : false;
+    }
+
+    @Override
+    public ScoreDoc next() {
+      if (isCurrentCollectorExhausted()) {
+        search();
+        offset = 0;
+      }
+      progressRef.currentHitPosition.set(counter);
+      counter++;
+      return scoreDocs[offset++];
+    }
+
+    private boolean isCurrentCollectorExhausted() {
+      return offset < scoreDocs.length ? false : true;
+    }
+
+    @Override
+    public void remove() {
+      throw new RuntimeException("read only");
+    }
+  }
+
+  private Iterator<ScoreDoc> skipHits(Iterator<ScoreDoc> iterator) {
+    progressRef.skipTo.set(skipTo);
+    for (int i = 0; i < skipTo && iterator.hasNext(); i++) {
+      // eats the hits, and moves the iterator to the desired skip to position.
+      progressRef.currentHitPosition.set(i);
+      iterator.next();
+    }
+    return iterator;
+  }
+
+  public static void setDefaultNumberOfHitsToCollect(int num) {
+    DEFAULT_NUMBER_OF_HITS_TO_COLLECT = num;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/PagingCollector.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/PagingCollector.java
 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/PagingCollector.java
new file mode 100644
index 0000000..2bead97
--- /dev/null
+++ 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/PagingCollector.java
@@ -0,0 +1,119 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.TopDocsCollector;
+import org.apache.lucene.util.PriorityQueue;
+
+/**
+ * The {@link PagingCollector} allows for paging through lucene hits.
+ */
+public class PagingCollector extends TopDocsCollector<ScoreDoc> {
+
+  private ScoreDoc pqTop;
+  private int docBase;
+  private Scorer scorer;
+  private ScoreDoc previousPassLowest;
+  private int numHits;
+
+  public PagingCollector(int numHits) {
+    // creates an empty score doc so that i don't have to check for null
+    // each time.
+    this(numHits, new ScoreDoc(-1, Float.MAX_VALUE));
+  }
+
+  public PagingCollector(int numHits, ScoreDoc previousPassLowest) {
+    super(new HitQueue(numHits, true));
+    this.pqTop = pq.top();
+    this.numHits = numHits;
+    this.previousPassLowest = previousPassLowest;
+  }
+
+  @Override
+  public boolean acceptsDocsOutOfOrder() {
+    return true;
+  }
+
+  @Override
+  public void collect(int doc) throws IOException {
+    float score = scorer.score();
+    totalHits++;
+    doc += docBase;
+    if (score > previousPassLowest.score) {
+      // this hit was gathered on a previous page.
+      return;
+    } else if (score == previousPassLowest.score && doc <= 
previousPassLowest.doc) {
+      // if the scores are the same and the doc is less than or equal to the
+      // previous pass lowest hit doc then skip because this collector favors
+      // lower number documents.
+      return;
+    } else if (score < pqTop.score || (score == pqTop.score && doc > 
pqTop.doc)) {
+      return;
+    }
+    pqTop.doc = doc;
+    pqTop.score = score;
+    pqTop = pq.updateTop();
+  }
+
+  @Override
+  public void setNextReader(IndexReader reader, int docBase) throws 
IOException {
+    this.docBase = docBase;
+  }
+
+  @Override
+  public void setScorer(Scorer scorer) throws IOException {
+    this.scorer = scorer;
+  }
+
+  public ScoreDoc getLastScoreDoc(TopDocs topDocs) {
+    return topDocs.scoreDocs[(totalHits < numHits ? totalHits : numHits) - 1];
+  }
+
+  public ScoreDoc getLastScoreDoc(ScoreDoc[] scoreDocs) {
+    return scoreDocs[(totalHits < numHits ? totalHits : numHits) - 1];
+  }
+
+  public static class HitQueue extends PriorityQueue<ScoreDoc> {
+
+    private boolean prePopulate;
+
+    HitQueue(int size, boolean prePopulate) {
+      this.prePopulate = prePopulate;
+      initialize(size);
+    }
+
+    @Override
+    protected ScoreDoc getSentinelObject() {
+      return !prePopulate ? null : new ScoreDoc(Integer.MAX_VALUE, 
Float.NEGATIVE_INFINITY);
+    }
+
+    @Override
+    protected final boolean lessThan(ScoreDoc hitA, ScoreDoc hitB) {
+      if (hitA.score == hitB.score) {
+        return hitA.doc > hitB.doc;
+      } else {
+        return hitA.score < hitB.score;
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/StopExecutionCollector.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/StopExecutionCollector.java
 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/StopExecutionCollector.java
new file mode 100644
index 0000000..7a8eebe
--- /dev/null
+++ 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/StopExecutionCollector.java
@@ -0,0 +1,67 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.Scorer;
+
+public class StopExecutionCollector extends Collector {
+
+  private static final long _5MS = TimeUnit.MILLISECONDS.toNanos(5);
+
+  private Collector _collector;
+  private AtomicBoolean _running;
+  private long last;
+
+  public StopExecutionCollector(Collector collector, AtomicBoolean running) {
+    _collector = collector;
+    _running = running;
+  }
+
+  public static class StopExecutionCollectorException extends RuntimeException 
{
+    private static final long serialVersionUID = 5753875017543945163L;
+  }
+
+  public boolean acceptsDocsOutOfOrder() {
+    return _collector.acceptsDocsOutOfOrder();
+  }
+
+  public void collect(int doc) throws IOException {
+    long now = System.nanoTime();
+    if (last + _5MS < now) {
+      if (!_running.get()) {
+        throw new StopExecutionCollectorException();
+      }
+      last = now;
+    }
+    _collector.collect(doc);
+  }
+
+  public void setNextReader(IndexReader reader, int docBase) throws 
IOException {
+    _collector.setNextReader(reader, docBase);
+  }
+
+  public void setScorer(Scorer scorer) throws IOException {
+    _collector.setScorer(scorer);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperParser.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperParser.java 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperParser.java
new file mode 100644
index 0000000..124229b
--- /dev/null
+++ b/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperParser.java
@@ -0,0 +1,215 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import static org.apache.blur.utils.BlurConstants.SEP;
+import static org.apache.blur.utils.BlurConstants.SUPER;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.blur.thrift.generated.ScoreType;
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.queryParser.QueryParser;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.FilteredQuery;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.search.MultiPhraseQuery;
+import org.apache.lucene.search.PhraseQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.Version;
+
+
+public class SuperParser extends QueryParser {
+
+  private Map<Query, String> fieldNames = new HashMap<Query, String>();
+  private boolean superSearch = true;
+  private Filter queryFilter;
+  private final ScoreType scoreType;
+
+  public SuperParser(Version matchVersion, Analyzer a, boolean superSearch, 
Filter queryFilter, ScoreType scoreType) {
+    super(matchVersion, SUPER, a);
+    this.setAutoGeneratePhraseQueries(true);
+    this.setAllowLeadingWildcard(true);
+    this.superSearch = superSearch;
+    this.queryFilter = queryFilter;
+    this.scoreType = scoreType;
+  }
+
+  @Override
+  public Query parse(String query) throws ParseException {
+    return reprocess(super.parse(query));
+  }
+
+  @Override
+  protected Query newFuzzyQuery(Term term, float minimumSimilarity, int 
prefixLength) {
+    return addField(super.newFuzzyQuery(term, minimumSimilarity, 
prefixLength), term.field());
+  }
+
+  @Override
+  protected Query newMatchAllDocsQuery() {
+    return addField(super.newMatchAllDocsQuery(), 
UUID.randomUUID().toString());
+  }
+
+  @Override
+  protected MultiPhraseQuery newMultiPhraseQuery() {
+    return new MultiPhraseQuery() {
+      private static final long serialVersionUID = 2743009696906520410L;
+
+      @Override
+      public void add(Term[] terms, int position) {
+        super.add(terms, position);
+        for (Term term : terms) {
+          addField(this, term.field());
+        }
+      }
+    };
+  }
+
+  @Override
+  protected PhraseQuery newPhraseQuery() {
+    return new PhraseQuery() {
+      private static final long serialVersionUID = 1927750709523859808L;
+
+      @Override
+      public void add(Term term, int position) {
+        super.add(term, position);
+        addField(this, term.field());
+      }
+    };
+  }
+
+  @Override
+  protected Query newPrefixQuery(Term prefix) {
+    return addField(super.newPrefixQuery(prefix), prefix.field());
+  }
+
+  @Override
+  protected Query newRangeQuery(String field, String part1, String part2, 
boolean inclusive) {
+    return addField(super.newRangeQuery(field, part1, part2, inclusive), 
field);
+  }
+
+  @Override
+  protected Query newTermQuery(Term term) {
+    return addField(super.newTermQuery(term), term.field());
+  }
+
+  @Override
+  protected Query newWildcardQuery(Term t) {
+    if (SUPER.equals(t.field()) && "*".equals(t.text())) {
+      return new MatchAllDocsQuery();
+    }
+    return addField(super.newWildcardQuery(t), t.field());
+  }
+
+  private Query reprocess(Query query) {
+    if (query == null || !isSuperSearch()) {
+      return wrapFilter(query);
+    }
+    if (query instanceof BooleanQuery) {
+      BooleanQuery booleanQuery = (BooleanQuery) query;
+      if (isSameGroupName(booleanQuery)) {
+        return newSuperQuery(query);
+      } else {
+        List<BooleanClause> clauses = booleanQuery.clauses();
+        for (BooleanClause clause : clauses) {
+          clause.setQuery(reprocess(clause.getQuery()));
+        }
+        return booleanQuery;
+      }
+    } else {
+      return newSuperQuery(query);
+    }
+  }
+
+  private SuperQuery newSuperQuery(Query query) {
+    return new SuperQuery(wrapFilter(query), scoreType);
+  }
+
+  private Query wrapFilter(Query query) {
+    if (queryFilter == null) {
+      return query;
+    }
+    return new FilteredQuery(query, queryFilter);
+  }
+
+  private boolean isSameGroupName(BooleanQuery booleanQuery) {
+    String groupName = findFirstGroupName(booleanQuery);
+    if (groupName == null) {
+      return false;
+    }
+    return isSameGroupName(booleanQuery, groupName);
+  }
+
+  private boolean isSameGroupName(Query query, String groupName) {
+    if (query instanceof BooleanQuery) {
+      BooleanQuery booleanQuery = (BooleanQuery) query;
+      for (BooleanClause clause : booleanQuery.clauses()) {
+        if (!isSameGroupName(clause.getQuery(), groupName)) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      String fieldName = fieldNames.get(query);
+      String currentGroupName = getGroupName(fieldName);
+      if (groupName.equals(currentGroupName)) {
+        return true;
+      }
+      return false;
+    }
+  }
+
+  private String getGroupName(String fieldName) {
+    if (fieldName == null) {
+      return null;
+    }
+    int index = fieldName.indexOf(SEP);
+    if (index < 0) {
+      return null;
+    }
+    return fieldName.substring(0, index);
+  }
+
+  private String findFirstGroupName(Query query) {
+    if (query instanceof BooleanQuery) {
+      BooleanQuery booleanQuery = (BooleanQuery) query;
+      for (BooleanClause clause : booleanQuery.clauses()) {
+        return findFirstGroupName(clause.getQuery());
+      }
+      return null;
+    } else {
+      String fieldName = fieldNames.get(query);
+      return getGroupName(fieldName);
+    }
+  }
+
+  private Query addField(Query q, String field) {
+    fieldNames.put(q, field);
+    return q;
+  }
+
+  public boolean isSuperSearch() {
+    return superSearch;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperQuery.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperQuery.java 
b/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperQuery.java
new file mode 100644
index 0000000..ef24626
--- /dev/null
+++ b/src/blur-core/src/main/java/org/apache/blur/lucene/search/SuperQuery.java
@@ -0,0 +1,267 @@
+package org.apache.blur.lucene.search;
+
+/**
+ * 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.
+ */
+import java.io.IOException;
+
+import org.apache.blur.thrift.generated.ScoreType;
+import org.apache.blur.utils.PrimeDocCache;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.search.Weight;
+import org.apache.lucene.util.OpenBitSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@SuppressWarnings("deprecation")
+public class SuperQuery extends AbstractWrapperQuery {
+
+  private static final long serialVersionUID = -5901574044714034398L;
+  private ScoreType scoreType;
+
+  public SuperQuery(Query query, ScoreType scoreType) {
+    super(query, false);
+    this.scoreType = scoreType;
+  }
+
+  public SuperQuery(Query query, ScoreType scoreType, boolean rewritten) {
+    super(query, rewritten);
+    this.scoreType = scoreType;
+  }
+
+  public Object clone() {
+    return new SuperQuery((Query) _query.clone(), scoreType, _rewritten);
+  }
+
+  public Weight createWeight(Searcher searcher) throws IOException {
+    Weight weight = _query.createWeight(searcher);
+    return new SuperWeight(weight, _query.toString(), this, scoreType);
+  }
+
+  public Query rewrite(IndexReader reader) throws IOException {
+    if (_rewritten) {
+      return this;
+    }
+    return new SuperQuery(_query.rewrite(reader), scoreType, true);
+  }
+
+  public String toString() {
+    return "super:{" + _query.toString() + "}";
+  }
+
+  public String toString(String field) {
+    return "super:{" + _query.toString(field) + "}";
+  }
+
+  public static class SuperWeight extends Weight {
+
+    private static final long serialVersionUID = -4832849792097064960L;
+
+    private Weight weight;
+    private String originalQueryStr;
+    private Query query;
+    private ScoreType scoreType;
+
+    public SuperWeight(Weight weight, String originalQueryStr, Query query, 
ScoreType scoreType) {
+      this.weight = weight;
+      this.originalQueryStr = originalQueryStr;
+      this.query = query;
+      this.scoreType = scoreType;
+    }
+
+    @Override
+    public Explanation explain(IndexReader reader, int doc) throws IOException 
{
+      throw new RuntimeException("not supported");
+    }
+
+    @Override
+    public Query getQuery() {
+      return query;
+    }
+
+    @Override
+    public float getValue() {
+      return weight.getValue();
+    }
+
+    @Override
+    public void normalize(float norm) {
+      weight.normalize(norm);
+    }
+
+    @Override
+    public Scorer scorer(IndexReader reader, boolean scoreDocsInOrder, boolean 
topScorer) throws IOException {
+      Scorer scorer = weight.scorer(reader, true, topScorer);
+      if (scorer == null) {
+        return null;
+      }
+      OpenBitSet primeDocBitSet = PrimeDocCache.getPrimeDocBitSet(reader);
+      return new SuperScorer(scorer, primeDocBitSet, originalQueryStr, 
scoreType);
+    }
+
+    @Override
+    public float sumOfSquaredWeights() throws IOException {
+      return weight.sumOfSquaredWeights();
+    }
+  }
+
+  @SuppressWarnings("unused")
+  public static class SuperScorer extends Scorer {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(SuperScorer.class);
+
+    private static final String DOC_ID = "docId";
+    private static final String NEXT_DOC = "nextDoc";
+    private static final String ADVANCE = "advance";
+    private static final double SUPER_POWER_CONSTANT = 2;
+    private static final boolean debug = false;
+    private Scorer scorer;
+    private OpenBitSet bitSet;
+    private int nextPrimeDoc;
+    private int primeDoc = -1;
+    private String originalQueryStr;
+    private ScoreType scoreType;
+
+    private int numDocs;
+    private float bestScore;
+    private float aggregateScore;
+    private int hitsInEntity;
+
+    protected SuperScorer(Scorer scorer, OpenBitSet bitSet, String 
originalQueryStr, ScoreType scoreType) {
+      super(scorer.getSimilarity());
+      this.scorer = scorer;
+      this.bitSet = bitSet;
+      this.originalQueryStr = originalQueryStr;
+      this.scoreType = scoreType;
+    }
+
+    @Override
+    public float score() throws IOException {
+      switch (scoreType) {
+      case AGGREGATE:
+        return aggregateScore;
+      case BEST:
+        return bestScore;
+      case CONSTANT:
+        return 1;
+      case SUPER:
+        double log = Math.log10(aggregateScore) + 1.0;
+        double avg = aggregateScore / hitsInEntity;
+        double pow = Math.pow(avg, SUPER_POWER_CONSTANT);
+        return (float) Math.pow(log + pow, 1.0 / SUPER_POWER_CONSTANT);
+      }
+      throw new RuntimeException("Unknown Score type[" + scoreType + "]");
+    }
+
+    @Override
+    public int docID() {
+      return print(DOC_ID, primeDoc);
+    }
+
+    @Override
+    public int advance(int target) throws IOException {
+      if (target == NO_MORE_DOCS) {
+        return print(ADVANCE, primeDoc = scorer.advance(NO_MORE_DOCS));
+      }
+      int doc = scorer.docID();
+      int odoc = doc;
+      if (isScorerExhausted(doc)) {
+        return print(ADVANCE, primeDoc = doc);
+      }
+      if (target > doc || doc == -1) {
+        doc = scorer.advance(target);
+        if (isScorerExhausted(doc)) {
+          return print(ADVANCE, primeDoc = doc);
+        }
+      } else if (isScorerExhausted(doc)) {
+        return print(ADVANCE, primeDoc == -1 ? primeDoc = doc : primeDoc);
+      }
+      return print(ADVANCE, gatherAllHitsSuperDoc(doc));
+    }
+
+    private int print(String message, int i) {
+      if (debug) {
+        System.out.println(message + " [" + i + "] " + originalQueryStr);
+      }
+      return i;
+    }
+
+    @Override
+    public int nextDoc() throws IOException {
+      int doc = scorer.docID();
+      int odoc = doc;
+      if (isScorerExhausted(doc)) {
+        return primeDoc = doc;
+      }
+      if (doc == -1) {
+        doc = scorer.nextDoc();
+        if (isScorerExhausted(doc)) {
+          return print(NEXT_DOC, primeDoc = doc);
+        }
+      } else if (isScorerExhausted(doc)) {
+        return print(NEXT_DOC, primeDoc == -1 ? primeDoc = doc : primeDoc);
+      }
+
+      return print(NEXT_DOC, gatherAllHitsSuperDoc(doc));
+    }
+
+    private int gatherAllHitsSuperDoc(int doc) throws IOException {
+      reset();
+      primeDoc = getPrimeDoc(doc);
+      nextPrimeDoc = getNextPrimeDoc(doc);
+      numDocs = nextPrimeDoc - primeDoc;
+      float currentDocScore = 0;
+      while (doc < nextPrimeDoc) {
+        currentDocScore = scorer.score();
+        aggregateScore += currentDocScore;
+        if (currentDocScore > bestScore) {
+          bestScore = currentDocScore;
+        }
+        hitsInEntity++;
+        doc = scorer.nextDoc();
+      }
+      return primeDoc;
+    }
+
+    private void reset() {
+      numDocs = 0;
+      bestScore = 0;
+      aggregateScore = 0;
+      hitsInEntity = 0;
+    }
+
+    private int getNextPrimeDoc(int doc) {
+      int nextSetBit = bitSet.nextSetBit(doc + 1);
+      return nextSetBit == -1 ? NO_MORE_DOCS : nextSetBit;
+    }
+
+    private int getPrimeDoc(int doc) {
+      if (bitSet.fastGet(doc)) {
+        return doc;
+      }
+      return bitSet.prevSetBit(doc);
+    }
+
+    private boolean isScorerExhausted(int doc) {
+      return doc == NO_MORE_DOCS ? true : false;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/manager/BlurFilterCache.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/manager/BlurFilterCache.java 
b/src/blur-core/src/main/java/org/apache/blur/manager/BlurFilterCache.java
new file mode 100644
index 0000000..83f39ab
--- /dev/null
+++ b/src/blur-core/src/main/java/org/apache/blur/manager/BlurFilterCache.java
@@ -0,0 +1,37 @@
+package org.apache.blur.manager;
+
+/**
+ * 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.
+ */
+import org.apache.blur.manager.writer.BlurIndex;
+import org.apache.lucene.search.Filter;
+
+
+public abstract class BlurFilterCache {
+
+  public abstract Filter fetchPreFilter(String table, String filterStr);
+
+  public abstract Filter fetchPostFilter(String table, String filterStr);
+
+  public abstract Filter storePreFilter(String table, String filterStr, Filter 
filter);
+
+  public abstract Filter storePostFilter(String table, String filterStr, 
Filter filter);
+
+  public abstract void closing(String table, String shard, BlurIndex index);
+
+  public abstract void opening(String table, String shard, BlurIndex index);
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/manager/BlurPartitioner.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/manager/BlurPartitioner.java 
b/src/blur-core/src/main/java/org/apache/blur/manager/BlurPartitioner.java
new file mode 100644
index 0000000..9ca3a9a
--- /dev/null
+++ b/src/blur-core/src/main/java/org/apache/blur/manager/BlurPartitioner.java
@@ -0,0 +1,27 @@
+package org.apache.blur.manager;
+
+/**
+ * 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.
+ */
+import org.apache.hadoop.mapreduce.Partitioner;
+
+public class BlurPartitioner<BytesWritable, V> extends 
Partitioner<BytesWritable, V> {
+
+  public int getPartition(BytesWritable key, V value, int numReduceTasks) {
+    return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/manager/BlurQueryChecker.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/manager/BlurQueryChecker.java 
b/src/blur-core/src/main/java/org/apache/blur/manager/BlurQueryChecker.java
new file mode 100644
index 0000000..2676d21
--- /dev/null
+++ b/src/blur-core/src/main/java/org/apache/blur/manager/BlurQueryChecker.java
@@ -0,0 +1,66 @@
+package org.apache.blur.manager;
+
+/**
+ * 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.
+ */
+import org.apache.blur.BlurConfiguration;
+import org.apache.blur.log.Log;
+import org.apache.blur.log.LogFactory;
+import org.apache.blur.thrift.generated.BlurException;
+import org.apache.blur.thrift.generated.BlurQuery;
+
+
+import static org.apache.blur.utils.BlurConstants.*;
+
+public class BlurQueryChecker {
+
+  private static final Log LOG = LogFactory.getLog(BlurQueryChecker.class);
+
+  private int _maxQueryRowFetch;
+  private int _maxQueryRecordFetch;
+  private int _maxQueryResultsFetch;
+
+  public BlurQueryChecker(BlurConfiguration configuration) {
+    _maxQueryResultsFetch = configuration.getInt(BLUR_QUERY_MAX_RESULTS_FETCH, 
100);
+    _maxQueryRowFetch = configuration.getInt(BLUR_QUERY_MAX_ROW_FETCH, 100);
+    _maxQueryRecordFetch = configuration.getInt(BLUR_QUERY_MAX_RECORD_FETCH, 
100);
+  }
+
+  public void checkQuery(BlurQuery blurQuery) throws BlurException {
+    if (blurQuery.selector != null) {
+      if (blurQuery.selector.recordOnly) {
+        if (blurQuery.fetch > _maxQueryRecordFetch) {
+          LOG.warn("Number of records requested to be fetched [{0}] is greater 
than the max allowed [{1}]", _maxQueryRecordFetch);
+          blurQuery.fetch = (int) blurQuery.minimumNumberOfResults;
+        }
+      } else {
+        if (blurQuery.fetch > _maxQueryRowFetch) {
+          LOG.warn("Number of rows requested to be fetched [{0}] is greater 
than the max allowed [{1}]", _maxQueryRowFetch);
+          blurQuery.fetch = (int) blurQuery.minimumNumberOfResults;
+        }
+      }
+    }
+    if (blurQuery.fetch > _maxQueryResultsFetch) {
+      LOG.warn("Number of results requested to be fetched [{0}] is greater 
than the max allowed [{1}]", _maxQueryResultsFetch);
+      blurQuery.fetch = (int) blurQuery.minimumNumberOfResults;
+    }
+    if (blurQuery.fetch > blurQuery.minimumNumberOfResults) {
+      LOG.warn("Number of rows/records requested to be fetched [{0}] is 
greater than the minimum number of results [{1}]", blurQuery.fetch, 
blurQuery.minimumNumberOfResults);
+      blurQuery.fetch = (int) blurQuery.minimumNumberOfResults;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/33df9310/src/blur-core/src/main/java/org/apache/blur/manager/DefaultBlurFilterCache.java
----------------------------------------------------------------------
diff --git 
a/src/blur-core/src/main/java/org/apache/blur/manager/DefaultBlurFilterCache.java
 
b/src/blur-core/src/main/java/org/apache/blur/manager/DefaultBlurFilterCache.java
new file mode 100644
index 0000000..ef46895
--- /dev/null
+++ 
b/src/blur-core/src/main/java/org/apache/blur/manager/DefaultBlurFilterCache.java
@@ -0,0 +1,54 @@
+package org.apache.blur.manager;
+
+/**
+ * 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.
+ */
+import org.apache.blur.manager.writer.BlurIndex;
+import org.apache.lucene.search.Filter;
+
+
+public class DefaultBlurFilterCache extends BlurFilterCache {
+
+  @Override
+  public Filter storePreFilter(String table, String filterStr, Filter filter) {
+    return filter;
+  }
+
+  @Override
+  public Filter storePostFilter(String table, String filterStr, Filter filter) 
{
+    return filter;
+  }
+
+  @Override
+  public Filter fetchPreFilter(String table, String filterStr) {
+    return null;
+  }
+
+  @Override
+  public Filter fetchPostFilter(String table, String filterStr) {
+    return null;
+  }
+
+  @Override
+  public void closing(String table, String shard, BlurIndex index) {
+
+  }
+
+  @Override
+  public void opening(String table, String shard, BlurIndex index) {
+
+  }
+}
\ No newline at end of file

Reply via email to