lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From paulir...@apache.org
Subject [38/53] [abbrv] git commit: Port much of Facet.Search and some others
Date Thu, 07 Nov 2013 13:53:53 GMT
Port much of Facet.Search and some others


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/318dea52
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/318dea52
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/318dea52

Branch: refs/heads/branch_4x
Commit: 318dea523be3d80789377cfcc06e6fa6b2d6e1a0
Parents: 9e1b6df
Author: Paul Irwin <paulirwin@gmail.com>
Authored: Wed Nov 6 08:59:46 2013 -0500
Committer: Paul Irwin <paulirwin@gmail.com>
Committed: Wed Nov 6 08:59:46 2013 -0500

----------------------------------------------------------------------
 src/contrib/Facet/Collections/IIntIterator.cs   |  14 +
 src/contrib/Facet/Collections/IntToObjectMap.cs | 428 +++++++++++++++
 .../Complements/ComplementCountingAggregator.cs |  26 +
 .../Facet/Complements/TotalFacetCounts.cs       | 164 ++++++
 .../Facet/Complements/TotalFacetCountsCache.cs  | 190 +++++++
 src/contrib/Facet/Contrib.Facet.csproj          |  28 +
 .../Partitions/IIntermediateFacetResult.cs      |  13 +
 .../Partitions/PartitionsFacetResultsHandler.cs |  36 ++
 src/contrib/Facet/Search/CountFacetRequest.cs   |  38 ++
 src/contrib/Facet/Search/CountingAggregator.cs  |  48 ++
 .../Facet/Search/CountingFacetsAggregator.cs    |  38 ++
 .../Facet/Search/DepthOneFacetResultsHandler.cs |  98 ++++
 src/contrib/Facet/Search/FacetResult.cs         |  70 +++
 src/contrib/Facet/Search/FacetResultsHandler.cs |  24 +
 src/contrib/Facet/Search/FacetsAccumulator.cs   | 157 ++++++
 src/contrib/Facet/Search/FacetsCollector.cs     | 208 ++++++++
 .../Search/FastCountingFacetsAggregator.cs      |  70 +++
 .../Facet/Search/FloatFacetResultsHandler.cs    |  65 +++
 src/contrib/Facet/Search/IFacetsAggregator.cs   |  17 +
 .../Facet/Search/IntFacetResultsHandler.cs      |  64 +++
 .../Facet/Search/IntRollupFacetsAggregator.cs   |  43 ++
 .../Facet/Search/MatchingDocsAsScoredDocIDs.cs  | 209 ++++++++
 .../Facet/Search/StandardFacetsAccumulator.cs   | 308 +++++++++++
 .../Facet/Search/TopKFacetResultsHandler.cs     | 227 ++++++++
 .../Facet/Search/TopKInEachNodeHandler.cs       | 520 +++++++++++++++++++
 25 files changed, 3103 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Collections/IIntIterator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Collections/IIntIterator.cs b/src/contrib/Facet/Collections/IIntIterator.cs
new file mode 100644
index 0000000..f357478
--- /dev/null
+++ b/src/contrib/Facet/Collections/IIntIterator.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Collections
+{
+    public interface IIntIterator
+    {
+        bool HasNext();
+        int Next();
+        void Remove();
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Collections/IntToObjectMap.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Collections/IntToObjectMap.cs b/src/contrib/Facet/Collections/IntToObjectMap.cs
new file mode 100644
index 0000000..05db8cd
--- /dev/null
+++ b/src/contrib/Facet/Collections/IntToObjectMap.cs
@@ -0,0 +1,428 @@
+using Lucene.Net.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Collections
+{
+    public class IntToObjectMap<T> : IEnumerable<T>
+    {
+        private sealed class IndexIterator : IIntIterator
+        {
+            private int baseHashIndex = 0;
+            private int index = 0;
+            private int lastIndex = 0;
+            private readonly IntToObjectMap<T> parent;
+
+            public IndexIterator(IntToObjectMap<T> parent)
+            {
+                this.parent = parent;
+
+                for (baseHashIndex = 0; baseHashIndex < parent.baseHash.Length; ++baseHashIndex)
+                {
+                    index = parent.baseHash[baseHashIndex];
+                    if (index != 0)
+                    {
+                        break;
+                    }
+                }
+            }
+
+            public bool HasNext()
+            {
+                return (index != 0);
+            }
+
+            public int Next()
+            {
+                lastIndex = index;
+                index = parent.next[index];
+                while (index == 0 && ++baseHashIndex < parent.baseHash.Length)
+                {
+                    index = parent.baseHash[baseHashIndex];
+                }
+
+                return lastIndex;
+            }
+
+            public void Remove()
+            {
+                parent.Remove(parent.keys[lastIndex]);
+            }
+        }
+
+        private sealed class KeyIterator : IIntIterator
+        {
+            private IIntIterator iterator; // = new IndexIterator();
+            private readonly IntToObjectMap<T> parent;
+
+            internal KeyIterator(IntToObjectMap<T> parent)
+            {
+                this.parent = parent;
+                iterator = new IndexIterator(parent);
+            }
+
+            public bool HasNext()
+            {
+                return iterator.HasNext();
+            }
+
+            public int Next()
+            {
+                return parent.keys[iterator.Next()];
+            }
+
+            public void Remove()
+            {
+                iterator.Remove();
+            }
+        }
+
+        private sealed class ValueIterator : IEnumerator<T>
+        {
+            private IIntIterator iterator; // = new IndexIterator();
+            private readonly IntToObjectMap<T> parent;
+
+            internal ValueIterator(IntToObjectMap<T> parent)
+            {
+                this.parent = parent;
+                iterator = new IndexIterator(parent);
+            }
+
+            public bool MoveNext()
+            {
+                return iterator.HasNext();
+            }
+
+            public T Current
+            {
+                get
+                {
+                    return (T)parent.values[iterator.Next()];
+                }
+            }
+
+            public void Remove()
+            {
+                iterator.Remove();
+            }
+
+            public void Dispose()
+            {
+            }
+
+            object System.Collections.IEnumerator.Current
+            {
+                get { return Current; }
+            }
+
+            public void Reset()
+            {
+            }
+        }
+
+        private static int defaultCapacity = 16;
+        int[] baseHash;
+        private int capacity;
+        private int firstEmpty;
+        private int hashFactor;
+        int[] keys;
+        int[] next;
+        private int prev;
+        private int size;
+        Object[] values;
+
+        public IntToObjectMap()
+            : this(defaultCapacity)
+        {
+        }
+
+        public IntToObjectMap(int capacity)
+        {
+            this.capacity = 16;
+            while (this.capacity < capacity)
+            {
+                this.capacity <<= 1;
+            }
+
+            int arrayLength = this.capacity + 1;
+            this.values = new Object[arrayLength];
+            this.keys = new int[arrayLength];
+            this.next = new int[arrayLength];
+            int baseHashSize = this.capacity << 1;
+            this.baseHash = new int[baseHashSize];
+            this.hashFactor = baseHashSize - 1;
+            this.size = 0;
+            Clear();
+        }
+
+        private void Prvt_put(int key, T e)
+        {
+            int hashIndex = CalcBaseHashIndex(key);
+            int objectIndex = firstEmpty;
+            firstEmpty = next[firstEmpty];
+            values[objectIndex] = e;
+            keys[objectIndex] = key;
+            next[objectIndex] = baseHash[hashIndex];
+            baseHash[hashIndex] = objectIndex;
+            ++size;
+        }
+
+        protected virtual int CalcBaseHashIndex(int key)
+        {
+            return key & hashFactor;
+        }
+
+        public virtual void Clear()
+        {
+            Arrays.Fill(this.baseHash, 0);
+            size = 0;
+            firstEmpty = 1;
+            for (int i = 1; i < this.capacity; )
+            {
+                next[i] = ++i;
+            }
+
+            next[this.capacity] = 0;
+        }
+
+        public virtual bool ContainsKey(int key)
+        {
+            return Find(key) != 0;
+        }
+
+        public virtual bool ContainsValue(Object o)
+        {
+            for (IEnumerator<T> iterator = GetEnumerator(); iterator.MoveNext(); )
+            {
+                T obj = iterator.Current;
+                if (obj.Equals(o))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        protected virtual int Find(int key)
+        {
+            int baseHashIndex = CalcBaseHashIndex(key);
+            int localIndex = baseHash[baseHashIndex];
+            while (localIndex != 0)
+            {
+                if (keys[localIndex] == key)
+                {
+                    return localIndex;
+                }
+
+                localIndex = next[localIndex];
+            }
+
+            return 0;
+        }
+
+        private int FindForRemove(int key, int baseHashIndex)
+        {
+            this.prev = 0;
+            int index = baseHash[baseHashIndex];
+            while (index != 0)
+            {
+                if (keys[index] == key)
+                {
+                    return index;
+                }
+
+                prev = index;
+                index = next[index];
+            }
+
+            this.prev = 0;
+            return 0;
+        }
+
+        public virtual T Get(int key)
+        {
+            return (T)values[Find(key)];
+        }
+
+        protected virtual void Grow()
+        {
+            IntToObjectMap<T> that = new IntToObjectMap<T>(this.capacity * 2);
+            for (IndexIterator iterator = new IndexIterator(this); iterator.HasNext(); )
+            {
+                int index = iterator.Next();
+                that.Prvt_put(this.keys[index], (T)this.values[index]);
+            }
+
+            this.capacity = that.capacity;
+            this.size = that.size;
+            this.firstEmpty = that.firstEmpty;
+            this.values = that.values;
+            this.keys = that.keys;
+            this.next = that.next;
+            this.baseHash = that.baseHash;
+            this.hashFactor = that.hashFactor;
+        }
+
+        public virtual bool IsEmpty
+        {
+            get
+            {
+                return size == 0;
+            }
+        }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return new ValueIterator(this);
+        }
+
+        public virtual IIntIterator GetKeyIterator()
+        {
+            return new KeyIterator(this);
+        }
+
+        private string GetBaseHashAsString()
+        {
+            return Arrays.ToString(baseHash);
+        }
+
+        public virtual T Put(int key, T e)
+        {
+            int index = Find(key);
+            if (index != 0)
+            {
+                T old = (T)values[index];
+                values[index] = e;
+                return old;
+            }
+
+            if (size == capacity)
+            {
+                Grow();
+            }
+
+            Prvt_put(key, e);
+            return default(T);
+        }
+
+        public virtual T Remove(int key)
+        {
+            int baseHashIndex = CalcBaseHashIndex(key);
+            int index = FindForRemove(key, baseHashIndex);
+            if (index != 0)
+            {
+                if (prev == 0)
+                {
+                    baseHash[baseHashIndex] = next[index];
+                }
+
+                next[prev] = next[index];
+                next[index] = firstEmpty;
+                firstEmpty = index;
+                --size;
+                return (T)values[index];
+            }
+
+            return default(T);
+        }
+
+        public virtual int Size
+        {
+            get
+            {
+                return this.size;
+            }
+        }
+
+        public virtual Object[] ToArray()
+        {
+            int j = -1;
+            Object[] array = new Object[size];
+            for (IEnumerator<T> iterator = GetEnumerator(); iterator.MoveNext(); )
+            {
+                array[++j] = iterator.Current;
+            }
+
+            return array;
+        }
+
+        public virtual T[] ToArray(T[] a)
+        {
+            int j = 0;
+            for (IEnumerator<T> iterator = GetEnumerator(); j < a.Length && iterator.MoveNext(); ++j)
+            {
+                a[j] = iterator.Current;
+            }
+
+            if (j < a.Length)
+            {
+                a[j] = default(T);
+            }
+
+            return a;
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.Append('{');
+            IIntIterator keyIterator = GetKeyIterator();
+            while (keyIterator.HasNext())
+            {
+                int key = keyIterator.Next();
+                sb.Append(key);
+                sb.Append('=');
+                sb.Append(Get(key));
+                if (keyIterator.HasNext())
+                {
+                    sb.Append(',');
+                    sb.Append(' ');
+                }
+            }
+
+            sb.Append('}');
+            return sb.ToString();
+        }
+
+        public override int GetHashCode()
+        {
+            return GetType().GetHashCode() ^ Size;
+        }
+
+        public override bool Equals(Object o)
+        {
+            IntToObjectMap<T> that = (IntToObjectMap<T>)o;
+            if (that.Size != this.Size)
+            {
+                return false;
+            }
+
+            IIntIterator it = GetKeyIterator();
+            while (it.HasNext())
+            {
+                int key = it.Next();
+                if (!that.ContainsKey(key))
+                {
+                    return false;
+                }
+
+                T v1 = this.Get(key);
+                T v2 = that.Get(key);
+                if ((v1 == null && v2 != null) || (v1 != null && v2 == null) || (!v1.Equals(v2)))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Complements/ComplementCountingAggregator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Complements/ComplementCountingAggregator.cs b/src/contrib/Facet/Complements/ComplementCountingAggregator.cs
new file mode 100644
index 0000000..b130b09
--- /dev/null
+++ b/src/contrib/Facet/Complements/ComplementCountingAggregator.cs
@@ -0,0 +1,26 @@
+using Lucene.Net.Facet.Search;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Complements
+{
+    public class ComplementCountingAggregator : CountingAggregator
+    {
+        public ComplementCountingAggregator(int[] counterArray)
+            : base(counterArray)
+        {
+        }
+
+        public override void Aggregate(int docID, float score, IntsRef ordinals)
+        {
+            for (int i = 0; i < ordinals.length; i++)
+            {
+                int ord = ordinals.ints[i];
+                --counterArray[ord];
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Complements/TotalFacetCounts.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Complements/TotalFacetCounts.cs b/src/contrib/Facet/Complements/TotalFacetCounts.cs
new file mode 100644
index 0000000..945acec
--- /dev/null
+++ b/src/contrib/Facet/Complements/TotalFacetCounts.cs
@@ -0,0 +1,164 @@
+using Lucene.Net.Facet.Params;
+using Lucene.Net.Facet.Search;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Facet.Util;
+using Lucene.Net.Index;
+using Lucene.Net.Support;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace Lucene.Net.Facet.Complements
+{
+    public class TotalFacetCounts
+    {
+        private int[][] totalCounts = null;
+        private readonly TaxonomyReader taxonomy;
+        private readonly FacetIndexingParams facetIndexingParams;
+        private static int atomicGen4Test = 1;
+
+        enum CreationType
+        {
+            Computed,
+            Loaded
+        }
+
+        readonly int gen4test;
+        readonly CreationType createType4test;
+
+        private TotalFacetCounts(TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams, 
+            int[][] counts, CreationType createType4Test)
+        {
+            this.taxonomy = taxonomy;
+            this.facetIndexingParams = facetIndexingParams;
+            this.totalCounts = counts;
+            this.createType4test = createType4Test;
+            this.gen4test = Interlocked.Increment(ref atomicGen4Test);
+        }
+
+        public virtual void FillTotalCountsForPartition(int[] partitionArray, int partition)
+        {
+            int partitionSize = partitionArray.Length;
+            int[] countArray = totalCounts[partition];
+            if (countArray == null)
+            {
+                countArray = new int[partitionSize];
+                totalCounts[partition] = countArray;
+            }
+
+            int length = Math.Min(partitionSize, countArray.Length);
+            Array.Copy(countArray, 0, partitionArray, 0, length);
+        }
+
+        public virtual int GetTotalCount(int ordinal)
+        {
+            int partition = PartitionsUtils.PartitionNumber(facetIndexingParams, ordinal);
+            int offset = ordinal % PartitionsUtils.PartitionSize(facetIndexingParams, taxonomy);
+            return totalCounts[partition][offset];
+        }
+
+        internal static TotalFacetCounts LoadFromFile(FileInfo inputFile, TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams)
+        {
+            var fstream = inputFile.OpenRead();
+            var dis = new BinaryReader(fstream);
+            try
+            {
+                int[][] counts = new int[dis.ReadInt32()][];
+                for (int i = 0; i < counts.Length; i++)
+                {
+                    int size = dis.ReadInt32();
+                    if (size < 0)
+                    {
+                        counts[i] = null;
+                    }
+                    else
+                    {
+                        counts[i] = new int[size];
+                        for (int j = 0; j < size; j++)
+                        {
+                            counts[i][j] = dis.ReadInt32();
+                        }
+                    }
+                }
+
+                return new TotalFacetCounts(taxonomy, facetIndexingParams, counts, CreationType.Loaded);
+            }
+            finally
+            {
+                dis.Dispose();
+                fstream.Dispose();
+            }
+        }
+
+        internal static void StoreToFile(FileInfo outputFile, TotalFacetCounts tfc)
+        {
+            var fstream = outputFile.OpenWrite();
+            var dos = new BinaryWriter(fstream);
+            try
+            {
+                dos.Write(tfc.totalCounts.Length);
+                foreach (int[] counts in tfc.totalCounts)
+                {
+                    if (counts == null)
+                    {
+                        dos.Write(-1);
+                    }
+                    else
+                    {
+                        dos.Write(counts.Length);
+                        foreach (int i in counts)
+                        {
+                            dos.Write(i);
+                        }
+                    }
+                }
+            }
+            finally
+            {
+                dos.Dispose();
+                fstream.Dispose();
+            }
+        }
+
+        private static readonly FacetRequest DUMMY_REQ = new CountFacetRequest(CategoryPath.EMPTY, 1);
+
+        internal static TotalFacetCounts Compute(IndexReader indexReader, TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams)
+        {
+            int partitionSize = PartitionsUtils.PartitionSize(facetIndexingParams, taxonomy);
+            int[][] counts = new int[(int)Math.Ceiling(taxonomy.Size / (float)partitionSize)][];
+            FacetSearchParams newSearchParams = new FacetSearchParams(facetIndexingParams, DUMMY_REQ);
+            StandardFacetsAccumulator sfa = new AnonymousStandardFacetsAccumulator(newSearchParams, indexReader, taxonomy, counts, facetIndexingParams);
+            sfa.ComplementThreshold = StandardFacetsAccumulator.DISABLE_COMPLEMENT;
+            sfa.Accumulate(ScoredDocIdsUtils.CreateAllDocsScoredDocIDs(indexReader));
+            return new TotalFacetCounts(taxonomy, facetIndexingParams, counts, CreationType.Computed);
+        }
+
+        private sealed class AnonymousStandardFacetsAccumulator : StandardFacetsAccumulator
+        {
+            public AnonymousStandardFacetsAccumulator(FacetSearchParams newSearchParams, IndexReader indexReader, TaxonomyReader taxonomyReader, int[][] counts, FacetIndexingParams facetIndexingParams)
+                : base(newSearchParams, indexReader, taxonomyReader)
+            {
+                this.counts = counts;
+                this.facetIndexingParams = facetIndexingParams;
+            }
+
+            private readonly int[][] counts;
+            private readonly FacetIndexingParams facetIndexingParams;
+
+            protected override HashMap<ICategoryListIterator, IAggregator> GetCategoryListMap(FacetArrays facetArrays, int partition)
+            {
+                IAggregator aggregator = new CountingAggregator(counts[partition]);
+                HashMap<ICategoryListIterator, IAggregator> map = new HashMap<ICategoryListIterator, IAggregator>();
+                foreach (CategoryListParams clp in facetIndexingParams.AllCategoryListParams)
+                {
+                    map[clp.CreateCategoryListIterator(partition)] = aggregator;
+                }
+
+                return map;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Complements/TotalFacetCountsCache.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Complements/TotalFacetCountsCache.cs b/src/contrib/Facet/Complements/TotalFacetCountsCache.cs
new file mode 100644
index 0000000..0442528
--- /dev/null
+++ b/src/contrib/Facet/Complements/TotalFacetCountsCache.cs
@@ -0,0 +1,190 @@
+using Lucene.Net.Facet.Params;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Index;
+using Lucene.Net.Support;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace Lucene.Net.Facet.Complements
+{
+    public sealed class TotalFacetCountsCache
+    {
+        public static readonly int DEFAULT_CACHE_SIZE = 2;
+        private static readonly TotalFacetCountsCache singleton = new TotalFacetCountsCache();
+
+        public static TotalFacetCountsCache GetSingleton()
+        {
+            return singleton;
+        }
+
+        private ConcurrentHashMap<TFCKey, TotalFacetCounts> cache = new ConcurrentHashMap<TFCKey, TotalFacetCounts>();
+        private LinkedList<TFCKey> lruKeys = new LinkedList<TFCKey>(); // .NET Port: this collection is not concurrent, so we have to lock around it
+        private int maxCacheSize = DEFAULT_CACHE_SIZE;
+
+        private TotalFacetCountsCache()
+        {
+        }
+
+        public TotalFacetCounts GetTotalCounts(IndexReader indexReader, TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams)
+        {
+            TFCKey key = new TFCKey(indexReader, taxonomy, facetIndexingParams);
+            TotalFacetCounts tfc = cache[key];
+            if (tfc != null)
+            {
+                MarkRecentlyUsed(key);
+                return tfc;
+            }
+
+            return ComputeAndCache(key);
+        }
+
+        private void MarkRecentlyUsed(TFCKey key)
+        {
+            lock (this)
+            {
+                lruKeys.Remove(key);
+                lruKeys.AddLast(key);
+            }
+        }
+
+        private void TrimCache()
+        {
+            lock (this)
+            {
+                while (cache.Count > maxCacheSize)
+                {
+                    TFCKey key;
+
+                    if (lruKeys.Count > 0)
+                    {
+                        key = lruKeys.First.Value;
+                        lruKeys.RemoveFirst();
+                    }
+                    else
+                    {
+                        key = cache.Keys.FirstOrDefault();
+                    }
+
+                    cache.Remove(key);
+                }
+            }
+        }
+
+        private TotalFacetCounts ComputeAndCache(TFCKey key)
+        {
+            lock (this)
+            {
+                TotalFacetCounts tfc = cache[key];
+                if (tfc == null)
+                {
+                    tfc = TotalFacetCounts.Compute(key.indexReader, key.taxonomy, key.facetIndexingParams);
+                    lruKeys.AddLast(key);
+                    cache[key] = tfc;
+                    TrimCache();
+                }
+
+                return tfc;
+            }
+        }
+
+        public void Load(FileInfo inputFile, IndexReader indexReader, TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams)
+        {
+            lock (this)
+            {
+                if (!inputFile.Exists)
+                {
+                    throw new ArgumentException(@"Exepecting an existing readable file: " + inputFile);
+                }
+
+                TFCKey key = new TFCKey(indexReader, taxonomy, facetIndexingParams);
+                TotalFacetCounts tfc = TotalFacetCounts.LoadFromFile(inputFile, taxonomy, facetIndexingParams);
+                cache[key] = tfc;
+                TrimCache();
+                MarkRecentlyUsed(key);
+            }
+        }
+
+        public void Store(FileInfo outputFile, IndexReader indexReader, TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams)
+        {
+            TotalFacetCounts tfc = GetTotalCounts(indexReader, taxonomy, facetIndexingParams);
+            TotalFacetCounts.StoreToFile(outputFile, tfc);
+        }
+
+        private class TFCKey
+        {
+            internal readonly IndexReader indexReader;
+            internal readonly TaxonomyReader taxonomy;
+            private readonly IEnumerable<CategoryListParams> clps;
+            private readonly int hashCode;
+            private readonly int nDels;
+            internal readonly FacetIndexingParams facetIndexingParams;
+
+            public TFCKey(IndexReader indexReader, TaxonomyReader taxonomy, FacetIndexingParams facetIndexingParams)
+            {
+                this.indexReader = indexReader;
+                this.taxonomy = taxonomy;
+                this.facetIndexingParams = facetIndexingParams;
+                this.clps = facetIndexingParams.AllCategoryListParams;
+                this.nDels = indexReader.NumDeletedDocs;
+                hashCode = indexReader.GetHashCode() ^ taxonomy.GetHashCode();
+            }
+
+            public override int GetHashCode()
+            {
+                return hashCode;
+            }
+
+            public override bool Equals(Object other)
+            {
+                TFCKey o = (TFCKey)other;
+                if (indexReader != o.indexReader || taxonomy != o.taxonomy || nDels != o.nDels)
+                {
+                    return false;
+                }
+
+                IEnumerator<CategoryListParams> it1 = clps.GetEnumerator();
+                IEnumerator<CategoryListParams> it2 = o.clps.GetEnumerator();
+                while (it1.MoveNext() && it2.MoveNext())
+                {
+                    if (!it1.Current.Equals(it2.Current))
+                    {
+                        return false;
+                    }
+                }
+
+                return it1.MoveNext() == it2.MoveNext();
+            }
+        }
+
+        public void Clear()
+        {
+            lock (this)
+            {
+                cache.Clear();
+                lruKeys.Clear();
+            }
+        }
+
+        public int GetCacheSize()
+        {
+            return maxCacheSize;
+        }
+
+        public void SetCacheSize(int size)
+        {
+            if (size < 1)
+                size = 1;
+            int origSize = maxCacheSize;
+            maxCacheSize = size;
+            if (maxCacheSize < origSize)
+            {
+                TrimCache();
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Contrib.Facet.csproj
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Contrib.Facet.csproj b/src/contrib/Facet/Contrib.Facet.csproj
index 750ab35..8e52f70 100644
--- a/src/contrib/Facet/Contrib.Facet.csproj
+++ b/src/contrib/Facet/Contrib.Facet.csproj
@@ -31,7 +31,11 @@
   </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Runtime.Serialization" />
+    <Reference Include="System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
+    <Reference Include="System.ServiceModel.DomainServices.Server, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
     <Reference Include="System.Xml.Linq" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="Microsoft.CSharp" />
@@ -44,7 +48,12 @@
     <Compile Include="Codecs\Facet42\Facet42DocValuesConsumer.cs" />
     <Compile Include="Codecs\Facet42\Facet42DocValuesFormat.cs" />
     <Compile Include="Codecs\Facet42\Facet42DocValuesProducer.cs" />
+    <Compile Include="Collections\IIntIterator.cs" />
+    <Compile Include="Collections\IntToObjectMap.cs" />
     <Compile Include="Collections\LRUHashMap.cs" />
+    <Compile Include="Complements\ComplementCountingAggregator.cs" />
+    <Compile Include="Complements\TotalFacetCounts.cs" />
+    <Compile Include="Complements\TotalFacetCountsCache.cs" />
     <Compile Include="Encoding\DGapVInt8IntDecoder.cs" />
     <Compile Include="Encoding\DGapVInt8IntEncoder.cs" />
     <Compile Include="Encoding\IntDecoder.cs" />
@@ -57,16 +66,35 @@
     <Compile Include="Params\FacetSearchParams.cs" />
     <Compile Include="Params\PerDimensionIndexingParams.cs" />
     <Compile Include="Params\PerDimensionOrdinalPolicy.cs" />
+    <Compile Include="Partitions\IIntermediateFacetResult.cs" />
+    <Compile Include="Partitions\PartitionsFacetResultsHandler.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Search\CountFacetRequest.cs" />
+    <Compile Include="Search\CountingAggregator.cs" />
+    <Compile Include="Search\CountingFacetsAggregator.cs" />
+    <Compile Include="Search\DepthOneFacetResultsHandler.cs" />
     <Compile Include="Search\DocValuesCategoryListIterator.cs" />
     <Compile Include="Search\FacetArrays.cs" />
     <Compile Include="Search\FacetRequest.cs" />
+    <Compile Include="Search\FacetResult.cs" />
     <Compile Include="Search\FacetResultNode.cs" />
+    <Compile Include="Search\FacetResultsHandler.cs" />
+    <Compile Include="Search\FacetsAccumulator.cs" />
+    <Compile Include="Search\FacetsCollector.cs" />
+    <Compile Include="Search\FastCountingFacetsAggregator.cs" />
+    <Compile Include="Search\FloatFacetResultsHandler.cs" />
     <Compile Include="Search\IAggregator.cs" />
     <Compile Include="Search\ICategoryListIterator.cs" />
+    <Compile Include="Search\IFacetsAggregator.cs" />
     <Compile Include="Search\IHeap.cs" />
+    <Compile Include="Search\IntFacetResultsHandler.cs" />
+    <Compile Include="Search\IntRollupFacetsAggregator.cs" />
     <Compile Include="Search\IScoredDocIDs.cs" />
     <Compile Include="Search\IScoredDocIDsIterator.cs" />
+    <Compile Include="Search\MatchingDocsAsScoredDocIDs.cs" />
+    <Compile Include="Search\StandardFacetsAccumulator.cs" />
+    <Compile Include="Search\TopKFacetResultsHandler.cs" />
+    <Compile Include="Search\TopKInEachNodeHandler.cs" />
     <Compile Include="Taxonomy\CategoryPath.cs" />
     <Compile Include="Taxonomy\Directory\Consts.cs" />
     <Compile Include="Taxonomy\Directory\DirectoryTaxonomyReader.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Partitions/IIntermediateFacetResult.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Partitions/IIntermediateFacetResult.cs b/src/contrib/Facet/Partitions/IIntermediateFacetResult.cs
new file mode 100644
index 0000000..fdbb6a0
--- /dev/null
+++ b/src/contrib/Facet/Partitions/IIntermediateFacetResult.cs
@@ -0,0 +1,13 @@
+using Lucene.Net.Facet.Search;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Partitions
+{
+    public interface IIntermediateFacetResult
+    {
+        FacetRequest FacetRequest { get; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Partitions/PartitionsFacetResultsHandler.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Partitions/PartitionsFacetResultsHandler.cs b/src/contrib/Facet/Partitions/PartitionsFacetResultsHandler.cs
new file mode 100644
index 0000000..5e9bdf3
--- /dev/null
+++ b/src/contrib/Facet/Partitions/PartitionsFacetResultsHandler.cs
@@ -0,0 +1,36 @@
+using Lucene.Net.Facet.Search;
+using Lucene.Net.Facet.Taxonomy;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Partitions
+{
+    public abstract class PartitionsFacetResultsHandler : FacetResultsHandler
+    {
+        public PartitionsFacetResultsHandler(TaxonomyReader taxonomyReader, FacetRequest facetRequest, FacetArrays facetArrays)
+            : base(taxonomyReader, facetRequest, facetArrays)
+        {
+        }
+
+        public abstract IIntermediateFacetResult FetchPartitionResult(int offset);
+        public abstract IIntermediateFacetResult MergeResults(params IIntermediateFacetResult[] tmpResults);
+        public abstract FacetResult RenderFacetResult(IIntermediateFacetResult tmpResult);
+        public abstract FacetResult RearrangeFacetResult(FacetResult facetResult);
+        public abstract void LabelResult(FacetResult facetResult);
+
+        protected virtual bool IsSelfPartition(int ordinal, FacetArrays facetArrays, int offset)
+        {
+            int partitionSize = facetArrays.arrayLength;
+            return ordinal / partitionSize == offset / partitionSize;
+        }
+
+        public override FacetResult Compute()
+        {
+            FacetResult res = RenderFacetResult(FetchPartitionResult(0));
+            LabelResult(res);
+            return res;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/CountFacetRequest.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/CountFacetRequest.cs b/src/contrib/Facet/Search/CountFacetRequest.cs
new file mode 100644
index 0000000..e8d47f5
--- /dev/null
+++ b/src/contrib/Facet/Search/CountFacetRequest.cs
@@ -0,0 +1,38 @@
+using Lucene.Net.Facet.Complements;
+using Lucene.Net.Facet.Taxonomy;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public class CountFacetRequest : FacetRequest
+    {
+        public CountFacetRequest(CategoryPath path, int num)
+            : base(path, num)
+        {
+        }
+
+        public override IAggregator CreateAggregator(bool useComplements, FacetArrays arrays, TaxonomyReader taxonomy)
+        {
+            int[] a = arrays.GetIntArray();
+            if (useComplements)
+            {
+                return new ComplementCountingAggregator(a);
+            }
+
+            return new CountingAggregator(a);
+        }
+
+        public override double GetValueOf(FacetArrays arrays, int ordinal)
+        {
+            return arrays.GetIntArray()[ordinal];
+        }
+
+        public override FacetArraysSource FacetArraysSourceValue
+        {
+            get { return FacetArraysSource.INT; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/CountingAggregator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/CountingAggregator.cs b/src/contrib/Facet/Search/CountingAggregator.cs
new file mode 100644
index 0000000..db461e1
--- /dev/null
+++ b/src/contrib/Facet/Search/CountingAggregator.cs
@@ -0,0 +1,48 @@
+using Lucene.Net.Index;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public class CountingAggregator : IAggregator
+    {
+        protected int[] counterArray;
+
+        public CountingAggregator(int[] counterArray)
+        {
+            this.counterArray = counterArray;
+        }
+
+        public virtual void Aggregate(int docID, float score, IntsRef ordinals)
+        {
+            for (int i = 0; i < ordinals.length; i++)
+            {
+                counterArray[ordinals.ints[i]]++;
+            }
+        }
+
+        public override bool Equals(Object obj)
+        {
+            if (obj == null || obj.GetType() != this.GetType())
+            {
+                return false;
+            }
+
+            CountingAggregator that = (CountingAggregator)obj;
+            return that.counterArray == this.counterArray;
+        }
+
+        public override int GetHashCode()
+        {
+            return counterArray == null ? 0 : counterArray.GetHashCode();
+        }
+
+        public virtual bool SetNextReader(AtomicReaderContext context)
+        {
+            return true;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/CountingFacetsAggregator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/CountingFacetsAggregator.cs b/src/contrib/Facet/Search/CountingFacetsAggregator.cs
new file mode 100644
index 0000000..cf5f347
--- /dev/null
+++ b/src/contrib/Facet/Search/CountingFacetsAggregator.cs
@@ -0,0 +1,38 @@
+using Lucene.Net.Facet.Params;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public class CountingFacetsAggregator : IntRollupFacetsAggregator
+    {
+        private readonly IntsRef ordinals = new IntsRef(32);
+
+        public override void Aggregate(FacetsCollector.MatchingDocs matchingDocs, CategoryListParams clp, FacetArrays facetArrays)
+        {
+            ICategoryListIterator cli = clp.CreateCategoryListIterator(0);
+            if (!cli.SetNextReader(matchingDocs.context))
+            {
+                return;
+            }
+
+            int length = matchingDocs.bits.Length;
+            int[] counts = facetArrays.GetIntArray();
+            int doc = 0;
+            while (doc < length && (doc = matchingDocs.bits.NextSetBit(doc)) != -1)
+            {
+                cli.GetOrdinals(doc, ordinals);
+                int upto = ordinals.offset + ordinals.length;
+                for (int i = ordinals.offset; i < upto; i++)
+                {
+                    ++counts[ordinals.ints[i]];
+                }
+
+                ++doc;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/DepthOneFacetResultsHandler.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/DepthOneFacetResultsHandler.cs b/src/contrib/Facet/Search/DepthOneFacetResultsHandler.cs
new file mode 100644
index 0000000..f28cc7f
--- /dev/null
+++ b/src/contrib/Facet/Search/DepthOneFacetResultsHandler.cs
@@ -0,0 +1,98 @@
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public abstract class DepthOneFacetResultsHandler : FacetResultsHandler
+    {
+        private class FacetResultNodeQueue : PriorityQueue<FacetResultNode>
+        {
+            public FacetResultNodeQueue(int maxSize, bool prepopulate)
+                : base(maxSize, prepopulate)
+            {
+            }
+
+            protected override FacetResultNode SentinelObject
+            {
+                get
+                {
+                    return new FacetResultNode(TaxonomyReader.INVALID_ORDINAL, 0);
+                }
+            }
+
+            public override bool LessThan(FacetResultNode a, FacetResultNode b)
+            {
+                if (a.value < b.value)
+                    return true;
+                if (a.value > b.value)
+                    return false;
+                return a.ordinal < b.ordinal;
+            }
+        }
+
+        public DepthOneFacetResultsHandler(TaxonomyReader taxonomyReader, FacetRequest facetRequest, FacetArrays facetArrays)
+            : base(taxonomyReader, facetRequest, facetArrays)
+        {
+        }
+
+        protected abstract double ValueOf(int ordinal);
+        protected abstract void AddSiblings(int ordinal, int[] siblings, List<FacetResultNode> nodes);
+        protected abstract int AddSiblings(int ordinal, int[] siblings, PriorityQueue<FacetResultNode> pq);
+        public override FacetResult Compute()
+        {
+            ParallelTaxonomyArrays arrays = taxonomyReader.ParallelTaxonomyArrays;
+            int[] children = arrays.Children;
+            int[] siblings = arrays.Siblings;
+            int rootOrd = taxonomyReader.GetOrdinal(facetRequest.categoryPath);
+            FacetResultNode root = new FacetResultNode(rootOrd, ValueOf(rootOrd));
+            root.label = facetRequest.categoryPath;
+            if (facetRequest.numResults > taxonomyReader.Size)
+            {
+                List<FacetResultNode> nodes = new List<FacetResultNode>();
+                int child = children[rootOrd];
+                AddSiblings(child, siblings, nodes);
+                nodes.Sort(new AnonymousComparator());
+                root.subResults = nodes;
+                return new FacetResult(facetRequest, root, nodes.Count);
+            }
+
+            PriorityQueue<FacetResultNode> pq = new FacetResultNodeQueue(facetRequest.numResults, true);
+            int numSiblings = AddSiblings(children[rootOrd], siblings, pq);
+            int pqsize = pq.Size;
+            int size = numSiblings < pqsize ? numSiblings : pqsize;
+            for (int i = pqsize - size; i > 0; i--)
+            {
+                pq.Pop();
+            }
+
+            FacetResultNode[] subResults = new FacetResultNode[size];
+            for (int i = size - 1; i >= 0; i--)
+            {
+                FacetResultNode node = pq.Pop();
+                node.label = taxonomyReader.GetPath(node.ordinal);
+                subResults[i] = node;
+            }
+
+            root.subResults = subResults;
+            return new FacetResult(facetRequest, root, numSiblings);
+        }
+
+        private sealed class AnonymousComparator : IComparer<FacetResultNode>
+        {
+            public int Compare(FacetResultNode o1, FacetResultNode o2)
+            {
+                int value = (int)(o2.value - o1.value);
+                if (value == 0)
+                {
+                    value = o2.ordinal - o1.ordinal;
+                }
+
+                return value;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/FacetResult.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/FacetResult.cs b/src/contrib/Facet/Search/FacetResult.cs
new file mode 100644
index 0000000..e76ec69
--- /dev/null
+++ b/src/contrib/Facet/Search/FacetResult.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public class FacetResult
+    {
+        private readonly FacetRequest facetRequest;
+        private readonly FacetResultNode rootNode;
+        private readonly int numValidDescendants;
+
+        public FacetResult(FacetRequest facetRequest, FacetResultNode rootNode, int numValidDescendants)
+        {
+            this.facetRequest = facetRequest;
+            this.rootNode = rootNode;
+            this.numValidDescendants = numValidDescendants;
+        }
+
+        public FacetResultNode FacetResultNode
+        {
+            get
+            {
+                return rootNode;
+            }
+        }
+
+        public int NumValidDescendants
+        {
+            get
+            {
+                return numValidDescendants;
+            }
+        }
+
+        public FacetRequest FacetRequest
+        {
+            get
+            {
+                return this.facetRequest;
+            }
+        }
+
+        public virtual string ToString(string prefix)
+        {
+            StringBuilder sb = new StringBuilder();
+            string nl = @"";
+            if (this.facetRequest != null)
+            {
+                sb.Append(nl).Append(prefix).Append(@"Request: ").Append(this.facetRequest.ToString());
+                nl = @"\n";
+            }
+
+            sb.Append(nl).Append(prefix).Append(@"Num valid Descendants (up to specified depth): ").Append(this.numValidDescendants);
+            nl = @"\n";
+            if (this.rootNode != null)
+            {
+                sb.Append(nl).Append(this.rootNode.ToString(prefix + @"\t"));
+            }
+
+            return sb.ToString();
+        }
+
+        public override string ToString()
+        {
+            return ToString(@"");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/FacetResultsHandler.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/FacetResultsHandler.cs b/src/contrib/Facet/Search/FacetResultsHandler.cs
new file mode 100644
index 0000000..77c4bfc
--- /dev/null
+++ b/src/contrib/Facet/Search/FacetResultsHandler.cs
@@ -0,0 +1,24 @@
+using Lucene.Net.Facet.Taxonomy;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public abstract class FacetResultsHandler
+    {
+        public readonly TaxonomyReader taxonomyReader;
+        public readonly FacetRequest facetRequest;
+        protected readonly FacetArrays facetArrays;
+
+        public FacetResultsHandler(TaxonomyReader taxonomyReader, FacetRequest facetRequest, FacetArrays facetArrays)
+        {
+            this.taxonomyReader = taxonomyReader;
+            this.facetRequest = facetRequest;
+            this.facetArrays = facetArrays;
+        }
+
+        public abstract FacetResult Compute();
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/FacetsAccumulator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/FacetsAccumulator.cs b/src/contrib/Facet/Search/FacetsAccumulator.cs
new file mode 100644
index 0000000..819085b
--- /dev/null
+++ b/src/contrib/Facet/Search/FacetsAccumulator.cs
@@ -0,0 +1,157 @@
+using Lucene.Net.Facet.Params;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Index;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public class FacetsAccumulator
+    {
+        public readonly TaxonomyReader taxonomyReader;
+        public readonly IndexReader indexReader;
+        public readonly FacetArrays facetArrays;
+        public FacetSearchParams searchParams;
+
+        public FacetsAccumulator(FacetSearchParams searchParams, IndexReader indexReader, TaxonomyReader taxonomyReader)
+            : this(searchParams, indexReader, taxonomyReader, null)
+        {
+        }
+
+        public static FacetsAccumulator Create(FacetSearchParams fsp, IndexReader indexReader, TaxonomyReader taxoReader)
+        {
+            if (fsp.indexingParams.PartitionSize != int.MaxValue)
+            {
+                return new StandardFacetsAccumulator(fsp, indexReader, taxoReader);
+            }
+
+            foreach (FacetRequest fr in fsp.facetRequests)
+            {
+                if (!(fr is CountFacetRequest))
+                {
+                    return new StandardFacetsAccumulator(fsp, indexReader, taxoReader);
+                }
+            }
+
+            return new FacetsAccumulator(fsp, indexReader, taxoReader);
+        }
+
+        protected static FacetResult EmptyResult(int ordinal, FacetRequest fr)
+        {
+            FacetResultNode root = new FacetResultNode(ordinal, 0);
+            root.label = fr.categoryPath;
+            return new FacetResult(fr, root, 0);
+        }
+
+        public FacetsAccumulator(FacetSearchParams searchParams, IndexReader indexReader, TaxonomyReader taxonomyReader, FacetArrays facetArrays)
+        {
+            if (facetArrays == null)
+            {
+                facetArrays = new FacetArrays(taxonomyReader.Size);
+            }
+
+            this.facetArrays = facetArrays;
+            this.indexReader = indexReader;
+            this.taxonomyReader = taxonomyReader;
+            this.searchParams = searchParams;
+        }
+
+        public virtual IFacetsAggregator Aggregator
+        {
+            get
+            {
+                if (FastCountingFacetsAggregator.VerifySearchParams(searchParams))
+                {
+                    return new FastCountingFacetsAggregator();
+                }
+                else
+                {
+                    return new CountingFacetsAggregator();
+                }
+            }
+        }
+
+        protected virtual FacetResultsHandler CreateFacetResultsHandler(FacetRequest fr)
+        {
+            if (fr.Depth == 1 && fr.SortOrderValue == FacetRequest.SortOrder.DESCENDING)
+            {
+                FacetRequest.FacetArraysSource fas = fr.FacetArraysSourceValue;
+                if (fas == FacetRequest.FacetArraysSource.INT)
+                {
+                    return new IntFacetResultsHandler(taxonomyReader, fr, facetArrays);
+                }
+
+                if (fas == FacetRequest.FacetArraysSource.FLOAT)
+                {
+                    return new FloatFacetResultsHandler(taxonomyReader, fr, facetArrays);
+                }
+            }
+
+            if (fr.ResultModeValue == FacetRequest.ResultMode.PER_NODE_IN_TREE)
+            {
+                return new TopKInEachNodeHandler(taxonomyReader, fr, facetArrays);
+            }
+
+            return new TopKFacetResultsHandler(taxonomyReader, fr, facetArrays);
+        }
+
+        protected virtual ISet<CategoryListParams> GetCategoryLists()
+        {
+            if (searchParams.indexingParams.AllCategoryListParams.Count == 1)
+            {
+                return new HashSet<CategoryListParams>(new[] { searchParams.indexingParams.GetCategoryListParams(null) });
+            }
+
+            HashSet<CategoryListParams> clps = new HashSet<CategoryListParams>();
+            foreach (FacetRequest fr in searchParams.facetRequests)
+            {
+                clps.Add(searchParams.indexingParams.GetCategoryListParams(fr.categoryPath));
+            }
+
+            return clps;
+        }
+
+        public virtual List<FacetResult> Accumulate(List<FacetsCollector.MatchingDocs> matchingDocs)
+        {
+            IFacetsAggregator aggregator = Aggregator;
+            foreach (CategoryListParams clp in GetCategoryLists())
+            {
+                foreach (FacetsCollector.MatchingDocs md in matchingDocs)
+                {
+                    aggregator.Aggregate(md, clp, facetArrays);
+                }
+            }
+
+            ParallelTaxonomyArrays arrays = taxonomyReader.ParallelTaxonomyArrays;
+            int[] children = arrays.Children;
+            int[] siblings = arrays.Siblings;
+            List<FacetResult> res = new List<FacetResult>();
+            foreach (FacetRequest fr in searchParams.facetRequests)
+            {
+                int rootOrd = taxonomyReader.GetOrdinal(fr.categoryPath);
+                if (rootOrd == TaxonomyReader.INVALID_ORDINAL)
+                {
+                    res.Add(EmptyResult(rootOrd, fr));
+                    continue;
+                }
+
+                CategoryListParams clp = searchParams.indexingParams.GetCategoryListParams(fr.categoryPath);
+                if (fr.categoryPath.length > 0)
+                {
+                    CategoryListParams.OrdinalPolicy ordinalPolicy = clp.GetOrdinalPolicy(fr.categoryPath.components[0]);
+                    if (ordinalPolicy == CategoryListParams.OrdinalPolicy.NO_PARENTS)
+                    {
+                        aggregator.RollupValues(fr, rootOrd, children, siblings, facetArrays);
+                    }
+                }
+
+                FacetResultsHandler frh = CreateFacetResultsHandler(fr);
+                res.Add(frh.Compute());
+            }
+
+            return res;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/FacetsCollector.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/FacetsCollector.cs b/src/contrib/Facet/Search/FacetsCollector.cs
new file mode 100644
index 0000000..797c97e
--- /dev/null
+++ b/src/contrib/Facet/Search/FacetsCollector.cs
@@ -0,0 +1,208 @@
+using Lucene.Net.Facet.Params;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public abstract class FacetsCollector : Collector
+    {
+        private sealed class DocsAndScoresCollector : FacetsCollector
+        {
+            private AtomicReaderContext context;
+            private Scorer scorer;
+            private FixedBitSet bits;
+            private int totalHits;
+            private float[] scores;
+
+            public DocsAndScoresCollector(FacetsAccumulator accumulator)
+                : base(accumulator)
+            {
+            }
+
+            protected override void Finish()
+            {
+                if (bits != null)
+                {
+                    matchingDocs.Add(new MatchingDocs(this.context, bits, totalHits, scores));
+                    bits = null;
+                    scores = null;
+                    context = null;
+                }
+            }
+
+            public override bool AcceptsDocsOutOfOrder
+            {
+                get
+                {
+                    return false;
+                }
+            }
+
+            public override void Collect(int doc)
+            {
+                bits.Set(doc);
+                if (totalHits >= scores.Length)
+                {
+                    float[] newScores = new float[ArrayUtil.Oversize(totalHits + 1, 4)];
+                    Array.Copy(scores, 0, newScores, 0, totalHits);
+                    scores = newScores;
+                }
+
+                scores[totalHits] = scorer.Score();
+                totalHits++;
+            }
+
+            public override void SetScorer(Scorer scorer)
+            {
+                this.scorer = scorer;
+            }
+
+            protected override void DoSetNextReader(AtomicReaderContext context)
+            {
+                if (bits != null)
+                {
+                    matchingDocs.Add(new MatchingDocs(this.context, bits, totalHits, scores));
+                }
+
+                bits = new FixedBitSet(context.AtomicReader.MaxDoc);
+                totalHits = 0;
+                scores = new float[64];
+                this.context = context;
+            }
+        }
+
+        private sealed class DocsOnlyCollector : FacetsCollector
+        {
+            private AtomicReaderContext context;
+            private FixedBitSet bits;
+            private int totalHits;
+
+            public DocsOnlyCollector(FacetsAccumulator accumulator)
+                : base(accumulator)
+            {
+            }
+
+            protected override void Finish()
+            {
+                if (bits != null)
+                {
+                    matchingDocs.Add(new MatchingDocs(this.context, bits, totalHits, null));
+                    bits = null;
+                    context = null;
+                }
+            }
+
+            public override bool AcceptsDocsOutOfOrder
+            {
+                get
+                {
+                    return true;
+                }
+            }
+
+            public override void Collect(int doc)
+            {
+                totalHits++;
+                bits.Set(doc);
+            }
+
+            public override void SetScorer(Scorer scorer)
+            {
+            }
+
+            protected override void DoSetNextReader(AtomicReaderContext context)
+            {
+                if (bits != null)
+                {
+                    matchingDocs.Add(new MatchingDocs(this.context, bits, totalHits, null));
+                }
+
+                bits = new FixedBitSet(context.AtomicReader.MaxDoc);
+                totalHits = 0;
+                this.context = context;
+            }
+        }
+
+        public sealed class MatchingDocs
+        {
+            public readonly AtomicReaderContext context;
+            public readonly FixedBitSet bits;
+            public readonly float[] scores;
+            public readonly int totalHits;
+
+            public MatchingDocs(AtomicReaderContext context, FixedBitSet bits, int totalHits, float[] scores)
+            {
+                this.context = context;
+                this.bits = bits;
+                this.scores = scores;
+                this.totalHits = totalHits;
+            }
+        }
+
+        public static FacetsCollector Create(FacetSearchParams fsp, IndexReader indexReader, TaxonomyReader taxoReader)
+        {
+            return Create(FacetsAccumulator.Create(fsp, indexReader, taxoReader));
+        }
+
+        public static FacetsCollector Create(FacetsAccumulator accumulator)
+        {
+            if (accumulator.Aggregator.RequiresDocScores)
+            {
+                return new DocsAndScoresCollector(accumulator);
+            }
+            else
+            {
+                return new DocsOnlyCollector(accumulator);
+            }
+        }
+
+        private readonly FacetsAccumulator accumulator;
+        private List<FacetResult> cachedResults;
+        protected readonly List<MatchingDocs> matchingDocs = new List<MatchingDocs>();
+
+        protected FacetsCollector(FacetsAccumulator accumulator)
+        {
+            this.accumulator = accumulator;
+        }
+
+        protected abstract void Finish();
+        
+        protected abstract void DoSetNextReader(AtomicReaderContext context);
+
+        public List<FacetResult> GetFacetResults()
+        {
+            if (cachedResults == null)
+            {
+                Finish();
+                cachedResults = accumulator.Accumulate(matchingDocs);
+            }
+
+            return cachedResults;
+        }
+
+        public List<MatchingDocs> GetMatchingDocs()
+        {
+            Finish();
+            return matchingDocs;
+        }
+
+        public void Reset()
+        {
+            Finish();
+            matchingDocs.Clear();
+            cachedResults = null;
+        }
+
+        public override void SetNextReader(AtomicReaderContext context)
+        {
+            cachedResults = null;
+            DoSetNextReader(context);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/FastCountingFacetsAggregator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/FastCountingFacetsAggregator.cs b/src/contrib/Facet/Search/FastCountingFacetsAggregator.cs
new file mode 100644
index 0000000..524cc10
--- /dev/null
+++ b/src/contrib/Facet/Search/FastCountingFacetsAggregator.cs
@@ -0,0 +1,70 @@
+using Lucene.Net.Facet.Encoding;
+using Lucene.Net.Facet.Params;
+using Lucene.Net.Index;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public sealed class FastCountingFacetsAggregator : IntRollupFacetsAggregator
+    {
+        private readonly BytesRef buf = new BytesRef(32);
+
+        internal static bool VerifySearchParams(FacetSearchParams fsp)
+        {
+            foreach (FacetRequest fr in fsp.facetRequests)
+            {
+                CategoryListParams clp = fsp.indexingParams.GetCategoryListParams(fr.categoryPath);
+                if (clp.CreateEncoder().CreateMatchingDecoder().GetType() != typeof(DGapVInt8IntDecoder))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public override void Aggregate(FacetsCollector.MatchingDocs matchingDocs, CategoryListParams clp, FacetArrays facetArrays)
+        {
+            BinaryDocValues dv = matchingDocs.context.AtomicReader.GetBinaryDocValues(clp.field);
+            if (dv == null)
+            {
+                return;
+            }
+
+            int length = matchingDocs.bits.Length;
+            int[] counts = facetArrays.GetIntArray();
+            int doc = 0;
+            while (doc < length && (doc = matchingDocs.bits.NextSetBit(doc)) != -1)
+            {
+                dv.Get(doc, buf);
+                if (buf.length > 0)
+                {
+                    int upto = buf.offset + buf.length;
+                    int ord = 0;
+                    int offset = buf.offset;
+                    int prev = 0;
+                    while (offset < upto)
+                    {
+                        sbyte b = buf.bytes[offset++];
+                        if (b >= 0)
+                        {
+                            prev = ord = ((ord << 7) | (byte)b) + prev;
+                            ++counts[ord];
+                            ord = 0;
+                        }
+                        else
+                        {
+                            ord = (ord << 7) | (b & 0x7F);
+                        }
+                    }
+                }
+
+                ++doc;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/FloatFacetResultsHandler.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/FloatFacetResultsHandler.cs b/src/contrib/Facet/Search/FloatFacetResultsHandler.cs
new file mode 100644
index 0000000..79981b1
--- /dev/null
+++ b/src/contrib/Facet/Search/FloatFacetResultsHandler.cs
@@ -0,0 +1,65 @@
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public sealed class FloatFacetResultsHandler : DepthOneFacetResultsHandler
+    {
+        private readonly float[] values;
+
+        public FloatFacetResultsHandler(TaxonomyReader taxonomyReader, FacetRequest facetRequest, FacetArrays facetArrays)
+            : base(taxonomyReader, facetRequest, facetArrays)
+        {
+            this.values = facetArrays.GetFloatArray();
+        }
+
+        protected override double ValueOf(int ordinal)
+        {
+            return values[ordinal];
+        }
+
+        protected override int AddSiblings(int ordinal, int[] siblings, PriorityQueue<FacetResultNode> pq)
+        {
+            FacetResultNode top = pq.Top();
+            int numResults = 0;
+            while (ordinal != TaxonomyReader.INVALID_ORDINAL)
+            {
+                float value = values[ordinal];
+                if (value > 0F)
+                {
+                    ++numResults;
+                    if (value > top.value)
+                    {
+                        top.value = value;
+                        top.ordinal = ordinal;
+                        top = pq.UpdateTop();
+                    }
+                }
+
+                ordinal = siblings[ordinal];
+            }
+
+            return numResults;
+        }
+
+        protected override void AddSiblings(int ordinal, int[] siblings, List<FacetResultNode> nodes)
+        {
+            while (ordinal != TaxonomyReader.INVALID_ORDINAL)
+            {
+                float value = values[ordinal];
+                if (value > 0)
+                {
+                    FacetResultNode node = new FacetResultNode(ordinal, value);
+                    node.label = taxonomyReader.GetPath(ordinal);
+                    nodes.Add(node);
+                }
+
+                ordinal = siblings[ordinal];
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/IFacetsAggregator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/IFacetsAggregator.cs b/src/contrib/Facet/Search/IFacetsAggregator.cs
new file mode 100644
index 0000000..5d66d5b
--- /dev/null
+++ b/src/contrib/Facet/Search/IFacetsAggregator.cs
@@ -0,0 +1,17 @@
+using Lucene.Net.Facet.Params;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public interface IFacetsAggregator
+    {
+        void Aggregate(FacetsCollector.MatchingDocs matchingDocs, CategoryListParams clp, FacetArrays facetArrays);
+
+        void RollupValues(FacetRequest fr, int ordinal, int[] children, int[] siblings, FacetArrays facetArrays);
+
+        bool RequiresDocScores { get; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/IntFacetResultsHandler.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/IntFacetResultsHandler.cs b/src/contrib/Facet/Search/IntFacetResultsHandler.cs
new file mode 100644
index 0000000..de3712e
--- /dev/null
+++ b/src/contrib/Facet/Search/IntFacetResultsHandler.cs
@@ -0,0 +1,64 @@
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public sealed class IntFacetResultsHandler : DepthOneFacetResultsHandler
+    {
+        private readonly int[] values;
+        public IntFacetResultsHandler(TaxonomyReader taxonomyReader, FacetRequest facetRequest, FacetArrays facetArrays)
+            : base(taxonomyReader, facetRequest, facetArrays)
+        {
+            this.values = facetArrays.GetIntArray();
+        }
+
+        protected override double ValueOf(int ordinal)
+        {
+            return values[ordinal];
+        }
+
+        protected override int AddSiblings(int ordinal, int[] siblings, PriorityQueue<FacetResultNode> pq)
+        {
+            FacetResultNode top = pq.Top();
+            int numResults = 0;
+            while (ordinal != TaxonomyReader.INVALID_ORDINAL)
+            {
+                int value = values[ordinal];
+                if (value > 0)
+                {
+                    ++numResults;
+                    if (value > top.value)
+                    {
+                        top.value = value;
+                        top.ordinal = ordinal;
+                        top = pq.UpdateTop();
+                    }
+                }
+
+                ordinal = siblings[ordinal];
+            }
+
+            return numResults;
+        }
+
+        protected override void AddSiblings(int ordinal, int[] siblings, List<FacetResultNode> nodes)
+        {
+            while (ordinal != TaxonomyReader.INVALID_ORDINAL)
+            {
+                int value = values[ordinal];
+                if (value > 0)
+                {
+                    FacetResultNode node = new FacetResultNode(ordinal, value);
+                    node.label = taxonomyReader.GetPath(ordinal);
+                    nodes.Add(node);
+                }
+
+                ordinal = siblings[ordinal];
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/IntRollupFacetsAggregator.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/IntRollupFacetsAggregator.cs b/src/contrib/Facet/Search/IntRollupFacetsAggregator.cs
new file mode 100644
index 0000000..913d5a3
--- /dev/null
+++ b/src/contrib/Facet/Search/IntRollupFacetsAggregator.cs
@@ -0,0 +1,43 @@
+using Lucene.Net.Facet.Params;
+using Lucene.Net.Facet.Taxonomy;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public abstract class IntRollupFacetsAggregator : IFacetsAggregator
+    {
+        public abstract void Aggregate(FacetsCollector.MatchingDocs matchingDocs, CategoryListParams clp, FacetArrays facetArrays);
+
+        private int RollupValues(int ordinal, int[] children, int[] siblings, int[] values)
+        {
+            int value = 0;
+            while (ordinal != TaxonomyReader.INVALID_ORDINAL)
+            {
+                int childValue = values[ordinal];
+                childValue += RollupValues(children[ordinal], children, siblings, values);
+                values[ordinal] = childValue;
+                value += childValue;
+                ordinal = siblings[ordinal];
+            }
+
+            return value;
+        }
+
+        public void RollupValues(FacetRequest fr, int ordinal, int[] children, int[] siblings, FacetArrays facetArrays)
+        {
+            int[] values = facetArrays.GetIntArray();
+            values[ordinal] += RollupValues(children[ordinal], children, siblings, values);
+        }
+
+        public bool RequiresDocScores
+        {
+            get
+            {
+                return false;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/318dea52/src/contrib/Facet/Search/MatchingDocsAsScoredDocIDs.cs
----------------------------------------------------------------------
diff --git a/src/contrib/Facet/Search/MatchingDocsAsScoredDocIDs.cs b/src/contrib/Facet/Search/MatchingDocsAsScoredDocIDs.cs
new file mode 100644
index 0000000..1827516
--- /dev/null
+++ b/src/contrib/Facet/Search/MatchingDocsAsScoredDocIDs.cs
@@ -0,0 +1,209 @@
+using Lucene.Net.Search;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Lucene.Net.Facet.Search
+{
+    public class MatchingDocsAsScoredDocIDs : IScoredDocIDs
+    {
+        readonly List<FacetsCollector.MatchingDocs> matchingDocs;
+        readonly int size;
+
+        public MatchingDocsAsScoredDocIDs(List<FacetsCollector.MatchingDocs> matchingDocs)
+        {
+            this.matchingDocs = matchingDocs;
+            int totalSize = 0;
+            foreach (FacetsCollector.MatchingDocs md in matchingDocs)
+            {
+                totalSize += md.totalHits;
+            }
+
+            this.size = totalSize;
+        }
+
+        public IScoredDocIDsIterator Iterator()
+        {
+            return new AnonymousScoredDocIDsIterator(this);
+        }
+
+        private sealed class AnonymousScoredDocIDsIterator : IScoredDocIDsIterator
+        {
+            public AnonymousScoredDocIDsIterator(MatchingDocsAsScoredDocIDs parent)
+            {
+                this.parent = parent;
+                mdIter = parent.matchingDocs.GetEnumerator();
+            }
+
+            private readonly MatchingDocsAsScoredDocIDs parent;
+            readonly IEnumerator<FacetsCollector.MatchingDocs> mdIter; // = parent.matchingDocs.GetEnumerator();
+            int scoresIdx = 0;
+            int doc = 0;
+            FacetsCollector.MatchingDocs current;
+            int currentLength;
+            bool done = false;
+
+            public bool Next()
+            {
+                if (done)
+                {
+                    return false;
+                }
+
+                while (current == null)
+                {
+                    if (!mdIter.MoveNext())
+                    {
+                        done = true;
+                        return false;
+                    }
+
+                    current = mdIter.Current;
+                    currentLength = current.bits.Length;
+                    doc = 0;
+                    scoresIdx = 0;
+                    if (doc >= currentLength || (doc = current.bits.NextSetBit(doc)) == -1)
+                    {
+                        current = null;
+                    }
+                    else
+                    {
+                        doc = -1;
+                    }
+                }
+
+                ++doc;
+                if (doc >= currentLength || (doc = current.bits.NextSetBit(doc)) == -1)
+                {
+                    current = null;
+                    return Next();
+                }
+
+                return true;
+            }
+
+            public float Score
+            {
+                get
+                {
+                    return current.scores == null ? ScoredDocIDsIterator.DEFAULT_SCORE : current.scores[scoresIdx++];
+                }
+            }
+
+            public int DocID
+            {
+                get
+                {
+                    return done ? DocIdSetIterator.NO_MORE_DOCS : doc + current.context.docBase;
+                }
+            }
+        }
+
+        public DocIdSet DocIDs
+        {
+            get
+            {
+                return new AnonymousDocIdSet(this);
+            }
+        }
+
+        private sealed class AnonymousDocIdSetIterator : DocIdSetIterator
+        {
+            public AnonymousDocIdSetIterator(AnonymousDocIdSet parent)
+            {
+                this.parent = parent;
+            }
+
+            private readonly AnonymousDocIdSet parent;
+
+            public override int NextDoc()
+            {
+                if (parent.done)
+                {
+                    return DocIdSetIterator.NO_MORE_DOCS;
+                }
+
+                while (parent.current == null)
+                {
+                    if (!parent.mdIter.MoveNext())
+                    {
+                        parent.done = true;
+                        return DocIdSetIterator.NO_MORE_DOCS;
+                    }
+
+                    parent.current = parent.mdIter.Current;
+                    parent.currentLength = parent.current.bits.Length;
+                    parent.doc = 0;
+                    if (parent.doc >= parent.currentLength || (parent.doc = parent.current.bits.NextSetBit(parent.doc)) == -1)
+                    {
+                        parent.current = null;
+                    }
+                    else
+                    {
+                        parent.doc = -1;
+                    }
+                }
+
+                ++parent.doc;
+                if (parent.doc >= parent.currentLength || (parent.doc = parent.current.bits.NextSetBit(parent.doc)) == -1)
+                {
+                    parent.current = null;
+                    return NextDoc();
+                }
+
+                return parent.doc + parent.current.context.docBase;
+            }
+
+            public override int DocID
+            {
+                get
+                {
+                    return parent.doc + parent.current.context.docBase;
+                }
+            }
+
+            public override long Cost
+            {
+                get
+                {
+                    return parent.parent.size;
+                }
+            }
+
+            public override int Advance(int target)
+            {
+                throw new NotSupportedException(@"not supported");
+            }
+        }
+
+        private sealed class AnonymousDocIdSet : DocIdSet
+        {
+            public AnonymousDocIdSet(MatchingDocsAsScoredDocIDs parent)
+            {
+                this.parent = parent;
+                mdIter = parent.matchingDocs.GetEnumerator();
+            }
+
+            internal readonly MatchingDocsAsScoredDocIDs parent;
+            internal readonly IEnumerator<FacetsCollector.MatchingDocs> mdIter; // = matchingDocs.GetEnumerator();
+            internal int doc = 0;
+            internal FacetsCollector.MatchingDocs current;
+            internal int currentLength;
+            internal bool done = false;
+            
+            public override DocIdSetIterator Iterator()
+            {
+                return new AnonymousDocIdSetIterator(this);
+            }
+        }
+
+        public int Size
+        {
+            get
+            {
+                return size;
+            }
+        }
+    }
+}


Mime
View raw message