You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by sy...@apache.org on 2014/09/16 00:46:59 UTC

[01/11] git commit: Commenting this out for now to fix compilation

Repository: lucenenet
Updated Branches:
  refs/heads/master 0ebac7269 -> 531b4af02


Commenting this out for now to fix compilation


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

Branch: refs/heads/master
Commit: 895be41b1efd5b33704578f13ae1426f2511a590
Parents: 0ebac72
Author: Itamar Syn-Hershko <it...@code972.com>
Authored: Tue Sep 16 01:25:16 2014 +0300
Committer: Itamar Syn-Hershko <it...@code972.com>
Committed: Tue Sep 16 01:25:16 2014 +0300

----------------------------------------------------------------------
 src/Lucene.Net.Core/Util/OfflineSorter.cs | 1286 ++++++++++++------------
 1 file changed, 643 insertions(+), 643 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/895be41b/src/Lucene.Net.Core/Util/OfflineSorter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Core/Util/OfflineSorter.cs b/src/Lucene.Net.Core/Util/OfflineSorter.cs
index f966e77..4f72585 100644
--- a/src/Lucene.Net.Core/Util/OfflineSorter.cs
+++ b/src/Lucene.Net.Core/Util/OfflineSorter.cs
@@ -32,648 +32,648 @@ namespace Lucene.Net.Util
     /// </summary>
     public sealed class OfflineSorter
     {
-        private bool InstanceFieldsInitialized = false;
-
-        private void InitializeInstanceFields()
-        {
-            Buffer = new BytesRefArray(BufferBytesUsed);
-        }
-
-        /// <summary>
-        /// Convenience constant for megabytes </summary>
-        public const long MB = 1024 * 1024;
-        /// <summary>
-        /// Convenience constant for gigabytes </summary>
-        public static readonly long GB = MB * 1024;
-
-        /// <summary>
-        /// Minimum recommended buffer size for sorting.
-        /// </summary>
-        public const long MIN_BUFFER_SIZE_MB = 32;
-
-        /// <summary>
-        /// Absolute minimum required buffer size for sorting.
-        /// </summary>
-        public static readonly long ABSOLUTE_MIN_SORT_BUFFER_SIZE = MB / 2;
-        private const string MIN_BUFFER_SIZE_MSG = "At least 0.5MB RAM buffer is needed";
-
-        /// <summary>
-        /// Maximum number of temporary files before doing an intermediate merge.
-        /// </summary>
-        public const int MAX_TEMPFILES = 128;
-
-        /// <summary>
-        /// A bit more descriptive unit for constructors.
-        /// </summary>
-        /// <seealso cref= #automatic() </seealso>
-        /// <seealso cref= #megabytes(long) </seealso>
-        public sealed class BufferSize
-        {
-            internal readonly int Bytes;
-
-            internal BufferSize(long bytes)
-            {
-                if (bytes > int.MaxValue)
-                {
-                    throw new System.ArgumentException("Buffer too large for Java (" + (int.MaxValue / MB) + "mb max): " + bytes);
-                }
-
-                if (bytes < ABSOLUTE_MIN_SORT_BUFFER_SIZE)
-                {
-                    throw new System.ArgumentException(MIN_BUFFER_SIZE_MSG + ": " + bytes);
-                }
-
-                this.Bytes = (int)bytes;
-            }
-
-            /// <summary>
-            /// Creates a <seealso cref="BufferSize"/> in MB. The given
-            /// values must be &gt; 0 and &lt; 2048.
-            /// </summary>
-            public static BufferSize Megabytes(long mb)
-            {
-                return new BufferSize(mb * MB);
-            }
-
-            /// <summary>
-            /// Approximately half of the currently available free heap, but no less
-            /// than <seealso cref="#ABSOLUTE_MIN_SORT_BUFFER_SIZE"/>. However if current heap allocation
-            /// is insufficient or if there is a large portion of unallocated heap-space available
-            /// for sorting consult with max allowed heap size.
-            /// </summary>
-            public static BufferSize Automatic()
-            {
-                var proc = Process.GetCurrentProcess();
-
-                // take sizes in "conservative" order
-                long max = proc.PeakVirtualMemorySize64; // max allocated; java has it as Runtime.maxMemory();
-                long total = proc.VirtualMemorySize64; // currently allocated; java has it as Runtime.totalMemory();
-                long free = rt.freeMemory(); // unused portion of currently allocated
-                long totalAvailableBytes = max - total + free;
-
-                // by free mem (attempting to not grow the heap for this)
-                long sortBufferByteSize = free / 2;
-                const long minBufferSizeBytes = MIN_BUFFER_SIZE_MB * MB;
-                if (sortBufferByteSize < minBufferSizeBytes || totalAvailableBytes > 10 * minBufferSizeBytes) // lets see if we need/should to grow the heap
-                {
-                    if (totalAvailableBytes / 2 > minBufferSizeBytes) // there is enough mem for a reasonable buffer
-                    {
-                        sortBufferByteSize = totalAvailableBytes / 2; // grow the heap
-                    }
-                    else
-                    {
-                        //heap seems smallish lets be conservative fall back to the free/2
-                        sortBufferByteSize = Math.Max(ABSOLUTE_MIN_SORT_BUFFER_SIZE, sortBufferByteSize);
-                    }
-                }
-                return new BufferSize(Math.Min((long)int.MaxValue, sortBufferByteSize));
-            }
-        }
-
-        /// <summary>
-        /// Sort info (debugging mostly).
-        /// </summary>
-        public class SortInfo
-        {
-            internal bool InstanceFieldsInitialized = false;
-
-            internal virtual void InitializeInstanceFields()
-            {
-                BufferSize = OuterInstance.RamBufferSize.Bytes;
-            }
-
-            private readonly OfflineSorter OuterInstance;
-
-            /// <summary>
-            /// number of temporary files created when merging partitions </summary>
-            public int TempMergeFiles;
-            /// <summary>
-            /// number of partition merges </summary>
-            public int MergeRounds;
-            /// <summary>
-            /// number of lines of data read </summary>
-            public int Lines;
-            /// <summary>
-            /// time spent merging sorted partitions (in milliseconds) </summary>
-            public long MergeTime;
-            /// <summary>
-            /// time spent sorting data (in milliseconds) </summary>
-            public long SortTime;
-            /// <summary>
-            /// total time spent (in milliseconds) </summary>
-            public long TotalTime;
-            /// <summary>
-            /// time spent in i/o read (in milliseconds) </summary>
-            public long ReadTime;
-            /// <summary>
-            /// read buffer size (in bytes) </summary>
-            public long BufferSize;
-
-            /// <summary>
-            /// create a new SortInfo (with empty statistics) for debugging </summary>
-            public SortInfo(OfflineSorter outerInstance)
-            {
-                this.OuterInstance = outerInstance;
-
-                if (!InstanceFieldsInitialized)
-                {
-                    InitializeInstanceFields();
-                    InstanceFieldsInitialized = true;
-                }
-            }
-
-            public override string ToString()
-            {
-                return string.Format("time=%.2f sec. total (%.2f reading, %.2f sorting, %.2f merging), lines=%d, temp files=%d, merges=%d, soft ram limit=%.2f MB", TotalTime / 1000.0d, ReadTime / 1000.0d, SortTime / 1000.0d, MergeTime / 1000.0d, Lines, TempMergeFiles, MergeRounds, (double)BufferSize / MB);
-            }
-        }
-
-        private readonly BufferSize RamBufferSize;
-
-        private readonly Counter BufferBytesUsed = Counter.NewCounter();
-        private BytesRefArray Buffer;
-        private SortInfo sortInfo;
-        private readonly int MaxTempFiles;
-        private readonly IComparer<BytesRef> comparator;
-
-        /// <summary>
-        /// Default comparator: sorts in binary (codepoint) order </summary>
-        public static readonly IComparer<BytesRef> DEFAULT_COMPARATOR = BytesRef.UTF8SortedAsUnicodeComparator.Instance;
-
-        /// <summary>
-        /// Defaults constructor.
-        /// </summary>
-        /// <seealso cref= #defaultTempDir() </seealso>
-        /// <seealso cref= BufferSize#automatic() </seealso>
-        public OfflineSorter()
-            : this(DEFAULT_COMPARATOR, BufferSize.Automatic(), DefaultTempDir(), MAX_TEMPFILES)
-        {
-            if (!InstanceFieldsInitialized)
-            {
-                InitializeInstanceFields();
-                InstanceFieldsInitialized = true;
-            }
-        }
-
-        /// <summary>
-        /// Defaults constructor with a custom comparator.
-        /// </summary>
-        /// <seealso cref= #defaultTempDir() </seealso>
-        /// <seealso cref= BufferSize#automatic() </seealso>
-        public OfflineSorter(IComparer<BytesRef> comparator)
-            : this(comparator, BufferSize.Automatic(), DefaultTempDir(), MAX_TEMPFILES)
-        {
-            if (!InstanceFieldsInitialized)
-            {
-                InitializeInstanceFields();
-                InstanceFieldsInitialized = true;
-            }
-        }
-
-        /// <summary>
-        /// All-details constructor.
-        /// </summary>
-        public OfflineSorter(IComparer<BytesRef> comparator, BufferSize ramBufferSize, /*DirectoryInfo tempDirectory,*/ int maxTempfiles)
-        {
-            if (!InstanceFieldsInitialized)
-            {
-                InitializeInstanceFields();
-                InstanceFieldsInitialized = true;
-            }
-            if (ramBufferSize.Bytes < ABSOLUTE_MIN_SORT_BUFFER_SIZE)
-            {
-                throw new System.ArgumentException(MIN_BUFFER_SIZE_MSG + ": " + ramBufferSize.Bytes);
-            }
-
-            if (maxTempfiles < 2)
-            {
-                throw new System.ArgumentException("maxTempFiles must be >= 2");
-            }
-
-            this.RamBufferSize = ramBufferSize;
-            this.MaxTempFiles = maxTempfiles;
-            this.comparator = comparator;
-        }
-
-        /// <summary>
-        /// Sort input to output, explicit hint for the buffer size. The amount of allocated
-        /// memory may deviate from the hint (may be smaller or larger).
-        /// </summary>
-        public SortInfo Sort(FileInfo input, FileInfo output)
-        {
-            sortInfo = new SortInfo(this) {TotalTime = DateTime.Now.Millisecond};
-
-            output.Delete();
-
-            var merges = new List<FileInfo>();
-            bool success2 = false;
-            try
-            {
-                var inputStream = new ByteSequencesReader(input);
-                bool success = false;
-                try
-                {
-                    int lines = 0;
-                    while ((lines = ReadPartition(inputStream)) > 0)
-                    {
-                        merges.Add(SortPartition(lines));
-                        sortInfo.TempMergeFiles++;
-                        sortInfo.Lines += lines;
-
-                        // Handle intermediate merges.
-                        if (merges.Count == MaxTempFiles)
-                        {
-                            var intermediate = new FileInfo(Path.GetTempFileName());
-                            try
-                            {
-                                MergePartitions(merges, intermediate);
-                            }
-                            finally
-                            {
-                                foreach (var file in merges)
-                                {
-                                    file.Delete();
-                                }
-                                merges.Clear();
-                                merges.Add(intermediate);
-                            }
-                            sortInfo.TempMergeFiles++;
-                        }
-                    }
-                    success = true;
-                }
-                finally
-                {
-                    if (success)
-                    {
-                        IOUtils.Close(inputStream);
-                    }
-                    else
-                    {
-                        IOUtils.CloseWhileHandlingException(inputStream);
-                    }
-                }
-
-                // One partition, try to rename or copy if unsuccessful.
-                if (merges.Count == 1)
-                {
-                    FileInfo single = merges[0];
-                    Copy(single, output);
-                    try
-                    {
-                        File.Delete(single.FullName);
-                    }
-                    catch (Exception)
-                    {
-                        // ignored
-                    }
-                }
-                else
-                {
-                    // otherwise merge the partitions with a priority queue.
-                    MergePartitions(merges, output);
-                }
-                success2 = true;
-            }
-            finally
-            {
-                foreach (FileInfo file in merges)
-                {
-                    file.Delete();
-                }
-                if (!success2)
-                {
-                    output.Delete();
-                }
-            }
-
-            sortInfo.TotalTime = (DateTime.Now.Millisecond - sortInfo.TotalTime);
-            return sortInfo;
-        }
-
-        /// <summary>
-        /// Returns the default temporary directory. By default, the System's temp folder. If not accessible
-        /// or not available, an IOException is thrown
-        /// </summary>
-        public static DirectoryInfo DefaultTempDir()
-        {
-            return new DirectoryInfo(Path.GetTempPath());
-        }
-
-        /// <summary>
-        /// Copies one file to another.
-        /// </summary>
-        private static void Copy(FileInfo file, FileInfo output)
-        {
-            File.Copy(file.FullName, output.FullName);
-        }
-
-        /// <summary>
-        /// Sort a single partition in-memory. </summary>
-        internal FileInfo SortPartition(int len)
-        {
-            var data = this.Buffer;
-            var tempFile = new FileInfo(Path.GetTempFileName());
-            //var tempFile1 = File.Create(new ());
-            //FileInfo tempFile = FileInfo.createTempFile("sort", "partition", TempDirectory);
-
-            long start = DateTime.Now.Millisecond;
-            sortInfo.SortTime += (DateTime.Now.Millisecond - start);
-
-            var @out = new ByteSequencesWriter(tempFile);
-            BytesRef spare;
-            try
-            {
-                BytesRefIterator iter = Buffer.Iterator(comparator);
-                while ((spare = iter.Next()) != null)
-                {
-                    Debug.Assert(spare.Length <= short.MaxValue);
-                    @out.Write(spare);
-                }
-
-                @out.Dispose();
-
-                // Clean up the buffer for the next partition.
-                data.Clear();
-                return tempFile;
-            }
-            finally
-            {
-                IOUtils.Close(@out);
-            }
-        }
-
-        /// <summary>
-        /// Merge a list of sorted temporary files (partitions) into an output file </summary>
-        internal void MergePartitions(IList<FileInfo> merges, FileInfo outputFile)
-        {
-            long start = DateTime.Now.Millisecond;
-
-            var @out = new ByteSequencesWriter(outputFile);
-
-            PriorityQueue<FileAndTop> queue = new PriorityQueueAnonymousInnerClassHelper(this, merges.Count);
-
-            var streams = new ByteSequencesReader[merges.Count];
-            try
-            {
-                // Open streams and read the top for each file
-                for (int i = 0; i < merges.Count; i++)
-                {
-                    streams[i] = new ByteSequencesReader(merges[i]);
-                    sbyte[] line = streams[i].Read();
-                    if (line != null)
-                    {
-                        queue.InsertWithOverflow(new FileAndTop(i, line));
-                    }
-                }
-
-                // Unix utility sort() uses ordered array of files to pick the next line from, updating
-                // it as it reads new lines. The PQ used here is a more elegant solution and has
-                // a nicer theoretical complexity bound :) The entire sorting process is I/O bound anyway
-                // so it shouldn't make much of a difference (didn't check).
-                FileAndTop top;
-                while ((top = queue.Top()) != null)
-                {
-                    @out.Write(top.Current);
-                    if (!streams[top.Fd].Read(top.Current))
-                    {
-                        queue.Pop();
-                    }
-                    else
-                    {
-                        queue.UpdateTop();
-                    }
-                }
-
-                SortInfo.MergeTime += DateTime.UtcNow.Ticks - start;
-                SortInfo.MergeRounds++;
-            }
-            finally
-            {
-                // The logic below is: if an exception occurs in closing out, it has a priority over exceptions
-                // happening in closing streams.
-                try
-                {
-                    IOUtils.Close(streams);
-                }
-                finally
-                {
-                    IOUtils.Close(@out);
-                }
-            }
-        }
-
-        private class PriorityQueueAnonymousInnerClassHelper : PriorityQueue<FileAndTop>
-        {
-            private readonly OfflineSorter OuterInstance;
-
-            public PriorityQueueAnonymousInnerClassHelper(OfflineSorter outerInstance, int size)
-                : base(size)
-            {
-                this.OuterInstance = outerInstance;
-            }
-
-            public override bool LessThan(FileAndTop a, FileAndTop b)
-            {
-                return OuterInstance.comparator.Compare(a.Current, b.Current) < 0;
-            }
-        }
-
-        /// <summary>
-        /// Read in a single partition of data </summary>
-        internal int ReadPartition(ByteSequencesReader reader)
-        {
-            long start = DateTime.Now.Millisecond;
-            var scratch = new BytesRef();
-            while ((scratch.Bytes = reader.Read()) != null)
-            {
-                scratch.Length = scratch.Bytes.Length;
-                Buffer.Append(scratch);
-                // Account for the created objects.
-                // (buffer slots do not account to buffer size.)
-                if (RamBufferSize.Bytes < BufferBytesUsed.Get())
-                {
-                    break;
-                }
-            }
-            sortInfo.ReadTime += (DateTime.Now.Millisecond - start);
-            return Buffer.Size();
-        }
-
-        internal class FileAndTop
-        {
-            internal readonly int Fd;
-            internal readonly BytesRef Current;
-
-            internal FileAndTop(int fd, sbyte[] firstLine)
-            {
-                this.Fd = fd;
-                this.Current = new BytesRef(firstLine);
-            }
-        }
-
-        /// <summary>
-        /// Utility class to emit length-prefixed byte[] entries to an output stream for sorting.
-        /// Complementary to <seealso cref="ByteSequencesReader"/>.
-        /// </summary>
-        public class ByteSequencesWriter : IDisposable
-        {
-            internal readonly DataOutput Os;
-
-            /// <summary>
-            /// Constructs a ByteSequencesWriter to the provided File </summary>
-            public ByteSequencesWriter(FileInfo file)
-                : this(new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))))
-            {
-            }
-
-            /// <summary>
-            /// Constructs a ByteSequencesWriter to the provided DataOutput </summary>
-            public ByteSequencesWriter(DataOutput os)
-            {
-                this.Os = os;
-            }
-
-            /// <summary>
-            /// Writes a BytesRef. </summary>
-            /// <seealso cref= #write(byte[], int, int) </seealso>
-            public virtual void Write(BytesRef @ref)
-            {
-                Debug.Assert(@ref != null);
-                Write(@ref.Bytes, @ref.Offset, @ref.Length);
-            }
-
-            /// <summary>
-            /// Writes a byte array. </summary>
-            /// <seealso cref= #write(byte[], int, int) </seealso>
-            public virtual void Write(sbyte[] bytes)
-            {
-                Write(bytes, 0, bytes.Length);
-            }
-
-            /// <summary>
-            /// Writes a byte array.
-            /// <p>
-            /// The length is written as a <code>short</code>, followed
-            /// by the bytes.
-            /// </summary>
-            public virtual void Write(sbyte[] bytes, int off, int len)
-            {
-                Debug.Assert(bytes != null);
-                Debug.Assert(off >= 0 && off + len <= bytes.Length);
-                Debug.Assert(len >= 0);
-                Os.WriteShort(len);
-                Os.Write(bytes, off, len);
-            }
-
-            /// <summary>
-            /// Closes the provided <seealso cref="DataOutput"/> if it is <seealso cref="IDisposable"/>.
-            /// </summary>
-            public void Dispose()
-            {
-                var os = Os as IDisposable;
-                if (os != null)
-                {
-                    os.Dispose();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Utility class to read length-prefixed byte[] entries from an input.
-        /// Complementary to <seealso cref="ByteSequencesWriter"/>.
-        /// </summary>
-        public class ByteSequencesReader : IDisposable
-        {
-            internal readonly DataInput inputStream;
-
-            /// <summary>
-            /// Constructs a ByteSequencesReader from the provided File </summary>
-            public ByteSequencesReader(FileInfo file)
-                : this(new DataInputStream(new BufferedInputStream(new FileInputStream(file))))
-            {
-            }
-
-            /// <summary>
-            /// Constructs a ByteSequencesReader from the provided DataInput </summary>
-            public ByteSequencesReader(DataInput inputStream)
-            {
-                this.inputStream = inputStream;
-            }
-
-            /// <summary>
-            /// Reads the next entry into the provided <seealso cref="BytesRef"/>. The internal
-            /// storage is resized if needed.
-            /// </summary>
-            /// <returns> Returns <code>false</code> if EOF occurred when trying to read
-            /// the header of the next sequence. Returns <code>true</code> otherwise. </returns>
-            /// <exception cref="EOFException"> if the file ends before the full sequence is read. </exception>
-            public virtual bool Read(BytesRef @ref)
-            {
-                short length;
-                try
-                {
-                    length = inputStream.ReadShort();
-                }
-                catch (EOFException)
-                {
-                    return false;
-                }
-
-                @ref.Grow(length);
-                @ref.Offset = 0;
-                @ref.Length = length;
-                inputStream.ReadFully(@ref.Bytes, 0, length);
-                return true;
-            }
-
-            /// <summary>
-            /// Reads the next entry and returns it if successful.
-            /// </summary>
-            /// <seealso cref= #read(BytesRef)
-            /// </seealso>
-            /// <returns> Returns <code>null</code> if EOF occurred before the next entry
-            /// could be read. </returns>
-            /// <exception cref="EOFException"> if the file ends before the full sequence is read. </exception>
-            public virtual sbyte[] Read()
-            {
-                short length;
-                try
-                {
-                    length = inputStream.ReadShort();
-                }
-                catch (EOFException e)
-                {
-                    return null;
-                }
-
-                Debug.Assert(length >= 0, "Sanity: sequence length < 0: " + length);
-                sbyte[] result = new sbyte[length];
-                inputStream.ReadFully(result);
-                return result;
-            }
-
-            /// <summary>
-            /// Closes the provided <seealso cref="DataInput"/> if it is <seealso cref="IDisposable"/>.
-            /// </summary>
-            public void Dispose()
-            {
-                var @is = inputStream as IDisposable;
-                if (@is != null)
-                {
-                    @is.Dispose();
-                }
-            }
-        }
-
-        /// <summary>
-        /// Returns the comparator in use to sort entries </summary>
-        public IComparer<BytesRef> Comparator
-        {
-            get
-            {
-                return comparator;
-            }
-        }
+//        private bool InstanceFieldsInitialized = false;
+//
+//        private void InitializeInstanceFields()
+//        {
+//            Buffer = new BytesRefArray(BufferBytesUsed);
+//        }
+//
+//        /// <summary>
+//        /// Convenience constant for megabytes </summary>
+//        public const long MB = 1024 * 1024;
+//        /// <summary>
+//        /// Convenience constant for gigabytes </summary>
+//        public static readonly long GB = MB * 1024;
+//
+//        /// <summary>
+//        /// Minimum recommended buffer size for sorting.
+//        /// </summary>
+//        public const long MIN_BUFFER_SIZE_MB = 32;
+//
+//        /// <summary>
+//        /// Absolute minimum required buffer size for sorting.
+//        /// </summary>
+//        public static readonly long ABSOLUTE_MIN_SORT_BUFFER_SIZE = MB / 2;
+//        private const string MIN_BUFFER_SIZE_MSG = "At least 0.5MB RAM buffer is needed";
+//
+//        /// <summary>
+//        /// Maximum number of temporary files before doing an intermediate merge.
+//        /// </summary>
+//        public const int MAX_TEMPFILES = 128;
+//
+//        /// <summary>
+//        /// A bit more descriptive unit for constructors.
+//        /// </summary>
+//        /// <seealso cref= #automatic() </seealso>
+//        /// <seealso cref= #megabytes(long) </seealso>
+//        public sealed class BufferSize
+//        {
+//            internal readonly int Bytes;
+//
+//            internal BufferSize(long bytes)
+//            {
+//                if (bytes > int.MaxValue)
+//                {
+//                    throw new System.ArgumentException("Buffer too large for Java (" + (int.MaxValue / MB) + "mb max): " + bytes);
+//                }
+//
+//                if (bytes < ABSOLUTE_MIN_SORT_BUFFER_SIZE)
+//                {
+//                    throw new System.ArgumentException(MIN_BUFFER_SIZE_MSG + ": " + bytes);
+//                }
+//
+//                this.Bytes = (int)bytes;
+//            }
+//
+//            /// <summary>
+//            /// Creates a <seealso cref="BufferSize"/> in MB. The given
+//            /// values must be &gt; 0 and &lt; 2048.
+//            /// </summary>
+//            public static BufferSize Megabytes(long mb)
+//            {
+//                return new BufferSize(mb * MB);
+//            }
+//
+//            /// <summary>
+//            /// Approximately half of the currently available free heap, but no less
+//            /// than <seealso cref="#ABSOLUTE_MIN_SORT_BUFFER_SIZE"/>. However if current heap allocation
+//            /// is insufficient or if there is a large portion of unallocated heap-space available
+//            /// for sorting consult with max allowed heap size.
+//            /// </summary>
+//            public static BufferSize Automatic()
+//            {
+//                var proc = Process.GetCurrentProcess();
+//
+//                // take sizes in "conservative" order
+//                long max = proc.PeakVirtualMemorySize64; // max allocated; java has it as Runtime.maxMemory();
+//                long total = proc.VirtualMemorySize64; // currently allocated; java has it as Runtime.totalMemory();
+//                long free = rt.freeMemory(); // unused portion of currently allocated
+//                long totalAvailableBytes = max - total + free;
+//
+//                // by free mem (attempting to not grow the heap for this)
+//                long sortBufferByteSize = free / 2;
+//                const long minBufferSizeBytes = MIN_BUFFER_SIZE_MB * MB;
+//                if (sortBufferByteSize < minBufferSizeBytes || totalAvailableBytes > 10 * minBufferSizeBytes) // lets see if we need/should to grow the heap
+//                {
+//                    if (totalAvailableBytes / 2 > minBufferSizeBytes) // there is enough mem for a reasonable buffer
+//                    {
+//                        sortBufferByteSize = totalAvailableBytes / 2; // grow the heap
+//                    }
+//                    else
+//                    {
+//                        //heap seems smallish lets be conservative fall back to the free/2
+//                        sortBufferByteSize = Math.Max(ABSOLUTE_MIN_SORT_BUFFER_SIZE, sortBufferByteSize);
+//                    }
+//                }
+//                return new BufferSize(Math.Min((long)int.MaxValue, sortBufferByteSize));
+//            }
+//        }
+//
+//        /// <summary>
+//        /// Sort info (debugging mostly).
+//        /// </summary>
+//        public class SortInfo
+//        {
+//            internal bool InstanceFieldsInitialized = false;
+//
+//            internal virtual void InitializeInstanceFields()
+//            {
+//                BufferSize = OuterInstance.RamBufferSize.Bytes;
+//            }
+//
+//            private readonly OfflineSorter OuterInstance;
+//
+//            /// <summary>
+//            /// number of temporary files created when merging partitions </summary>
+//            public int TempMergeFiles;
+//            /// <summary>
+//            /// number of partition merges </summary>
+//            public int MergeRounds;
+//            /// <summary>
+//            /// number of lines of data read </summary>
+//            public int Lines;
+//            /// <summary>
+//            /// time spent merging sorted partitions (in milliseconds) </summary>
+//            public long MergeTime;
+//            /// <summary>
+//            /// time spent sorting data (in milliseconds) </summary>
+//            public long SortTime;
+//            /// <summary>
+//            /// total time spent (in milliseconds) </summary>
+//            public long TotalTime;
+//            /// <summary>
+//            /// time spent in i/o read (in milliseconds) </summary>
+//            public long ReadTime;
+//            /// <summary>
+//            /// read buffer size (in bytes) </summary>
+//            public long BufferSize;
+//
+//            /// <summary>
+//            /// create a new SortInfo (with empty statistics) for debugging </summary>
+//            public SortInfo(OfflineSorter outerInstance)
+//            {
+//                this.OuterInstance = outerInstance;
+//
+//                if (!InstanceFieldsInitialized)
+//                {
+//                    InitializeInstanceFields();
+//                    InstanceFieldsInitialized = true;
+//                }
+//            }
+//
+//            public override string ToString()
+//            {
+//                return string.Format("time=%.2f sec. total (%.2f reading, %.2f sorting, %.2f merging), lines=%d, temp files=%d, merges=%d, soft ram limit=%.2f MB", TotalTime / 1000.0d, ReadTime / 1000.0d, SortTime / 1000.0d, MergeTime / 1000.0d, Lines, TempMergeFiles, MergeRounds, (double)BufferSize / MB);
+//            }
+//        }
+//
+//        private readonly BufferSize RamBufferSize;
+//
+//        private readonly Counter BufferBytesUsed = Counter.NewCounter();
+//        private BytesRefArray Buffer;
+//        private SortInfo sortInfo;
+//        private readonly int MaxTempFiles;
+//        private readonly IComparer<BytesRef> comparator;
+//
+//        /// <summary>
+//        /// Default comparator: sorts in binary (codepoint) order </summary>
+//        public static readonly IComparer<BytesRef> DEFAULT_COMPARATOR = BytesRef.UTF8SortedAsUnicodeComparator.Instance;
+//
+//        /// <summary>
+//        /// Defaults constructor.
+//        /// </summary>
+//        /// <seealso cref= #defaultTempDir() </seealso>
+//        /// <seealso cref= BufferSize#automatic() </seealso>
+//        public OfflineSorter()
+//            : this(DEFAULT_COMPARATOR, BufferSize.Automatic(), DefaultTempDir(), MAX_TEMPFILES)
+//        {
+//            if (!InstanceFieldsInitialized)
+//            {
+//                InitializeInstanceFields();
+//                InstanceFieldsInitialized = true;
+//            }
+//        }
+//
+//        /// <summary>
+//        /// Defaults constructor with a custom comparator.
+//        /// </summary>
+//        /// <seealso cref= #defaultTempDir() </seealso>
+//        /// <seealso cref= BufferSize#automatic() </seealso>
+//        public OfflineSorter(IComparer<BytesRef> comparator)
+//            : this(comparator, BufferSize.Automatic(), DefaultTempDir(), MAX_TEMPFILES)
+//        {
+//            if (!InstanceFieldsInitialized)
+//            {
+//                InitializeInstanceFields();
+//                InstanceFieldsInitialized = true;
+//            }
+//        }
+//
+//        /// <summary>
+//        /// All-details constructor.
+//        /// </summary>
+//        public OfflineSorter(IComparer<BytesRef> comparator, BufferSize ramBufferSize, /*DirectoryInfo tempDirectory,*/ int maxTempfiles)
+//        {
+//            if (!InstanceFieldsInitialized)
+//            {
+//                InitializeInstanceFields();
+//                InstanceFieldsInitialized = true;
+//            }
+//            if (ramBufferSize.Bytes < ABSOLUTE_MIN_SORT_BUFFER_SIZE)
+//            {
+//                throw new System.ArgumentException(MIN_BUFFER_SIZE_MSG + ": " + ramBufferSize.Bytes);
+//            }
+//
+//            if (maxTempfiles < 2)
+//            {
+//                throw new System.ArgumentException("maxTempFiles must be >= 2");
+//            }
+//
+//            this.RamBufferSize = ramBufferSize;
+//            this.MaxTempFiles = maxTempfiles;
+//            this.comparator = comparator;
+//        }
+//
+//        /// <summary>
+//        /// Sort input to output, explicit hint for the buffer size. The amount of allocated
+//        /// memory may deviate from the hint (may be smaller or larger).
+//        /// </summary>
+//        public SortInfo Sort(FileInfo input, FileInfo output)
+//        {
+//            sortInfo = new SortInfo(this) {TotalTime = DateTime.Now.Millisecond};
+//
+//            output.Delete();
+//
+//            var merges = new List<FileInfo>();
+//            bool success2 = false;
+//            try
+//            {
+//                var inputStream = new ByteSequencesReader(input);
+//                bool success = false;
+//                try
+//                {
+//                    int lines = 0;
+//                    while ((lines = ReadPartition(inputStream)) > 0)
+//                    {
+//                        merges.Add(SortPartition(lines));
+//                        sortInfo.TempMergeFiles++;
+//                        sortInfo.Lines += lines;
+//
+//                        // Handle intermediate merges.
+//                        if (merges.Count == MaxTempFiles)
+//                        {
+//                            var intermediate = new FileInfo(Path.GetTempFileName());
+//                            try
+//                            {
+//                                MergePartitions(merges, intermediate);
+//                            }
+//                            finally
+//                            {
+//                                foreach (var file in merges)
+//                                {
+//                                    file.Delete();
+//                                }
+//                                merges.Clear();
+//                                merges.Add(intermediate);
+//                            }
+//                            sortInfo.TempMergeFiles++;
+//                        }
+//                    }
+//                    success = true;
+//                }
+//                finally
+//                {
+//                    if (success)
+//                    {
+//                        IOUtils.Close(inputStream);
+//                    }
+//                    else
+//                    {
+//                        IOUtils.CloseWhileHandlingException(inputStream);
+//                    }
+//                }
+//
+//                // One partition, try to rename or copy if unsuccessful.
+//                if (merges.Count == 1)
+//                {
+//                    FileInfo single = merges[0];
+//                    Copy(single, output);
+//                    try
+//                    {
+//                        File.Delete(single.FullName);
+//                    }
+//                    catch (Exception)
+//                    {
+//                        // ignored
+//                    }
+//                }
+//                else
+//                {
+//                    // otherwise merge the partitions with a priority queue.
+//                    MergePartitions(merges, output);
+//                }
+//                success2 = true;
+//            }
+//            finally
+//            {
+//                foreach (FileInfo file in merges)
+//                {
+//                    file.Delete();
+//                }
+//                if (!success2)
+//                {
+//                    output.Delete();
+//                }
+//            }
+//
+//            sortInfo.TotalTime = (DateTime.Now.Millisecond - sortInfo.TotalTime);
+//            return sortInfo;
+//        }
+//
+//        /// <summary>
+//        /// Returns the default temporary directory. By default, the System's temp folder. If not accessible
+//        /// or not available, an IOException is thrown
+//        /// </summary>
+//        public static DirectoryInfo DefaultTempDir()
+//        {
+//            return new DirectoryInfo(Path.GetTempPath());
+//        }
+//
+//        /// <summary>
+//        /// Copies one file to another.
+//        /// </summary>
+//        private static void Copy(FileInfo file, FileInfo output)
+//        {
+//            File.Copy(file.FullName, output.FullName);
+//        }
+//
+//        /// <summary>
+//        /// Sort a single partition in-memory. </summary>
+//        internal FileInfo SortPartition(int len)
+//        {
+//            var data = this.Buffer;
+//            var tempFile = new FileInfo(Path.GetTempFileName());
+//            //var tempFile1 = File.Create(new ());
+//            //FileInfo tempFile = FileInfo.createTempFile("sort", "partition", TempDirectory);
+//
+//            long start = DateTime.Now.Millisecond;
+//            sortInfo.SortTime += (DateTime.Now.Millisecond - start);
+//
+//            var @out = new ByteSequencesWriter(tempFile);
+//            BytesRef spare;
+//            try
+//            {
+//                BytesRefIterator iter = Buffer.Iterator(comparator);
+//                while ((spare = iter.Next()) != null)
+//                {
+//                    Debug.Assert(spare.Length <= short.MaxValue);
+//                    @out.Write(spare);
+//                }
+//
+//                @out.Dispose();
+//
+//                // Clean up the buffer for the next partition.
+//                data.Clear();
+//                return tempFile;
+//            }
+//            finally
+//            {
+//                IOUtils.Close(@out);
+//            }
+//        }
+//
+//        /// <summary>
+//        /// Merge a list of sorted temporary files (partitions) into an output file </summary>
+//        internal void MergePartitions(IList<FileInfo> merges, FileInfo outputFile)
+//        {
+//            long start = DateTime.Now.Millisecond;
+//
+//            var @out = new ByteSequencesWriter(outputFile);
+//
+//            PriorityQueue<FileAndTop> queue = new PriorityQueueAnonymousInnerClassHelper(this, merges.Count);
+//
+//            var streams = new ByteSequencesReader[merges.Count];
+//            try
+//            {
+//                // Open streams and read the top for each file
+//                for (int i = 0; i < merges.Count; i++)
+//                {
+//                    streams[i] = new ByteSequencesReader(merges[i]);
+//                    sbyte[] line = streams[i].Read();
+//                    if (line != null)
+//                    {
+//                        queue.InsertWithOverflow(new FileAndTop(i, line));
+//                    }
+//                }
+//
+//                // Unix utility sort() uses ordered array of files to pick the next line from, updating
+//                // it as it reads new lines. The PQ used here is a more elegant solution and has
+//                // a nicer theoretical complexity bound :) The entire sorting process is I/O bound anyway
+//                // so it shouldn't make much of a difference (didn't check).
+//                FileAndTop top;
+//                while ((top = queue.Top()) != null)
+//                {
+//                    @out.Write(top.Current);
+//                    if (!streams[top.Fd].Read(top.Current))
+//                    {
+//                        queue.Pop();
+//                    }
+//                    else
+//                    {
+//                        queue.UpdateTop();
+//                    }
+//                }
+//
+//                SortInfo.MergeTime += DateTime.UtcNow.Ticks - start;
+//                SortInfo.MergeRounds++;
+//            }
+//            finally
+//            {
+//                // The logic below is: if an exception occurs in closing out, it has a priority over exceptions
+//                // happening in closing streams.
+//                try
+//                {
+//                    IOUtils.Close(streams);
+//                }
+//                finally
+//                {
+//                    IOUtils.Close(@out);
+//                }
+//            }
+//        }
+//
+//        private class PriorityQueueAnonymousInnerClassHelper : PriorityQueue<FileAndTop>
+//        {
+//            private readonly OfflineSorter OuterInstance;
+//
+//            public PriorityQueueAnonymousInnerClassHelper(OfflineSorter outerInstance, int size)
+//                : base(size)
+//            {
+//                this.OuterInstance = outerInstance;
+//            }
+//
+//            public override bool LessThan(FileAndTop a, FileAndTop b)
+//            {
+//                return OuterInstance.comparator.Compare(a.Current, b.Current) < 0;
+//            }
+//        }
+//
+//        /// <summary>
+//        /// Read in a single partition of data </summary>
+//        internal int ReadPartition(ByteSequencesReader reader)
+//        {
+//            long start = DateTime.Now.Millisecond;
+//            var scratch = new BytesRef();
+//            while ((scratch.Bytes = reader.Read()) != null)
+//            {
+//                scratch.Length = scratch.Bytes.Length;
+//                Buffer.Append(scratch);
+//                // Account for the created objects.
+//                // (buffer slots do not account to buffer size.)
+//                if (RamBufferSize.Bytes < BufferBytesUsed.Get())
+//                {
+//                    break;
+//                }
+//            }
+//            sortInfo.ReadTime += (DateTime.Now.Millisecond - start);
+//            return Buffer.Size();
+//        }
+//
+//        internal class FileAndTop
+//        {
+//            internal readonly int Fd;
+//            internal readonly BytesRef Current;
+//
+//            internal FileAndTop(int fd, sbyte[] firstLine)
+//            {
+//                this.Fd = fd;
+//                this.Current = new BytesRef(firstLine);
+//            }
+//        }
+//
+//        /// <summary>
+//        /// Utility class to emit length-prefixed byte[] entries to an output stream for sorting.
+//        /// Complementary to <seealso cref="ByteSequencesReader"/>.
+//        /// </summary>
+//        public class ByteSequencesWriter : IDisposable
+//        {
+//            internal readonly DataOutput Os;
+//
+//            /// <summary>
+//            /// Constructs a ByteSequencesWriter to the provided File </summary>
+//            public ByteSequencesWriter(FileInfo file)
+//                : this(new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))))
+//            {
+//            }
+//
+//            /// <summary>
+//            /// Constructs a ByteSequencesWriter to the provided DataOutput </summary>
+//            public ByteSequencesWriter(DataOutput os)
+//            {
+//                this.Os = os;
+//            }
+//
+//            /// <summary>
+//            /// Writes a BytesRef. </summary>
+//            /// <seealso cref= #write(byte[], int, int) </seealso>
+//            public virtual void Write(BytesRef @ref)
+//            {
+//                Debug.Assert(@ref != null);
+//                Write(@ref.Bytes, @ref.Offset, @ref.Length);
+//            }
+//
+//            /// <summary>
+//            /// Writes a byte array. </summary>
+//            /// <seealso cref= #write(byte[], int, int) </seealso>
+//            public virtual void Write(sbyte[] bytes)
+//            {
+//                Write(bytes, 0, bytes.Length);
+//            }
+//
+//            /// <summary>
+//            /// Writes a byte array.
+//            /// <p>
+//            /// The length is written as a <code>short</code>, followed
+//            /// by the bytes.
+//            /// </summary>
+//            public virtual void Write(sbyte[] bytes, int off, int len)
+//            {
+//                Debug.Assert(bytes != null);
+//                Debug.Assert(off >= 0 && off + len <= bytes.Length);
+//                Debug.Assert(len >= 0);
+//                Os.WriteShort(len);
+//                Os.Write(bytes, off, len);
+//            }
+//
+//            /// <summary>
+//            /// Closes the provided <seealso cref="DataOutput"/> if it is <seealso cref="IDisposable"/>.
+//            /// </summary>
+//            public void Dispose()
+//            {
+//                var os = Os as IDisposable;
+//                if (os != null)
+//                {
+//                    os.Dispose();
+//                }
+//            }
+//        }
+//
+//        /// <summary>
+//        /// Utility class to read length-prefixed byte[] entries from an input.
+//        /// Complementary to <seealso cref="ByteSequencesWriter"/>.
+//        /// </summary>
+//        public class ByteSequencesReader : IDisposable
+//        {
+//            internal readonly DataInput inputStream;
+//
+//            /// <summary>
+//            /// Constructs a ByteSequencesReader from the provided File </summary>
+//            public ByteSequencesReader(FileInfo file)
+//                : this(new DataInputStream(new BufferedInputStream(new FileInputStream(file))))
+//            {
+//            }
+//
+//            /// <summary>
+//            /// Constructs a ByteSequencesReader from the provided DataInput </summary>
+//            public ByteSequencesReader(DataInput inputStream)
+//            {
+//                this.inputStream = inputStream;
+//            }
+//
+//            /// <summary>
+//            /// Reads the next entry into the provided <seealso cref="BytesRef"/>. The internal
+//            /// storage is resized if needed.
+//            /// </summary>
+//            /// <returns> Returns <code>false</code> if EOF occurred when trying to read
+//            /// the header of the next sequence. Returns <code>true</code> otherwise. </returns>
+//            /// <exception cref="EOFException"> if the file ends before the full sequence is read. </exception>
+//            public virtual bool Read(BytesRef @ref)
+//            {
+//                short length;
+//                try
+//                {
+//                    length = inputStream.ReadShort();
+//                }
+//                catch (EOFException)
+//                {
+//                    return false;
+//                }
+//
+//                @ref.Grow(length);
+//                @ref.Offset = 0;
+//                @ref.Length = length;
+//                inputStream.ReadFully(@ref.Bytes, 0, length);
+//                return true;
+//            }
+//
+//            /// <summary>
+//            /// Reads the next entry and returns it if successful.
+//            /// </summary>
+//            /// <seealso cref= #read(BytesRef)
+//            /// </seealso>
+//            /// <returns> Returns <code>null</code> if EOF occurred before the next entry
+//            /// could be read. </returns>
+//            /// <exception cref="EOFException"> if the file ends before the full sequence is read. </exception>
+//            public virtual sbyte[] Read()
+//            {
+//                short length;
+//                try
+//                {
+//                    length = inputStream.ReadShort();
+//                }
+//                catch (EOFException e)
+//                {
+//                    return null;
+//                }
+//
+//                Debug.Assert(length >= 0, "Sanity: sequence length < 0: " + length);
+//                sbyte[] result = new sbyte[length];
+//                inputStream.ReadFully(result);
+//                return result;
+//            }
+//
+//            /// <summary>
+//            /// Closes the provided <seealso cref="DataInput"/> if it is <seealso cref="IDisposable"/>.
+//            /// </summary>
+//            public void Dispose()
+//            {
+//                var @is = inputStream as IDisposable;
+//                if (@is != null)
+//                {
+//                    @is.Dispose();
+//                }
+//            }
+//        }
+//
+//        /// <summary>
+//        /// Returns the comparator in use to sort entries </summary>
+//        public IComparer<BytesRef> Comparator
+//        {
+//            get
+//            {
+//                return comparator;
+//            }
+//        }
     }
 }
\ No newline at end of file


[06/11] Skeleton porting of Lucene.Net.Queries

Posted by sy...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/DocValues/BoolDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/DocValues/BoolDocValues.cs b/src/Lucene.Net.Queries/Function/DocValues/BoolDocValues.cs
new file mode 100644
index 0000000..1ad0517
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/DocValues/BoolDocValues.cs
@@ -0,0 +1,122 @@
+using System;
+
+namespace org.apache.lucene.queries.function.docvalues
+{
+
+	/*
+	 * 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.
+	 */
+
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueBool = org.apache.lucene.util.mutable.MutableValueBool;
+
+	/// <summary>
+	/// Abstract <seealso cref="FunctionValues"/> implementation which supports retrieving boolean values.
+	/// Implementations can control how the boolean values are loaded through <seealso cref="#boolVal(int)"/>}
+	/// </summary>
+	public abstract class BoolDocValues : FunctionValues
+	{
+	  protected internal readonly ValueSource vs;
+
+	  public BoolDocValues(ValueSource vs)
+	  {
+		this.vs = vs;
+	  }
+
+	  public override abstract bool boolVal(int doc);
+
+	  public override sbyte byteVal(int doc)
+	  {
+		return boolVal(doc) ? (sbyte)1 : (sbyte)0;
+	  }
+
+	  public override short shortVal(int doc)
+	  {
+		return boolVal(doc) ? (short)1 : (short)0;
+	  }
+
+	  public override float floatVal(int doc)
+	  {
+		return boolVal(doc) ? (float)1 : (float)0;
+	  }
+
+	  public override int intVal(int doc)
+	  {
+		return boolVal(doc) ? 1 : 0;
+	  }
+
+	  public override long longVal(int doc)
+	  {
+		return boolVal(doc) ? (long)1 : (long)0;
+	  }
+
+	  public override double doubleVal(int doc)
+	  {
+		return boolVal(doc) ? (double)1 : (double)0;
+	  }
+
+	  public override string strVal(int doc)
+	  {
+		return Convert.ToString(boolVal(doc));
+	  }
+
+	  public override object objectVal(int doc)
+	  {
+		return exists(doc) ? boolVal(doc) : null;
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return vs.description() + '=' + strVal(doc);
+	  }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly BoolDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(BoolDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueBool();
+		  }
+
+		  private readonly MutableValueBool mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			mval.value = outerInstance.boolVal(doc);
+			mval.exists = outerInstance.exists(doc);
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/DocValues/DocTermsIndexDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/DocValues/DocTermsIndexDocValues.cs b/src/Lucene.Net.Queries/Function/DocValues/DocTermsIndexDocValues.cs
new file mode 100644
index 0000000..79f490c
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/DocValues/DocTermsIndexDocValues.cs
@@ -0,0 +1,234 @@
+using System;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.docvalues
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using SortedDocValues = org.apache.lucene.index.SortedDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+	using CharsRef = org.apache.lucene.util.CharsRef;
+	using UnicodeUtil = org.apache.lucene.util.UnicodeUtil;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueStr = org.apache.lucene.util.mutable.MutableValueStr;
+
+	/// <summary>
+	/// Serves as base class for FunctionValues based on DocTermsIndex.
+	/// @lucene.internal
+	/// </summary>
+	public abstract class DocTermsIndexDocValues : FunctionValues
+	{
+	  protected internal readonly SortedDocValues termsIndex;
+	  protected internal readonly ValueSource vs;
+	  protected internal readonly MutableValueStr val = new MutableValueStr();
+	  protected internal readonly BytesRef spare = new BytesRef();
+	  protected internal readonly CharsRef spareChars = new CharsRef();
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public DocTermsIndexDocValues(org.apache.lucene.queries.function.ValueSource vs, org.apache.lucene.index.AtomicReaderContext context, String field) throws java.io.IOException
+	  public DocTermsIndexDocValues(ValueSource vs, AtomicReaderContext context, string field)
+	  {
+		try
+		{
+		  termsIndex = FieldCache.DEFAULT.getTermsIndex(context.reader(), field);
+		}
+		catch (Exception e)
+		{
+		  throw new DocTermsIndexException(field, e);
+		}
+		this.vs = vs;
+	  }
+
+	  protected internal abstract string toTerm(string readableValue);
+
+	  public override bool exists(int doc)
+	  {
+		return ordVal(doc) >= 0;
+	  }
+
+	  public override int ordVal(int doc)
+	  {
+		return termsIndex.getOrd(doc);
+	  }
+
+	  public override int numOrd()
+	  {
+		return termsIndex.ValueCount;
+	  }
+
+	  public override bool bytesVal(int doc, BytesRef target)
+	  {
+		termsIndex.get(doc, target);
+		return target.length > 0;
+	  }
+
+	  public override string strVal(int doc)
+	  {
+		termsIndex.get(doc, spare);
+		if (spare.length == 0)
+		{
+		  return null;
+		}
+		UnicodeUtil.UTF8toUTF16(spare, spareChars);
+		return spareChars.ToString();
+	  }
+
+	  public override bool boolVal(int doc)
+	  {
+		return exists(doc);
+	  }
+
+	  public override abstract object objectVal(int doc); // force subclasses to override
+
+	  public override ValueSourceScorer getRangeScorer(IndexReader reader, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
+	  {
+		// TODO: are lowerVal and upperVal in indexed form or not?
+		lowerVal = lowerVal == null ? null : toTerm(lowerVal);
+		upperVal = upperVal == null ? null : toTerm(upperVal);
+
+		int lower = int.MinValue;
+		if (lowerVal != null)
+		{
+		  lower = termsIndex.lookupTerm(new BytesRef(lowerVal));
+		  if (lower < 0)
+		  {
+			lower = -lower - 1;
+		  }
+		  else if (!includeLower)
+		  {
+			lower++;
+		  }
+		}
+
+		int upper = int.MaxValue;
+		if (upperVal != null)
+		{
+		  upper = termsIndex.lookupTerm(new BytesRef(upperVal));
+		  if (upper < 0)
+		  {
+			upper = -upper - 2;
+		  }
+		  else if (!includeUpper)
+		  {
+			upper--;
+		  }
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int ll = lower;
+		int ll = lower;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int uu = upper;
+		int uu = upper;
+
+		return new ValueSourceScorerAnonymousInnerClassHelper(this, reader, this, ll, uu);
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper : ValueSourceScorer
+	  {
+		  private readonly DocTermsIndexDocValues outerInstance;
+
+		  private int ll;
+		  private int uu;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper(DocTermsIndexDocValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.docvalues.DocTermsIndexDocValues this, int ll, int uu) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.ll = ll;
+			  this.uu = uu;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			int ord = outerInstance.termsIndex.getOrd(doc);
+			return ord >= ll && ord <= uu;
+		  }
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return vs.description() + '=' + strVal(doc);
+	  }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly DocTermsIndexDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(DocTermsIndexDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueStr();
+		  }
+
+		  private readonly MutableValueStr mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			int ord = outerInstance.termsIndex.getOrd(doc);
+			if (ord == -1)
+			{
+			  mval.value.bytes = BytesRef.EMPTY_BYTES;
+			  mval.value.offset = 0;
+			  mval.value.length = 0;
+			  mval.exists = false;
+			}
+			else
+			{
+			  outerInstance.termsIndex.lookupOrd(ord, mval.value);
+			  mval.exists = true;
+			}
+		  }
+	  }
+
+	  /// <summary>
+	  /// Custom Exception to be thrown when the DocTermsIndex for a field cannot be generated
+	  /// </summary>
+	  public sealed class DocTermsIndexException : Exception
+	  {
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public DocTermsIndexException(final String fieldName, final RuntimeException cause)
+		public DocTermsIndexException(string fieldName, Exception cause) : base("Can't initialize DocTermsIndex to generate (function) FunctionValues for field: " + fieldName, cause)
+		{
+		}
+
+	  }
+
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/DocValues/DoubleDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/DocValues/DoubleDocValues.cs b/src/Lucene.Net.Queries/Function/DocValues/DoubleDocValues.cs
new file mode 100644
index 0000000..afc2a59
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/DocValues/DoubleDocValues.cs
@@ -0,0 +1,256 @@
+using System;
+
+namespace org.apache.lucene.queries.function.docvalues
+{
+
+	/*
+	 * 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.
+	 */
+
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueDouble = org.apache.lucene.util.mutable.MutableValueDouble;
+
+	/// <summary>
+	/// Abstract <seealso cref="FunctionValues"/> implementation which supports retrieving double values.
+	/// Implementations can control how the double values are loaded through <seealso cref="#doubleVal(int)"/>}
+	/// </summary>
+	public abstract class DoubleDocValues : FunctionValues
+	{
+	  protected internal readonly ValueSource vs;
+
+	  public DoubleDocValues(ValueSource vs)
+	  {
+		this.vs = vs;
+	  }
+
+	  public override sbyte byteVal(int doc)
+	  {
+		return (sbyte)doubleVal(doc);
+	  }
+
+	  public override short shortVal(int doc)
+	  {
+		return (short)doubleVal(doc);
+	  }
+
+	  public override float floatVal(int doc)
+	  {
+		return (float)doubleVal(doc);
+	  }
+
+	  public override int intVal(int doc)
+	  {
+		return (int)doubleVal(doc);
+	  }
+
+	  public override long longVal(int doc)
+	  {
+		return (long)doubleVal(doc);
+	  }
+
+	  public override bool boolVal(int doc)
+	  {
+		return doubleVal(doc) != 0;
+	  }
+
+	  public override abstract double doubleVal(int doc);
+
+	  public override string strVal(int doc)
+	  {
+		return Convert.ToString(doubleVal(doc));
+	  }
+
+	  public override object objectVal(int doc)
+	  {
+		return exists(doc) ? doubleVal(doc) : null;
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return vs.description() + '=' + strVal(doc);
+	  }
+
+	  public override ValueSourceScorer getRangeScorer(IndexReader reader, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
+	  {
+		double lower, upper;
+
+		if (lowerVal == null)
+		{
+		  lower = double.NegativeInfinity;
+		}
+		else
+		{
+		  lower = Convert.ToDouble(lowerVal);
+		}
+
+		 if (upperVal == null)
+		 {
+		  upper = double.PositiveInfinity;
+		 }
+		else
+		{
+		  upper = Convert.ToDouble(upperVal);
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final double l = lower;
+		double l = lower;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final double u = upper;
+		double u = upper;
+
+
+		if (includeLower && includeUpper)
+		{
+		  return new ValueSourceScorerAnonymousInnerClassHelper(this, reader, this, l, u);
+		}
+		else if (includeLower && !includeUpper)
+		{
+		  return new ValueSourceScorerAnonymousInnerClassHelper2(this, reader, this, l, u);
+		}
+		else if (!includeLower && includeUpper)
+		{
+		  return new ValueSourceScorerAnonymousInnerClassHelper3(this, reader, this, l, u);
+		}
+		else
+		{
+		  return new ValueSourceScorerAnonymousInnerClassHelper4(this, reader, this, l, u);
+		}
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper : ValueSourceScorer
+	  {
+		  private readonly DoubleDocValues outerInstance;
+
+		  private double l;
+		  private double u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper(DoubleDocValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.docvalues.DoubleDocValues this, double l, double u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			double docVal = outerInstance.doubleVal(doc);
+			return docVal >= l && docVal <= u;
+		  }
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper2 : ValueSourceScorer
+	  {
+		  private readonly DoubleDocValues outerInstance;
+
+		  private double l;
+		  private double u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper2(DoubleDocValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.docvalues.DoubleDocValues this, double l, double u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			double docVal = outerInstance.doubleVal(doc);
+			return docVal >= l && docVal < u;
+		  }
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper3 : ValueSourceScorer
+	  {
+		  private readonly DoubleDocValues outerInstance;
+
+		  private double l;
+		  private double u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper3(DoubleDocValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.docvalues.DoubleDocValues this, double l, double u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			double docVal = outerInstance.doubleVal(doc);
+			return docVal > l && docVal <= u;
+		  }
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper4 : ValueSourceScorer
+	  {
+		  private readonly DoubleDocValues outerInstance;
+
+		  private double l;
+		  private double u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper4(DoubleDocValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.docvalues.DoubleDocValues this, double l, double u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			double docVal = outerInstance.doubleVal(doc);
+			return docVal > l && docVal < u;
+		  }
+	  }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly DoubleDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(DoubleDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueDouble();
+		  }
+
+		  private readonly MutableValueDouble mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			mval.value = outerInstance.doubleVal(doc);
+			mval.exists = outerInstance.exists(doc);
+		  }
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/DocValues/FloatDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/DocValues/FloatDocValues.cs b/src/Lucene.Net.Queries/Function/DocValues/FloatDocValues.cs
new file mode 100644
index 0000000..72df9b0
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/DocValues/FloatDocValues.cs
@@ -0,0 +1,117 @@
+using System;
+
+namespace org.apache.lucene.queries.function.docvalues
+{
+
+	/*
+	 * 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.
+	 */
+
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueFloat = org.apache.lucene.util.mutable.MutableValueFloat;
+
+	/// <summary>
+	/// Abstract <seealso cref="FunctionValues"/> implementation which supports retrieving float values.
+	/// Implementations can control how the float values are loaded through <seealso cref="#floatVal(int)"/>}
+	/// </summary>
+	public abstract class FloatDocValues : FunctionValues
+	{
+	  protected internal readonly ValueSource vs;
+
+	  public FloatDocValues(ValueSource vs)
+	  {
+		this.vs = vs;
+	  }
+
+	  public override sbyte byteVal(int doc)
+	  {
+		return (sbyte)floatVal(doc);
+	  }
+
+	  public override short shortVal(int doc)
+	  {
+		return (short)floatVal(doc);
+	  }
+
+	  public override abstract float floatVal(int doc);
+
+	  public override int intVal(int doc)
+	  {
+		return (int)floatVal(doc);
+	  }
+
+	  public override long longVal(int doc)
+	  {
+		return (long)floatVal(doc);
+	  }
+
+	  public override double doubleVal(int doc)
+	  {
+		return (double)floatVal(doc);
+	  }
+
+	  public override string strVal(int doc)
+	  {
+		return Convert.ToString(floatVal(doc));
+	  }
+
+	  public override object objectVal(int doc)
+	  {
+		return exists(doc) ? floatVal(doc) : null;
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return vs.description() + '=' + strVal(doc);
+	  }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly FloatDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(FloatDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueFloat();
+		  }
+
+		  private readonly MutableValueFloat mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			mval.value = outerInstance.floatVal(doc);
+			mval.exists = outerInstance.exists(doc);
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/DocValues/IntDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/DocValues/IntDocValues.cs b/src/Lucene.Net.Queries/Function/DocValues/IntDocValues.cs
new file mode 100644
index 0000000..c3f934e
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/DocValues/IntDocValues.cs
@@ -0,0 +1,183 @@
+using System;
+
+namespace org.apache.lucene.queries.function.docvalues
+{
+
+	/*
+	 * 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.
+	 */
+
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueInt = org.apache.lucene.util.mutable.MutableValueInt;
+
+	/// <summary>
+	/// Abstract <seealso cref="FunctionValues"/> implementation which supports retrieving int values.
+	/// Implementations can control how the int values are loaded through <seealso cref="#intVal(int)"/>
+	/// </summary>
+	public abstract class IntDocValues : FunctionValues
+	{
+	  protected internal readonly ValueSource vs;
+
+	  public IntDocValues(ValueSource vs)
+	  {
+		this.vs = vs;
+	  }
+
+	  public override sbyte byteVal(int doc)
+	  {
+		return (sbyte)intVal(doc);
+	  }
+
+	  public override short shortVal(int doc)
+	  {
+		return (short)intVal(doc);
+	  }
+
+	  public override float floatVal(int doc)
+	  {
+		return (float)intVal(doc);
+	  }
+
+	  public override abstract int intVal(int doc);
+
+	  public override long longVal(int doc)
+	  {
+		return (long)intVal(doc);
+	  }
+
+	  public override double doubleVal(int doc)
+	  {
+		return (double)intVal(doc);
+	  }
+
+	  public override string strVal(int doc)
+	  {
+		return Convert.ToString(intVal(doc));
+	  }
+
+	  public override object objectVal(int doc)
+	  {
+		return exists(doc) ? intVal(doc) : null;
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return vs.description() + '=' + strVal(doc);
+	  }
+
+	  public override ValueSourceScorer getRangeScorer(IndexReader reader, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
+	  {
+		int lower, upper;
+
+		// instead of using separate comparison functions, adjust the endpoints.
+
+		if (lowerVal == null)
+		{
+		  lower = int.MinValue;
+		}
+		else
+		{
+		  lower = Convert.ToInt32(lowerVal);
+		  if (!includeLower && lower < int.MaxValue)
+		  {
+			  lower++;
+		  }
+		}
+
+		 if (upperVal == null)
+		 {
+		  upper = int.MaxValue;
+		 }
+		else
+		{
+		  upper = Convert.ToInt32(upperVal);
+		  if (!includeUpper && upper > int.MinValue)
+		  {
+			  upper--;
+		  }
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int ll = lower;
+		int ll = lower;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int uu = upper;
+		int uu = upper;
+
+		return new ValueSourceScorerAnonymousInnerClassHelper(this, reader, this, ll, uu);
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper : ValueSourceScorer
+	  {
+		  private readonly IntDocValues outerInstance;
+
+		  private int ll;
+		  private int uu;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper(IntDocValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.docvalues.IntDocValues this, int ll, int uu) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.ll = ll;
+			  this.uu = uu;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			int val = outerInstance.intVal(doc);
+			// only check for deleted if it's the default value
+			// if (val==0 && reader.isDeleted(doc)) return false;
+			return val >= ll && val <= uu;
+		  }
+	  }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly IntDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(IntDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueInt();
+		  }
+
+		  private readonly MutableValueInt mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			mval.value = outerInstance.intVal(doc);
+			mval.exists = outerInstance.exists(doc);
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/DocValues/LongDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/DocValues/LongDocValues.cs b/src/Lucene.Net.Queries/Function/DocValues/LongDocValues.cs
new file mode 100644
index 0000000..da27a4c
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/DocValues/LongDocValues.cs
@@ -0,0 +1,193 @@
+using System;
+
+namespace org.apache.lucene.queries.function.docvalues
+{
+
+	/*
+	 * 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.
+	 */
+
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueLong = org.apache.lucene.util.mutable.MutableValueLong;
+
+	/// <summary>
+	/// Abstract <seealso cref="FunctionValues"/> implementation which supports retrieving long values.
+	/// Implementations can control how the long values are loaded through <seealso cref="#longVal(int)"/>}
+	/// </summary>
+	public abstract class LongDocValues : FunctionValues
+	{
+	  protected internal readonly ValueSource vs;
+
+	  public LongDocValues(ValueSource vs)
+	  {
+		this.vs = vs;
+	  }
+
+	  public override sbyte byteVal(int doc)
+	  {
+		return (sbyte)longVal(doc);
+	  }
+
+	  public override short shortVal(int doc)
+	  {
+		return (short)longVal(doc);
+	  }
+
+	  public override float floatVal(int doc)
+	  {
+		return (float)longVal(doc);
+	  }
+
+	  public override int intVal(int doc)
+	  {
+		return (int)longVal(doc);
+	  }
+
+	  public override abstract long longVal(int doc);
+
+	  public override double doubleVal(int doc)
+	  {
+		return (double)longVal(doc);
+	  }
+
+	  public override bool boolVal(int doc)
+	  {
+		return longVal(doc) != 0;
+	  }
+
+	  public override string strVal(int doc)
+	  {
+		return Convert.ToString(longVal(doc));
+	  }
+
+	  public override object objectVal(int doc)
+	  {
+		return exists(doc) ? longVal(doc) : null;
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return vs.description() + '=' + strVal(doc);
+	  }
+
+	  protected internal virtual long externalToLong(string extVal)
+	  {
+		return Convert.ToInt64(extVal);
+	  }
+
+	  public override ValueSourceScorer getRangeScorer(IndexReader reader, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
+	  {
+		long lower, upper;
+
+		// instead of using separate comparison functions, adjust the endpoints.
+
+		if (lowerVal == null)
+		{
+		  lower = long.MinValue;
+		}
+		else
+		{
+		  lower = externalToLong(lowerVal);
+		  if (!includeLower && lower < long.MaxValue)
+		  {
+			  lower++;
+		  }
+		}
+
+		 if (upperVal == null)
+		 {
+		  upper = long.MaxValue;
+		 }
+		else
+		{
+		  upper = externalToLong(upperVal);
+		  if (!includeUpper && upper > long.MinValue)
+		  {
+			  upper--;
+		  }
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long ll = lower;
+		long ll = lower;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long uu = upper;
+		long uu = upper;
+
+		return new ValueSourceScorerAnonymousInnerClassHelper(this, reader, this, ll, uu);
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper : ValueSourceScorer
+	  {
+		  private readonly LongDocValues outerInstance;
+
+		  private long ll;
+		  private long uu;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper(LongDocValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.docvalues.LongDocValues this, long ll, long uu) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.ll = ll;
+			  this.uu = uu;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			long val = outerInstance.longVal(doc);
+			// only check for deleted if it's the default value
+			// if (val==0 && reader.isDeleted(doc)) return false;
+			return val >= ll && val <= uu;
+		  }
+	  }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly LongDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(LongDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueLong();
+		  }
+
+		  private readonly MutableValueLong mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			mval.value = outerInstance.longVal(doc);
+			mval.exists = outerInstance.exists(doc);
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/DocValues/StrDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/DocValues/StrDocValues.cs b/src/Lucene.Net.Queries/Function/DocValues/StrDocValues.cs
new file mode 100644
index 0000000..ea3c450
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/DocValues/StrDocValues.cs
@@ -0,0 +1,89 @@
+namespace org.apache.lucene.queries.function.docvalues
+{
+
+	/*
+	 * 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.
+	 */
+
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueStr = org.apache.lucene.util.mutable.MutableValueStr;
+
+	/// <summary>
+	/// Abstract <seealso cref="FunctionValues"/> implementation which supports retrieving String values.
+	/// Implementations can control how the String values are loaded through <seealso cref="#strVal(int)"/>}
+	/// </summary>
+	public abstract class StrDocValues : FunctionValues
+	{
+	  protected internal readonly ValueSource vs;
+
+	  public StrDocValues(ValueSource vs)
+	  {
+		this.vs = vs;
+	  }
+
+	  public override abstract string strVal(int doc);
+
+	  public override object objectVal(int doc)
+	  {
+		return exists(doc) ? strVal(doc) : null;
+	  }
+
+	  public override bool boolVal(int doc)
+	  {
+		return exists(doc);
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return vs.description() + "='" + strVal(doc) + "'";
+	  }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly StrDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(StrDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueStr();
+		  }
+
+		  private readonly MutableValueStr mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			mval.exists = outerInstance.bytesVal(doc, mval.value);
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/FunctionQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/FunctionQuery.cs b/src/Lucene.Net.Queries/Function/FunctionQuery.cs
new file mode 100644
index 0000000..e0642f1
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/FunctionQuery.cs
@@ -0,0 +1,270 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.queries.function
+{
+
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using Term = org.apache.lucene.index.Term;
+	using org.apache.lucene.search;
+	using MultiFields = org.apache.lucene.index.MultiFields;
+	using Bits = org.apache.lucene.util.Bits;
+
+
+
+	/// <summary>
+	/// Returns a score for each document based on a ValueSource,
+	/// often some function of the value of a field.
+	/// 
+	/// <b>Note: This API is experimental and may change in non backward-compatible ways in the future</b>
+	/// 
+	/// 
+	/// </summary>
+	public class FunctionQuery : Query
+	{
+	  internal readonly ValueSource func;
+
+	  /// <param name="func"> defines the function to be used for scoring </param>
+	  public FunctionQuery(ValueSource func)
+	  {
+		this.func = func;
+	  }
+
+	  /// <returns> The associated ValueSource </returns>
+	  public virtual ValueSource ValueSource
+	  {
+		  get
+		  {
+			return func;
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Query rewrite(org.apache.lucene.index.IndexReader reader) throws java.io.IOException
+	  public override Query rewrite(IndexReader reader)
+	  {
+		return this;
+	  }
+
+	  public override void extractTerms(HashSet<Term> terms)
+	  {
+	  }
+
+	  protected internal class FunctionWeight : Weight
+	  {
+		  private readonly FunctionQuery outerInstance;
+
+		protected internal readonly IndexSearcher searcher;
+		protected internal float queryNorm;
+		protected internal float queryWeight;
+		protected internal readonly IDictionary context;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public FunctionWeight(IndexSearcher searcher) throws java.io.IOException
+		public FunctionWeight(FunctionQuery outerInstance, IndexSearcher searcher)
+		{
+			this.outerInstance = outerInstance;
+		  this.searcher = searcher;
+		  this.context = ValueSource.newContext(searcher);
+		  outerInstance.func.createWeight(context, searcher);
+		}
+
+		public override Query Query
+		{
+			get
+			{
+			  return outerInstance;
+			}
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float getValueForNormalization() throws java.io.IOException
+		public override float ValueForNormalization
+		{
+			get
+			{
+			  queryWeight = Boost;
+			  return queryWeight * queryWeight;
+			}
+		}
+
+		public override void normalize(float norm, float topLevelBoost)
+		{
+		  this.queryNorm = norm * topLevelBoost;
+		  queryWeight *= this.queryNorm;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Scorer scorer(org.apache.lucene.index.AtomicReaderContext context, org.apache.lucene.util.Bits acceptDocs) throws java.io.IOException
+		public override Scorer scorer(AtomicReaderContext context, Bits acceptDocs)
+		{
+		  return new AllScorer(outerInstance, context, acceptDocs, this, queryWeight);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Explanation explain(org.apache.lucene.index.AtomicReaderContext context, int doc) throws java.io.IOException
+		public override Explanation explain(AtomicReaderContext context, int doc)
+		{
+		  return ((AllScorer)scorer(context, context.reader().LiveDocs)).explain(doc);
+		}
+	  }
+
+	  protected internal class AllScorer : Scorer
+	  {
+		  private readonly FunctionQuery outerInstance;
+
+		internal readonly IndexReader reader;
+		internal readonly FunctionWeight weight;
+		internal readonly int maxDoc;
+		internal readonly float qWeight;
+		internal int doc = -1;
+		internal readonly FunctionValues vals;
+		internal readonly Bits acceptDocs;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public AllScorer(org.apache.lucene.index.AtomicReaderContext context, org.apache.lucene.util.Bits acceptDocs, FunctionWeight w, float qWeight) throws java.io.IOException
+		public AllScorer(FunctionQuery outerInstance, AtomicReaderContext context, Bits acceptDocs, FunctionWeight w, float qWeight) : base(w)
+		{
+			this.outerInstance = outerInstance;
+		  this.weight = w;
+		  this.qWeight = qWeight;
+		  this.reader = context.reader();
+		  this.maxDoc = reader.maxDoc();
+		  this.acceptDocs = acceptDocs;
+		  vals = outerInstance.func.getValues(weight.context, context);
+		}
+
+		public override int docID()
+		{
+		  return doc;
+		}
+
+		// instead of matching all docs, we could also embed a query.
+		// the score could either ignore the subscore, or boost it.
+		// Containment:  floatline(foo:myTerm, "myFloatField", 1.0, 0.0f)
+		// Boost:        foo:myTerm^floatline("myFloatField",1.0,0.0f)
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextDoc() throws java.io.IOException
+		public override int nextDoc()
+		{
+		  for (;;)
+		  {
+			++doc;
+			if (doc >= maxDoc)
+			{
+			  return doc = NO_MORE_DOCS;
+			}
+			if (acceptDocs != null && !acceptDocs.get(doc))
+			{
+				continue;
+			}
+			return doc;
+		  }
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(int target) throws java.io.IOException
+		public override int advance(int target)
+		{
+		  // this will work even if target==NO_MORE_DOCS
+		  doc = target - 1;
+		  return nextDoc();
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float score() throws java.io.IOException
+		public override float score()
+		{
+		  float score = qWeight * vals.floatVal(doc);
+
+		  // Current Lucene priority queues can't handle NaN and -Infinity, so
+		  // map to -Float.MAX_VALUE. This conditional handles both -infinity
+		  // and NaN since comparisons with NaN are always false.
+		  return score > float.NegativeInfinity ? score : -float.MaxValue;
+		}
+
+		public override long cost()
+		{
+		  return maxDoc;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		public override int freq()
+		{
+		  return 1;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public Explanation explain(int doc) throws java.io.IOException
+		public virtual Explanation explain(int doc)
+		{
+		  float sc = qWeight * vals.floatVal(doc);
+
+		  Explanation result = new ComplexExplanation(true, sc, "FunctionQuery(" + outerInstance.func + "), product of:");
+
+		  result.addDetail(vals.explain(doc));
+		  result.addDetail(new Explanation(Boost, "boost"));
+		  result.addDetail(new Explanation(weight.queryNorm,"queryNorm"));
+		  return result;
+		}
+	  }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Weight createWeight(IndexSearcher searcher) throws java.io.IOException
+	  public override Weight createWeight(IndexSearcher searcher)
+	  {
+		return new FunctionQuery.FunctionWeight(this, searcher);
+	  }
+
+
+	  /// <summary>
+	  /// Prints a user-readable version of this query. </summary>
+	  public override string ToString(string field)
+	  {
+		float boost = Boost;
+		return (boost != 1.0?"(":"") + func.ToString() + (boost == 1.0 ? "" : ")^" + boost);
+	  }
+
+
+	  /// <summary>
+	  /// Returns true if <code>o</code> is equal to this. </summary>
+	  public override bool Equals(object o)
+	  {
+		if (!typeof(FunctionQuery).IsInstanceOfType(o))
+		{
+			return false;
+		}
+		FunctionQuery other = (FunctionQuery)o;
+		return this.Boost == other.Boost && this.func.Equals(other.func);
+	  }
+
+	  /// <summary>
+	  /// Returns a hash code value for this object. </summary>
+	  public override int GetHashCode()
+	  {
+		return func.GetHashCode() * 31 + float.floatToIntBits(Boost);
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/FunctionValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/FunctionValues.cs b/src/Lucene.Net.Queries/Function/FunctionValues.cs
new file mode 100644
index 0000000..862d0ba
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/FunctionValues.cs
@@ -0,0 +1,362 @@
+using System;
+
+namespace org.apache.lucene.queries.function
+{
+
+	/*
+	 * 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.
+	 */
+
+	using org.apache.lucene.search;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueFloat = org.apache.lucene.util.mutable.MutableValueFloat;
+
+	/// <summary>
+	/// Represents field values as different types.
+	/// Normally created via a <seealso cref="ValueSource"/> for a particular field and reader.
+	/// 
+	/// 
+	/// </summary>
+
+	// FunctionValues is distinct from ValueSource because
+	// there needs to be an object created at query evaluation time that
+	// is not referenced by the query itself because:
+	// - Query objects should be MT safe
+	// - For caching, Query objects are often used as keys... you don't
+	//   want the Query carrying around big objects
+	public abstract class FunctionValues
+	{
+
+	  public virtual sbyte byteVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual short shortVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+
+	  public virtual float floatVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual int intVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual long longVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual double doubleVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  // TODO: should we make a termVal, returns BytesRef?
+	  public virtual string strVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+
+	  public virtual bool boolVal(int doc)
+	  {
+		return intVal(doc) != 0;
+	  }
+
+	  /// <summary>
+	  /// returns the bytes representation of the string val - TODO: should this return the indexed raw bytes not? </summary>
+	  public virtual bool bytesVal(int doc, BytesRef target)
+	  {
+		string s = strVal(doc);
+		if (s == null)
+		{
+		  target.length = 0;
+		  return false;
+		}
+		target.copyChars(s);
+		return true;
+	  }
+
+	  /// <summary>
+	  /// Native Java Object representation of the value </summary>
+	  public virtual object objectVal(int doc)
+	  {
+		// most FunctionValues are functions, so by default return a Float()
+		return floatVal(doc);
+	  }
+
+	  /// <summary>
+	  /// Returns true if there is a value for this document </summary>
+	  public virtual bool exists(int doc)
+	  {
+		return true;
+	  }
+
+	  /// <param name="doc"> The doc to retrieve to sort ordinal for </param>
+	  /// <returns> the sort ordinal for the specified doc
+	  /// TODO: Maybe we can just use intVal for this... </returns>
+	  public virtual int ordVal(int doc)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+
+	  /// <returns> the number of unique sort ordinals this instance has </returns>
+	  public virtual int numOrd()
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public abstract string ToString(int doc);
+
+	  /// <summary>
+	  /// Abstraction of the logic required to fill the value of a specified doc into
+	  /// a reusable <seealso cref="MutableValue"/>.  Implementations of <seealso cref="FunctionValues"/>
+	  /// are encouraged to define their own implementations of ValueFiller if their
+	  /// value is not a float.
+	  /// 
+	  /// @lucene.experimental
+	  /// </summary>
+	  public abstract class ValueFiller
+	  {
+		/// <summary>
+		/// MutableValue will be reused across calls </summary>
+		public abstract MutableValue Value {get;}
+
+		/// <summary>
+		/// MutableValue will be reused across calls.  Returns true if the value exists. </summary>
+		public abstract void fillValue(int doc);
+	  }
+
+	  /// <summary>
+	  /// @lucene.experimental </summary>
+	  public virtual ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly FunctionValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(FunctionValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueFloat();
+		  }
+
+		  private readonly MutableValueFloat mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			mval.value = outerInstance.floatVal(doc);
+		  }
+	  }
+
+	  //For Functions that can work with multiple values from the same document.  This does not apply to all functions
+	  public virtual void byteVal(int doc, sbyte[] vals)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual void shortVal(int doc, short[] vals)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+
+	  public virtual void floatVal(int doc, float[] vals)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual void intVal(int doc, int[] vals)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual void longVal(int doc, long[] vals)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+	  public virtual void doubleVal(int doc, double[] vals)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+
+	  // TODO: should we make a termVal, fills BytesRef[]?
+	  public virtual void strVal(int doc, string[] vals)
+	  {
+		  throw new System.NotSupportedException();
+	  }
+
+	  public virtual Explanation explain(int doc)
+	  {
+		return new Explanation(floatVal(doc), ToString(doc));
+	  }
+
+	  public virtual ValueSourceScorer getScorer(IndexReader reader)
+	  {
+		return new ValueSourceScorer(reader, this);
+	  }
+
+	  // A RangeValueSource can't easily be a ValueSource that takes another ValueSource
+	  // because it needs different behavior depending on the type of fields.  There is also
+	  // a setup cost - parsing and normalizing params, and doing a binary search on the StringIndex.
+	  // TODO: change "reader" to AtomicReaderContext
+	  public virtual ValueSourceScorer getRangeScorer(IndexReader reader, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
+	  {
+		float lower;
+		float upper;
+
+		if (lowerVal == null)
+		{
+		  lower = float.NegativeInfinity;
+		}
+		else
+		{
+		  lower = Convert.ToSingle(lowerVal);
+		}
+		if (upperVal == null)
+		{
+		  upper = float.PositiveInfinity;
+		}
+		else
+		{
+		  upper = Convert.ToSingle(upperVal);
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float l = lower;
+		float l = lower;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float u = upper;
+		float u = upper;
+
+		if (includeLower && includeUpper)
+		{
+		  return new ValueSourceScorerAnonymousInnerClassHelper(this, reader, this, l, u);
+		}
+		else if (includeLower && !includeUpper)
+		{
+		   return new ValueSourceScorerAnonymousInnerClassHelper2(this, reader, this, l, u);
+		}
+		else if (!includeLower && includeUpper)
+		{
+		   return new ValueSourceScorerAnonymousInnerClassHelper3(this, reader, this, l, u);
+		}
+		else
+		{
+		   return new ValueSourceScorerAnonymousInnerClassHelper4(this, reader, this, l, u);
+		}
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper : ValueSourceScorer
+	  {
+		  private readonly FunctionValues outerInstance;
+
+		  private float l;
+		  private float u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper(FunctionValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.FunctionValues this, float l, float u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			float docVal = outerInstance.floatVal(doc);
+			return docVal >= l && docVal <= u;
+		  }
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper2 : ValueSourceScorer
+	  {
+		  private readonly FunctionValues outerInstance;
+
+		  private float l;
+		  private float u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper2(FunctionValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.FunctionValues this, float l, float u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			float docVal = outerInstance.floatVal(doc);
+			return docVal >= l && docVal < u;
+		  }
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper3 : ValueSourceScorer
+	  {
+		  private readonly FunctionValues outerInstance;
+
+		  private float l;
+		  private float u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper3(FunctionValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.FunctionValues this, float l, float u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			float docVal = outerInstance.floatVal(doc);
+			return docVal > l && docVal <= u;
+		  }
+	  }
+
+	  private class ValueSourceScorerAnonymousInnerClassHelper4 : ValueSourceScorer
+	  {
+		  private readonly FunctionValues outerInstance;
+
+		  private float l;
+		  private float u;
+
+		  public ValueSourceScorerAnonymousInnerClassHelper4(FunctionValues outerInstance, IndexReader reader, org.apache.lucene.queries.function.FunctionValues this, float l, float u) : base(reader, this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.l = l;
+			  this.u = u;
+		  }
+
+		  public override bool matchesValue(int doc)
+		  {
+			float docVal = outerInstance.floatVal(doc);
+			return docVal > l && docVal < u;
+		  }
+	  }
+	}
+
+
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource.cs
new file mode 100644
index 0000000..bb131af
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource.cs
@@ -0,0 +1,223 @@
+using System.Collections;
+
+namespace org.apache.lucene.queries.function
+{
+
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FieldComparator = org.apache.lucene.search.FieldComparator;
+	using FieldComparatorSource = org.apache.lucene.search.FieldComparatorSource;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using SortField = org.apache.lucene.search.SortField;
+
+
+	/// <summary>
+	/// Instantiates <seealso cref="FunctionValues"/> for a particular reader.
+	/// <br>
+	/// Often used when creating a <seealso cref="FunctionQuery"/>.
+	/// 
+	/// 
+	/// </summary>
+	public abstract class ValueSource
+	{
+
+	  /// <summary>
+	  /// Gets the values for this reader and the context that was previously
+	  /// passed to createWeight()
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public abstract FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException;
+	  public abstract FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext);
+
+	  public override abstract bool Equals(object o);
+
+	  public override abstract int GetHashCode();
+
+	  /// <summary>
+	  /// description of field, used in explain()
+	  /// </summary>
+	  public abstract string description();
+
+	  public override string ToString()
+	  {
+		return description();
+	  }
+
+
+	  /// <summary>
+	  /// Implementations should propagate createWeight to sub-ValueSources which can optionally store
+	  /// weight info in the context. The context object will be passed to getValues()
+	  /// where this info can be retrieved.
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public virtual void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+	  }
+
+	  /// <summary>
+	  /// Returns a new non-threadsafe context map.
+	  /// </summary>
+	  public static IDictionary newContext(IndexSearcher searcher)
+	  {
+		IDictionary context = new IdentityHashMap();
+		context["searcher"] = searcher;
+		return context;
+	  }
+
+
+	  //
+	  // Sorting by function
+	  //
+
+	  /// <summary>
+	  /// EXPERIMENTAL: This method is subject to change.
+	  /// <para>
+	  /// Get the SortField for this ValueSource.  Uses the <seealso cref="#getValues(java.util.Map, AtomicReaderContext)"/>
+	  /// to populate the SortField.
+	  /// 
+	  /// </para>
+	  /// </summary>
+	  /// <param name="reverse"> true if this is a reverse sort. </param>
+	  /// <returns> The <seealso cref="org.apache.lucene.search.SortField"/> for the ValueSource </returns>
+	  public virtual SortField getSortField(bool reverse)
+	  {
+		return new ValueSourceSortField(this, reverse);
+	  }
+
+	  internal class ValueSourceSortField : SortField
+	  {
+		  private readonly ValueSource outerInstance;
+
+		public ValueSourceSortField(ValueSource outerInstance, bool reverse) : base(outerInstance.description(), SortField.Type.REWRITEABLE, reverse)
+		{
+			this.outerInstance = outerInstance;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.SortField rewrite(org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+		public override SortField rewrite(IndexSearcher searcher)
+		{
+		  IDictionary context = newContext(searcher);
+		  outerInstance.createWeight(context, searcher);
+		  return new SortField(Field, new ValueSourceComparatorSource(outerInstance, context), Reverse);
+		}
+	  }
+
+	  internal class ValueSourceComparatorSource : FieldComparatorSource
+	  {
+		  private readonly ValueSource outerInstance;
+
+		internal readonly IDictionary context;
+
+		public ValueSourceComparatorSource(ValueSource outerInstance, IDictionary context)
+		{
+			this.outerInstance = outerInstance;
+		  this.context = context;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.FieldComparator<Double> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws java.io.IOException
+		public override FieldComparator<double?> newComparator(string fieldname, int numHits, int sortPos, bool reversed)
+		{
+		  return new ValueSourceComparator(outerInstance, context, numHits);
+		}
+	  }
+
+	  /// <summary>
+	  /// Implement a <seealso cref="org.apache.lucene.search.FieldComparator"/> that works
+	  /// off of the <seealso cref="FunctionValues"/> for a ValueSource
+	  /// instead of the normal Lucene FieldComparator that works off of a FieldCache.
+	  /// </summary>
+	  internal class ValueSourceComparator : FieldComparator<double?>
+	  {
+		  private readonly ValueSource outerInstance;
+
+		internal readonly double[] values;
+		internal FunctionValues docVals;
+		internal double bottom;
+		internal readonly IDictionary fcontext;
+		internal double topValue;
+
+		internal ValueSourceComparator(ValueSource outerInstance, IDictionary fcontext, int numHits)
+		{
+			this.outerInstance = outerInstance;
+		  this.fcontext = fcontext;
+		  values = new double[numHits];
+		}
+
+		public override int compare(int slot1, int slot2)
+		{
+		  return values[slot1].CompareTo(values[slot2]);
+		}
+
+		public override int compareBottom(int doc)
+		{
+		  return bottom.CompareTo(docVals.doubleVal(doc));
+		}
+
+		public override void copy(int slot, int doc)
+		{
+		  values[slot] = docVals.doubleVal(doc);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.FieldComparator setNextReader(org.apache.lucene.index.AtomicReaderContext context) throws java.io.IOException
+		public override FieldComparator setNextReader(AtomicReaderContext context)
+		{
+		  docVals = outerInstance.getValues(fcontext, context);
+		  return this;
+		}
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: @Override public void setBottom(final int bottom)
+		public override int Bottom
+		{
+			set
+			{
+			  this.bottom = values[value];
+			}
+		}
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: @Override public void setTopValue(final Double value)
+		public override double? TopValue
+		{
+			set
+			{
+			  this.topValue = (double)value;
+			}
+		}
+
+		public override double? value(int slot)
+		{
+		  return values[slot];
+		}
+
+		public override int compareTop(int doc)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final double docValue = docVals.doubleVal(doc);
+		  double docValue = docVals.doubleVal(doc);
+		  return topValue.CompareTo(docValue);
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/BoolFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/BoolFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/BoolFunction.cs
new file mode 100644
index 0000000..85399df
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/BoolFunction.cs
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	/// <summary>
+	/// Abstract parent class for those <seealso cref="ValueSource"/> implementations which
+	/// apply boolean logic to their values
+	/// </summary>
+	public abstract class BoolFunction : ValueSource
+	{
+	  // TODO: placeholder to return type, among other common future functionality
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ByteFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ByteFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/ByteFieldSource.cs
new file mode 100644
index 0000000..0e2ffc6
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ByteFieldSource.cs
@@ -0,0 +1,142 @@
+using System;
+using System.Collections;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+
+	/// <summary>
+	/// Obtains int field values from the <seealso cref="org.apache.lucene.search.FieldCache"/>
+	/// using <code>getInts()</code>
+	/// and makes those values available as other numeric types, casting as needed. *
+	/// 
+	/// 
+	/// </summary>
+	[Obsolete]
+	public class ByteFieldSource : FieldCacheSource
+	{
+
+	  private readonly FieldCache.ByteParser parser;
+
+	  public ByteFieldSource(string field) : this(field, null)
+	  {
+	  }
+
+	  public ByteFieldSource(string field, FieldCache.ByteParser parser) : base(field)
+	  {
+		this.parser = parser;
+	  }
+
+	  public override string description()
+	  {
+		return "byte(" + field + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldCache.Bytes arr = cache.getBytes(readerContext.reader(), field, parser, false);
+		FieldCache.Bytes arr = cache.getBytes(readerContext.reader(), field, parser, false);
+
+		return new FunctionValuesAnonymousInnerClassHelper(this, arr);
+	  }
+
+	  private class FunctionValuesAnonymousInnerClassHelper : FunctionValues
+	  {
+		  private readonly ByteFieldSource outerInstance;
+
+		  private FieldCache.Bytes arr;
+
+		  public FunctionValuesAnonymousInnerClassHelper(ByteFieldSource outerInstance, FieldCache.Bytes arr)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.arr = arr;
+		  }
+
+		  public override sbyte byteVal(int doc)
+		  {
+			return arr.get(doc);
+		  }
+
+		  public override short shortVal(int doc)
+		  {
+			return (short) arr.get(doc);
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return (float) arr.get(doc);
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			return (int) arr.get(doc);
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return (long) arr.get(doc);
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return (double) arr.get(doc);
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return Convert.ToString(arr.get(doc));
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description() + '=' + byteVal(doc);
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return arr.get(doc); // TODO: valid?
+		  }
+
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o.GetType() != typeof(ByteFieldSource))
+		{
+			return false;
+		}
+		ByteFieldSource other = (ByteFieldSource) o;
+		return base.Equals(other) && (this.parser == null ? other.parser == null : this.parser.GetType() == other.parser.GetType());
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = parser == null ? typeof(sbyte?).GetHashCode() : parser.GetType().GetHashCode();
+		h += base.GetHashCode();
+		return h;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/BytesRefFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/BytesRefFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/BytesRefFieldSource.cs
new file mode 100644
index 0000000..f091aee
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/BytesRefFieldSource.cs
@@ -0,0 +1,140 @@
+using System.Collections;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using BinaryDocValues = org.apache.lucene.index.BinaryDocValues;
+	using FieldInfo = org.apache.lucene.index.FieldInfo;
+	using DocValuesType = org.apache.lucene.index.FieldInfo.DocValuesType;
+	using DocTermsIndexDocValues = org.apache.lucene.queries.function.docvalues.DocTermsIndexDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using Bits = org.apache.lucene.util.Bits;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+	/// <summary>
+	/// An implementation for retrieving <seealso cref="FunctionValues"/> instances for string based fields.
+	/// </summary>
+	public class BytesRefFieldSource : FieldCacheSource
+	{
+
+	  public BytesRefFieldSource(string field) : base(field)
+	  {
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.FieldInfo fieldInfo = readerContext.reader().getFieldInfos().fieldInfo(field);
+		FieldInfo fieldInfo = readerContext.reader().FieldInfos.fieldInfo(field);
+		// To be sorted or not to be sorted, that is the question
+		// TODO: do it cleaner?
+		if (fieldInfo != null && fieldInfo.DocValuesType == FieldInfo.DocValuesType.BINARY)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.BinaryDocValues binaryValues = org.apache.lucene.search.FieldCache.DEFAULT.getTerms(readerContext.reader(), field, true);
+		  BinaryDocValues binaryValues = FieldCache.DEFAULT.getTerms(readerContext.reader(), field, true);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits docsWithField = org.apache.lucene.search.FieldCache.DEFAULT.getDocsWithField(readerContext.reader(), field);
+		  Bits docsWithField = FieldCache.DEFAULT.getDocsWithField(readerContext.reader(), field);
+		  return new FunctionValuesAnonymousInnerClassHelper(this, binaryValues, docsWithField);
+		}
+		else
+		{
+		  return new DocTermsIndexDocValuesAnonymousInnerClassHelper(this, this, readerContext, field);
+		}
+	  }
+
+	  private class FunctionValuesAnonymousInnerClassHelper : FunctionValues
+	  {
+		  private readonly BytesRefFieldSource outerInstance;
+
+		  private BinaryDocValues binaryValues;
+		  private Bits docsWithField;
+
+		  public FunctionValuesAnonymousInnerClassHelper(BytesRefFieldSource outerInstance, BinaryDocValues binaryValues, Bits docsWithField)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.binaryValues = binaryValues;
+			  this.docsWithField = docsWithField;
+		  }
+
+
+		  public override bool exists(int doc)
+		  {
+			return docsWithField.get(doc);
+		  }
+
+		  public override bool bytesVal(int doc, BytesRef target)
+		  {
+			binaryValues.get(doc, target);
+			return target.length > 0;
+		  }
+
+		  public override string strVal(int doc)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.BytesRef bytes = new org.apache.lucene.util.BytesRef();
+			BytesRef bytes = new BytesRef();
+			return bytesVal(doc, bytes) ? bytes.utf8ToString() : null;
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return strVal(doc);
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description() + '=' + strVal(doc);
+		  }
+	  }
+
+	  private class DocTermsIndexDocValuesAnonymousInnerClassHelper : DocTermsIndexDocValues
+	  {
+		  private readonly BytesRefFieldSource outerInstance;
+
+		  public DocTermsIndexDocValuesAnonymousInnerClassHelper(BytesRefFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.BytesRefFieldSource this, AtomicReaderContext readerContext, string field) : base(this, readerContext, field)
+		  {
+			  this.outerInstance = outerInstance;
+		  }
+
+
+		  protected internal override string toTerm(string readableValue)
+		  {
+			return readableValue;
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return strVal(doc);
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description() + '=' + strVal(doc);
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ConstNumberSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ConstNumberSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/ConstNumberSource.cs
new file mode 100644
index 0000000..33a0aa0
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ConstNumberSource.cs
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	/// <summary>
+	/// <code>ConstNumberSource</code> is the base class for all constant numbers
+	/// </summary>
+	public abstract class ConstNumberSource : ValueSource
+	{
+	  public abstract int Int {get;}
+	  public abstract long Long {get;}
+	  public abstract float Float {get;}
+	  public abstract double Double {get;}
+	  public abstract Number Number {get;}
+	  public abstract bool Bool {get;}
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ConstValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ConstValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/ConstValueSource.cs
new file mode 100644
index 0000000..9933f13
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ConstValueSource.cs
@@ -0,0 +1,156 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+
+
+	/// <summary>
+	/// <code>ConstValueSource</code> returns a constant for all documents
+	/// </summary>
+	public class ConstValueSource : ConstNumberSource
+	{
+	  internal readonly float constant;
+	  private readonly double dv;
+
+	  public ConstValueSource(float constant)
+	  {
+		this.constant = constant;
+		this.dv = constant;
+	  }
+
+	  public override string description()
+	  {
+		return "const(" + constant + ")";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly ConstValueSource outerInstance;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(ConstValueSource outerInstance, org.apache.lucene.queries.function.valuesource.ConstValueSource this) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return outerInstance.constant;
+		  }
+		  public override int intVal(int doc)
+		  {
+			return (int)outerInstance.constant;
+		  }
+		  public override long longVal(int doc)
+		  {
+			return (long)outerInstance.constant;
+		  }
+		  public override double doubleVal(int doc)
+		  {
+			return outerInstance.dv;
+		  }
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description();
+		  }
+		  public override object objectVal(int doc)
+		  {
+			return outerInstance.constant;
+		  }
+		  public override bool boolVal(int doc)
+		  {
+			return outerInstance.constant != 0.0f;
+		  }
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return float.floatToIntBits(constant) * 31;
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (!(o is ConstValueSource))
+		{
+			return false;
+		}
+		ConstValueSource other = (ConstValueSource)o;
+		return this.constant == other.constant;
+	  }
+
+	  public override int Int
+	  {
+		  get
+		  {
+			return (int)constant;
+		  }
+	  }
+
+	  public override long Long
+	  {
+		  get
+		  {
+			return (long)constant;
+		  }
+	  }
+
+	  public override float Float
+	  {
+		  get
+		  {
+			return constant;
+		  }
+	  }
+
+	  public override double Double
+	  {
+		  get
+		  {
+			return dv;
+		  }
+	  }
+
+	  public override Number Number
+	  {
+		  get
+		  {
+			return constant;
+		  }
+	  }
+
+	  public override bool Bool
+	  {
+		  get
+		  {
+			return constant != 0.0f;
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/DefFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/DefFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/DefFunction.cs
new file mode 100644
index 0000000..48a67d4
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/DefFunction.cs
@@ -0,0 +1,153 @@
+using System.Collections;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// <seealso cref="ValueSource"/> implementation which only returns the values from the provided
+	/// ValueSources which are available for a particular docId.  Consequently, when combined
+	/// with a <seealso cref="ConstValueSource"/>, this function serves as a way to return a default
+	/// value when the values for a field are unavailable.
+	/// </summary>
+	public class DefFunction : MultiFunction
+	{
+	  public DefFunction(IList<ValueSource> sources) : base(sources)
+	  {
+	  }
+
+	  protected internal override string name()
+	  {
+		return "def";
+	  }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map fcontext, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary fcontext, AtomicReaderContext readerContext)
+	  {
+
+
+		return new ValuesAnonymousInnerClassHelper(this, valsArr(sources, fcontext, readerContext));
+	  }
+
+	  private class ValuesAnonymousInnerClassHelper : Values
+	  {
+		  private readonly DefFunction outerInstance;
+
+		  public ValuesAnonymousInnerClassHelper(DefFunction outerInstance, FunctionValues[] valsArr) : base(outerInstance, valsArr)
+		  {
+			  this.outerInstance = outerInstance;
+			  upto = valsArr.Length - 1;
+		  }
+
+		  internal readonly int upto;
+
+		  private FunctionValues get(int doc)
+		  {
+			for (int i = 0; i < upto; i++)
+			{
+			  FunctionValues vals = valsArr[i];
+			  if (vals.exists(doc))
+			  {
+				return vals;
+			  }
+			}
+			return valsArr[upto];
+		  }
+
+		  public override sbyte byteVal(int doc)
+		  {
+			return get(doc).byteVal(doc);
+		  }
+
+		  public override short shortVal(int doc)
+		  {
+			return get(doc).shortVal(doc);
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return get(doc).floatVal(doc);
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			return get(doc).intVal(doc);
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return get(doc).longVal(doc);
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return get(doc).doubleVal(doc);
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return get(doc).strVal(doc);
+		  }
+
+		  public override bool boolVal(int doc)
+		  {
+			return get(doc).boolVal(doc);
+		  }
+
+		  public override bool bytesVal(int doc, BytesRef target)
+		  {
+			return get(doc).bytesVal(doc, target);
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return get(doc).objectVal(doc);
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			// return true if any source is exists?
+			foreach (FunctionValues vals in valsArr)
+			{
+			  if (vals.exists(doc))
+			  {
+				return true;
+			  }
+			}
+			return false;
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				// TODO: need ValueSource.type() to determine correct type
+				return base.ValueFiller;
+			  }
+		  }
+	  }
+	}
+}
\ No newline at end of file


[11/11] git commit: Skeleton port of Lucene.Net.Memory

Posted by sy...@apache.org.
Skeleton port of Lucene.Net.Memory


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

Branch: refs/heads/master
Commit: 531b4af02d67e3025b8092d1c88e99f47af051d1
Parents: 674f0cb
Author: Itamar Syn-Hershko <it...@code972.com>
Authored: Tue Sep 16 01:44:12 2014 +0300
Committer: Itamar Syn-Hershko <it...@code972.com>
Committed: Tue Sep 16 01:44:12 2014 +0300

----------------------------------------------------------------------
 src/Lucene.Net.Memory/HashMapHelperClass.cs     |   26 +
 src/Lucene.Net.Memory/Lucene.Net.Memory.csproj  |   61 +
 src/Lucene.Net.Memory/MemoryIndex.cs            | 1606 ++++++++++++++++++
 .../MemoryIndexNormDocValues.cs                 |   47 +
 .../Properties/AssemblyInfo.cs                  |   35 +
 5 files changed, 1775 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/531b4af0/src/Lucene.Net.Memory/HashMapHelperClass.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Memory/HashMapHelperClass.cs b/src/Lucene.Net.Memory/HashMapHelperClass.cs
new file mode 100644
index 0000000..395d53e
--- /dev/null
+++ b/src/Lucene.Net.Memory/HashMapHelperClass.cs
@@ -0,0 +1,26 @@
+//---------------------------------------------------------------------------------------------------------
+//	Copyright © 2007 - 2014 Tangible Software Solutions Inc.
+//	This class can be used by anyone provided that the copyright notice remains intact.
+//
+//	This class is used to replace calls to some Java HashMap or Hashtable methods.
+//---------------------------------------------------------------------------------------------------------
+using System.Collections.Generic;
+internal static class HashMapHelperClass
+{
+	internal static HashSet<KeyValuePair<TKey, TValue>> SetOfKeyValuePairs<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
+	{
+		var entries = new HashSet<KeyValuePair<TKey, TValue>>();
+		foreach (KeyValuePair<TKey, TValue> keyValuePair in dictionary)
+		{
+			entries.Add(keyValuePair);
+		}
+		return entries;
+	}
+
+	internal static TValue GetValueOrNull<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
+	{
+		TValue ret;
+		dictionary.TryGetValue(key, out ret);
+		return ret;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/531b4af0/src/Lucene.Net.Memory/Lucene.Net.Memory.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Memory/Lucene.Net.Memory.csproj b/src/Lucene.Net.Memory/Lucene.Net.Memory.csproj
new file mode 100644
index 0000000..3ba5780
--- /dev/null
+++ b/src/Lucene.Net.Memory/Lucene.Net.Memory.csproj
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{42ECF239-AFC1-427D-921E-B5A277809CF0}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Memory</RootNamespace>
+    <AssemblyName>Lucene.Net.Memory</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="HashMapHelperClass.cs" />
+    <Compile Include="MemoryIndex.cs" />
+    <Compile Include="MemoryIndexNormDocValues.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Lucene.Net.Core\Lucene.Net.csproj">
+      <Project>{5d4ad9be-1ffb-41ab-9943-25737971bf57}</Project>
+      <Name>Lucene.Net</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/531b4af0/src/Lucene.Net.Memory/MemoryIndex.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Memory/MemoryIndex.cs b/src/Lucene.Net.Memory/MemoryIndex.cs
new file mode 100644
index 0000000..8e339ca
--- /dev/null
+++ b/src/Lucene.Net.Memory/MemoryIndex.cs
@@ -0,0 +1,1606 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using Lucene.Net.Analysis;
+using Lucene.Net.Analysis.Tokenattributes;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Search.Similarities;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+
+namespace Lucene.Net.Memory
+{
+
+	/*
+	 * 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.
+	 */
+
+    /// <summary>
+	/// High-performance single-document main memory Apache Lucene fulltext search index. 
+	/// 
+	/// <h4>Overview</h4>
+	/// 
+	/// This class is a replacement/substitute for a large subset of
+	/// <seealso cref="RAMDirectory"/> functionality. It is designed to
+	/// enable maximum efficiency for on-the-fly matchmaking combining structured and 
+	/// fuzzy fulltext search in realtime streaming applications such as Nux XQuery based XML 
+	/// message queues, publish-subscribe systems for Blogs/newsfeeds, text chat, data acquisition and 
+	/// distribution systems, application level routers, firewalls, classifiers, etc. 
+	/// Rather than targeting fulltext search of infrequent queries over huge persistent 
+	/// data archives (historic search), this class targets fulltext search of huge 
+	/// numbers of queries over comparatively small transient realtime data (prospective 
+	/// search). 
+	/// For example as in 
+	/// <pre class="prettyprint">
+	/// float score = search(String text, Query query)
+	/// </pre>
+	/// <para>
+	/// Each instance can hold at most one Lucene "document", with a document containing
+	/// zero or more "fields", each field having a name and a fulltext value. The
+	/// fulltext value is tokenized (split and transformed) into zero or more index terms 
+	/// (aka words) on <code>addField()</code>, according to the policy implemented by an
+	/// Analyzer. For example, Lucene analyzers can split on whitespace, normalize to lower case
+	/// for case insensitivity, ignore common terms with little discriminatory value such as "he", "in", "and" (stop
+	/// words), reduce the terms to their natural linguistic root form such as "fishing"
+	/// being reduced to "fish" (stemming), resolve synonyms/inflexions/thesauri 
+	/// (upon indexing and/or querying), etc. For details, see
+	/// <a target="_blank" href="http://today.java.net/pub/a/today/2003/07/30/LuceneIntro.html">Lucene Analyzer Intro</a>.
+	/// </para>
+	/// <para>
+	/// Arbitrary Lucene queries can be run against this class - see <a target="_blank" 
+	/// href="{@docRoot}/../queryparser/org/apache/lucene/queryparser/classic/package-summary.html#package_description">
+	/// Lucene Query Syntax</a>
+	/// as well as <a target="_blank" 
+	/// href="http://today.java.net/pub/a/today/2003/11/07/QueryParserRules.html">Query Parser Rules</a>.
+	/// Note that a Lucene query selects on the field names and associated (indexed) 
+	/// tokenized terms, not on the original fulltext(s) - the latter are not stored 
+	/// but rather thrown away immediately after tokenization.
+	/// </para>
+	/// <para>
+	/// For some interesting background information on search technology, see Bob Wyman's
+	/// <a target="_blank" 
+	/// href="http://bobwyman.pubsub.com/main/2005/05/mary_hodder_poi.html">Prospective Search</a>, 
+	/// Jim Gray's
+	/// <a target="_blank" href="http://www.acmqueue.org/modules.php?name=Content&pa=showpage&pid=293&page=4">
+	/// A Call to Arms - Custom subscriptions</a>, and Tim Bray's
+	/// <a target="_blank" 
+	/// href="http://www.tbray.org/ongoing/When/200x/2003/07/30/OnSearchTOC">On Search, the Series</a>.
+	/// 
+	/// 
+	/// <h4>Example Usage</h4> 
+	/// 
+	/// <pre class="prettyprint">
+	/// Analyzer analyzer = new SimpleAnalyzer(version);
+	/// MemoryIndex index = new MemoryIndex();
+	/// index.addField("content", "Readings about Salmons and other select Alaska fishing Manuals", analyzer);
+	/// index.addField("author", "Tales of James", analyzer);
+	/// QueryParser parser = new QueryParser(version, "content", analyzer);
+	/// float score = index.search(parser.parse("+author:james +salmon~ +fish* manual~"));
+	/// if (score &gt; 0.0f) {
+	///     System.out.println("it's a match");
+	/// } else {
+	///     System.out.println("no match found");
+	/// }
+	/// System.out.println("indexData=" + index.toString());
+	/// </pre>
+	/// 
+	/// 
+	/// <h4>Example XQuery Usage</h4> 
+	/// 
+	/// <pre class="prettyprint">
+	/// (: An XQuery that finds all books authored by James that have something to do with "salmon fishing manuals", sorted by relevance :)
+	/// declare namespace lucene = "java:nux.xom.pool.FullTextUtil";
+	/// declare variable $query := "+salmon~ +fish* manual~"; (: any arbitrary Lucene query can go here :)
+	/// 
+	/// for $book in /books/book[author="James" and lucene:match(abstract, $query) > 0.0]
+	/// let $score := lucene:match($book/abstract, $query)
+	/// order by $score descending
+	/// return $book
+	/// </pre>
+	/// 
+	/// 
+	/// <h4>No thread safety guarantees</h4>
+	/// 
+	/// An instance can be queried multiple times with the same or different queries,
+	/// but an instance is not thread-safe. If desired use idioms such as:
+	/// <pre class="prettyprint">
+	/// MemoryIndex index = ...
+	/// synchronized (index) {
+	///    // read and/or write index (i.e. add fields and/or query)
+	/// } 
+	/// </pre>
+	/// 
+	/// 
+	/// <h4>Performance Notes</h4>
+	/// 
+	/// Internally there's a new data structure geared towards efficient indexing 
+	/// and searching, plus the necessary support code to seamlessly plug into the Lucene 
+	/// framework.
+	/// </para>
+	/// <para>
+	/// This class performs very well for very small texts (e.g. 10 chars) 
+	/// as well as for large texts (e.g. 10 MB) and everything in between. 
+	/// Typically, it is about 10-100 times faster than <code>RAMDirectory</code>.
+	/// Note that <code>RAMDirectory</code> has particularly 
+	/// large efficiency overheads for small to medium sized texts, both in time and space.
+	/// Indexing a field with N tokens takes O(N) in the best case, and O(N logN) in the worst 
+	/// case. Memory consumption is probably larger than for <code>RAMDirectory</code>.
+	/// </para>
+	/// <para>
+	/// Example throughput of many simple term queries over a single MemoryIndex: 
+	/// ~500000 queries/sec on a MacBook Pro, jdk 1.5.0_06, server VM. 
+	/// As always, your mileage may vary.
+	/// </para>
+	/// <para>
+	/// If you're curious about
+	/// the whereabouts of bottlenecks, run java 1.5 with the non-perturbing '-server
+	/// -agentlib:hprof=cpu=samples,depth=10' flags, then study the trace log and
+	/// correlate its hotspot trailer with its call stack headers (see <a
+	/// target="_blank"
+	/// href="http://java.sun.com/developer/technicalArticles/Programming/HPROF.html">
+	/// hprof tracing </a>).
+	/// 
+	/// </para>
+	/// </summary>
+	public class MemoryIndex
+	{
+
+	  /// <summary>
+	  /// info for each field: Map<String fieldName, Info field> </summary>
+	  private readonly Dictionary<string, Info> fields = new Dictionary<string, Info>();
+
+	  /// <summary>
+	  /// fields sorted ascending by fieldName; lazily computed on demand </summary>
+	  [NonSerialized]
+	  private KeyValuePair<string, Info>[] sortedFields;
+
+	  private readonly bool storeOffsets;
+
+	  private const bool DEBUG = false;
+
+	  private readonly ByteBlockPool byteBlockPool;
+	  private readonly IntBlockPool intBlockPool;
+	//  private final IntBlockPool.SliceReader postingsReader;
+	  private readonly IntBlockPool.SliceWriter postingsWriter;
+
+	  private Dictionary<string, FieldInfo> fieldInfos = new Dictionary<string, FieldInfo>();
+
+	  private Counter bytesUsed;
+
+	  /// <summary>
+	  /// Sorts term entries into ascending order; also works for
+	  /// Arrays.binarySearch() and Arrays.sort()
+	  /// </summary>
+	  private static readonly IComparer<object> termComparator = new ComparatorAnonymousInnerClassHelper();
+
+	  private class ComparatorAnonymousInnerClassHelper : IComparer<object>
+	  {
+		  public ComparatorAnonymousInnerClassHelper()
+		  {
+		  }
+
+//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
+//ORIGINAL LINE: @Override @SuppressWarnings({"unchecked","rawtypes"}) public int compare(Object o1, Object o2)
+		  public virtual int Compare(object o1, object o2)
+		  {
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: if (o1 instanceof java.util.Map.Entry<?,?>)
+			if (o1 is KeyValuePair<?, ?>)
+			{
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: o1 = ((java.util.Map.Entry<?,?>) o1).getKey();
+				o1 = ((KeyValuePair<?, ?>) o1).Key;
+			}
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: if (o2 instanceof java.util.Map.Entry<?,?>)
+			if (o2 is KeyValuePair<?, ?>)
+			{
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: o2 = ((java.util.Map.Entry<?,?>) o2).getKey();
+				o2 = ((KeyValuePair<?, ?>) o2).Key;
+			}
+			if (o1 == o2)
+			{
+				return 0;
+			}
+			return ((IComparable) o1).CompareTo((IComparable) o2);
+		  }
+	  }
+
+	  /// <summary>
+	  /// Constructs an empty instance.
+	  /// </summary>
+	  public MemoryIndex() : this(false)
+	  {
+	  }
+
+	  /// <summary>
+	  /// Constructs an empty instance that can optionally store the start and end
+	  /// character offset of each token term in the text. This can be useful for
+	  /// highlighting of hit locations with the Lucene highlighter package.
+	  /// Protected until the highlighter package matures, so that this can actually
+	  /// be meaningfully integrated.
+	  /// </summary>
+	  /// <param name="storeOffsets">
+	  ///            whether or not to store the start and end character offset of
+	  ///            each token term in the text </param>
+	  public MemoryIndex(bool storeOffsets) : this(storeOffsets, 0)
+	  {
+
+	  }
+
+	  /// <summary>
+	  /// Expert: This constructor accepts an upper limit for the number of bytes that should be reused if this instance is <seealso cref="#reset()"/>. </summary>
+	  /// <param name="storeOffsets"> <code>true</code> if offsets should be stored </param>
+	  /// <param name="maxReusedBytes"> the number of bytes that should remain in the internal memory pools after <seealso cref="#reset()"/> is called </param>
+	  internal MemoryIndex(bool storeOffsets, long maxReusedBytes)
+	  {
+		this.storeOffsets = storeOffsets;
+		this.bytesUsed = Counter.newCounter();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int maxBufferedByteBlocks = (int)((maxReusedBytes/2) / org.apache.lucene.util.ByteBlockPool.BYTE_BLOCK_SIZE);
+		int maxBufferedByteBlocks = (int)((maxReusedBytes / 2) / ByteBlockPool.BYTE_BLOCK_SIZE);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int maxBufferedIntBlocks = (int)((maxReusedBytes - (maxBufferedByteBlocks*org.apache.lucene.util.ByteBlockPool.BYTE_BLOCK_SIZE))/(org.apache.lucene.util.IntBlockPool.INT_BLOCK_SIZE * org.apache.lucene.util.RamUsageEstimator.NUM_BYTES_INT));
+		int maxBufferedIntBlocks = (int)((maxReusedBytes - (maxBufferedByteBlocks * ByteBlockPool.BYTE_BLOCK_SIZE)) / (IntBlockPool.INT_BLOCK_SIZE * RamUsageEstimator.NUM_BYTES_INT));
+		assert(maxBufferedByteBlocks * ByteBlockPool.BYTE_BLOCK_SIZE) + (maxBufferedIntBlocks * IntBlockPool.INT_BLOCK_SIZE * RamUsageEstimator.NUM_BYTES_INT) <= maxReusedBytes;
+		byteBlockPool = new ByteBlockPool(new RecyclingByteBlockAllocator(ByteBlockPool.BYTE_BLOCK_SIZE, maxBufferedByteBlocks, bytesUsed));
+		intBlockPool = new IntBlockPool(new RecyclingIntBlockAllocator(IntBlockPool.INT_BLOCK_SIZE, maxBufferedIntBlocks, bytesUsed));
+		postingsWriter = new SliceWriter(intBlockPool);
+	  }
+
+	  /// <summary>
+	  /// Convenience method; Tokenizes the given field text and adds the resulting
+	  /// terms to the index; Equivalent to adding an indexed non-keyword Lucene
+	  /// <seealso cref="org.apache.lucene.document.Field"/> that is tokenized, not stored,
+	  /// termVectorStored with positions (or termVectorStored with positions and offsets),
+	  /// </summary>
+	  /// <param name="fieldName">
+	  ///            a name to be associated with the text </param>
+	  /// <param name="text">
+	  ///            the text to tokenize and index. </param>
+	  /// <param name="analyzer">
+	  ///            the analyzer to use for tokenization </param>
+	  public virtual void addField(string fieldName, string text, Analyzer analyzer)
+	  {
+		if (fieldName == null)
+		{
+		  throw new System.ArgumentException("fieldName must not be null");
+		}
+		if (text == null)
+		{
+		  throw new System.ArgumentException("text must not be null");
+		}
+		if (analyzer == null)
+		{
+		  throw new System.ArgumentException("analyzer must not be null");
+		}
+
+		TokenStream stream;
+		try
+		{
+		  stream = analyzer.TokenStream(fieldName, text);
+		}
+		catch (IOException ex)
+		{
+		  throw new Exception(ex);
+		}
+
+		addField(fieldName, stream, 1.0f, analyzer.GetPositionIncrementGap(fieldName), analyzer.GetOffsetGap(fieldName));
+	  }
+
+	  /// <summary>
+	  /// Convenience method; Creates and returns a token stream that generates a
+	  /// token for each keyword in the given collection, "as is", without any
+	  /// transforming text analysis. The resulting token stream can be fed into
+	  /// <seealso cref="#addField(String, TokenStream)"/>, perhaps wrapped into another
+	  /// <seealso cref="org.apache.lucene.analysis.TokenFilter"/>, as desired.
+	  /// </summary>
+	  /// <param name="keywords">
+	  ///            the keywords to generate tokens for </param>
+	  /// <returns> the corresponding token stream </returns>
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public <T> org.apache.lucene.analysis.TokenStream keywordTokenStream(final java.util.Collection<T> keywords)
+	  public virtual TokenStream keywordTokenStream<T>(ICollection<T> keywords)
+	  {
+		// TODO: deprecate & move this method into AnalyzerUtil?
+		if (keywords == null)
+		{
+		  throw new System.ArgumentException("keywords must not be null");
+		}
+
+		return new TokenStreamAnonymousInnerClassHelper(this, keywords);
+	  }
+
+	  private class TokenStreamAnonymousInnerClassHelper : TokenStream
+	  {
+		  private readonly MemoryIndex outerInstance;
+
+		  private ICollection<T> keywords;
+
+		  public TokenStreamAnonymousInnerClassHelper(MemoryIndex outerInstance, ICollection<T> keywords)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.keywords = keywords;
+			  iter = keywords.GetEnumerator();
+			  start = 0;
+			  termAtt = addAttribute(typeof(CharTermAttribute));
+			  offsetAtt = addAttribute(typeof(OffsetAttribute));
+		  }
+
+		  private IEnumerator<T> iter;
+		  private int start;
+		  private readonly CharTermAttribute termAtt;
+		  private readonly OffsetAttribute offsetAtt;
+
+		  public override bool incrementToken()
+		  {
+			if (!iter.hasNext())
+			{
+				return false;
+			}
+
+			T obj = iter.next();
+			if (obj == null)
+			{
+			  throw new System.ArgumentException("keyword must not be null");
+			}
+
+			string term = obj.ToString();
+			clearAttributes();
+			termAtt.setEmpty().append(term);
+			offsetAtt.setOffset(start, start + termAtt.length());
+			start += term.Length + 1; // separate words by 1 (blank) character
+			return true;
+		  }
+	  }
+
+	  /// <summary>
+	  /// Equivalent to <code>addField(fieldName, stream, 1.0f)</code>.
+	  /// </summary>
+	  /// <param name="fieldName">
+	  ///            a name to be associated with the text </param>
+	  /// <param name="stream">
+	  ///            the token stream to retrieve tokens from </param>
+	  public virtual void addField(string fieldName, TokenStream stream)
+	  {
+		addField(fieldName, stream, 1.0f);
+	  }
+
+	  /// <summary>
+	  /// Iterates over the given token stream and adds the resulting terms to the index;
+	  /// Equivalent to adding a tokenized, indexed, termVectorStored, unstored,
+	  /// Lucene <seealso cref="org.apache.lucene.document.Field"/>.
+	  /// Finally closes the token stream. Note that untokenized keywords can be added with this method via 
+	  /// <seealso cref="#keywordTokenStream(Collection)"/>, the Lucene <code>KeywordTokenizer</code> or similar utilities.
+	  /// </summary>
+	  /// <param name="fieldName">
+	  ///            a name to be associated with the text </param>
+	  /// <param name="stream">
+	  ///            the token stream to retrieve tokens from. </param>
+	  /// <param name="boost">
+	  ///            the boost factor for hits for this field
+	  /// </param>
+	  /// <seealso cref= org.apache.lucene.document.Field#setBoost(float) </seealso>
+	  public virtual void addField(string fieldName, TokenStream stream, float boost)
+	  {
+		addField(fieldName, stream, boost, 0);
+	  }
+
+
+	  /// <summary>
+	  /// Iterates over the given token stream and adds the resulting terms to the index;
+	  /// Equivalent to adding a tokenized, indexed, termVectorStored, unstored,
+	  /// Lucene <seealso cref="org.apache.lucene.document.Field"/>.
+	  /// Finally closes the token stream. Note that untokenized keywords can be added with this method via
+	  /// <seealso cref="#keywordTokenStream(Collection)"/>, the Lucene <code>KeywordTokenizer</code> or similar utilities.
+	  /// </summary>
+	  /// <param name="fieldName">
+	  ///            a name to be associated with the text </param>
+	  /// <param name="stream">
+	  ///            the token stream to retrieve tokens from. </param>
+	  /// <param name="boost">
+	  ///            the boost factor for hits for this field
+	  /// </param>
+	  /// <param name="positionIncrementGap">
+	  ///            the position increment gap if fields with the same name are added more than once
+	  /// 
+	  /// </param>
+	  /// <seealso cref= org.apache.lucene.document.Field#setBoost(float) </seealso>
+	  public virtual void addField(string fieldName, TokenStream stream, float boost, int positionIncrementGap)
+	  {
+		addField(fieldName, stream, boost, positionIncrementGap, 1);
+	  }
+
+	  /// <summary>
+	  /// Iterates over the given token stream and adds the resulting terms to the index;
+	  /// Equivalent to adding a tokenized, indexed, termVectorStored, unstored,
+	  /// Lucene <seealso cref="org.apache.lucene.document.Field"/>.
+	  /// Finally closes the token stream. Note that untokenized keywords can be added with this method via 
+	  /// <seealso cref="#keywordTokenStream(Collection)"/>, the Lucene <code>KeywordTokenizer</code> or similar utilities.
+	  /// 
+	  /// </summary>
+	  /// <param name="fieldName">
+	  ///            a name to be associated with the text </param>
+	  /// <param name="stream">
+	  ///            the token stream to retrieve tokens from. </param>
+	  /// <param name="boost">
+	  ///            the boost factor for hits for this field </param>
+	  /// <param name="positionIncrementGap">
+	  ///            the position increment gap if fields with the same name are added more than once </param>
+	  /// <param name="offsetGap">
+	  ///            the offset gap if fields with the same name are added more than once </param>
+	  /// <seealso cref= org.apache.lucene.document.Field#setBoost(float) </seealso>
+	  public virtual void addField(string fieldName, TokenStream stream, float boost, int positionIncrementGap, int offsetGap)
+	  {
+		try
+		{
+		  if (fieldName == null)
+		  {
+			throw new System.ArgumentException("fieldName must not be null");
+		  }
+		  if (stream == null)
+		  {
+			  throw new System.ArgumentException("token stream must not be null");
+		  }
+		  if (boost <= 0.0f)
+		  {
+			  throw new System.ArgumentException("boost factor must be greater than 0.0");
+		  }
+		  int numTokens = 0;
+		  int numOverlapTokens = 0;
+		  int pos = -1;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.BytesRefHash terms;
+		  BytesRefHash terms;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final SliceByteStartArray sliceArray;
+		  SliceByteStartArray sliceArray;
+		  Info info = null;
+		  long sumTotalTermFreq = 0;
+		  int offset = 0;
+		  if ((info = fields[fieldName]) != null)
+		  {
+			numTokens = info.numTokens;
+			numOverlapTokens = info.numOverlapTokens;
+			pos = info.lastPosition + positionIncrementGap;
+			offset = info.lastOffset + offsetGap;
+			terms = info.terms;
+			boost *= info.boost;
+			sliceArray = info.sliceArray;
+			sumTotalTermFreq = info.sumTotalTermFreq;
+		  }
+		  else
+		  {
+			sliceArray = new SliceByteStartArray(BytesRefHash.DEFAULT_CAPACITY);
+			terms = new BytesRefHash(byteBlockPool, BytesRefHash.DEFAULT_CAPACITY, sliceArray);
+		  }
+
+		  if (!fieldInfos.ContainsKey(fieldName))
+		  {
+			fieldInfos[fieldName] = new FieldInfo(fieldName, true, fieldInfos.Count, false, false, false, this.storeOffsets ? FieldInfo.IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS : FieldInfo.IndexOptions.DOCS_AND_FREQS_AND_POSITIONS, null, null, null);
+		  }
+		  TermToBytesRefAttribute termAtt = stream.getAttribute(typeof(TermToBytesRefAttribute));
+		  PositionIncrementAttribute posIncrAttribute = stream.addAttribute(typeof(PositionIncrementAttribute));
+		  OffsetAttribute offsetAtt = stream.addAttribute(typeof(OffsetAttribute));
+		  BytesRef @ref = termAtt.BytesRef;
+		  stream.reset();
+
+		  while (stream.incrementToken())
+		  {
+			termAtt.fillBytesRef();
+	//        if (DEBUG) System.err.println("token='" + term + "'");
+			numTokens++;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int posIncr = posIncrAttribute.getPositionIncrement();
+			int posIncr = posIncrAttribute.PositionIncrement;
+			if (posIncr == 0)
+			{
+			  numOverlapTokens++;
+			}
+			pos += posIncr;
+			int ord = terms.add(@ref);
+			if (ord < 0)
+			{
+			  ord = (-ord) - 1;
+			  postingsWriter.reset(sliceArray.end[ord]);
+			}
+			else
+			{
+			  sliceArray.start[ord] = postingsWriter.startNewSlice();
+			}
+			sliceArray.freq[ord]++;
+			sumTotalTermFreq++;
+			if (!storeOffsets)
+			{
+			  postingsWriter.writeInt(pos);
+			}
+			else
+			{
+			  postingsWriter.writeInt(pos);
+			  postingsWriter.writeInt(offsetAtt.startOffset() + offset);
+			  postingsWriter.writeInt(offsetAtt.endOffset() + offset);
+			}
+			sliceArray.end[ord] = postingsWriter.CurrentOffset;
+		  }
+		  stream.end();
+
+		  // ensure infos.numTokens > 0 invariant; needed for correct operation of terms()
+		  if (numTokens > 0)
+		  {
+			fields[fieldName] = new Info(terms, sliceArray, numTokens, numOverlapTokens, boost, pos, offsetAtt.endOffset() + offset, sumTotalTermFreq);
+			sortedFields = null; // invalidate sorted view, if any
+		  }
+		} // can never happen
+		catch (Exception e)
+		{
+		  throw new Exception(e);
+		}
+		finally
+		{
+		  try
+		  {
+			if (stream != null)
+			{
+			  stream.close();
+			}
+		  }
+		  catch (IOException e2)
+		  {
+			throw new Exception(e2);
+		  }
+		}
+	  }
+
+	  /// <summary>
+	  /// Creates and returns a searcher that can be used to execute arbitrary
+	  /// Lucene queries and to collect the resulting query results as hits.
+	  /// </summary>
+	  /// <returns> a searcher </returns>
+	  public virtual IndexSearcher createSearcher()
+	  {
+		MemoryIndexReader reader = new MemoryIndexReader(this);
+		IndexSearcher searcher = new IndexSearcher(reader); // ensures no auto-close !!
+		reader.Searcher = searcher; // to later get hold of searcher.getSimilarity()
+		return searcher;
+	  }
+
+	  /// <summary>
+	  /// Convenience method that efficiently returns the relevance score by
+	  /// matching this index against the given Lucene query expression.
+	  /// </summary>
+	  /// <param name="query">
+	  ///            an arbitrary Lucene query to run against this index </param>
+	  /// <returns> the relevance score of the matchmaking; A number in the range
+	  ///         [0.0 .. 1.0], with 0.0 indicating no match. The higher the number
+	  ///         the better the match.
+	  ///  </returns>
+	  public virtual float Search(Query query)
+	  {
+		if (query == null)
+		{
+		  throw new System.ArgumentException("query must not be null");
+		}
+
+		IndexSearcher searcher = createSearcher();
+		try
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float[] scores = new float[1];
+		  float[] scores = new float[1]; // inits to 0.0f (no match)
+		  searcher.search(query, new CollectorAnonymousInnerClassHelper(this, scores));
+		  float score = scores[0];
+		  return score;
+		} // can never happen (RAMDirectory)
+		catch (IOException e)
+		{
+		  throw new Exception(e);
+		}
+		finally
+		{
+		  // searcher.close();
+		  /*
+		   * Note that it is harmless and important for good performance to
+		   * NOT close the index reader!!! This avoids all sorts of
+		   * unnecessary baggage and locking in the Lucene IndexReader
+		   * superclass, all of which is completely unnecessary for this main
+		   * memory index data structure without thread-safety claims.
+		   * 
+		   * Wishing IndexReader would be an interface...
+		   * 
+		   * Actually with the new tight createSearcher() API auto-closing is now
+		   * made impossible, hence searcher.close() would be harmless and also 
+		   * would not degrade performance...
+		   */
+		}
+	  }
+
+	  private class CollectorAnonymousInnerClassHelper : Collector
+	  {
+		  private readonly MemoryIndex outerInstance;
+
+		  private float[] scores;
+
+		  public CollectorAnonymousInnerClassHelper(MemoryIndex outerInstance, float[] scores)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.scores = scores;
+		  }
+
+		  private Scorer scorer;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void collect(int doc) throws java.io.IOException
+		  public override void collect(int doc)
+		  {
+			scores[0] = scorer.score();
+		  }
+
+		  public override Scorer Scorer
+		  {
+			  set
+			  {
+				this.scorer = value;
+			  }
+		  }
+
+		  public override bool acceptsDocsOutOfOrder()
+		  {
+			return true;
+		  }
+
+		  public override AtomicReaderContext NextReader
+		  {
+			  set
+			  {
+			  }
+		  }
+	  }
+
+	  /// <summary>
+	  /// Returns a reasonable approximation of the main memory [bytes] consumed by
+	  /// this instance. Useful for smart memory sensititive caches/pools. </summary>
+	  /// <returns> the main memory consumption </returns>
+	  public virtual long MemorySize
+	  {
+		  get
+		  {
+			return RamUsageEstimator.sizeOf(this);
+		  }
+	  }
+
+	  /// <summary>
+	  /// sorts into ascending order (on demand), reusing memory along the way </summary>
+	  private void sortFields()
+	  {
+		if (sortedFields == null)
+		{
+			sortedFields = sort(fields);
+		}
+	  }
+
+	  /// <summary>
+	  /// returns a view of the given map's entries, sorted ascending by key </summary>
+	  private static KeyValuePair<K, V>[] sort<K, V>(Dictionary<K, V> map)
+	  {
+		int size = map.Count;
+//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
+//ORIGINAL LINE: @SuppressWarnings("unchecked") java.util.Map.Entry<K,V>[] entries = new java.util.Map.Entry[size];
+		KeyValuePair<K, V>[] entries = new DictionaryEntry[size];
+
+		IEnumerator<KeyValuePair<K, V>> iter = map.SetOfKeyValuePairs().GetEnumerator();
+		for (int i = 0; i < size; i++)
+		{
+//JAVA TO C# CONVERTER TODO TASK: Java iterators are only converted within the context of 'while' and 'for' loops:
+		  entries[i] = iter.next();
+		}
+
+		if (size > 1)
+		{
+			ArrayUtil.introSort(entries, termComparator);
+		}
+		return entries;
+	  }
+
+	  /// <summary>
+	  /// Returns a String representation of the index data for debugging purposes.
+	  /// </summary>
+	  /// <returns> the string representation </returns>
+	  public override string ToString()
+	  {
+		StringBuilder result = new StringBuilder(256);
+		sortFields();
+		int sumPositions = 0;
+		int sumTerms = 0;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.BytesRef spare = new org.apache.lucene.util.BytesRef();
+		BytesRef spare = new BytesRef();
+		for (int i = 0; i < sortedFields.Length; i++)
+		{
+		  KeyValuePair<string, Info> entry = sortedFields[i];
+		  string fieldName = entry.Key;
+		  Info info = entry.Value;
+		  info.sortTerms();
+		  result.Append(fieldName + ":\n");
+		  SliceByteStartArray sliceArray = info.sliceArray;
+		  int numPositions = 0;
+		  SliceReader postingsReader = new SliceReader(intBlockPool);
+		  for (int j = 0; j < info.terms.size(); j++)
+		  {
+			int ord = info.sortedTerms[j];
+			info.terms.get(ord, spare);
+			int freq = sliceArray.freq[ord];
+			result.Append("\t'" + spare + "':" + freq + ":");
+			postingsReader.reset(sliceArray.start[ord], sliceArray.end[ord]);
+			result.Append(" [");
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int iters = storeOffsets ? 3 : 1;
+			int iters = storeOffsets ? 3 : 1;
+			while (!postingsReader.endOfSlice())
+			{
+			  result.Append("(");
+
+			  for (int k = 0; k < iters; k++)
+			  {
+				result.Append(postingsReader.readInt());
+				if (k < iters - 1)
+				{
+				  result.Append(", ");
+				}
+			  }
+			  result.Append(")");
+			  if (!postingsReader.endOfSlice())
+			  {
+				result.Append(",");
+			  }
+
+			}
+			result.Append("]");
+			result.Append("\n");
+			numPositions += freq;
+		  }
+
+		  result.Append("\tterms=" + info.terms.size());
+		  result.Append(", positions=" + numPositions);
+		  result.Append(", memory=" + RamUsageEstimator.humanReadableUnits(RamUsageEstimator.sizeOf(info)));
+		  result.Append("\n");
+		  sumPositions += numPositions;
+		  sumTerms += info.terms.size();
+		}
+
+		result.Append("\nfields=" + sortedFields.Length);
+		result.Append(", terms=" + sumTerms);
+		result.Append(", positions=" + sumPositions);
+		result.Append(", memory=" + RamUsageEstimator.humanReadableUnits(MemorySize));
+		return result.ToString();
+	  }
+
+	  /// <summary>
+	  /// Index data structure for a field; Contains the tokenized term texts and
+	  /// their positions.
+	  /// </summary>
+	  private sealed class Info
+	  {
+
+		/// <summary>
+		/// Term strings and their positions for this field: Map <String
+		/// termText, ArrayIntList positions>
+		/// </summary>
+		internal readonly BytesRefHash terms;
+
+		internal readonly SliceByteStartArray sliceArray;
+
+		/// <summary>
+		/// Terms sorted ascending by term text; computed on demand </summary>
+		[NonSerialized]
+		internal int[] sortedTerms;
+
+		/// <summary>
+		/// Number of added tokens for this field </summary>
+		internal readonly int numTokens;
+
+		/// <summary>
+		/// Number of overlapping tokens for this field </summary>
+		internal readonly int numOverlapTokens;
+
+		/// <summary>
+		/// Boost factor for hits for this field </summary>
+		internal readonly float boost;
+
+		internal readonly long sumTotalTermFreq;
+
+		/// <summary>
+		/// the last position encountered in this field for multi field support </summary>
+		internal int lastPosition;
+
+		/// <summary>
+		/// the last offset encountered in this field for multi field support </summary>
+		internal int lastOffset;
+
+		public Info(BytesRefHash terms, SliceByteStartArray sliceArray, int numTokens, int numOverlapTokens, float boost, int lastPosition, int lastOffset, long sumTotalTermFreq)
+		{
+		  this.terms = terms;
+		  this.sliceArray = sliceArray;
+		  this.numTokens = numTokens;
+		  this.numOverlapTokens = numOverlapTokens;
+		  this.boost = boost;
+		  this.sumTotalTermFreq = sumTotalTermFreq;
+		  this.lastPosition = lastPosition;
+		  this.lastOffset = lastOffset;
+		}
+
+		public long SumTotalTermFreq
+		{
+			get
+			{
+			  return sumTotalTermFreq;
+			}
+		}
+
+		/// <summary>
+		/// Sorts hashed terms into ascending order, reusing memory along the
+		/// way. Note that sorting is lazily delayed until required (often it's
+		/// not required at all). If a sorted view is required then hashing +
+		/// sort + binary search is still faster and smaller than TreeMap usage
+		/// (which would be an alternative and somewhat more elegant approach,
+		/// apart from more sophisticated Tries / prefix trees).
+		/// </summary>
+		public void sortTerms()
+		{
+		  if (sortedTerms == null)
+		  {
+			sortedTerms = terms.sort(BytesRef.UTF8SortedAsUnicodeComparator);
+		  }
+		}
+
+		public float Boost
+		{
+			get
+			{
+			  return boost;
+			}
+		}
+	  }
+
+	  ///////////////////////////////////////////////////////////////////////////////
+	  // Nested classes:
+	  ///////////////////////////////////////////////////////////////////////////////
+
+	  /// <summary>
+	  /// Search support for Lucene framework integration; implements all methods
+	  /// required by the Lucene IndexReader contracts.
+	  /// </summary>
+	  private sealed class MemoryIndexReader : AtomicReader
+	  {
+		  private readonly MemoryIndex outerInstance;
+
+
+		internal IndexSearcher searcher; // needed to find searcher.getSimilarity()
+
+		internal MemoryIndexReader(MemoryIndex outerInstance) : base(); // avoid as much superclass baggage as possible
+		{
+			this.outerInstance = outerInstance;
+		}
+
+		internal Info getInfo(string fieldName)
+		{
+		  return outerInstance.fields[fieldName];
+		}
+
+		internal Info getInfo(int pos)
+		{
+		  return outerInstance.sortedFields[pos].Value;
+		}
+
+		public override Bits LiveDocs
+		{
+			get
+			{
+			  return null;
+			}
+		}
+
+		public override FieldInfos FieldInfos
+		{
+			get
+			{
+			  return new FieldInfos(outerInstance.fieldInfos.Values.toArray(new FieldInfo[outerInstance.fieldInfos.Count]));
+			}
+		}
+
+		public override NumericDocValues getNumericDocValues(string field)
+		{
+		  return null;
+		}
+
+		public override BinaryDocValues getBinaryDocValues(string field)
+		{
+		  return null;
+		}
+
+		public override SortedDocValues getSortedDocValues(string field)
+		{
+		  return null;
+		}
+
+		public override SortedSetDocValues getSortedSetDocValues(string field)
+		{
+		  return null;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.util.Bits getDocsWithField(String field) throws java.io.IOException
+		public override Bits getDocsWithField(string field)
+		{
+		  return null;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void checkIntegrity() throws java.io.IOException
+		public override void checkIntegrity()
+		{
+		  // no-op
+		}
+
+		private class MemoryFields : Fields
+		{
+			private readonly MemoryIndex.MemoryIndexReader outerInstance;
+
+			public MemoryFields(MemoryIndex.MemoryIndexReader outerInstance)
+			{
+				this.outerInstance = outerInstance;
+			}
+
+		  public override IEnumerator<string> iterator()
+		  {
+			return new IteratorAnonymousInnerClassHelper(this);
+		  }
+
+		  private class IteratorAnonymousInnerClassHelper : IEnumerator<string>
+		  {
+			  private readonly MemoryFields outerInstance;
+
+			  public IteratorAnonymousInnerClassHelper(MemoryFields outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+				  upto = -1;
+			  }
+
+			  internal int upto;
+
+			  public virtual string next()
+			  {
+				upto++;
+				if (upto >= outerInstance.outerInstance.outerInstance.sortedFields.Length)
+				{
+				  throw new NoSuchElementException();
+				}
+				return outerInstance.outerInstance.outerInstance.sortedFields[upto].Key;
+			  }
+
+			  public virtual bool hasNext()
+			  {
+				return upto + 1 < outerInstance.outerInstance.outerInstance.sortedFields.Length;
+			  }
+
+			  public virtual void remove()
+			  {
+				throw new System.NotSupportedException();
+			  }
+		  }
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.Terms terms(final String field)
+		  public override Terms terms(string field)
+		  {
+			int i = Arrays.binarySearch(outerInstance.outerInstance.sortedFields, field, termComparator);
+			if (i < 0)
+			{
+			  return null;
+			}
+			else
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Info info = getInfo(i);
+			  Info info = outerInstance.getInfo(i);
+			  info.sortTerms();
+
+			  return new TermsAnonymousInnerClassHelper(this, info);
+			}
+		  }
+
+		  private class TermsAnonymousInnerClassHelper : Terms
+		  {
+			  private readonly MemoryFields outerInstance;
+
+			  private MemoryIndex.Info info;
+
+			  public TermsAnonymousInnerClassHelper(MemoryFields outerInstance, MemoryIndex.Info info)
+			  {
+				  this.outerInstance = outerInstance;
+				  this.info = info;
+			  }
+
+			  public override TermsEnum iterator(TermsEnum reuse)
+			  {
+				return new MemoryTermsEnum(outerInstance.outerInstance, info);
+			  }
+
+			  public override IComparer<BytesRef> Comparator
+			  {
+				  get
+				  {
+					return BytesRef.UTF8SortedAsUnicodeComparator;
+				  }
+			  }
+
+			  public override long size()
+			  {
+				return info.terms.size();
+			  }
+
+			  public override long SumTotalTermFreq
+			  {
+				  get
+				  {
+					return info.SumTotalTermFreq;
+				  }
+			  }
+
+			  public override long SumDocFreq
+			  {
+				  get
+				  {
+					// each term has df=1
+					return info.terms.size();
+				  }
+			  }
+
+			  public override int DocCount
+			  {
+				  get
+				  {
+					return info.terms.size() > 0 ? 1 : 0;
+				  }
+			  }
+
+			  public override bool hasFreqs()
+			  {
+				return true;
+			  }
+
+			  public override bool hasOffsets()
+			  {
+				return outerInstance.outerInstance.outerInstance.storeOffsets;
+			  }
+
+			  public override bool hasPositions()
+			  {
+				return true;
+			  }
+
+			  public override bool hasPayloads()
+			  {
+				return false;
+			  }
+		  }
+
+		  public override int size()
+		  {
+			return outerInstance.outerInstance.sortedFields.Length;
+		  }
+		}
+
+		public override Fields fields()
+		{
+		  outerInstance.sortFields();
+		  return new MemoryFields(this);
+		}
+
+		private class MemoryTermsEnum : TermsEnum
+		{
+			private readonly MemoryIndex.MemoryIndexReader outerInstance;
+
+		  internal readonly Info info;
+		  internal readonly BytesRef br = new BytesRef();
+		  internal int termUpto = -1;
+
+		  public MemoryTermsEnum(MemoryIndex.MemoryIndexReader outerInstance, Info info)
+		  {
+			  this.outerInstance = outerInstance;
+			this.info = info;
+			info.sortTerms();
+		  }
+
+		  internal int binarySearch(BytesRef b, BytesRef bytesRef, int low, int high, BytesRefHash hash, int[] ords, IComparer<BytesRef> comparator)
+		  {
+			int mid = 0;
+			while (low <= high)
+			{
+			  mid = (int)((uint)(low + high) >> 1);
+			  hash.get(ords[mid], bytesRef);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int cmp = comparator.compare(bytesRef, b);
+			  int cmp = comparator.Compare(bytesRef, b);
+			  if (cmp < 0)
+			  {
+				low = mid + 1;
+			  }
+			  else if (cmp > 0)
+			  {
+				high = mid - 1;
+			  }
+			  else
+			  {
+				return mid;
+			  }
+			}
+			Debug.Assert(comparator.Compare(bytesRef, b) != 0);
+			return -(low + 1);
+		  }
+
+
+		  public override bool seekExact(BytesRef text)
+		  {
+			termUpto = binarySearch(text, br, 0, info.terms.size() - 1, info.terms, info.sortedTerms, BytesRef.UTF8SortedAsUnicodeComparator);
+			return termUpto >= 0;
+		  }
+
+		  public override SeekStatus seekCeil(BytesRef text)
+		  {
+			termUpto = binarySearch(text, br, 0, info.terms.size() - 1, info.terms, info.sortedTerms, BytesRef.UTF8SortedAsUnicodeComparator);
+			if (termUpto < 0) // not found; choose successor
+			{
+			  termUpto = -termUpto - 1;
+			  if (termUpto >= info.terms.size())
+			  {
+				return SeekStatus.END;
+			  }
+			  else
+			  {
+				info.terms.get(info.sortedTerms[termUpto], br);
+				return SeekStatus.NOT_FOUND;
+			  }
+			}
+			else
+			{
+			  return SeekStatus.FOUND;
+			}
+		  }
+
+		  public override void SeekExact(long ord)
+		  {
+			Debug.Assert(ord < info.terms.size());
+			termUpto = (int) ord;
+		  }
+
+		  public override BytesRef Next()
+		  {
+			termUpto++;
+			if (termUpto >= info.terms.size())
+			{
+			  return null;
+			}
+			else
+			{
+			  info.terms.get(info.sortedTerms[termUpto], br);
+			  return br;
+			}
+		  }
+
+		  public override BytesRef term()
+		  {
+			return br;
+		  }
+
+		  public override long ord()
+		  {
+			return termUpto;
+		  }
+
+		  public override int docFreq()
+		  {
+			return 1;
+		  }
+
+		  public override long totalTermFreq()
+		  {
+			return info.sliceArray.freq[info.sortedTerms[termUpto]];
+		  }
+
+		  public override DocsEnum docs(Bits liveDocs, DocsEnum reuse, int flags)
+		  {
+			if (reuse == null || !(reuse is MemoryDocsEnum))
+			{
+			  reuse = new MemoryDocsEnum(outerInstance);
+			}
+			return ((MemoryDocsEnum) reuse).reset(liveDocs, info.sliceArray.freq[info.sortedTerms[termUpto]]);
+		  }
+
+		  public override DocsAndPositionsEnum docsAndPositions(Bits liveDocs, DocsAndPositionsEnum reuse, int flags)
+		  {
+			if (reuse == null || !(reuse is MemoryDocsAndPositionsEnum))
+			{
+			  reuse = new MemoryDocsAndPositionsEnum(outerInstance);
+			}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int ord = info.sortedTerms[termUpto];
+			int ord = info.sortedTerms[termUpto];
+			return ((MemoryDocsAndPositionsEnum) reuse).reset(liveDocs, info.sliceArray.start[ord], info.sliceArray.end[ord], info.sliceArray.freq[ord]);
+		  }
+
+		  public override IComparer<BytesRef> Comparator
+		  {
+			  get
+			  {
+				return BytesRef.UTF8SortedAsUnicodeComparator;
+			  }
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void seekExact(org.apache.lucene.util.BytesRef term, org.apache.lucene.index.TermState state) throws java.io.IOException
+		  public override void seekExact(BytesRef term, TermState state)
+		  {
+			Debug.Assert(state != null);
+			this.seekExact(((OrdTermState)state).ord);
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.TermState termState() throws java.io.IOException
+		  public override TermState termState()
+		  {
+			OrdTermState ts = new OrdTermState();
+			ts.ord = termUpto;
+			return ts;
+		  }
+		}
+
+		private class MemoryDocsEnum : DocsEnum
+		{
+			private readonly MemoryIndex.MemoryIndexReader outerInstance;
+
+			public MemoryDocsEnum(MemoryIndex.MemoryIndexReader outerInstance)
+			{
+				this.outerInstance = outerInstance;
+			}
+
+		  internal bool hasNext;
+		  internal Bits liveDocs;
+		  internal int doc = -1;
+		  internal int freq_Renamed;
+
+		  public virtual DocsEnum reset(Bits liveDocs, int freq)
+		  {
+			this.liveDocs = liveDocs;
+			hasNext = true;
+			doc = -1;
+			this.freq_Renamed = freq;
+			return this;
+		  }
+
+		  public override int docID()
+		  {
+			return doc;
+		  }
+
+		  public override int nextDoc()
+		  {
+			if (hasNext && (liveDocs == null || liveDocs.get(0)))
+			{
+			  hasNext = false;
+			  return doc = 0;
+			}
+			else
+			{
+			  return doc = NO_MORE_DOCS;
+			}
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(int target) throws java.io.IOException
+		  public override int advance(int target)
+		  {
+			return slowAdvance(target);
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		  public override int freq()
+		  {
+			return freq_Renamed;
+		  }
+
+		  public override long cost()
+		  {
+			return 1;
+		  }
+		}
+
+		private class MemoryDocsAndPositionsEnum : DocsAndPositionsEnum
+		{
+			private readonly MemoryIndex.MemoryIndexReader outerInstance;
+
+		  internal int posUpto; // for assert
+		  internal bool hasNext;
+		  internal Bits liveDocs;
+		  internal int doc = -1;
+		  internal SliceReader sliceReader;
+		  internal int freq_Renamed;
+		  internal int startOffset_Renamed;
+		  internal int endOffset_Renamed;
+
+		  public MemoryDocsAndPositionsEnum(MemoryIndex.MemoryIndexReader outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			this.sliceReader = new SliceReader(outerInstance.outerInstance.intBlockPool);
+		  }
+
+		  public virtual DocsAndPositionsEnum reset(Bits liveDocs, int start, int end, int freq)
+		  {
+			this.liveDocs = liveDocs;
+			this.sliceReader.reset(start, end);
+			posUpto = 0; // for assert
+			hasNext = true;
+			doc = -1;
+			this.freq_Renamed = freq;
+			return this;
+		  }
+
+
+		  public override int docID()
+		  {
+			return doc;
+		  }
+
+		  public override int nextDoc()
+		  {
+			if (hasNext && (liveDocs == null || liveDocs.get(0)))
+			{
+			  hasNext = false;
+			  return doc = 0;
+			}
+			else
+			{
+			  return doc = NO_MORE_DOCS;
+			}
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(int target) throws java.io.IOException
+		  public override int advance(int target)
+		  {
+			return slowAdvance(target);
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		  public override int freq()
+		  {
+			return freq_Renamed;
+		  }
+
+		  public override int nextPosition()
+		  {
+			Debug.Assert(posUpto++ < freq_Renamed);
+			Debug.Assert(!sliceReader.endOfSlice(), " stores offsets : " + startOffset_Renamed);
+			if (outerInstance.outerInstance.storeOffsets)
+			{
+			  int pos = sliceReader.readInt();
+			  startOffset_Renamed = sliceReader.readInt();
+			  endOffset_Renamed = sliceReader.readInt();
+			  return pos;
+			}
+			else
+			{
+			  return sliceReader.readInt();
+			}
+		  }
+
+		  public override int startOffset()
+		  {
+			return startOffset_Renamed;
+		  }
+
+		  public override int endOffset()
+		  {
+			return endOffset_Renamed;
+		  }
+
+		  public override BytesRef Payload
+		  {
+			  get
+			  {
+				return null;
+			  }
+		  }
+
+		  public override long cost()
+		  {
+			return 1;
+		  }
+		}
+
+		public override Fields getTermVectors(int docID)
+		{
+		  if (docID == 0)
+		  {
+			return fields();
+		  }
+		  else
+		  {
+			return null;
+		  }
+		}
+
+		internal Similarity Similarity
+		{
+			get
+			{
+			  if (searcher != null)
+			  {
+				  return searcher.Similarity;
+			  }
+			  return IndexSearcher.DefaultSimilarity;
+			}
+		}
+
+		internal IndexSearcher Searcher
+		{
+			set
+			{
+			  this.searcher = value;
+			}
+		}
+
+		public override int numDocs()
+		{
+		  if (DEBUG)
+		  {
+			  Console.Error.WriteLine("MemoryIndexReader.numDocs");
+		  }
+		  return 1;
+		}
+
+		public override int maxDoc()
+		{
+		  if (DEBUG)
+		  {
+			  Console.Error.WriteLine("MemoryIndexReader.maxDoc");
+		  }
+		  return 1;
+		}
+
+		public override void document(int docID, StoredFieldVisitor visitor)
+		{
+		  if (DEBUG)
+		  {
+			  Console.Error.WriteLine("MemoryIndexReader.document");
+		  }
+		  // no-op: there are no stored fields
+		}
+
+		protected internal override void doClose()
+		{
+		  if (DEBUG)
+		  {
+			  Console.Error.WriteLine("MemoryIndexReader.doClose");
+		  }
+		}
+
+		/// <summary>
+		/// performance hack: cache norms to avoid repeated expensive calculations </summary>
+		internal NumericDocValues cachedNormValues;
+		internal string cachedFieldName;
+		internal Similarity cachedSimilarity;
+
+		public override NumericDocValues getNormValues(string field)
+		{
+		  FieldInfo fieldInfo = outerInstance.fieldInfos[field];
+		  if (fieldInfo == null || fieldInfo.omitsNorms())
+		  {
+			return null;
+		  }
+		  NumericDocValues norms = cachedNormValues;
+		  Similarity sim = Similarity;
+		  if (!field.Equals(cachedFieldName) || sim != cachedSimilarity) // not cached?
+		  {
+			Info info = getInfo(field);
+			int numTokens = info != null ? info.numTokens : 0;
+			int numOverlapTokens = info != null ? info.numOverlapTokens : 0;
+			float boost = info != null ? info.Boost : 1.0f;
+			FieldInvertState invertState = new FieldInvertState(field, 0, numTokens, numOverlapTokens, 0, boost);
+			long value = sim.computeNorm(invertState);
+			norms = new MemoryIndexNormDocValues(value);
+			// cache it for future reuse
+			cachedNormValues = norms;
+			cachedFieldName = field;
+			cachedSimilarity = sim;
+			if (DEBUG)
+			{
+				Console.Error.WriteLine("MemoryIndexReader.norms: " + field + ":" + value + ":" + numTokens);
+			}
+		  }
+		  return norms;
+		}
+	  }
+
+	  /// <summary>
+	  /// Resets the <seealso cref="MemoryIndex"/> to its initial state and recycles all internal buffers.
+	  /// </summary>
+	  public virtual void reset()
+	  {
+		this.fieldInfos.Clear();
+		this.fields.Clear();
+		this.sortedFields = null;
+		byteBlockPool.reset(false, false); // no need to 0-fill the buffers
+		intBlockPool.reset(true, false); // here must must 0-fill since we use slices
+	  }
+
+	  private sealed class SliceByteStartArray : BytesRefHash.DirectBytesStartArray
+	  {
+		internal int[] start; // the start offset in the IntBlockPool per term
+		internal int[] end; // the end pointer in the IntBlockPool for the postings slice per term
+		internal int[] freq; // the term frequency
+
+		public SliceByteStartArray(int initSize) : base(initSize)
+		{
+		}
+
+		public override int[] init()
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int[] ord = base.init();
+		  int[] ord = base.init();
+		  start = new int[ArrayUtil.oversize(ord.Length, RamUsageEstimator.NUM_BYTES_INT)];
+		  end = new int[ArrayUtil.oversize(ord.Length, RamUsageEstimator.NUM_BYTES_INT)];
+		  freq = new int[ArrayUtil.oversize(ord.Length, RamUsageEstimator.NUM_BYTES_INT)];
+		  Debug.Assert(start.Length >= ord.Length);
+		  Debug.Assert(end.Length >= ord.Length);
+		  Debug.Assert(freq.Length >= ord.Length);
+		  return ord;
+		}
+
+		public override int[] grow()
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int[] ord = base.grow();
+		  int[] ord = base.grow();
+		  if (start.Length < ord.Length)
+		  {
+			start = ArrayUtil.grow(start, ord.Length);
+			end = ArrayUtil.grow(end, ord.Length);
+			freq = ArrayUtil.grow(freq, ord.Length);
+		  }
+		  Debug.Assert(start.Length >= ord.Length);
+		  Debug.Assert(end.Length >= ord.Length);
+		  Debug.Assert(freq.Length >= ord.Length);
+		  return ord;
+		}
+
+		public override int[] clear()
+		{
+		 start = end = null;
+		 return base.clear();
+		}
+
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/531b4af0/src/Lucene.Net.Memory/MemoryIndexNormDocValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Memory/MemoryIndexNormDocValues.cs b/src/Lucene.Net.Memory/MemoryIndexNormDocValues.cs
new file mode 100644
index 0000000..cc051b9
--- /dev/null
+++ b/src/Lucene.Net.Memory/MemoryIndexNormDocValues.cs
@@ -0,0 +1,47 @@
+using Lucene.Net.Index;
+
+namespace Lucene.Net.Memory
+{
+    /*
+     * 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.
+     */
+
+    /// 
+    /// <summary>
+    /// @lucene.internal
+    /// </summary>
+    internal class MemoryIndexNormDocValues : NumericDocValues
+    {
+        private readonly long value;
+        public MemoryIndexNormDocValues(long value)
+        {
+            this.value = value;
+        }
+
+        public override long Get(int docID)
+        {
+            if (docID != 0)
+            {
+                throw new System.IndexOutOfRangeException();
+            }
+            else
+            {
+                return value;
+            }
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/531b4af0/src/Lucene.Net.Memory/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Memory/Properties/AssemblyInfo.cs b/src/Lucene.Net.Memory/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4b92a94
--- /dev/null
+++ b/src/Lucene.Net.Memory/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Lucene.Net.Memory")]
+[assembly: AssemblyDescription("Single-document in-memory index implementation")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Lucene.Net.Memory")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("ca052094-4c45-44d7-9dcf-3d46ae6930fe")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]


[08/11] Skeleton porting of Lucene.Net.Misc

Posted by sy...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Store/NativeUnixDirectory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Store/NativeUnixDirectory.cs b/src/Lucene.Net.Misc/Store/NativeUnixDirectory.cs
new file mode 100644
index 0000000..ad74aa1
--- /dev/null
+++ b/src/Lucene.Net.Misc/Store/NativeUnixDirectory.cs
@@ -0,0 +1,527 @@
+using System;
+using System.Diagnostics;
+
+namespace org.apache.lucene.store
+{
+
+	/*
+	 * 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.
+	 */
+
+	ignore
+	import java.nio.channels.FileChannel;
+
+	import org.apache.lucene.store.Directory; // javadoc
+	import org.apache.lucene.store.IOContext.Context;
+
+	// TODO
+	//   - newer Linux kernel versions (after 2.6.29) have
+	//     improved MADV_SEQUENTIAL (and hopefully also
+	//     FADV_SEQUENTIAL) interaction with the buffer
+	//     cache; we should explore using that instead of direct
+	//     IO when context is merge
+
+	/// <summary>
+	/// A <seealso cref="Directory"/> implementation for all Unixes that uses
+	/// DIRECT I/O to bypass OS level IO caching during
+	/// merging.  For all other cases (searching, writing) we delegate
+	/// to the provided Directory instance.
+	/// 
+	/// <para>See <a
+	/// href="{@docRoot}/overview-summary.html#NativeUnixDirectory">Overview</a>
+	/// for more details.
+	/// 
+	/// </para>
+	/// <para>To use this you must compile
+	/// NativePosixUtil.cpp (exposes Linux-specific APIs through
+	/// JNI) for your platform, by running <code>ant
+	/// build-native-unix</code>, and then putting the resulting
+	/// <code>libNativePosixUtil.so</code> (from
+	/// <code>lucene/build/native</code>) onto your dynamic
+	/// linker search path.
+	/// 
+	/// </para>
+	/// <para><b>WARNING</b>: this code is very new and quite easily
+	/// could contain horrible bugs.  For example, here's one
+	/// known issue: if you use seek in <code>IndexOutput</code>, and then
+	/// write more than one buffer's worth of bytes, then the
+	/// file will be wrong.  Lucene does not do this today (only writes
+	/// small number of bytes after seek), but that may change.
+	/// 
+	/// </para>
+	/// <para>This directory passes Solr and Lucene tests on Linux
+	/// and OS X; other Unixes should work but have not been
+	/// tested!  Use at your own risk.
+	/// 
+	/// @lucene.experimental
+	/// </para>
+	/// </summary>
+	public class NativeUnixDirectory extends FSDirectory
+	{
+
+	  // TODO: this is OS dependent, but likely 512 is the LCD
+	  private final static long ALIGN = 512;
+	  private final static long ALIGN_NOT_MASK = ~(ALIGN - 1);
+
+	  /// <summary>
+	  /// Default buffer size before writing to disk (256 KB);
+	  ///  larger means less IO load but more RAM and direct
+	  ///  buffer storage space consumed during merging. 
+	  /// </summary>
+
+	  public final static int DEFAULT_MERGE_BUFFER_SIZE = 262144;
+
+	  /// <summary>
+	  /// Default min expected merge size before direct IO is
+	  ///  used (10 MB): 
+	  /// </summary>
+	  public final static long DEFAULT_MIN_BYTES_DIRECT = 10 * 1024 * 1024;
+
+	  private final int mergeBufferSize;
+	  private final long minBytesDirect;
+	  private final Directory @delegate;
+
+	  /// <summary>
+	  /// Create a new NIOFSDirectory for the named location.
+	  /// </summary>
+	  /// <param name="path"> the path of the directory </param>
+	  /// <param name="mergeBufferSize"> Size of buffer to use for
+	  ///    merging.  See <seealso cref="#DEFAULT_MERGE_BUFFER_SIZE"/>. </param>
+	  /// <param name="minBytesDirect"> Merges, or files to be opened for
+	  ///   reading, smaller than this will
+	  ///   not use direct IO.  See {@link
+	  ///   #DEFAULT_MIN_BYTES_DIRECT} </param>
+	  /// <param name="delegate"> fallback Directory for non-merges </param>
+	  /// <exception cref="IOException"> If there is a low-level I/O error </exception>
+	  public NativeUnixDirectory(File path, int mergeBufferSize, long minBytesDirect, Directory @delegate) throws IOException
+	  {
+		base(path, @delegate.LockFactory);
+		if ((mergeBufferSize & ALIGN) != 0)
+		{
+		  throw new System.ArgumentException("mergeBufferSize must be 0 mod " + ALIGN + " (got: " + mergeBufferSize + ")");
+		}
+		this.mergeBufferSize = mergeBufferSize;
+		this.minBytesDirect = minBytesDirect;
+		this.@delegate = @delegate;
+	  }
+
+	  /// <summary>
+	  /// Create a new NIOFSDirectory for the named location.
+	  /// </summary>
+	  /// <param name="path"> the path of the directory </param>
+	  /// <param name="delegate"> fallback Directory for non-merges </param>
+	  /// <exception cref="IOException"> If there is a low-level I/O error </exception>
+	  public NativeUnixDirectory(File path, Directory @delegate) throws IOException
+	  {
+		this(path, DEFAULT_MERGE_BUFFER_SIZE, DEFAULT_MIN_BYTES_DIRECT, @delegate);
+	  }
+
+	  public IndexInput openInput(string name, IOContext context) throws IOException
+	  {
+		ensureOpen();
+		if (context.context != Context.MERGE || context.mergeInfo.estimatedMergeBytes < minBytesDirect || fileLength(name) < minBytesDirect)
+		{
+		  return @delegate.openInput(name, context);
+		}
+		else
+		{
+		  return new NativeUnixIndexInput(new File(Directory, name), mergeBufferSize);
+		}
+	  }
+
+	  public IndexOutput createOutput(string name, IOContext context) throws IOException
+	  {
+		ensureOpen();
+		if (context.context != Context.MERGE || context.mergeInfo.estimatedMergeBytes < minBytesDirect)
+		{
+		  return @delegate.createOutput(name, context);
+		}
+		else
+		{
+		  ensureCanWrite(name);
+		  return new NativeUnixIndexOutput(new File(Directory, name), mergeBufferSize);
+		}
+	  }
+
+	  private final static class NativeUnixIndexOutput extends IndexOutput
+	  {
+		private final ByteBuffer buffer;
+		private final FileOutputStream fos;
+		private final FileChannel channel;
+		private final int bufferSize;
+
+		//private final File path;
+
+		private int bufferPos;
+		private long filePos;
+		private long fileLength;
+		private bool isOpen;
+
+		public NativeUnixIndexOutput(File path, int bufferSize) throws IOException
+		{
+		  //this.path = path;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.io.FileDescriptor fd = NativePosixUtil.open_direct(path.toString(), false);
+		  FileDescriptor fd = NativePosixUtil.open_direct(path.ToString(), false);
+		  fos = new FileOutputStream(fd);
+		  //fos = new FileOutputStream(path);
+		  channel = fos.Channel;
+		  buffer = ByteBuffer.allocateDirect(bufferSize);
+		  this.bufferSize = bufferSize;
+		  isOpen = true;
+		}
+
+		public void writeByte(sbyte b) throws IOException
+		{
+		  Debug.Assert(bufferPos == buffer.position(), "bufferPos=" + bufferPos + " vs buffer.position()=" + buffer.position());
+		  buffer.put(b);
+		  if (++bufferPos == bufferSize)
+		  {
+			dump();
+		  }
+		}
+
+		public void writeBytes(sbyte[] src, int offset, int len) throws IOException
+		{
+		  int toWrite = len;
+		  while (true)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int left = bufferSize - bufferPos;
+			int left = bufferSize - bufferPos;
+			if (left <= toWrite)
+			{
+			  buffer.put(src, offset, left);
+			  toWrite -= left;
+			  offset += left;
+			  bufferPos = bufferSize;
+			  dump();
+			}
+			else
+			{
+			  buffer.put(src, offset, toWrite);
+			  bufferPos += toWrite;
+			  break;
+			}
+		  }
+		}
+
+		//@Override
+		//public void setLength() throws IOException {
+		//   TODO -- how to impl this?  neither FOS nor
+		//   FileChannel provides an API?
+		//}
+
+		public void flush()
+		{
+		  // TODO -- I don't think this method is necessary?
+		}
+
+		private void dump() throws IOException
+		{
+		  buffer.flip();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long limit = filePos + buffer.limit();
+		  long limit = filePos + buffer.limit();
+		  if (limit > fileLength)
+		  {
+			// this dump extends the file
+			fileLength = limit;
+		  }
+		  else
+		  {
+			// we had seek'd back & wrote some changes
+		  }
+
+		  // must always round to next block
+		  buffer.limit((int)((buffer.limit() + ALIGN - 1) & ALIGN_NOT_MASK));
+
+		  assert(buffer.limit() & ALIGN_NOT_MASK) == buffer.limit() : "limit=" + buffer.limit() + " vs " + (buffer.limit() & ALIGN_NOT_MASK);
+		  assert(filePos & ALIGN_NOT_MASK) == filePos;
+		  //System.out.println(Thread.currentThread().getName() + ": dump to " + filePos + " limit=" + buffer.limit() + " fos=" + fos);
+		  channel.write(buffer, filePos);
+		  filePos += bufferPos;
+		  bufferPos = 0;
+		  buffer.clear();
+		  //System.out.println("dump: done");
+
+		  // TODO: the case where we'd seek'd back, wrote an
+		  // entire buffer, we must here read the next buffer;
+		  // likely Lucene won't trip on this since we only
+		  // write smallish amounts on seeking back
+		}
+
+		public long FilePointer
+		{
+		  return filePos + bufferPos;
+		}
+
+		// TODO: seek is fragile at best; it can only properly
+		// handle seek & then change bytes that fit entirely
+		// within one buffer
+		public void seek(long pos) throws IOException
+		{
+		  if (pos != FilePointer)
+		  {
+			dump();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long alignedPos = pos & ALIGN_NOT_MASK;
+			long alignedPos = pos & ALIGN_NOT_MASK;
+			filePos = alignedPos;
+			int n = (int) NativePosixUtil.pread(fos.FD, filePos, buffer);
+			if (n < bufferSize)
+			{
+			  buffer.limit(n);
+			}
+			//System.out.println("seek refill=" + n);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int delta = (int)(pos - alignedPos);
+			int delta = (int)(pos - alignedPos);
+			buffer.position(delta);
+			bufferPos = delta;
+		  }
+		}
+
+		public long length()
+		{
+		  return fileLength + bufferPos;
+		}
+
+		public long Checksum throws IOException
+		{
+		  throw new System.NotSupportedException("this directory currently does not work at all!");
+		}
+
+		public void close() throws IOException
+		{
+		  if (isOpen)
+		  {
+			isOpen = false;
+			try
+			{
+			  dump();
+			}
+			finally
+			{
+			  try
+			  {
+				//System.out.println("direct close set len=" + fileLength + " vs " + channel.size() + " path=" + path);
+				channel.truncate(fileLength);
+				//System.out.println("  now: " + channel.size());
+			  }
+			  finally
+			  {
+				try
+				{
+				  channel.close();
+				}
+				finally
+				{
+				  fos.close();
+				  //System.out.println("  final len=" + path.length());
+				}
+			  }
+			}
+		  }
+		}
+	  }
+
+	  private final static class NativeUnixIndexInput extends IndexInput
+	  {
+		private final ByteBuffer buffer;
+		private final FileInputStream fis;
+		private final FileChannel channel;
+		private final int bufferSize;
+
+		private bool isOpen;
+		private bool isClone;
+		private long filePos;
+		private int bufferPos;
+
+		public NativeUnixIndexInput(File path, int bufferSize) throws IOException
+		{
+		  base("NativeUnixIndexInput(path=\"" + path.Path + "\")");
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.io.FileDescriptor fd = NativePosixUtil.open_direct(path.toString(), true);
+		  FileDescriptor fd = NativePosixUtil.open_direct(path.ToString(), true);
+		  fis = new FileInputStream(fd);
+		  channel = fis.Channel;
+		  this.bufferSize = bufferSize;
+		  buffer = ByteBuffer.allocateDirect(bufferSize);
+		  isOpen = true;
+		  isClone = false;
+		  filePos = -bufferSize;
+		  bufferPos = bufferSize;
+		  //System.out.println("D open " + path + " this=" + this);
+		}
+
+		// for clone
+		public NativeUnixIndexInput(NativeUnixIndexInput other) throws IOException
+		{
+		  base(other.ToString());
+		  this.fis = null;
+		  channel = other.channel;
+		  this.bufferSize = other.bufferSize;
+		  buffer = ByteBuffer.allocateDirect(bufferSize);
+		  filePos = -bufferSize;
+		  bufferPos = bufferSize;
+		  isOpen = true;
+		  isClone = true;
+		  //System.out.println("D clone this=" + this);
+		  seek(other.FilePointer);
+		}
+
+		public void close() throws IOException
+		{
+		  if (isOpen && !isClone)
+		  {
+			try
+			{
+			  channel.close();
+			}
+			finally
+			{
+			  if (!isClone)
+			  {
+				fis.close();
+			  }
+			}
+		  }
+		}
+
+		public long FilePointer
+		{
+		  return filePos + bufferPos;
+		}
+
+		public void seek(long pos) throws IOException
+		{
+		  if (pos != FilePointer)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long alignedPos = pos & ALIGN_NOT_MASK;
+			long alignedPos = pos & ALIGN_NOT_MASK;
+			filePos = alignedPos - bufferSize;
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int delta = (int)(pos - alignedPos);
+			int delta = (int)(pos - alignedPos);
+			if (delta != 0)
+			{
+			  refill();
+			  buffer.position(delta);
+			  bufferPos = delta;
+			}
+			else
+			{
+			  // force refill on next read
+			  bufferPos = bufferSize;
+			}
+		  }
+		}
+
+		public long length()
+		{
+		  try
+		  {
+			return channel.size();
+		  }
+		  catch (IOException ioe)
+		  {
+			throw new Exception("IOException during length(): " + this, ioe);
+		  }
+		}
+
+		public sbyte readByte() throws IOException
+		{
+		  // NOTE: we don't guard against EOF here... ie the
+		  // "final" buffer will typically be filled to less
+		  // than bufferSize
+		  if (bufferPos == bufferSize)
+		  {
+			refill();
+		  }
+		  Debug.Assert(bufferPos == buffer.position(), "bufferPos=" + bufferPos + " vs buffer.position()=" + buffer.position());
+		  bufferPos++;
+		  return buffer.get();
+		}
+
+		private void refill() throws IOException
+		{
+		  buffer.clear();
+		  filePos += bufferSize;
+		  bufferPos = 0;
+		  assert(filePos & ALIGN_NOT_MASK) == filePos : "filePos=" + filePos + " anded=" + (filePos & ALIGN_NOT_MASK);
+		  //System.out.println("X refill filePos=" + filePos);
+		  int n;
+		  try
+		  {
+			n = channel.read(buffer, filePos);
+		  }
+		  catch (IOException ioe)
+		  {
+			throw new IOException(ioe.Message + ": " + this, ioe);
+		  }
+		  if (n < 0)
+		  {
+			throw new EOFException("read past EOF: " + this);
+		  }
+		  buffer.rewind();
+		}
+
+		public void readBytes(sbyte[] dst, int offset, int len) throws IOException
+		{
+		  int toRead = len;
+		  //System.out.println("\nX readBytes len=" + len + " fp=" + getFilePointer() + " size=" + length() + " this=" + this);
+		  while (true)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int left = bufferSize - bufferPos;
+			int left = bufferSize - bufferPos;
+			if (left < toRead)
+			{
+			  //System.out.println("  copy " + left);
+			  buffer.get(dst, offset, left);
+			  toRead -= left;
+			  offset += left;
+			  refill();
+			}
+			else
+			{
+			  //System.out.println("  copy " + toRead);
+			  buffer.get(dst, offset, toRead);
+			  bufferPos += toRead;
+			  //System.out.println("  readBytes done");
+			  break;
+			}
+		  }
+		}
+
+		public NativeUnixIndexInput MemberwiseClone()
+		{
+		  try
+		  {
+			return new NativeUnixIndexInput(this);
+		  }
+		  catch (IOException ioe)
+		  {
+			throw new Exception("IOException during clone: " + this, ioe);
+		  }
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Store/WindowsDirectory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Store/WindowsDirectory.cs b/src/Lucene.Net.Misc/Store/WindowsDirectory.cs
new file mode 100644
index 0000000..324a0dd
--- /dev/null
+++ b/src/Lucene.Net.Misc/Store/WindowsDirectory.cs
@@ -0,0 +1,181 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace org.apache.lucene.store
+{
+
+	/*
+	 * 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.
+	 */
+
+
+
+	/// <summary>
+	/// Native <seealso cref="Directory"/> implementation for Microsoft Windows.
+	/// <para>
+	/// Steps:
+	/// <ol> 
+	///   <li>Compile the source code to create WindowsDirectory.dll:
+	///       <blockquote>
+	/// c:\mingw\bin\g++ -Wall -D_JNI_IMPLEMENTATION_ -Wl,--kill-at 
+	/// -I"%JAVA_HOME%\include" -I"%JAVA_HOME%\include\win32" -static-libgcc 
+	/// -static-libstdc++ -shared WindowsDirectory.cpp -o WindowsDirectory.dll
+	///       </blockquote> 
+	///       For 64-bit JREs, use mingw64, with the -m64 option. 
+	///   <li>Put WindowsDirectory.dll into some directory in your windows PATH
+	///   <li>Open indexes with WindowsDirectory and use it.
+	/// </ol>
+	/// </para>
+	/// @lucene.experimental
+	/// </summary>
+	public class WindowsDirectory : FSDirectory
+	{
+	  private const int DEFAULT_BUFFERSIZE = 4096; // default pgsize on ia32/amd64
+
+	  static WindowsDirectory()
+	  {
+//JAVA TO C# CONVERTER TODO TASK: The library is specified in the 'DllImport' attribute for .NET:
+//		System.loadLibrary("WindowsDirectory");
+	  }
+
+	  /// <summary>
+	  /// Create a new WindowsDirectory for the named location.
+	  /// </summary>
+	  /// <param name="path"> the path of the directory </param>
+	  /// <param name="lockFactory"> the lock factory to use, or null for the default
+	  /// (<seealso cref="NativeFSLockFactory"/>); </param>
+	  /// <exception cref="IOException"> If there is a low-level I/O error </exception>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public WindowsDirectory(java.io.File path, LockFactory lockFactory) throws java.io.IOException
+	  public WindowsDirectory(File path, LockFactory lockFactory) : base(path, lockFactory)
+	  {
+	  }
+
+	  /// <summary>
+	  /// Create a new WindowsDirectory for the named location and <seealso cref="NativeFSLockFactory"/>.
+	  /// </summary>
+	  /// <param name="path"> the path of the directory </param>
+	  /// <exception cref="IOException"> If there is a low-level I/O error </exception>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public WindowsDirectory(java.io.File path) throws java.io.IOException
+	  public WindowsDirectory(File path) : base(path, null)
+	  {
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public IndexInput openInput(String name, IOContext context) throws java.io.IOException
+	  public override IndexInput openInput(string name, IOContext context)
+	  {
+		ensureOpen();
+		return new WindowsIndexInput(new File(Directory, name), Math.Max(BufferedIndexInput.bufferSize(context), DEFAULT_BUFFERSIZE));
+	  }
+
+	  internal class WindowsIndexInput : BufferedIndexInput
+	  {
+		internal readonly long fd;
+		internal readonly long length_Renamed;
+		internal bool isClone;
+		internal bool isOpen;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public WindowsIndexInput(java.io.File file, int bufferSize) throws java.io.IOException
+		public WindowsIndexInput(File file, int bufferSize) : base("WindowsIndexInput(path=\"" + file.Path + "\")", bufferSize)
+		{
+		  fd = WindowsDirectory.open(file.Path);
+		  length_Renamed = WindowsDirectory.length(fd);
+		  isOpen = true;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override protected void readInternal(byte[] b, int offset, int length) throws java.io.IOException
+		protected internal override void readInternal(sbyte[] b, int offset, int length)
+		{
+		  int bytesRead;
+		  try
+		  {
+			bytesRead = WindowsDirectory.read(fd, b, offset, length, FilePointer);
+		  }
+		  catch (IOException ioe)
+		  {
+			throw new IOException(ioe.Message + ": " + this, ioe);
+		  }
+
+		  if (bytesRead != length)
+		  {
+			throw new EOFException("read past EOF: " + this);
+		  }
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override protected void seekInternal(long pos) throws java.io.IOException
+		protected internal override void seekInternal(long pos)
+		{
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public synchronized void close() throws java.io.IOException
+		public override void close()
+		{
+			lock (this)
+			{
+			  // NOTE: we synchronize and track "isOpen" because Lucene sometimes closes IIs twice!
+			  if (!isClone && isOpen)
+			  {
+				WindowsDirectory.close(fd);
+				isOpen = false;
+			  }
+			}
+		}
+
+		public override long length()
+		{
+		  return length_Renamed;
+		}
+
+		public override WindowsIndexInput clone()
+		{
+		  WindowsIndexInput clone = (WindowsIndexInput)base.clone();
+		  clone.isClone = true;
+		  return clone;
+		}
+	  }
+
+	  /// <summary>
+	  /// Opens a handle to a file. </summary>
+//JAVA TO C# CONVERTER TODO TASK: Replace 'unknown' with the appropriate dll name:
+	  [DllImport("unknown")]
+	  private static extern long open(string filename);
+
+	  /// <summary>
+	  /// Reads data from a file at pos into bytes </summary>
+//JAVA TO C# CONVERTER TODO TASK: Replace 'unknown' with the appropriate dll name:
+	  [DllImport("unknown")]
+	  private static extern int read(long fd, sbyte[] bytes, int offset, int length, long pos);
+
+	  /// <summary>
+	  /// Closes a handle to a file </summary>
+//JAVA TO C# CONVERTER TODO TASK: Replace 'unknown' with the appropriate dll name:
+	  [DllImport("unknown")]
+	  private static extern void close(long fd);
+
+	  /// <summary>
+	  /// Returns the length of a file </summary>
+//JAVA TO C# CONVERTER TODO TASK: Replace 'unknown' with the appropriate dll name:
+	  [DllImport("unknown")]
+	  private static extern long length(long fd);
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Util/Fst/ListOfOutputs.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Util/Fst/ListOfOutputs.cs b/src/Lucene.Net.Misc/Util/Fst/ListOfOutputs.cs
new file mode 100644
index 0000000..e4660a6
--- /dev/null
+++ b/src/Lucene.Net.Misc/Util/Fst/ListOfOutputs.cs
@@ -0,0 +1,246 @@
+using System.Diagnostics;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.lucene.util.fst
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using DataInput = org.apache.lucene.store.DataInput;
+	using DataOutput = org.apache.lucene.store.DataOutput;
+
+	/// <summary>
+	/// Wraps another Outputs implementation and encodes one or
+	/// more of its output values.  You can use this when a single
+	/// input may need to map to more than one output,
+	/// maintaining order: pass the same input with a different
+	/// output by calling <seealso cref="Builder#add(IntsRef,Object)"/> multiple
+	/// times.  The builder will then combine the outputs using
+	/// the <seealso cref="Outputs#merge(Object,Object)"/> method.
+	/// 
+	/// <para>The resulting FST may not be minimal when an input has
+	/// more than one output, as this requires pushing all
+	/// multi-output values to a final state.
+	/// 
+	/// </para>
+	/// <para>NOTE: the only way to create multiple outputs is to
+	/// add the same input to the FST multiple times in a row.  This is
+	/// how the FST maps a single input to multiple outputs (e.g. you
+	/// cannot pass a List&lt;Object&gt; to <seealso cref="Builder#add"/>).  If
+	/// your outputs are longs, and you need at most 2, then use
+	/// <seealso cref="UpToTwoPositiveIntOutputs"/> instead since it stores
+	/// the outputs more compactly (by stealing a bit from each
+	/// long value).
+	/// 
+	/// </para>
+	/// <para>NOTE: this cannot wrap itself (ie you cannot make an
+	/// FST with List&lt;List&lt;Object&gt;&gt; outputs using this).
+	/// 
+	/// @lucene.experimental
+	/// </para>
+	/// </summary>
+
+
+	// NOTE: i think we could get a more compact FST if, instead
+	// of adding the same input multiple times with a different
+	// output each time, we added it only once with a
+	// pre-constructed List<T> output.  This way the "multiple
+	// values" is fully opaque to the Builder/FST.  It would
+	// require implementing the full algebra using set
+	// arithmetic (I think?); maybe SetOfOutputs is a good name.
+
+//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
+//ORIGINAL LINE: @SuppressWarnings("unchecked") public final class ListOfOutputs<T> extends Outputs<Object>
+	public sealed class ListOfOutputs<T> : Outputs<object>
+	{
+
+	  private readonly Outputs<T> outputs;
+
+	  public ListOfOutputs(Outputs<T> outputs)
+	  {
+		this.outputs = outputs;
+	  }
+
+	  public override object common(object output1, object output2)
+	  {
+		// These will never be a list:
+		return outputs.common((T) output1, (T) output2);
+	  }
+
+	  public override object subtract(object @object, object inc)
+	  {
+		// These will never be a list:
+		return outputs.subtract((T) @object, (T) inc);
+	  }
+
+	  public override object add(object prefix, object output)
+	  {
+		Debug.Assert(!(prefix is IList));
+		if (!(output is IList))
+		{
+		  return outputs.add((T) prefix, (T) output);
+		}
+		else
+		{
+		  IList<T> outputList = (IList<T>) output;
+		  IList<T> addedList = new List<T>(outputList.Count);
+		  foreach (T _output in outputList)
+		  {
+			addedList.Add(outputs.add((T) prefix, _output));
+		  }
+		  return addedList;
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void write(Object output, org.apache.lucene.store.DataOutput out) throws java.io.IOException
+	  public override void write(object output, DataOutput @out)
+	  {
+		Debug.Assert(!(output is IList));
+		outputs.write((T) output, @out);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void writeFinalOutput(Object output, org.apache.lucene.store.DataOutput out) throws java.io.IOException
+	  public override void writeFinalOutput(object output, DataOutput @out)
+	  {
+		if (!(output is IList))
+		{
+		  @out.writeVInt(1);
+		  outputs.write((T) output, @out);
+		}
+		else
+		{
+		  IList<T> outputList = (IList<T>) output;
+		  @out.writeVInt(outputList.Count);
+		  foreach (T eachOutput in outputList)
+		  {
+			outputs.write(eachOutput, @out);
+		  }
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Object read(org.apache.lucene.store.DataInput in) throws java.io.IOException
+	  public override object read(DataInput @in)
+	  {
+		return outputs.read(@in);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Object readFinalOutput(org.apache.lucene.store.DataInput in) throws java.io.IOException
+	  public override object readFinalOutput(DataInput @in)
+	  {
+		int count = @in.readVInt();
+		if (count == 1)
+		{
+		  return outputs.read(@in);
+		}
+		else
+		{
+		  IList<T> outputList = new List<T>(count);
+		  for (int i = 0;i < count;i++)
+		  {
+			outputList.Add(outputs.read(@in));
+		  }
+		  return outputList;
+		}
+	  }
+
+	  public override object NoOutput
+	  {
+		  get
+		  {
+			return outputs.NoOutput;
+		  }
+	  }
+
+	  public override string outputToString(object output)
+	  {
+		if (!(output is IList))
+		{
+		  return outputs.outputToString((T) output);
+		}
+		else
+		{
+		  IList<T> outputList = (IList<T>) output;
+
+		  StringBuilder b = new StringBuilder();
+		  b.Append('[');
+
+		  for (int i = 0;i < outputList.Count;i++)
+		  {
+			if (i > 0)
+			{
+			  b.Append(", ");
+			}
+			b.Append(outputs.outputToString(outputList[i]));
+		  }
+		  b.Append(']');
+		  return b.ToString();
+		}
+	  }
+
+	  public override object merge(object first, object second)
+	  {
+		IList<T> outputList = new List<T>();
+		if (!(first is IList))
+		{
+		  outputList.Add((T) first);
+		}
+		else
+		{
+		  outputList.AddRange((IList<T>) first);
+		}
+		if (!(second is IList))
+		{
+		  outputList.Add((T) second);
+		}
+		else
+		{
+		  outputList.AddRange((IList<T>) second);
+		}
+		//System.out.println("MERGE: now " + outputList.size() + " first=" + outputToString(first) + " second=" + outputToString(second));
+		//System.out.println("  return " + outputToString(outputList));
+		return outputList;
+	  }
+
+	  public override string ToString()
+	  {
+		return "OneOrMoreOutputs(" + outputs + ")";
+	  }
+
+	  public IList<T> asList(object output)
+	  {
+		if (!(output is IList))
+		{
+		  IList<T> result = new List<T>(1);
+		  result.Add((T) output);
+		  return result;
+		}
+		else
+		{
+		  return (IList<T>) output;
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Util/Fst/UpToTwoPositiveIntOutputs.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Util/Fst/UpToTwoPositiveIntOutputs.cs b/src/Lucene.Net.Misc/Util/Fst/UpToTwoPositiveIntOutputs.cs
new file mode 100644
index 0000000..8302127
--- /dev/null
+++ b/src/Lucene.Net.Misc/Util/Fst/UpToTwoPositiveIntOutputs.cs
@@ -0,0 +1,328 @@
+using System;
+using System.Diagnostics;
+
+namespace org.apache.lucene.util.fst
+{
+
+	/*
+	 * 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.
+	 */
+
+	using DataInput = org.apache.lucene.store.DataInput;
+	using DataOutput = org.apache.lucene.store.DataOutput;
+
+	/// <summary>
+	/// An FST <seealso cref="Outputs"/> implementation where each output
+	/// is one or two non-negative long values.  If it's a
+	/// single output, Long is returned; else, TwoLongs.  Order
+	/// is preserved in the TwoLongs case, ie .first is the first
+	/// input/output added to Builder, and .second is the
+	/// second.  You cannot store 0 output with this (that's
+	/// reserved to mean "no output")!
+	/// 
+	/// <para>NOTE: the only way to create a TwoLongs output is to
+	/// add the same input to the FST twice in a row.  This is
+	/// how the FST maps a single input to two outputs (e.g. you
+	/// cannot pass a TwoLongs to <seealso cref="Builder#add"/>.  If you
+	/// need more than two then use <seealso cref="ListOfOutputs"/>, but if
+	/// you only have at most 2 then this implementation will
+	/// require fewer bytes as it steals one bit from each long
+	/// value.
+	/// 
+	/// </para>
+	/// <para>NOTE: the resulting FST is not guaranteed to be minimal!
+	/// See <seealso cref="Builder"/>.
+	/// 
+	/// @lucene.experimental
+	/// </para>
+	/// </summary>
+
+	public sealed class UpToTwoPositiveIntOutputs : Outputs<object>
+	{
+
+	  /// <summary>
+	  /// Holds two long outputs. </summary>
+	  public sealed class TwoLongs
+	  {
+		public readonly long first;
+		public readonly long second;
+
+		public TwoLongs(long first, long second)
+		{
+		  this.first = first;
+		  this.second = second;
+		  Debug.Assert(first >= 0);
+		  Debug.Assert(second >= 0);
+		}
+
+		public override string ToString()
+		{
+		  return "TwoLongs:" + first + "," + second;
+		}
+
+		public override bool Equals(object _other)
+		{
+		  if (_other is TwoLongs)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final TwoLongs other = (TwoLongs) _other;
+			TwoLongs other = (TwoLongs) _other;
+			return first == other.first && second == other.second;
+		  }
+		  else
+		  {
+			return false;
+		  }
+		}
+
+		public override int GetHashCode()
+		{
+		  return (int)((first ^ ((long)((ulong)first >> 32))) ^ (second ^ (second >> 32)));
+		}
+	  }
+
+	  private static readonly long? NO_OUTPUT = new long?(0);
+
+	  private readonly bool doShare;
+
+	  private static readonly UpToTwoPositiveIntOutputs singletonShare = new UpToTwoPositiveIntOutputs(true);
+	  private static readonly UpToTwoPositiveIntOutputs singletonNoShare = new UpToTwoPositiveIntOutputs(false);
+
+	  private UpToTwoPositiveIntOutputs(bool doShare)
+	  {
+		this.doShare = doShare;
+	  }
+
+	  public static UpToTwoPositiveIntOutputs getSingleton(bool doShare)
+	  {
+		return doShare ? singletonShare : singletonNoShare;
+	  }
+
+	  public long? get(long v)
+	  {
+		if (v == 0)
+		{
+		  return NO_OUTPUT;
+		}
+		else
+		{
+		  return Convert.ToInt64(v);
+		}
+	  }
+
+	  public TwoLongs get(long first, long second)
+	  {
+		return new TwoLongs(first, second);
+	  }
+
+	  public override long? common(object _output1, object _output2)
+	  {
+		Debug.Assert(valid(_output1, false));
+		Debug.Assert(valid(_output2, false));
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Long output1 = (Long) _output1;
+		long? output1 = (long?) _output1;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Long output2 = (Long) _output2;
+		long? output2 = (long?) _output2;
+		if (output1 == NO_OUTPUT || output2 == NO_OUTPUT)
+		{
+		  return NO_OUTPUT;
+		}
+		else if (doShare)
+		{
+		  Debug.Assert(output1 > 0);
+		  Debug.Assert(output2 > 0);
+		  return Math.Min(output1, output2);
+		}
+		else if (output1.Equals(output2))
+		{
+		  return output1;
+		}
+		else
+		{
+		  return NO_OUTPUT;
+		}
+	  }
+
+	  public override long? subtract(object _output, object _inc)
+	  {
+		Debug.Assert(valid(_output, false));
+		Debug.Assert(valid(_inc, false));
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Long output = (Long) _output;
+		long? output = (long?) _output;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Long inc = (Long) _inc;
+		long? inc = (long?) _inc;
+		Debug.Assert(output >= inc);
+
+		if (inc == NO_OUTPUT)
+		{
+		  return output;
+		}
+		else if (output.Equals(inc))
+		{
+		  return NO_OUTPUT;
+		}
+		else
+		{
+		  return output - inc;
+		}
+	  }
+
+	  public override object add(object _prefix, object _output)
+	  {
+		Debug.Assert(valid(_prefix, false));
+		Debug.Assert(valid(_output, true));
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Long prefix = (Long) _prefix;
+		long? prefix = (long?) _prefix;
+		if (_output is long?)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Long output = (Long) _output;
+		  long? output = (long?) _output;
+		  if (prefix == NO_OUTPUT)
+		  {
+			return output;
+		  }
+		  else if (output == NO_OUTPUT)
+		  {
+			return prefix;
+		  }
+		  else
+		  {
+			return prefix + output;
+		  }
+		}
+		else
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final TwoLongs output = (TwoLongs) _output;
+		  TwoLongs output = (TwoLongs) _output;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long v = prefix;
+		  long v = prefix.Value;
+		  return new TwoLongs(output.first + v, output.second + v);
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void write(Object _output, org.apache.lucene.store.DataOutput out) throws java.io.IOException
+	  public override void write(object _output, DataOutput @out)
+	  {
+		Debug.Assert(valid(_output, true));
+		if (_output is long?)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Long output = (Long) _output;
+		  long? output = (long?) _output;
+		  @out.writeVLong(output << 1);
+		}
+		else
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final TwoLongs output = (TwoLongs) _output;
+		  TwoLongs output = (TwoLongs) _output;
+		  @out.writeVLong((output.first << 1) | 1);
+		  @out.writeVLong(output.second);
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Object read(org.apache.lucene.store.DataInput in) throws java.io.IOException
+	  public override object read(DataInput @in)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long code = in.readVLong();
+		long code = @in.readVLong();
+		if ((code & 1) == 0)
+		{
+		  // single long
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long v = code >>> 1;
+		  long v = (long)((ulong)code >> 1);
+		  if (v == 0)
+		  {
+			return NO_OUTPUT;
+		  }
+		  else
+		  {
+			return Convert.ToInt64(v);
+		  }
+		}
+		else
+		{
+		  // two longs
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long first = code >>> 1;
+		  long first = (long)((ulong)code >> 1);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long second = in.readVLong();
+		  long second = @in.readVLong();
+		  return new TwoLongs(first, second);
+		}
+	  }
+
+	  private bool valid(long? o)
+	  {
+		Debug.Assert(o != null);
+		Debug.Assert(o is long?);
+		Debug.Assert(o == NO_OUTPUT || o > 0);
+		return true;
+	  }
+
+	  // Used only by assert
+	  private bool valid(object _o, bool allowDouble)
+	  {
+		if (!allowDouble)
+		{
+		  Debug.Assert(_o is long?);
+		  return valid((long?) _o);
+		}
+		else if (_o is TwoLongs)
+		{
+		  return true;
+		}
+		else
+		{
+		  return valid((long?) _o);
+		}
+	  }
+
+	  public override object NoOutput
+	  {
+		  get
+		  {
+			return NO_OUTPUT;
+		  }
+	  }
+
+	  public override string outputToString(object output)
+	  {
+		return output.ToString();
+	  }
+
+	  public override object merge(object first, object second)
+	  {
+		Debug.Assert(valid(first, false));
+		Debug.Assert(valid(second, false));
+		return new TwoLongs((long?) first, (long?) second);
+	  }
+	}
+
+}
\ No newline at end of file


[09/11] Skeleton porting of Lucene.Net.Misc

Posted by sy...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/Sorter/SortingAtomicReader.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/Sorter/SortingAtomicReader.cs b/src/Lucene.Net.Misc/Index/Sorter/SortingAtomicReader.cs
new file mode 100644
index 0000000..eb87148
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/Sorter/SortingAtomicReader.cs
@@ -0,0 +1,1081 @@
+using System;
+using System.Diagnostics;
+
+namespace org.apache.lucene.index.sorter
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using IndexOptions = org.apache.lucene.index.FieldInfo.IndexOptions;
+	using DocIdSetIterator = org.apache.lucene.search.DocIdSetIterator;
+	using Sort = org.apache.lucene.search.Sort;
+	using IndexInput = org.apache.lucene.store.IndexInput;
+	using IndexOutput = org.apache.lucene.store.IndexOutput;
+	using RAMFile = org.apache.lucene.store.RAMFile;
+	using RAMInputStream = org.apache.lucene.store.RAMInputStream;
+	using RAMOutputStream = org.apache.lucene.store.RAMOutputStream;
+	using ArrayUtil = org.apache.lucene.util.ArrayUtil;
+	using Bits = org.apache.lucene.util.Bits;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+	using TimSorter = org.apache.lucene.util.TimSorter;
+	using CompiledAutomaton = org.apache.lucene.util.automaton.CompiledAutomaton;
+
+	/// <summary>
+	/// An <seealso cref="AtomicReader"/> which supports sorting documents by a given
+	/// <seealso cref="Sort"/>. You can use this class to sort an index as follows:
+	/// 
+	/// <pre class="prettyprint">
+	/// IndexWriter writer; // writer to which the sorted index will be added
+	/// DirectoryReader reader; // reader on the input index
+	/// Sort sort; // determines how the documents are sorted
+	/// AtomicReader sortingReader = SortingAtomicReader.wrap(SlowCompositeReaderWrapper.wrap(reader), sort);
+	/// writer.addIndexes(reader);
+	/// writer.close();
+	/// reader.close();
+	/// </pre>
+	/// 
+	/// @lucene.experimental
+	/// </summary>
+	public class SortingAtomicReader : FilterAtomicReader
+	{
+
+	  private class SortingFields : FilterFields
+	  {
+
+		internal readonly Sorter.DocMap docMap;
+		internal readonly FieldInfos infos;
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public SortingFields(final org.apache.lucene.index.Fields in, org.apache.lucene.index.FieldInfos infos, Sorter.DocMap docMap)
+		public SortingFields(Fields @in, FieldInfos infos, Sorter.DocMap docMap) : base(@in)
+		{
+		  this.docMap = docMap;
+		  this.infos = infos;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.Terms terms(final String field) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		public override Terms terms(string field)
+		{
+		  Terms terms = @in.terms(field);
+		  if (terms == null)
+		  {
+			return null;
+		  }
+		  else
+		  {
+			return new SortingTerms(terms, infos.fieldInfo(field).IndexOptions, docMap);
+		  }
+		}
+
+	  }
+
+	  private class SortingTerms : FilterTerms
+	  {
+
+		internal readonly Sorter.DocMap docMap;
+		internal readonly IndexOptions indexOptions;
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public SortingTerms(final org.apache.lucene.index.Terms in, org.apache.lucene.index.FieldInfo.IndexOptions indexOptions, final Sorter.DocMap docMap)
+		public SortingTerms(Terms @in, IndexOptions indexOptions, Sorter.DocMap docMap) : base(@in)
+		{
+		  this.docMap = docMap;
+		  this.indexOptions = indexOptions;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.TermsEnum iterator(final org.apache.lucene.index.TermsEnum reuse) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		public override TermsEnum iterator(TermsEnum reuse)
+		{
+		  return new SortingTermsEnum(@in.iterator(reuse), docMap, indexOptions);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.TermsEnum intersect(org.apache.lucene.util.automaton.CompiledAutomaton compiled, org.apache.lucene.util.BytesRef startTerm) throws java.io.IOException
+		public override TermsEnum intersect(CompiledAutomaton compiled, BytesRef startTerm)
+		{
+		  return new SortingTermsEnum(@in.intersect(compiled, startTerm), docMap, indexOptions);
+		}
+
+	  }
+
+	  private class SortingTermsEnum : FilterTermsEnum
+	  {
+
+		internal readonly Sorter.DocMap docMap; // pkg-protected to avoid synthetic accessor methods
+		internal readonly IndexOptions indexOptions;
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public SortingTermsEnum(final org.apache.lucene.index.TermsEnum in, Sorter.DocMap docMap, org.apache.lucene.index.FieldInfo.IndexOptions indexOptions)
+		public SortingTermsEnum(TermsEnum @in, Sorter.DocMap docMap, IndexOptions indexOptions) : base(@in)
+		{
+		  this.docMap = docMap;
+		  this.indexOptions = indexOptions;
+		}
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: org.apache.lucene.util.Bits newToOld(final org.apache.lucene.util.Bits liveDocs)
+		internal virtual Bits newToOld(Bits liveDocs)
+		{
+		  if (liveDocs == null)
+		  {
+			return null;
+		  }
+		  return new BitsAnonymousInnerClassHelper(this, liveDocs);
+		}
+
+		private class BitsAnonymousInnerClassHelper : Bits
+		{
+			private readonly SortingTermsEnum outerInstance;
+
+			private Bits liveDocs;
+
+			public BitsAnonymousInnerClassHelper(SortingTermsEnum outerInstance, Bits liveDocs)
+			{
+				this.outerInstance = outerInstance;
+				this.liveDocs = liveDocs;
+			}
+
+
+			public override bool get(int index)
+			{
+			  return liveDocs.get(outerInstance.docMap.oldToNew(index));
+			}
+
+			public override int length()
+			{
+			  return liveDocs.length();
+			}
+
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.DocsEnum docs(org.apache.lucene.util.Bits liveDocs, org.apache.lucene.index.DocsEnum reuse, final int flags) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		public override DocsEnum docs(Bits liveDocs, DocsEnum reuse, int flags)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.DocsEnum inReuse;
+		  DocsEnum inReuse;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final SortingDocsEnum wrapReuse;
+		  SortingDocsEnum wrapReuse;
+		  if (reuse != null && reuse is SortingDocsEnum)
+		  {
+			// if we're asked to reuse the given DocsEnum and it is Sorting, return
+			// the wrapped one, since some Codecs expect it.
+			wrapReuse = (SortingDocsEnum) reuse;
+			inReuse = wrapReuse.Wrapped;
+		  }
+		  else
+		  {
+			wrapReuse = null;
+			inReuse = reuse;
+		  }
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.DocsEnum inDocs = in.docs(newToOld(liveDocs), inReuse, flags);
+		  DocsEnum inDocs = @in.docs(newToOld(liveDocs), inReuse, flags);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final boolean withFreqs = indexOptions.compareTo(org.apache.lucene.index.FieldInfo.IndexOptions.DOCS_AND_FREQS) >=0 && (flags & org.apache.lucene.index.DocsEnum.FLAG_FREQS) != 0;
+		  bool withFreqs = indexOptions.compareTo(IndexOptions.DOCS_AND_FREQS) >= 0 && (flags & DocsEnum.FLAG_FREQS) != 0;
+		  return new SortingDocsEnum(docMap.size(), wrapReuse, inDocs, withFreqs, docMap);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.DocsAndPositionsEnum docsAndPositions(org.apache.lucene.util.Bits liveDocs, org.apache.lucene.index.DocsAndPositionsEnum reuse, final int flags) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		public override DocsAndPositionsEnum docsAndPositions(Bits liveDocs, DocsAndPositionsEnum reuse, int flags)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.DocsAndPositionsEnum inReuse;
+		  DocsAndPositionsEnum inReuse;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final SortingDocsAndPositionsEnum wrapReuse;
+		  SortingDocsAndPositionsEnum wrapReuse;
+		  if (reuse != null && reuse is SortingDocsAndPositionsEnum)
+		  {
+			// if we're asked to reuse the given DocsEnum and it is Sorting, return
+			// the wrapped one, since some Codecs expect it.
+			wrapReuse = (SortingDocsAndPositionsEnum) reuse;
+			inReuse = wrapReuse.Wrapped;
+		  }
+		  else
+		  {
+			wrapReuse = null;
+			inReuse = reuse;
+		  }
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.DocsAndPositionsEnum inDocsAndPositions = in.docsAndPositions(newToOld(liveDocs), inReuse, flags);
+		  DocsAndPositionsEnum inDocsAndPositions = @in.docsAndPositions(newToOld(liveDocs), inReuse, flags);
+		  if (inDocsAndPositions == null)
+		  {
+			return null;
+		  }
+
+		  // we ignore the fact that offsets may be stored but not asked for,
+		  // since this code is expected to be used during addIndexes which will
+		  // ask for everything. if that assumption changes in the future, we can
+		  // factor in whether 'flags' says offsets are not required.
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final boolean storeOffsets = indexOptions.compareTo(org.apache.lucene.index.FieldInfo.IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) >= 0;
+		  bool storeOffsets = indexOptions.compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) >= 0;
+		  return new SortingDocsAndPositionsEnum(docMap.size(), wrapReuse, inDocsAndPositions, docMap, storeOffsets);
+		}
+
+	  }
+
+	  private class SortingBinaryDocValues : BinaryDocValues
+	  {
+
+		internal readonly BinaryDocValues @in;
+		internal readonly Sorter.DocMap docMap;
+
+		internal SortingBinaryDocValues(BinaryDocValues @in, Sorter.DocMap docMap)
+		{
+		  this.@in = @in;
+		  this.docMap = docMap;
+		}
+
+		public override void get(int docID, BytesRef result)
+		{
+		  @in.get(docMap.newToOld(docID), result);
+		}
+	  }
+
+	  private class SortingNumericDocValues : NumericDocValues
+	  {
+
+		internal readonly NumericDocValues @in;
+		internal readonly Sorter.DocMap docMap;
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public SortingNumericDocValues(final org.apache.lucene.index.NumericDocValues in, Sorter.DocMap docMap)
+		public SortingNumericDocValues(NumericDocValues @in, Sorter.DocMap docMap)
+		{
+		  this.@in = @in;
+		  this.docMap = docMap;
+		}
+
+		public override long get(int docID)
+		{
+		  return @in.get(docMap.newToOld(docID));
+		}
+	  }
+
+	  private class SortingBits : Bits
+	  {
+
+		internal readonly Bits @in;
+		internal readonly Sorter.DocMap docMap;
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public SortingBits(final org.apache.lucene.util.Bits in, Sorter.DocMap docMap)
+		public SortingBits(Bits @in, Sorter.DocMap docMap)
+		{
+		  this.@in = @in;
+		  this.docMap = docMap;
+		}
+
+		public override bool get(int index)
+		{
+		  return @in.get(docMap.newToOld(index));
+		}
+
+		public override int length()
+		{
+		  return @in.length();
+		}
+	  }
+
+	  private class SortingSortedDocValues : SortedDocValues
+	  {
+
+		internal readonly SortedDocValues @in;
+		internal readonly Sorter.DocMap docMap;
+
+		internal SortingSortedDocValues(SortedDocValues @in, Sorter.DocMap docMap)
+		{
+		  this.@in = @in;
+		  this.docMap = docMap;
+		}
+
+		public override int getOrd(int docID)
+		{
+		  return @in.getOrd(docMap.newToOld(docID));
+		}
+
+		public override void lookupOrd(int ord, BytesRef result)
+		{
+		  @in.lookupOrd(ord, result);
+		}
+
+		public override int ValueCount
+		{
+			get
+			{
+			  return @in.ValueCount;
+			}
+		}
+
+		public override void get(int docID, BytesRef result)
+		{
+		  @in.get(docMap.newToOld(docID), result);
+		}
+
+		public override int lookupTerm(BytesRef key)
+		{
+		  return @in.lookupTerm(key);
+		}
+	  }
+
+	  private class SortingSortedSetDocValues : SortedSetDocValues
+	  {
+
+		internal readonly SortedSetDocValues @in;
+		internal readonly Sorter.DocMap docMap;
+
+		internal SortingSortedSetDocValues(SortedSetDocValues @in, Sorter.DocMap docMap)
+		{
+		  this.@in = @in;
+		  this.docMap = docMap;
+		}
+
+		public override long nextOrd()
+		{
+		  return @in.nextOrd();
+		}
+
+		public override int Document
+		{
+			set
+			{
+			  @in.Document = docMap.newToOld(value);
+			}
+		}
+
+		public override void lookupOrd(long ord, BytesRef result)
+		{
+		  @in.lookupOrd(ord, result);
+		}
+
+		public override long ValueCount
+		{
+			get
+			{
+			  return @in.ValueCount;
+			}
+		}
+
+		public override long lookupTerm(BytesRef key)
+		{
+		  return @in.lookupTerm(key);
+		}
+	  }
+
+	  internal class SortingDocsEnum : FilterDocsEnum
+	  {
+
+		private sealed class DocFreqSorter : TimSorter
+		{
+
+		  internal int[] docs;
+		  internal int[] freqs;
+		  internal readonly int[] tmpDocs;
+		  internal int[] tmpFreqs;
+
+		  public DocFreqSorter(int maxDoc) : base(maxDoc / 64)
+		  {
+			this.tmpDocs = new int[maxDoc / 64];
+		  }
+
+		  public void reset(int[] docs, int[] freqs)
+		  {
+			this.docs = docs;
+			this.freqs = freqs;
+			if (freqs != null && tmpFreqs == null)
+			{
+			  tmpFreqs = new int[tmpDocs.Length];
+			}
+		  }
+
+		  protected internal override int compare(int i, int j)
+		  {
+			return docs[i] - docs[j];
+		  }
+
+		  protected internal override void swap(int i, int j)
+		  {
+			int tmpDoc = docs[i];
+			docs[i] = docs[j];
+			docs[j] = tmpDoc;
+
+			if (freqs != null)
+			{
+			  int tmpFreq = freqs[i];
+			  freqs[i] = freqs[j];
+			  freqs[j] = tmpFreq;
+			}
+		  }
+
+		  protected internal override void copy(int src, int dest)
+		  {
+			docs[dest] = docs[src];
+			if (freqs != null)
+			{
+			  freqs[dest] = freqs[src];
+			}
+		  }
+
+		  protected internal override void save(int i, int len)
+		  {
+			Array.Copy(docs, i, tmpDocs, 0, len);
+			if (freqs != null)
+			{
+			  Array.Copy(freqs, i, tmpFreqs, 0, len);
+			}
+		  }
+
+		  protected internal override void restore(int i, int j)
+		  {
+			docs[j] = tmpDocs[i];
+			if (freqs != null)
+			{
+			  freqs[j] = tmpFreqs[i];
+			}
+		  }
+
+		  protected internal override int compareSaved(int i, int j)
+		  {
+			return tmpDocs[i] - docs[j];
+		  }
+		}
+
+		internal readonly int maxDoc;
+		internal readonly DocFreqSorter sorter;
+		internal int[] docs;
+		internal int[] freqs;
+		internal int docIt = -1;
+		internal readonly int upto;
+		internal readonly bool withFreqs;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: SortingDocsEnum(int maxDoc, SortingDocsEnum reuse, final org.apache.lucene.index.DocsEnum in, boolean withFreqs, final Sorter.DocMap docMap) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		internal SortingDocsEnum(int maxDoc, SortingDocsEnum reuse, DocsEnum @in, bool withFreqs, Sorter.DocMap docMap) : base(@in)
+		{
+		  this.maxDoc = maxDoc;
+		  this.withFreqs = withFreqs;
+		  if (reuse != null)
+		  {
+			if (reuse.maxDoc == maxDoc)
+			{
+			  sorter = reuse.sorter;
+			}
+			else
+			{
+			  sorter = new DocFreqSorter(maxDoc);
+			}
+			docs = reuse.docs;
+			freqs = reuse.freqs; // maybe null
+		  }
+		  else
+		  {
+			docs = new int[64];
+			sorter = new DocFreqSorter(maxDoc);
+		  }
+		  docIt = -1;
+		  int i = 0;
+		  int doc;
+		  if (withFreqs)
+		  {
+			if (freqs == null || freqs.Length < docs.Length)
+			{
+			  freqs = new int[docs.Length];
+			}
+			while ((doc = @in.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS)
+			{
+			  if (i >= docs.Length)
+			  {
+				docs = ArrayUtil.grow(docs, docs.Length + 1);
+				freqs = ArrayUtil.grow(freqs, freqs.Length + 1);
+			  }
+			  docs[i] = docMap.oldToNew(doc);
+			  freqs[i] = @in.freq();
+			  ++i;
+			}
+		  }
+		  else
+		  {
+			freqs = null;
+			while ((doc = @in.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS)
+			{
+			  if (i >= docs.Length)
+			  {
+				docs = ArrayUtil.grow(docs, docs.Length + 1);
+			  }
+			  docs[i++] = docMap.oldToNew(doc);
+			}
+		  }
+		  // TimSort can save much time compared to other sorts in case of
+		  // reverse sorting, or when sorting a concatenation of sorted readers
+		  sorter.reset(docs, freqs);
+		  sorter.sort(0, i);
+		  upto = i;
+		}
+
+		// for testing
+		internal virtual bool reused(DocsEnum other)
+		{
+		  if (other == null || !(other is SortingDocsEnum))
+		  {
+			return false;
+		  }
+		  return docs == ((SortingDocsEnum) other).docs;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(final int target) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		public override int advance(int target)
+		{
+		  // need to support it for checkIndex, but in practice it won't be called, so
+		  // don't bother to implement efficiently for now.
+		  return slowAdvance(target);
+		}
+
+		public override int docID()
+		{
+		  return docIt < 0 ? - 1 : docIt >= upto ? NO_MORE_DOCS : docs[docIt];
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		public override int freq()
+		{
+		  return withFreqs && docIt < upto ? freqs[docIt] : 1;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextDoc() throws java.io.IOException
+		public override int nextDoc()
+		{
+		  if (++docIt >= upto)
+		  {
+			  return NO_MORE_DOCS;
+		  }
+		  return docs[docIt];
+		}
+
+		/// <summary>
+		/// Returns the wrapped <seealso cref="DocsEnum"/>. </summary>
+		internal virtual DocsEnum Wrapped
+		{
+			get
+			{
+			  return @in;
+			}
+		}
+	  }
+
+	  internal class SortingDocsAndPositionsEnum : FilterDocsAndPositionsEnum
+	  {
+
+		/// <summary>
+		/// A <seealso cref="TimSorter"/> which sorts two parallel arrays of doc IDs and
+		/// offsets in one go. Everytime a doc ID is 'swapped', its correponding offset
+		/// is swapped too.
+		/// </summary>
+		private sealed class DocOffsetSorter : TimSorter
+		{
+
+		  internal int[] docs;
+		  internal long[] offsets;
+		  internal readonly int[] tmpDocs;
+		  internal readonly long[] tmpOffsets;
+
+		  public DocOffsetSorter(int maxDoc) : base(maxDoc / 64)
+		  {
+			this.tmpDocs = new int[maxDoc / 64];
+			this.tmpOffsets = new long[maxDoc / 64];
+		  }
+
+		  public void reset(int[] docs, long[] offsets)
+		  {
+			this.docs = docs;
+			this.offsets = offsets;
+		  }
+
+		  protected internal override int compare(int i, int j)
+		  {
+			return docs[i] - docs[j];
+		  }
+
+		  protected internal override void swap(int i, int j)
+		  {
+			int tmpDoc = docs[i];
+			docs[i] = docs[j];
+			docs[j] = tmpDoc;
+
+			long tmpOffset = offsets[i];
+			offsets[i] = offsets[j];
+			offsets[j] = tmpOffset;
+		  }
+
+		  protected internal override void copy(int src, int dest)
+		  {
+			docs[dest] = docs[src];
+			offsets[dest] = offsets[src];
+		  }
+
+		  protected internal override void save(int i, int len)
+		  {
+			Array.Copy(docs, i, tmpDocs, 0, len);
+			Array.Copy(offsets, i, tmpOffsets, 0, len);
+		  }
+
+		  protected internal override void restore(int i, int j)
+		  {
+			docs[j] = tmpDocs[i];
+			offsets[j] = tmpOffsets[i];
+		  }
+
+		  protected internal override int compareSaved(int i, int j)
+		  {
+			return tmpDocs[i] - docs[j];
+		  }
+		}
+
+		internal readonly int maxDoc;
+		internal readonly DocOffsetSorter sorter;
+		internal int[] docs;
+		internal long[] offsets;
+		internal readonly int upto;
+
+		internal readonly IndexInput postingInput;
+		internal readonly bool storeOffsets;
+
+		internal int docIt = -1;
+		internal int pos;
+		internal int startOffset_Renamed = -1;
+		internal int endOffset_Renamed = -1;
+		internal readonly BytesRef payload;
+		internal int currFreq;
+
+		internal readonly RAMFile file;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: SortingDocsAndPositionsEnum(int maxDoc, SortingDocsAndPositionsEnum reuse, final org.apache.lucene.index.DocsAndPositionsEnum in, Sorter.DocMap docMap, boolean storeOffsets) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		internal SortingDocsAndPositionsEnum(int maxDoc, SortingDocsAndPositionsEnum reuse, DocsAndPositionsEnum @in, Sorter.DocMap docMap, bool storeOffsets) : base(@in)
+		{
+		  this.maxDoc = maxDoc;
+		  this.storeOffsets = storeOffsets;
+		  if (reuse != null)
+		  {
+			docs = reuse.docs;
+			offsets = reuse.offsets;
+			payload = reuse.payload;
+			file = reuse.file;
+			if (reuse.maxDoc == maxDoc)
+			{
+			  sorter = reuse.sorter;
+			}
+			else
+			{
+			  sorter = new DocOffsetSorter(maxDoc);
+			}
+		  }
+		  else
+		  {
+			docs = new int[32];
+			offsets = new long[32];
+			payload = new BytesRef(32);
+			file = new RAMFile();
+			sorter = new DocOffsetSorter(maxDoc);
+		  }
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.store.IndexOutput out = new org.apache.lucene.store.RAMOutputStream(file);
+		  IndexOutput @out = new RAMOutputStream(file);
+		  int doc;
+		  int i = 0;
+		  while ((doc = @in.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS)
+		  {
+			if (i == docs.Length)
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int newLength = org.apache.lucene.util.ArrayUtil.oversize(i + 1, 4);
+			  int newLength = ArrayUtil.oversize(i + 1, 4);
+			  docs = Arrays.copyOf(docs, newLength);
+			  offsets = Arrays.copyOf(offsets, newLength);
+			}
+			docs[i] = docMap.oldToNew(doc);
+			offsets[i] = @out.FilePointer;
+			addPositions(@in, @out);
+			i++;
+		  }
+		  upto = i;
+		  sorter.reset(docs, offsets);
+		  sorter.sort(0, upto);
+		  @out.close();
+		  this.postingInput = new RAMInputStream("", file);
+		}
+
+		// for testing
+		internal virtual bool reused(DocsAndPositionsEnum other)
+		{
+		  if (other == null || !(other is SortingDocsAndPositionsEnum))
+		  {
+			return false;
+		  }
+		  return docs == ((SortingDocsAndPositionsEnum) other).docs;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private void addPositions(final org.apache.lucene.index.DocsAndPositionsEnum in, final org.apache.lucene.store.IndexOutput out) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		internal virtual void addPositions(DocsAndPositionsEnum @in, IndexOutput @out)
+		{
+		  int freq = @in.freq();
+		  @out.writeVInt(freq);
+		  int previousPosition = 0;
+		  int previousEndOffset = 0;
+		  for (int i = 0; i < freq; i++)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int pos = in.nextPosition();
+			int pos = @in.nextPosition();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.BytesRef payload = in.getPayload();
+			BytesRef payload = @in.Payload;
+			// The low-order bit of token is set only if there is a payload, the
+			// previous bits are the delta-encoded position. 
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int token = (pos - previousPosition) << 1 | (payload == null ? 0 : 1);
+			int token = (pos - previousPosition) << 1 | (payload == null ? 0 : 1);
+			@out.writeVInt(token);
+			previousPosition = pos;
+			if (storeOffsets) // don't encode offsets if they are not stored
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int startOffset = in.startOffset();
+			  int startOffset = @in.startOffset();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int endOffset = in.endOffset();
+			  int endOffset = @in.endOffset();
+			  @out.writeVInt(startOffset - previousEndOffset);
+			  @out.writeVInt(endOffset - startOffset);
+			  previousEndOffset = endOffset;
+			}
+			if (payload != null)
+			{
+			  @out.writeVInt(payload.length);
+			  @out.writeBytes(payload.bytes, payload.offset, payload.length);
+			}
+		  }
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(final int target) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+		public override int advance(int target)
+		{
+		  // need to support it for checkIndex, but in practice it won't be called, so
+		  // don't bother to implement efficiently for now.
+		  return slowAdvance(target);
+		}
+
+		public override int docID()
+		{
+		  return docIt < 0 ? - 1 : docIt >= upto ? NO_MORE_DOCS : docs[docIt];
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int endOffset() throws java.io.IOException
+		public override int endOffset()
+		{
+		  return endOffset_Renamed;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		public override int freq()
+		{
+		  return currFreq;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.util.BytesRef getPayload() throws java.io.IOException
+		public override BytesRef Payload
+		{
+			get
+			{
+			  return payload.length == 0 ? null : payload;
+			}
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextDoc() throws java.io.IOException
+		public override int nextDoc()
+		{
+		  if (++docIt >= upto)
+		  {
+			  return DocIdSetIterator.NO_MORE_DOCS;
+		  }
+		  postingInput.seek(offsets[docIt]);
+		  currFreq = postingInput.readVInt();
+		  // reset variables used in nextPosition
+		  pos = 0;
+		  endOffset_Renamed = 0;
+		  return docs[docIt];
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextPosition() throws java.io.IOException
+		public override int nextPosition()
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int token = postingInput.readVInt();
+		  int token = postingInput.readVInt();
+		  pos += (int)((uint)token >> 1);
+		  if (storeOffsets)
+		  {
+			startOffset_Renamed = endOffset_Renamed + postingInput.readVInt();
+			endOffset_Renamed = startOffset_Renamed + postingInput.readVInt();
+		  }
+		  if ((token & 1) != 0)
+		  {
+			payload.offset = 0;
+			payload.length = postingInput.readVInt();
+			if (payload.length > payload.bytes.length)
+			{
+			  payload.bytes = new sbyte[ArrayUtil.oversize(payload.length, 1)];
+			}
+			postingInput.readBytes(payload.bytes, 0, payload.length);
+		  }
+		  else
+		  {
+			payload.length = 0;
+		  }
+		  return pos;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int startOffset() throws java.io.IOException
+		public override int startOffset()
+		{
+		  return startOffset_Renamed;
+		}
+
+		/// <summary>
+		/// Returns the wrapped <seealso cref="DocsAndPositionsEnum"/>. </summary>
+		internal virtual DocsAndPositionsEnum Wrapped
+		{
+			get
+			{
+			  return @in;
+			}
+		}
+	  }
+
+	  /// <summary>
+	  /// Return a sorted view of <code>reader</code> according to the order
+	  ///  defined by <code>sort</code>. If the reader is already sorted, this
+	  ///  method might return the reader as-is. 
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static org.apache.lucene.index.AtomicReader wrap(org.apache.lucene.index.AtomicReader reader, org.apache.lucene.search.Sort sort) throws java.io.IOException
+	  public static AtomicReader wrap(AtomicReader reader, Sort sort)
+	  {
+		return wrap(reader, (new Sorter(sort)).sort(reader));
+	  }
+
+	  /// <summary>
+	  /// Expert: same as <seealso cref="#wrap(AtomicReader, Sort)"/> but operates directly on a <seealso cref="Sorter.DocMap"/>. </summary>
+	  internal static AtomicReader wrap(AtomicReader reader, Sorter.DocMap docMap)
+	  {
+		if (docMap == null)
+		{
+		  // the reader is already sorter
+		  return reader;
+		}
+		if (reader.maxDoc() != docMap.size())
+		{
+		  throw new System.ArgumentException("reader.maxDoc() should be equal to docMap.size(), got" + reader.maxDoc() + " != " + docMap.size());
+		}
+		Debug.Assert(Sorter.isConsistent(docMap));
+		return new SortingAtomicReader(reader, docMap);
+	  }
+
+	  internal readonly Sorter.DocMap docMap; // pkg-protected to avoid synthetic accessor methods
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: private SortingAtomicReader(final org.apache.lucene.index.AtomicReader in, final Sorter.DocMap docMap)
+	  private SortingAtomicReader(AtomicReader @in, Sorter.DocMap docMap) : base(@in)
+	  {
+		this.docMap = docMap;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void document(final int docID, final org.apache.lucene.index.StoredFieldVisitor visitor) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+	  public override void document(int docID, StoredFieldVisitor visitor)
+	  {
+		@in.document(docMap.newToOld(docID), visitor);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.Fields fields() throws java.io.IOException
+	  public override Fields fields()
+	  {
+		Fields fields = @in.fields();
+		if (fields == null)
+		{
+		  return null;
+		}
+		else
+		{
+		  return new SortingFields(fields, @in.FieldInfos, docMap);
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.BinaryDocValues getBinaryDocValues(String field) throws java.io.IOException
+	  public override BinaryDocValues getBinaryDocValues(string field)
+	  {
+		BinaryDocValues oldDocValues = @in.getBinaryDocValues(field);
+		if (oldDocValues == null)
+		{
+		  return null;
+		}
+		else
+		{
+		  return new SortingBinaryDocValues(oldDocValues, docMap);
+		}
+	  }
+
+	  public override Bits LiveDocs
+	  {
+		  get
+		  {
+	//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+	//ORIGINAL LINE: final org.apache.lucene.util.Bits inLiveDocs = in.getLiveDocs();
+			Bits inLiveDocs = @in.LiveDocs;
+			if (inLiveDocs == null)
+			{
+			  return null;
+			}
+			else
+			{
+			  return new SortingBits(inLiveDocs, docMap);
+			}
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.NumericDocValues getNormValues(String field) throws java.io.IOException
+	  public override NumericDocValues getNormValues(string field)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.NumericDocValues norm = in.getNormValues(field);
+		NumericDocValues norm = @in.getNormValues(field);
+		if (norm == null)
+		{
+		  return null;
+		}
+		else
+		{
+		  return new SortingNumericDocValues(norm, docMap);
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.NumericDocValues getNumericDocValues(String field) throws java.io.IOException
+	  public override NumericDocValues getNumericDocValues(string field)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.NumericDocValues oldDocValues = in.getNumericDocValues(field);
+		NumericDocValues oldDocValues = @in.getNumericDocValues(field);
+		if (oldDocValues == null)
+		{
+			return null;
+		}
+		return new SortingNumericDocValues(oldDocValues, docMap);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.SortedDocValues getSortedDocValues(String field) throws java.io.IOException
+	  public override SortedDocValues getSortedDocValues(string field)
+	  {
+		SortedDocValues sortedDV = @in.getSortedDocValues(field);
+		if (sortedDV == null)
+		{
+		  return null;
+		}
+		else
+		{
+		  return new SortingSortedDocValues(sortedDV, docMap);
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.SortedSetDocValues getSortedSetDocValues(String field) throws java.io.IOException
+	  public override SortedSetDocValues getSortedSetDocValues(string field)
+	  {
+		SortedSetDocValues sortedSetDV = @in.getSortedSetDocValues(field);
+		if (sortedSetDV == null)
+		{
+		  return null;
+		}
+		else
+		{
+		  return new SortingSortedSetDocValues(sortedSetDV, docMap);
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.util.Bits getDocsWithField(String field) throws java.io.IOException
+	  public override Bits getDocsWithField(string field)
+	  {
+		Bits bits = @in.getDocsWithField(field);
+		if (bits == null || bits is Bits.MatchAllBits || bits is Bits.MatchNoBits)
+		{
+		  return bits;
+		}
+		else
+		{
+		  return new SortingBits(bits, docMap);
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.Fields getTermVectors(final int docID) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+	  public override Fields getTermVectors(int docID)
+	  {
+		return @in.getTermVectors(docMap.newToOld(docID));
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/Sorter/SortingMergePolicy.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/Sorter/SortingMergePolicy.cs b/src/Lucene.Net.Misc/Index/Sorter/SortingMergePolicy.cs
new file mode 100644
index 0000000..c455d2a
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/Sorter/SortingMergePolicy.cs
@@ -0,0 +1,309 @@
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.index.sorter
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using Analyzer = org.apache.lucene.analysis.Analyzer; // javadocs
+	using Sort = org.apache.lucene.search.Sort;
+	using Directory = org.apache.lucene.store.Directory;
+	using Bits = org.apache.lucene.util.Bits;
+	using MonotonicAppendingLongBuffer = org.apache.lucene.util.packed.MonotonicAppendingLongBuffer;
+
+	/// <summary>
+	/// A <seealso cref="MergePolicy"/> that reorders documents according to a <seealso cref="Sort"/>
+	///  before merging them. As a consequence, all segments resulting from a merge
+	///  will be sorted while segments resulting from a flush will be in the order
+	///  in which documents have been added.
+	///  <para><b>NOTE</b>: Never use this policy if you rely on
+	///  <seealso cref="IndexWriter#addDocuments(Iterable, Analyzer) IndexWriter.addDocuments"/>
+	///  to have sequentially-assigned doc IDs, this policy will scatter doc IDs.
+	/// </para>
+	///  <para><b>NOTE</b>: This policy should only be used with idempotent {@code Sort}s 
+	///  so that the order of segments is predictable. For example, using 
+	///  <seealso cref="Sort#INDEXORDER"/> in reverse (which is not idempotent) will make 
+	///  the order of documents in a segment depend on the number of times the segment 
+	///  has been merged.
+	///  @lucene.experimental 
+	/// </para>
+	/// </summary>
+	public sealed class SortingMergePolicy : MergePolicy
+	{
+
+	  /// <summary>
+	  /// Put in the <seealso cref="SegmentInfo#getDiagnostics() diagnostics"/> to denote that
+	  /// this segment is sorted.
+	  /// </summary>
+	  public const string SORTER_ID_PROP = "sorter";
+
+	  internal class SortingOneMerge : OneMerge
+	  {
+		  private readonly SortingMergePolicy outerInstance;
+
+
+		internal IList<AtomicReader> unsortedReaders;
+		internal Sorter.DocMap docMap;
+		internal AtomicReader sortedView;
+
+		internal SortingOneMerge(SortingMergePolicy outerInstance, IList<SegmentCommitInfo> segments) : base(segments)
+		{
+			this.outerInstance = outerInstance;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public java.util.List<org.apache.lucene.index.AtomicReader> getMergeReaders() throws java.io.IOException
+		public override IList<AtomicReader> MergeReaders
+		{
+			get
+			{
+			  if (unsortedReaders == null)
+			  {
+				unsortedReaders = base.MergeReaders;
+	//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+	//ORIGINAL LINE: final org.apache.lucene.index.AtomicReader atomicView;
+				AtomicReader atomicView;
+				if (unsortedReaders.Count == 1)
+				{
+				  atomicView = unsortedReaders[0];
+				}
+				else
+				{
+	//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+	//ORIGINAL LINE: final org.apache.lucene.index.IndexReader multiReader = new org.apache.lucene.index.MultiReader(unsortedReaders.toArray(new org.apache.lucene.index.AtomicReader[unsortedReaders.size()]));
+				  IndexReader multiReader = new MultiReader(unsortedReaders.ToArray());
+				  atomicView = SlowCompositeReaderWrapper.wrap(multiReader);
+				}
+				docMap = outerInstance.sorter.sort(atomicView);
+				sortedView = SortingAtomicReader.wrap(atomicView, docMap);
+			  }
+			  // a null doc map means that the readers are already sorted
+			  return docMap == null ? unsortedReaders : Collections.singletonList(sortedView);
+			}
+		}
+
+		public override SegmentCommitInfo Info
+		{
+			set
+			{
+			  IDictionary<string, string> diagnostics = value.info.Diagnostics;
+			  diagnostics[SORTER_ID_PROP] = outerInstance.sorter.ID;
+			  base.Info = value;
+			}
+		}
+
+		internal virtual MonotonicAppendingLongBuffer getDeletes(IList<AtomicReader> readers)
+		{
+		  MonotonicAppendingLongBuffer deletes = new MonotonicAppendingLongBuffer();
+		  int deleteCount = 0;
+		  foreach (AtomicReader reader in readers)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int maxDoc = reader.maxDoc();
+			int maxDoc = reader.maxDoc();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits liveDocs = reader.getLiveDocs();
+			Bits liveDocs = reader.LiveDocs;
+			for (int i = 0; i < maxDoc; ++i)
+			{
+			  if (liveDocs != null && !liveDocs.get(i))
+			  {
+				++deleteCount;
+			  }
+			  else
+			  {
+				deletes.add(deleteCount);
+			  }
+			}
+		  }
+		  deletes.freeze();
+		  return deletes;
+		}
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.index.MergePolicy.DocMap getDocMap(final org.apache.lucene.index.MergeState mergeState)
+		public override MergePolicy.DocMap getDocMap(MergeState mergeState)
+		{
+		  if (unsortedReaders == null)
+		  {
+			throw new IllegalStateException();
+		  }
+		  if (docMap == null)
+		  {
+			return base.getDocMap(mergeState);
+		  }
+		  Debug.Assert(mergeState.docMaps.length == 1); // we returned a singleton reader
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.packed.MonotonicAppendingLongBuffer deletes = getDeletes(unsortedReaders);
+		  MonotonicAppendingLongBuffer deletes = getDeletes(unsortedReaders);
+		  return new DocMapAnonymousInnerClassHelper(this, mergeState, deletes);
+		}
+
+		private class DocMapAnonymousInnerClassHelper : MergePolicy.DocMap
+		{
+			private readonly SortingOneMerge outerInstance;
+
+			private MergeState mergeState;
+			private MonotonicAppendingLongBuffer deletes;
+
+			public DocMapAnonymousInnerClassHelper(SortingOneMerge outerInstance, MergeState mergeState, MonotonicAppendingLongBuffer deletes)
+			{
+				this.outerInstance = outerInstance;
+				this.mergeState = mergeState;
+				this.deletes = deletes;
+			}
+
+			public override int map(int old)
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int oldWithDeletes = old + (int) deletes.get(old);
+			  int oldWithDeletes = old + (int) deletes.get(old);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int newWithDeletes = docMap.oldToNew(oldWithDeletes);
+			  int newWithDeletes = outerInstance.docMap.oldToNew(oldWithDeletes);
+			  return mergeState.docMaps[0].get(newWithDeletes);
+			}
+		}
+
+	  }
+
+	  internal class SortingMergeSpecification : MergeSpecification
+	  {
+		  private readonly SortingMergePolicy outerInstance;
+
+		  public SortingMergeSpecification(SortingMergePolicy outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+		  }
+
+
+		public override void add(OneMerge merge)
+		{
+		  base.add(new SortingOneMerge(outerInstance, merge.segments));
+		}
+
+		public override string segString(Directory dir)
+		{
+		  return "SortingMergeSpec(" + base.segString(dir) + ", sorter=" + outerInstance.sorter + ")";
+		}
+
+	  }
+
+	  /// <summary>
+	  /// Returns {@code true} if the given {@code reader} is sorted by the specified {@code sort}. </summary>
+	  public static bool isSorted(AtomicReader reader, Sort sort)
+	  {
+		if (reader is SegmentReader)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.SegmentReader segReader = (org.apache.lucene.index.SegmentReader) reader;
+		  SegmentReader segReader = (SegmentReader) reader;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.util.Map<String, String> diagnostics = segReader.getSegmentInfo().info.getDiagnostics();
+		  IDictionary<string, string> diagnostics = segReader.SegmentInfo.info.Diagnostics;
+		  if (diagnostics != null && sort.ToString().Equals(diagnostics[SORTER_ID_PROP]))
+		  {
+			return true;
+		  }
+		}
+		return false;
+	  }
+
+	  private MergeSpecification sortedMergeSpecification(MergeSpecification specification)
+	  {
+		if (specification == null)
+		{
+		  return null;
+		}
+		MergeSpecification sortingSpec = new SortingMergeSpecification(this);
+		foreach (OneMerge merge in specification.merges)
+		{
+		  sortingSpec.add(merge);
+		}
+		return sortingSpec;
+	  }
+
+	  internal readonly MergePolicy @in;
+	  internal readonly Sorter sorter;
+	  internal readonly Sort sort;
+
+	  /// <summary>
+	  /// Create a new {@code MergePolicy} that sorts documents with the given {@code sort}. </summary>
+	  public SortingMergePolicy(MergePolicy @in, Sort sort)
+	  {
+		this.@in = @in;
+		this.sorter = new Sorter(sort);
+		this.sort = sort;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public MergeSpecification findMerges(org.apache.lucene.index.MergeTrigger mergeTrigger, org.apache.lucene.index.SegmentInfos segmentInfos) throws java.io.IOException
+	  public override MergeSpecification findMerges(MergeTrigger mergeTrigger, SegmentInfos segmentInfos)
+	  {
+		return sortedMergeSpecification(@in.findMerges(mergeTrigger, segmentInfos));
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public MergeSpecification findForcedMerges(org.apache.lucene.index.SegmentInfos segmentInfos, int maxSegmentCount, java.util.Map<org.apache.lucene.index.SegmentCommitInfo,Boolean> segmentsToMerge) throws java.io.IOException
+	  public override MergeSpecification findForcedMerges(SegmentInfos segmentInfos, int maxSegmentCount, IDictionary<SegmentCommitInfo, bool?> segmentsToMerge)
+	  {
+		return sortedMergeSpecification(@in.findForcedMerges(segmentInfos, maxSegmentCount, segmentsToMerge));
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public MergeSpecification findForcedDeletesMerges(org.apache.lucene.index.SegmentInfos segmentInfos) throws java.io.IOException
+	  public override MergeSpecification findForcedDeletesMerges(SegmentInfos segmentInfos)
+	  {
+		return sortedMergeSpecification(@in.findForcedDeletesMerges(segmentInfos));
+	  }
+
+	  public override MergePolicy clone()
+	  {
+		return new SortingMergePolicy(@in.clone(), sort);
+	  }
+
+	  public override void close()
+	  {
+		@in.close();
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public boolean useCompoundFile(org.apache.lucene.index.SegmentInfos segments, org.apache.lucene.index.SegmentCommitInfo newSegment) throws java.io.IOException
+	  public override bool useCompoundFile(SegmentInfos segments, SegmentCommitInfo newSegment)
+	  {
+		return @in.useCompoundFile(segments, newSegment);
+	  }
+
+	  public override IndexWriter IndexWriter
+	  {
+		  set
+		  {
+			@in.IndexWriter = value;
+		  }
+	  }
+
+	  public override string ToString()
+	  {
+		return "SortingMergePolicy(" + @in + ", sorter=" + sorter + ")";
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Lucene.Net.Misc.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Lucene.Net.Misc.csproj b/src/Lucene.Net.Misc/Lucene.Net.Misc.csproj
new file mode 100644
index 0000000..e4bc070
--- /dev/null
+++ b/src/Lucene.Net.Misc/Lucene.Net.Misc.csproj
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{A3A0D943-B91A-4B7A-9FCB-6160EA575D95}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Misc</RootNamespace>
+    <AssemblyName>Lucene.Net.Misc</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ByteBuffer.cs" />
+    <Compile Include="Document\LazyDocument.cs" />
+    <Compile Include="Index\CompoundFileExtractor.cs" />
+    <Compile Include="Index\IndexSplitter.cs" />
+    <Compile Include="Index\MultiPassIndexSplitter.cs" />
+    <Compile Include="Index\PKIndexSplitter.cs" />
+    <Compile Include="Index\Sorter\BlockJoinComparatorSource.cs" />
+    <Compile Include="Index\Sorter\EarlyTerminatingSortingCollector.cs" />
+    <Compile Include="Index\Sorter\Sorter.cs" />
+    <Compile Include="Index\Sorter\SortingAtomicReader.cs" />
+    <Compile Include="Index\Sorter\SortingMergePolicy.cs" />
+    <Compile Include="Misc\GetTermInfo.cs" />
+    <Compile Include="Misc\HighFreqTerms.cs" />
+    <Compile Include="Misc\IndexMergeTool.cs" />
+    <Compile Include="Misc\SweetSpotSimilarity.cs" />
+    <Compile Include="Misc\TermStats.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Store\NativePosixUtil.cs" />
+    <Compile Include="Store\NativeUnixDirectory.cs" />
+    <Compile Include="Store\WindowsDirectory.cs" />
+    <Compile Include="Util\Fst\ListOfOutputs.cs" />
+    <Compile Include="Util\Fst\UpToTwoPositiveIntOutputs.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Misc/GetTermInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Misc/GetTermInfo.cs b/src/Lucene.Net.Misc/Misc/GetTermInfo.cs
new file mode 100644
index 0000000..9d56821
--- /dev/null
+++ b/src/Lucene.Net.Misc/Misc/GetTermInfo.cs
@@ -0,0 +1,74 @@
+using System;
+
+namespace org.apache.lucene.misc
+{
+
+	/*
+	 * 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.
+	 */
+
+	using Directory = org.apache.lucene.store.Directory;
+	using FSDirectory = org.apache.lucene.store.FSDirectory;
+	using DirectoryReader = org.apache.lucene.index.DirectoryReader;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using Term = org.apache.lucene.index.Term;
+
+	/// <summary>
+	/// Utility to get document frequency and total number of occurrences (sum of the tf for each doc)  of a term. 
+	/// </summary>
+	public class GetTermInfo
+	{
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static void main(String[] args) throws Exception
+	  public static void Main(string[] args)
+	  {
+
+		FSDirectory dir = null;
+		string inputStr = null;
+		string field = null;
+
+		if (args.Length == 3)
+		{
+		  dir = FSDirectory.open(new File(args[0]));
+		  field = args[1];
+		  inputStr = args[2];
+		}
+		else
+		{
+		  usage();
+		  Environment.Exit(1);
+		}
+
+		getTermInfo(dir,new Term(field, inputStr));
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static void getTermInfo(org.apache.lucene.store.Directory dir, org.apache.lucene.index.Term term) throws Exception
+	  public static void getTermInfo(Directory dir, Term term)
+	  {
+		IndexReader reader = DirectoryReader.open(dir);
+		System.out.printf(Locale.ROOT, "%s:%s \t totalTF = %,d \t doc freq = %,d \n", term.field(), term.text(), reader.totalTermFreq(term), reader.docFreq(term));
+	  }
+
+	  private static void usage()
+	  {
+//JAVA TO C# CONVERTER WARNING: The .NET Type.FullName property will not always yield results identical to the Java Class.getName method:
+		Console.WriteLine("\n\nusage:\n\t" + "java " + typeof(GetTermInfo).FullName + " <index dir> field term \n\n");
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Misc/HighFreqTerms.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Misc/HighFreqTerms.cs b/src/Lucene.Net.Misc/Misc/HighFreqTerms.cs
new file mode 100644
index 0000000..dccb173
--- /dev/null
+++ b/src/Lucene.Net.Misc/Misc/HighFreqTerms.cs
@@ -0,0 +1,230 @@
+using System;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.misc
+{
+
+	/*
+	 * 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.
+	 */
+
+	using DirectoryReader = org.apache.lucene.index.DirectoryReader;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using MultiFields = org.apache.lucene.index.MultiFields;
+	using Fields = org.apache.lucene.index.Fields;
+	using TermsEnum = org.apache.lucene.index.TermsEnum;
+	using Terms = org.apache.lucene.index.Terms;
+	using Directory = org.apache.lucene.store.Directory;
+	using FSDirectory = org.apache.lucene.store.FSDirectory;
+	using PriorityQueue = org.apache.lucene.util.PriorityQueue;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// <code>HighFreqTerms</code> class extracts the top n most frequent terms
+	/// (by document frequency) from an existing Lucene index and reports their
+	/// document frequency.
+	/// <para>
+	/// If the -t flag is given, both document frequency and total tf (total
+	/// number of occurrences) are reported, ordered by descending total tf.
+	/// 
+	/// </para>
+	/// </summary>
+	public class HighFreqTerms
+	{
+
+	  // The top numTerms will be displayed
+	  public const int DEFAULT_NUMTERMS = 100;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static void main(String[] args) throws Exception
+	  public static void Main(string[] args)
+	  {
+		string field = null;
+		int numTerms = DEFAULT_NUMTERMS;
+
+		if (args.Length == 0 || args.Length > 4)
+		{
+		  usage();
+		  Environment.Exit(1);
+		}
+
+		Directory dir = FSDirectory.open(new File(args[0]));
+
+		IComparer<TermStats> comparator = new DocFreqComparator();
+
+		for (int i = 1; i < args.Length; i++)
+		{
+		  if (args[i].Equals("-t"))
+		  {
+			comparator = new TotalTermFreqComparator();
+		  }
+		  else
+		  {
+			try
+			{
+			  numTerms = Convert.ToInt32(args[i]);
+			}
+			catch (NumberFormatException)
+			{
+			  field = args[i];
+			}
+		  }
+		}
+
+		IndexReader reader = DirectoryReader.open(dir);
+		TermStats[] terms = getHighFreqTerms(reader, numTerms, field, comparator);
+
+		for (int i = 0; i < terms.Length; i++)
+		{
+		  System.out.printf(Locale.ROOT, "%s:%s \t totalTF = %,d \t docFreq = %,d \n", terms[i].field, terms[i].termtext.utf8ToString(), terms[i].totalTermFreq, terms[i].docFreq);
+		}
+		reader.close();
+	  }
+
+	  private static void usage()
+	  {
+		Console.WriteLine("\n\n" + "java org.apache.lucene.misc.HighFreqTerms <index dir> [-t] [number_terms] [field]\n\t -t: order by totalTermFreq\n\n");
+	  }
+
+	  /// <summary>
+	  /// Returns TermStats[] ordered by the specified comparator
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static TermStats[] getHighFreqTerms(org.apache.lucene.index.IndexReader reader, int numTerms, String field, java.util.Comparator<TermStats> comparator) throws Exception
+	  public static TermStats[] getHighFreqTerms(IndexReader reader, int numTerms, string field, IComparer<TermStats> comparator)
+	  {
+		TermStatsQueue tiq = null;
+
+		if (field != null)
+		{
+		  Fields fields = MultiFields.getFields(reader);
+		  if (fields == null)
+		  {
+			throw new Exception("field " + field + " not found");
+		  }
+		  Terms terms = fields.terms(field);
+		  if (terms != null)
+		  {
+			TermsEnum termsEnum = terms.iterator(null);
+			tiq = new TermStatsQueue(numTerms, comparator);
+			tiq.fill(field, termsEnum);
+		  }
+		}
+		else
+		{
+		  Fields fields = MultiFields.getFields(reader);
+		  if (fields == null)
+		  {
+			throw new Exception("no fields found for this index");
+		  }
+		  tiq = new TermStatsQueue(numTerms, comparator);
+		  foreach (string fieldName in fields)
+		  {
+			Terms terms = fields.terms(fieldName);
+			if (terms != null)
+			{
+			  tiq.fill(fieldName, terms.iterator(null));
+			}
+		  }
+		}
+
+		TermStats[] result = new TermStats[tiq.size()];
+		// we want highest first so we read the queue and populate the array
+		// starting at the end and work backwards
+		int count = tiq.size() - 1;
+		while (tiq.size() != 0)
+		{
+		  result[count] = tiq.pop();
+		  count--;
+		}
+		return result;
+	  }
+
+	  /// <summary>
+	  /// Compares terms by docTermFreq
+	  /// </summary>
+	  public sealed class DocFreqComparator : IComparer<TermStats>
+	  {
+
+		public int Compare(TermStats a, TermStats b)
+		{
+		  int res = long.compare(a.docFreq, b.docFreq);
+		  if (res == 0)
+		  {
+			res = a.field.CompareTo(b.field);
+			if (res == 0)
+			{
+			  res = a.termtext.compareTo(b.termtext);
+			}
+		  }
+		  return res;
+		}
+	  }
+
+	  /// <summary>
+	  /// Compares terms by totalTermFreq
+	  /// </summary>
+	  public sealed class TotalTermFreqComparator : IComparer<TermStats>
+	  {
+
+		public int Compare(TermStats a, TermStats b)
+		{
+		  int res = long.compare(a.totalTermFreq, b.totalTermFreq);
+		  if (res == 0)
+		  {
+			res = a.field.CompareTo(b.field);
+			if (res == 0)
+			{
+			  res = a.termtext.compareTo(b.termtext);
+			}
+		  }
+		  return res;
+		}
+	  }
+
+	  /// <summary>
+	  /// Priority queue for TermStats objects
+	  /// 
+	  /// </summary>
+	  internal sealed class TermStatsQueue : PriorityQueue<TermStats>
+	  {
+		internal readonly IComparer<TermStats> comparator;
+
+		internal TermStatsQueue(int size, IComparer<TermStats> comparator) : base(size)
+		{
+		  this.comparator = comparator;
+		}
+
+		protected internal override bool lessThan(TermStats termInfoA, TermStats termInfoB)
+		{
+		  return comparator.Compare(termInfoA, termInfoB) < 0;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: protected void fill(String field, org.apache.lucene.index.TermsEnum termsEnum) throws java.io.IOException
+		protected internal void fill(string field, TermsEnum termsEnum)
+		{
+		  BytesRef term = null;
+		  while ((term = termsEnum.next()) != null)
+		  {
+			insertWithOverflow(new TermStats(field, term, termsEnum.docFreq(), termsEnum.totalTermFreq()));
+		  }
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Misc/IndexMergeTool.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Misc/IndexMergeTool.cs b/src/Lucene.Net.Misc/Misc/IndexMergeTool.cs
new file mode 100644
index 0000000..bba8704
--- /dev/null
+++ b/src/Lucene.Net.Misc/Misc/IndexMergeTool.cs
@@ -0,0 +1,66 @@
+using System;
+
+namespace org.apache.lucene.misc
+{
+
+	/// <summary>
+	/// Copyright 2005 The Apache Software Foundation
+	///  
+	/// Licensed 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.
+	/// </summary>
+
+	using IndexWriter = org.apache.lucene.index.IndexWriter;
+	using IndexWriterConfig = org.apache.lucene.index.IndexWriterConfig;
+	using OpenMode = org.apache.lucene.index.IndexWriterConfig.OpenMode;
+	using Directory = org.apache.lucene.store.Directory;
+	using FSDirectory = org.apache.lucene.store.FSDirectory;
+	using Version = org.apache.lucene.util.Version;
+
+
+	/// <summary>
+	/// Merges indices specified on the command line into the index
+	/// specified as the first command line argument.
+	/// </summary>
+	public class IndexMergeTool
+	{
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static void main(String[] args) throws java.io.IOException
+	  public static void Main(string[] args)
+	  {
+		if (args.Length < 3)
+		{
+		  Console.Error.WriteLine("Usage: IndexMergeTool <mergedIndex> <index1> <index2> [index3] ...");
+		  Environment.Exit(1);
+		}
+		FSDirectory mergedIndex = FSDirectory.open(new File(args[0]));
+
+		IndexWriter writer = new IndexWriter(mergedIndex, new IndexWriterConfig(Version.LUCENE_CURRENT, null)
+		   .setOpenMode(IndexWriterConfig.OpenMode.CREATE));
+
+		Directory[] indexes = new Directory[args.Length - 1];
+		for (int i = 1; i < args.Length; i++)
+		{
+		  indexes[i - 1] = FSDirectory.open(new File(args[i]));
+		}
+
+		Console.WriteLine("Merging...");
+		writer.addIndexes(indexes);
+
+		Console.WriteLine("Full merge...");
+		writer.forceMerge(1);
+		writer.close();
+		Console.WriteLine("Done.");
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Misc/SweetSpotSimilarity.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Misc/SweetSpotSimilarity.cs b/src/Lucene.Net.Misc/Misc/SweetSpotSimilarity.cs
new file mode 100644
index 0000000..bc0386c
--- /dev/null
+++ b/src/Lucene.Net.Misc/Misc/SweetSpotSimilarity.cs
@@ -0,0 +1,238 @@
+using System;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.misc
+{
+
+	using DefaultSimilarity = org.apache.lucene.search.similarities.DefaultSimilarity;
+	using FieldInvertState = org.apache.lucene.index.FieldInvertState;
+
+	/// <summary>
+	/// <para>
+	/// A similarity with a lengthNorm that provides for a "plateau" of
+	/// equally good lengths, and tf helper functions.
+	/// </para>
+	/// <para>
+	/// For lengthNorm, A min/max can be specified to define the
+	/// plateau of lengths that should all have a norm of 1.0.
+	/// Below the min, and above the max the lengthNorm drops off in a
+	/// sqrt function.
+	/// </para>
+	/// <para>
+	/// For tf, baselineTf and hyperbolicTf functions are provided, which
+	/// subclasses can choose between.
+	/// </para>
+	/// </summary>
+	/// <seealso cref= <a href="doc-files/ss.gnuplot">A Gnuplot file used to generate some of the visualizations refrenced from each function.</a>  </seealso>
+	public class SweetSpotSimilarity : DefaultSimilarity
+	{
+
+	  private int ln_min = 1;
+	  private int ln_max = 1;
+	  private float ln_steep = 0.5f;
+
+	  private float tf_base = 0.0f;
+	  private float tf_min = 0.0f;
+
+	  private float tf_hyper_min = 0.0f;
+	  private float tf_hyper_max = 2.0f;
+	  private double tf_hyper_base = 1.3d;
+	  private float tf_hyper_xoffset = 10.0f;
+
+	  public SweetSpotSimilarity() : base()
+	  {
+	  }
+
+	  /// <summary>
+	  /// Sets the baseline and minimum function variables for baselineTf
+	  /// </summary>
+	  /// <seealso cref= #baselineTf </seealso>
+	  public virtual void setBaselineTfFactors(float @base, float min)
+	  {
+		tf_min = min;
+		tf_base = @base;
+	  }
+
+	  /// <summary>
+	  /// Sets the function variables for the hyperbolicTf functions
+	  /// </summary>
+	  /// <param name="min"> the minimum tf value to ever be returned (default: 0.0) </param>
+	  /// <param name="max"> the maximum tf value to ever be returned (default: 2.0) </param>
+	  /// <param name="base"> the base value to be used in the exponential for the hyperbolic function (default: 1.3) </param>
+	  /// <param name="xoffset"> the midpoint of the hyperbolic function (default: 10.0) </param>
+	  /// <seealso cref= #hyperbolicTf </seealso>
+	  public virtual void setHyperbolicTfFactors(float min, float max, double @base, float xoffset)
+	  {
+		tf_hyper_min = min;
+		tf_hyper_max = max;
+		tf_hyper_base = @base;
+		tf_hyper_xoffset = xoffset;
+	  }
+
+	  /// <summary>
+	  /// Sets the default function variables used by lengthNorm when no field
+	  /// specific variables have been set.
+	  /// </summary>
+	  /// <seealso cref= #computeLengthNorm </seealso>
+	  public virtual void setLengthNormFactors(int min, int max, float steepness, bool discountOverlaps)
+	  {
+		this.ln_min = min;
+		this.ln_max = max;
+		this.ln_steep = steepness;
+		this.discountOverlaps = discountOverlaps;
+	  }
+
+	  /// <summary>
+	  /// Implemented as <code> state.getBoost() *
+	  /// computeLengthNorm(numTokens) </code> where
+	  /// numTokens does not count overlap tokens if
+	  /// discountOverlaps is true by default or true for this
+	  /// specific field. 
+	  /// </summary>
+	  public override float lengthNorm(FieldInvertState state)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int numTokens;
+		int numTokens;
+
+		if (discountOverlaps)
+		{
+		  numTokens = state.Length - state.NumOverlap;
+		}
+		else
+		{
+		  numTokens = state.Length;
+		}
+
+		return state.Boost * computeLengthNorm(numTokens);
+	  }
+
+	  /// <summary>
+	  /// Implemented as:
+	  /// <code>
+	  /// 1/sqrt( steepness * (abs(x-min) + abs(x-max) - (max-min)) + 1 )
+	  /// </code>.
+	  /// 
+	  /// <para>
+	  /// This degrades to <code>1/sqrt(x)</code> when min and max are both 1 and
+	  /// steepness is 0.5
+	  /// </para>
+	  /// 
+	  /// <para>
+	  /// :TODO: potential optimization is to just flat out return 1.0f if numTerms
+	  /// is between min and max.
+	  /// </para>
+	  /// </summary>
+	  /// <seealso cref= #setLengthNormFactors </seealso>
+	  /// <seealso cref= <a href="doc-files/ss.computeLengthNorm.svg">An SVG visualization of this function</a>  </seealso>
+	  public virtual float computeLengthNorm(int numTerms)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int l = ln_min;
+		int l = ln_min;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int h = ln_max;
+		int h = ln_max;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float s = ln_steep;
+		float s = ln_steep;
+
+		return (float)(1.0f / Math.Sqrt((s * (float)(Math.Abs(numTerms - l) + Math.Abs(numTerms - h) - (h - l))) + 1.0f));
+	  }
+
+	  /// <summary>
+	  /// Delegates to baselineTf
+	  /// </summary>
+	  /// <seealso cref= #baselineTf </seealso>
+	  public override float tf(float freq)
+	  {
+		return baselineTf(freq);
+	  }
+
+	  /// <summary>
+	  /// Implemented as:
+	  /// <code>
+	  ///  (x &lt;= min) &#63; base : sqrt(x+(base**2)-min)
+	  /// </code>
+	  /// ...but with a special case check for 0.
+	  /// <para>
+	  /// This degrates to <code>sqrt(x)</code> when min and base are both 0
+	  /// </para>
+	  /// </summary>
+	  /// <seealso cref= #setBaselineTfFactors </seealso>
+	  /// <seealso cref= <a href="doc-files/ss.baselineTf.svg">An SVG visualization of this function</a>  </seealso>
+	  public virtual float baselineTf(float freq)
+	  {
+
+		if (0.0f == freq)
+		{
+			return 0.0f;
+		}
+
+		return (freq <= tf_min) ? tf_base : (float)Math.Sqrt(freq + (tf_base * tf_base) - tf_min);
+	  }
+
+	  /// <summary>
+	  /// Uses a hyperbolic tangent function that allows for a hard max...
+	  /// 
+	  /// <code>
+	  /// tf(x)=min+(max-min)/2*(((base**(x-xoffset)-base**-(x-xoffset))/(base**(x-xoffset)+base**-(x-xoffset)))+1)
+	  /// </code>
+	  /// 
+	  /// <para>
+	  /// This code is provided as a convenience for subclasses that want
+	  /// to use a hyperbolic tf function.
+	  /// </para>
+	  /// </summary>
+	  /// <seealso cref= #setHyperbolicTfFactors </seealso>
+	  /// <seealso cref= <a href="doc-files/ss.hyperbolicTf.svg">An SVG visualization of this function</a>  </seealso>
+	  public virtual float hyperbolicTf(float freq)
+	  {
+		if (0.0f == freq)
+		{
+			return 0.0f;
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float min = tf_hyper_min;
+		float min = tf_hyper_min;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float max = tf_hyper_max;
+		float max = tf_hyper_max;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final double base = tf_hyper_base;
+		double @base = tf_hyper_base;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float xoffset = tf_hyper_xoffset;
+		float xoffset = tf_hyper_xoffset;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final double x = (double)(freq - xoffset);
+		double x = (double)(freq - xoffset);
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float result = min + (float)((max-min) / 2.0f * (((Math.pow(base,x) - Math.pow(base,-x)) / (Math.pow(base,x) + Math.pow(base,-x))) + 1.0d));
+		float result = min + (float)((max - min) / 2.0f * (((Math.Pow(@base,x) - Math.Pow(@base,-x)) / (Math.Pow(@base,x) + Math.Pow(@base,-x))) + 1.0d));
+
+		return float.IsNaN(result) ? max : result;
+
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Misc/TermStats.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Misc/TermStats.cs b/src/Lucene.Net.Misc/Misc/TermStats.cs
new file mode 100644
index 0000000..061cca3
--- /dev/null
+++ b/src/Lucene.Net.Misc/Misc/TermStats.cs
@@ -0,0 +1,55 @@
+namespace org.apache.lucene.misc
+{
+
+	/*
+	 * 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.
+	 */
+
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+	/// <summary>
+	/// Holder for a term along with its statistics
+	/// (<seealso cref="#docFreq"/> and <seealso cref="#totalTermFreq"/>).
+	/// </summary>
+	public sealed class TermStats
+	{
+	  public BytesRef termtext;
+	  public string field;
+	  public int docFreq;
+	  public long totalTermFreq;
+
+	  internal TermStats(string field, BytesRef termtext, int df, long tf)
+	  {
+		this.termtext = BytesRef.deepCopyOf(termtext);
+		this.field = field;
+		this.docFreq = df;
+		this.totalTermFreq = tf;
+	  }
+
+	  internal string TermText
+	  {
+		  get
+		  {
+			return termtext.utf8ToString();
+		  }
+	  }
+
+	  public override string ToString()
+	  {
+		return ("TermStats: term=" + termtext.utf8ToString() + " docFreq=" + docFreq + " totalTermFreq=" + totalTermFreq);
+	  }
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Properties/AssemblyInfo.cs b/src/Lucene.Net.Misc/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..39cfea7
--- /dev/null
+++ b/src/Lucene.Net.Misc/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Lucene.Net.Misc")]
+[assembly: AssemblyDescription("Index tools and other miscellaneous code")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Lucene.Net.Misc")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("b2a3a8e1-a92a-4bd6-9f87-7747470615c3")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Store/NativePosixUtil.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Store/NativePosixUtil.cs b/src/Lucene.Net.Misc/Store/NativePosixUtil.cs
new file mode 100644
index 0000000..3bb51d5
--- /dev/null
+++ b/src/Lucene.Net.Misc/Store/NativePosixUtil.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace org.apache.lucene.store
+{
+
+	/*
+	 * 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.
+	 */
+
+	ignore
+
+	/// <summary>
+	/// Provides JNI access to native methods such as madvise() for
+	/// <seealso cref="NativeUnixDirectory"/>
+	/// </summary>
+	public final class NativePosixUtil
+	{
+	  public final static int NORMAL = 0;
+	  public final static int SEQUENTIAL = 1;
+	  public final static int RANDOM = 2;
+	  public final static int WILLNEED = 3;
+	  public final static int DONTNEED = 4;
+	  public final static int NOREUSE = 5;
+
+//JAVA TO C# CONVERTER NOTE: This static initializer block is converted to a static constructor, but there is no current class:
+	  static ImpliedClass()
+	  {
+//JAVA TO C# CONVERTER TODO TASK: The library is specified in the 'DllImport' attribute for .NET:
+//		System.loadLibrary("NativePosixUtil");
+	  }
+
+	  private static native int posix_fadvise(FileDescriptor fd, long offset, long len, int advise) throws IOException;
+	  public static native int posix_madvise(ByteBuffer buf, int advise) throws IOException;
+	  public static native int madvise(ByteBuffer buf, int advise) throws IOException;
+	  public static native FileDescriptor open_direct(string filename, bool read) throws IOException;
+	  public static native long pread(FileDescriptor fd, long pos, ByteBuffer byteBuf) throws IOException;
+
+	  public static void advise(FileDescriptor fd, long offset, long len, int advise) throws IOException
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int code = posix_fadvise(fd, offset, len, advise);
+		int code = posix_fadvise(fd, offset, len, advise);
+		if (code != 0)
+		{
+		  throw new Exception("posix_fadvise failed code=" + code);
+		}
+	  }
+	}
+
+
+}
\ No newline at end of file


[03/11] Skeleton porting of Lucene.Net.Queries

Posted by sy...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/SumFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/SumFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/SumFloatFunction.cs
new file mode 100644
index 0000000..fcd3e41
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/SumFloatFunction.cs
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	/// <summary>
+	/// <code>SumFloatFunction</code> returns the sum of it's components.
+	/// </summary>
+	public class SumFloatFunction : MultiFloatFunction
+	{
+	  public SumFloatFunction(ValueSource[] sources) : base(sources)
+	  {
+	  }
+
+	  protected internal override string name()
+	  {
+		return "sum";
+	  }
+
+	  protected internal override float func(int doc, FunctionValues[] valsArr)
+	  {
+		float val = 0.0f;
+		foreach (FunctionValues vals in valsArr)
+		{
+		  val += vals.floatVal(doc);
+		}
+		return val;
+	  }
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/SumTotalTermFreqValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/SumTotalTermFreqValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/SumTotalTermFreqValueSource.cs
new file mode 100644
index 0000000..48a9600
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/SumTotalTermFreqValueSource.cs
@@ -0,0 +1,132 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using Fields = org.apache.lucene.index.Fields;
+	using Terms = org.apache.lucene.index.Terms;
+	using LongDocValues = org.apache.lucene.queries.function.docvalues.LongDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// <code>SumTotalTermFreqValueSource</code> returns the number of tokens.
+	/// (sum of term freqs across all documents, across all terms).
+	/// Returns -1 if frequencies were omitted for the field, or if 
+	/// the codec doesn't support this statistic.
+	/// @lucene.internal
+	/// </summary>
+	public class SumTotalTermFreqValueSource : ValueSource
+	{
+	  protected internal readonly string indexedField;
+
+	  public SumTotalTermFreqValueSource(string indexedField)
+	  {
+		this.indexedField = indexedField;
+	  }
+
+	  public virtual string name()
+	  {
+		return "sumtotaltermfreq";
+	  }
+
+	  public override string description()
+	  {
+		return name() + '(' + indexedField + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		return (FunctionValues)context[this];
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		long sumTotalTermFreq = 0;
+		foreach (AtomicReaderContext readerContext in searcher.TopReaderContext.leaves())
+		{
+		  Fields fields = readerContext.reader().fields();
+		  if (fields == null)
+		  {
+			  continue;
+		  }
+		  Terms terms = fields.terms(indexedField);
+		  if (terms == null)
+		  {
+			  continue;
+		  }
+		  long v = terms.SumTotalTermFreq;
+		  if (v == -1)
+		  {
+			sumTotalTermFreq = -1;
+			break;
+		  }
+		  else
+		  {
+			sumTotalTermFreq += v;
+		  }
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long ttf = sumTotalTermFreq;
+		long ttf = sumTotalTermFreq;
+		context[this] = new LongDocValuesAnonymousInnerClassHelper(this, this, ttf);
+	  }
+
+	  private class LongDocValuesAnonymousInnerClassHelper : LongDocValues
+	  {
+		  private readonly SumTotalTermFreqValueSource outerInstance;
+
+		  private long ttf;
+
+		  public LongDocValuesAnonymousInnerClassHelper(SumTotalTermFreqValueSource outerInstance, org.apache.lucene.queries.function.valuesource.SumTotalTermFreqValueSource this, long ttf) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.ttf = ttf;
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return ttf;
+		  }
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return this.GetType().GetHashCode() + indexedField.GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		SumTotalTermFreqValueSource other = (SumTotalTermFreqValueSource)o;
+		return this.indexedField.Equals(other.indexedField);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/TFValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/TFValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/TFValueSource.cs
new file mode 100644
index 0000000..e957cc8
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/TFValueSource.cs
@@ -0,0 +1,197 @@
+using System;
+using System.Collections;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	/*
+	 * 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.
+	 */
+
+	using org.apache.lucene.index;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using DocIdSetIterator = org.apache.lucene.search.DocIdSetIterator;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using TFIDFSimilarity = org.apache.lucene.search.similarities.TFIDFSimilarity;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// Function that returns <seealso cref="TFIDFSimilarity#tf(float)"/>
+	/// for every document.
+	/// <para>
+	/// Note that the configured Similarity for the field must be
+	/// a subclass of <seealso cref="TFIDFSimilarity"/>
+	/// @lucene.internal 
+	/// </para>
+	/// </summary>
+	public class TFValueSource : TermFreqValueSource
+	{
+	  public TFValueSource(string field, string val, string indexedField, BytesRef indexedBytes) : base(field, val, indexedField, indexedBytes)
+	  {
+	  }
+
+	  public override string name()
+	  {
+		return "tf";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		Fields fields = readerContext.reader().fields();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Terms terms = fields.terms(indexedField);
+		Terms terms = fields.terms(indexedField);
+		IndexSearcher searcher = (IndexSearcher)context["searcher"];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.similarities.TFIDFSimilarity similarity = IDFValueSource.asTFIDF(searcher.getSimilarity(), indexedField);
+		TFIDFSimilarity similarity = IDFValueSource.asTFIDF(searcher.Similarity, indexedField);
+		if (similarity == null)
+		{
+		  throw new System.NotSupportedException("requires a TFIDFSimilarity (such as DefaultSimilarity)");
+		}
+
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, terms, similarity);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly TFValueSource outerInstance;
+
+		  private Terms terms;
+		  private TFIDFSimilarity similarity;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(TFValueSource outerInstance, org.apache.lucene.queries.function.valuesource.TFValueSource this, Terms terms, TFIDFSimilarity similarity) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.terms = terms;
+			  this.similarity = similarity;
+			  lastDocRequested = -1;
+		  }
+
+		  internal DocsEnum docs;
+		  internal int atDoc;
+		  internal int lastDocRequested;
+
+//JAVA TO C# CONVERTER TODO TASK: Initialization blocks declared within anonymous inner classes are not converted:
+	//	  {
+	//		  reset();
+	//	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void reset() throws java.io.IOException
+		  public virtual void reset()
+		  {
+			// no one should call us for deleted docs?
+
+			if (terms != null)
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final TermsEnum termsEnum = terms.iterator(null);
+			  TermsEnum termsEnum = terms.iterator(null);
+			  if (termsEnum.seekExact(outerInstance.indexedBytes))
+			  {
+				docs = termsEnum.docs(null, null);
+			  }
+			  else
+			  {
+				docs = null;
+			  }
+			}
+			else
+			{
+			  docs = null;
+			}
+
+			if (docs == null)
+			{
+			  docs = new DocsEnumAnonymousInnerClassHelper(this);
+			}
+			atDoc = -1;
+		  }
+
+		  private class DocsEnumAnonymousInnerClassHelper : DocsEnum
+		  {
+			  private readonly FloatDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public DocsEnumAnonymousInnerClassHelper(FloatDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+			  }
+
+			  public override int freq()
+			  {
+				return 0;
+			  }
+
+			  public override int docID()
+			  {
+				return DocIdSetIterator.NO_MORE_DOCS;
+			  }
+
+			  public override int nextDoc()
+			  {
+				return DocIdSetIterator.NO_MORE_DOCS;
+			  }
+
+			  public override int advance(int target)
+			  {
+				return DocIdSetIterator.NO_MORE_DOCS;
+			  }
+
+			  public override long cost()
+			  {
+				return 0;
+			  }
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			try
+			{
+			  if (doc < lastDocRequested)
+			  {
+				// out-of-order access.... reset
+				reset();
+			  }
+			  lastDocRequested = doc;
+
+			  if (atDoc < doc)
+			  {
+				atDoc = docs.advance(doc);
+			  }
+
+			  if (atDoc > doc)
+			  {
+				// term doesn't match this document... either because we hit the
+				// end, or because the next doc is after this doc.
+				return similarity.tf(0);
+			  }
+
+			  // a match!
+			  return similarity.tf(docs.freq());
+			}
+			catch (IOException e)
+			{
+			  throw new Exception("caught exception in function " + outerInstance.description() + " : doc=" + doc, e);
+			}
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/TermFreqValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/TermFreqValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/TermFreqValueSource.cs
new file mode 100644
index 0000000..7e03f2b
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/TermFreqValueSource.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using org.apache.lucene.index;
+	using IntDocValues = org.apache.lucene.queries.function.docvalues.IntDocValues;
+	using DocIdSetIterator = org.apache.lucene.search.DocIdSetIterator;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// Function that returns <seealso cref="DocsEnum#freq()"/> for the
+	/// supplied term in every document.
+	/// <para>
+	/// If the term does not exist in the document, returns 0.
+	/// If frequencies are omitted, returns 1.
+	/// </para>
+	/// </summary>
+	public class TermFreqValueSource : DocFreqValueSource
+	{
+	  public TermFreqValueSource(string field, string val, string indexedField, BytesRef indexedBytes) : base(field, val, indexedField, indexedBytes)
+	  {
+	  }
+
+	  public override string name()
+	  {
+		return "termfreq";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		Fields fields = readerContext.reader().fields();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Terms terms = fields.terms(indexedField);
+		Terms terms = fields.terms(indexedField);
+
+		return new IntDocValuesAnonymousInnerClassHelper(this, this, terms);
+	  }
+
+	  private class IntDocValuesAnonymousInnerClassHelper : IntDocValues
+	  {
+		  private readonly TermFreqValueSource outerInstance;
+
+		  private Terms terms;
+
+		  public IntDocValuesAnonymousInnerClassHelper(TermFreqValueSource outerInstance, org.apache.lucene.queries.function.valuesource.TermFreqValueSource this, Terms terms) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.terms = terms;
+			  lastDocRequested = -1;
+		  }
+
+		  internal DocsEnum docs;
+		  internal int atDoc;
+		  internal int lastDocRequested;
+
+//JAVA TO C# CONVERTER TODO TASK: Initialization blocks declared within anonymous inner classes are not converted:
+	//	  {
+	//		  reset();
+	//	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void reset() throws java.io.IOException
+		  public virtual void reset()
+		  {
+			// no one should call us for deleted docs?
+
+			if (terms != null)
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final TermsEnum termsEnum = terms.iterator(null);
+			  TermsEnum termsEnum = terms.iterator(null);
+			  if (termsEnum.seekExact(outerInstance.indexedBytes))
+			  {
+				docs = termsEnum.docs(null, null);
+			  }
+			  else
+			  {
+				docs = null;
+			  }
+			}
+			else
+			{
+			  docs = null;
+			}
+
+			if (docs == null)
+			{
+			  docs = new DocsEnumAnonymousInnerClassHelper(this);
+			}
+			atDoc = -1;
+		  }
+
+		  private class DocsEnumAnonymousInnerClassHelper : DocsEnum
+		  {
+			  private readonly IntDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public DocsEnumAnonymousInnerClassHelper(IntDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+			  }
+
+			  public override int freq()
+			  {
+				return 0;
+			  }
+
+			  public override int docID()
+			  {
+				return DocIdSetIterator.NO_MORE_DOCS;
+			  }
+
+			  public override int nextDoc()
+			  {
+				return DocIdSetIterator.NO_MORE_DOCS;
+			  }
+
+			  public override int advance(int target)
+			  {
+				return DocIdSetIterator.NO_MORE_DOCS;
+			  }
+
+			  public override long cost()
+			  {
+				return 0;
+			  }
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			try
+			{
+			  if (doc < lastDocRequested)
+			  {
+				// out-of-order access.... reset
+				reset();
+			  }
+			  lastDocRequested = doc;
+
+			  if (atDoc < doc)
+			  {
+				atDoc = docs.advance(doc);
+			  }
+
+			  if (atDoc > doc)
+			  {
+				// term doesn't match this document... either because we hit the
+				// end, or because the next doc is after this doc.
+				return 0;
+			  }
+
+			  // a match!
+			  return docs.freq();
+			}
+			catch (IOException e)
+			{
+			  throw new Exception("caught exception in function " + outerInstance.description() + " : doc=" + doc, e);
+			}
+		  }
+	  }
+	}
+
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/TotalTermFreqValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/TotalTermFreqValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/TotalTermFreqValueSource.cs
new file mode 100644
index 0000000..629d6c6
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/TotalTermFreqValueSource.cs
@@ -0,0 +1,127 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using Term = org.apache.lucene.index.Term;
+	using LongDocValues = org.apache.lucene.queries.function.docvalues.LongDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// <code>TotalTermFreqValueSource</code> returns the total term freq 
+	/// (sum of term freqs across all documents).
+	/// Returns -1 if frequencies were omitted for the field, or if 
+	/// the codec doesn't support this statistic.
+	/// @lucene.internal
+	/// </summary>
+	public class TotalTermFreqValueSource : ValueSource
+	{
+	  protected internal readonly string field;
+	  protected internal readonly string indexedField;
+	  protected internal readonly string val;
+	  protected internal readonly BytesRef indexedBytes;
+
+	  public TotalTermFreqValueSource(string field, string val, string indexedField, BytesRef indexedBytes)
+	  {
+		this.field = field;
+		this.val = val;
+		this.indexedField = indexedField;
+		this.indexedBytes = indexedBytes;
+	  }
+
+	  public virtual string name()
+	  {
+		return "totaltermfreq";
+	  }
+
+	  public override string description()
+	  {
+		return name() + '(' + field + ',' + val + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		return (FunctionValues)context[this];
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		long totalTermFreq = 0;
+		foreach (AtomicReaderContext readerContext in searcher.TopReaderContext.leaves())
+		{
+		  long val = readerContext.reader().totalTermFreq(new Term(indexedField, indexedBytes));
+		  if (val == -1)
+		  {
+			totalTermFreq = -1;
+			break;
+		  }
+		  else
+		  {
+			totalTermFreq += val;
+		  }
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final long ttf = totalTermFreq;
+		long ttf = totalTermFreq;
+		context[this] = new LongDocValuesAnonymousInnerClassHelper(this, this, ttf);
+	  }
+
+	  private class LongDocValuesAnonymousInnerClassHelper : LongDocValues
+	  {
+		  private readonly TotalTermFreqValueSource outerInstance;
+
+		  private long ttf;
+
+		  public LongDocValuesAnonymousInnerClassHelper(TotalTermFreqValueSource outerInstance, org.apache.lucene.queries.function.valuesource.TotalTermFreqValueSource this, long ttf) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.ttf = ttf;
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return ttf;
+		  }
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return this.GetType().GetHashCode() + indexedField.GetHashCode() * 29 + indexedBytes.GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		TotalTermFreqValueSource other = (TotalTermFreqValueSource)o;
+		return this.indexedField.Equals(other.indexedField) && this.indexedBytes.Equals(other.indexedBytes);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/VectorValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/VectorValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/VectorValueSource.cs
new file mode 100644
index 0000000..2668ac2
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/VectorValueSource.cs
@@ -0,0 +1,293 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+
+	/// <summary>
+	/// Converts individual ValueSource instances to leverage the FunctionValues *Val functions that work with multiple values,
+	/// i.e. <seealso cref="org.apache.lucene.queries.function.FunctionValues#doubleVal(int, double[])"/>
+	/// </summary>
+	//Not crazy about the name, but...
+	public class VectorValueSource : MultiValueSource
+	{
+	  protected internal readonly IList<ValueSource> sources;
+
+
+	  public VectorValueSource(IList<ValueSource> sources)
+	  {
+		this.sources = sources;
+	  }
+
+	  public virtual IList<ValueSource> Sources
+	  {
+		  get
+		  {
+			return sources;
+		  }
+	  }
+
+	  public override int dimension()
+	  {
+		return sources.Count;
+	  }
+
+	  public virtual string name()
+	  {
+		return "vector";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		int size = sources.Count;
+
+		// special-case x,y and lat,lon since it's so common
+		if (size == 2)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues x = sources.get(0).getValues(context, readerContext);
+		  FunctionValues x = sources[0].getValues(context, readerContext);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues y = sources.get(1).getValues(context, readerContext);
+		  FunctionValues y = sources[1].getValues(context, readerContext);
+		  return new FunctionValuesAnonymousInnerClassHelper(this, x, y);
+		}
+
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues[] valsArr = new org.apache.lucene.queries.function.FunctionValues[size];
+		FunctionValues[] valsArr = new FunctionValues[size];
+		for (int i = 0; i < size; i++)
+		{
+		  valsArr[i] = sources[i].getValues(context, readerContext);
+		}
+
+		return new FunctionValuesAnonymousInnerClassHelper2(this, valsArr);
+	  }
+
+	  private class FunctionValuesAnonymousInnerClassHelper : FunctionValues
+	  {
+		  private readonly VectorValueSource outerInstance;
+
+		  private FunctionValues x;
+		  private FunctionValues y;
+
+		  public FunctionValuesAnonymousInnerClassHelper(VectorValueSource outerInstance, FunctionValues x, FunctionValues y)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.x = x;
+			  this.y = y;
+		  }
+
+		  public override void byteVal(int doc, sbyte[] vals)
+		  {
+			vals[0] = x.byteVal(doc);
+			vals[1] = y.byteVal(doc);
+		  }
+
+		  public override void shortVal(int doc, short[] vals)
+		  {
+			vals[0] = x.shortVal(doc);
+			vals[1] = y.shortVal(doc);
+		  }
+		  public override void intVal(int doc, int[] vals)
+		  {
+			vals[0] = x.intVal(doc);
+			vals[1] = y.intVal(doc);
+		  }
+		  public override void longVal(int doc, long[] vals)
+		  {
+			vals[0] = x.longVal(doc);
+			vals[1] = y.longVal(doc);
+		  }
+		  public override void floatVal(int doc, float[] vals)
+		  {
+			vals[0] = x.floatVal(doc);
+			vals[1] = y.floatVal(doc);
+		  }
+		  public override void doubleVal(int doc, double[] vals)
+		  {
+			vals[0] = x.doubleVal(doc);
+			vals[1] = y.doubleVal(doc);
+		  }
+		  public override void strVal(int doc, string[] vals)
+		  {
+			vals[0] = x.strVal(doc);
+			vals[1] = y.strVal(doc);
+		  }
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.name() + "(" + x.ToString(doc) + "," + y.ToString(doc) + ")";
+		  }
+	  }
+
+	  private class FunctionValuesAnonymousInnerClassHelper2 : FunctionValues
+	  {
+		  private readonly VectorValueSource outerInstance;
+
+		  private FunctionValues[] valsArr;
+
+		  public FunctionValuesAnonymousInnerClassHelper2(VectorValueSource outerInstance, FunctionValues[] valsArr)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.valsArr = valsArr;
+		  }
+
+		  public override void byteVal(int doc, sbyte[] vals)
+		  {
+			for (int i = 0; i < valsArr.Length; i++)
+			{
+			  vals[i] = valsArr[i].byteVal(doc);
+			}
+		  }
+
+		  public override void shortVal(int doc, short[] vals)
+		  {
+			for (int i = 0; i < valsArr.Length; i++)
+			{
+			  vals[i] = valsArr[i].shortVal(doc);
+			}
+		  }
+
+		  public override void floatVal(int doc, float[] vals)
+		  {
+			for (int i = 0; i < valsArr.Length; i++)
+			{
+			  vals[i] = valsArr[i].floatVal(doc);
+			}
+		  }
+
+		  public override void intVal(int doc, int[] vals)
+		  {
+			for (int i = 0; i < valsArr.Length; i++)
+			{
+			  vals[i] = valsArr[i].intVal(doc);
+			}
+		  }
+
+		  public override void longVal(int doc, long[] vals)
+		  {
+			for (int i = 0; i < valsArr.Length; i++)
+			{
+			  vals[i] = valsArr[i].longVal(doc);
+			}
+		  }
+
+		  public override void doubleVal(int doc, double[] vals)
+		  {
+			for (int i = 0; i < valsArr.Length; i++)
+			{
+			  vals[i] = valsArr[i].doubleVal(doc);
+			}
+		  }
+
+		  public override void strVal(int doc, string[] vals)
+		  {
+			for (int i = 0; i < valsArr.Length; i++)
+			{
+			  vals[i] = valsArr[i].strVal(doc);
+			}
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			StringBuilder sb = new StringBuilder();
+			sb.Append(outerInstance.name()).Append('(');
+			bool firstTime = true;
+			foreach (FunctionValues vals in valsArr)
+			{
+			  if (firstTime)
+			  {
+				firstTime = false;
+			  }
+			  else
+			  {
+				sb.Append(',');
+			  }
+			  sb.Append(vals.ToString(doc));
+			}
+			sb.Append(')');
+			return sb.ToString();
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		foreach (ValueSource source in sources)
+		{
+		  source.createWeight(context, searcher);
+		}
+	  }
+
+
+	  public override string description()
+	  {
+		StringBuilder sb = new StringBuilder();
+		sb.Append(name()).Append('(');
+		bool firstTime = true;
+		foreach (ValueSource source in sources)
+		{
+		  if (firstTime)
+		  {
+			firstTime = false;
+		  }
+		  else
+		  {
+			sb.Append(',');
+		  }
+		  sb.Append(source);
+		}
+		sb.Append(")");
+		return sb.ToString();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this == o)
+		{
+			return true;
+		}
+		if (!(o is VectorValueSource))
+		{
+			return false;
+		}
+
+		VectorValueSource that = (VectorValueSource) o;
+
+		return sources.Equals(that.sources);
+
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return sources.GetHashCode();
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSourceScorer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSourceScorer.cs b/src/Lucene.Net.Queries/Function/ValueSourceScorer.cs
new file mode 100644
index 0000000..fa79903
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSourceScorer.cs
@@ -0,0 +1,126 @@
+namespace org.apache.lucene.queries.function
+{
+
+	/*
+	 * 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.
+	 */
+
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using MultiFields = org.apache.lucene.index.MultiFields;
+	using Scorer = org.apache.lucene.search.Scorer;
+	using Bits = org.apache.lucene.util.Bits;
+
+	/// <summary>
+	/// <seealso cref="Scorer"/> which returns the result of <seealso cref="FunctionValues#floatVal(int)"/> as
+	/// the score for a document.
+	/// </summary>
+	public class ValueSourceScorer : Scorer
+	{
+	  protected internal readonly IndexReader reader;
+	  private int doc = -1;
+	  protected internal readonly int maxDoc;
+	  protected internal readonly FunctionValues values;
+	  protected internal bool checkDeletes;
+	  private readonly Bits liveDocs;
+
+	  protected internal ValueSourceScorer(IndexReader reader, FunctionValues values) : base(null)
+	  {
+		this.reader = reader;
+		this.maxDoc = reader.maxDoc();
+		this.values = values;
+		CheckDeletes = true;
+		this.liveDocs = MultiFields.getLiveDocs(reader);
+	  }
+
+	  public virtual IndexReader Reader
+	  {
+		  get
+		  {
+			return reader;
+		  }
+	  }
+
+	  public virtual bool CheckDeletes
+	  {
+		  set
+		  {
+			this.checkDeletes = value && reader.hasDeletions();
+		  }
+	  }
+
+	  public virtual bool matches(int doc)
+	  {
+		return (!checkDeletes || liveDocs.get(doc)) && matchesValue(doc);
+	  }
+
+	  public virtual bool matchesValue(int doc)
+	  {
+		return true;
+	  }
+
+	  public override int docID()
+	  {
+		return doc;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextDoc() throws java.io.IOException
+	  public override int nextDoc()
+	  {
+		for (; ;)
+		{
+		  doc++;
+		  if (doc >= maxDoc)
+		  {
+			  return doc = NO_MORE_DOCS;
+		  }
+		  if (matches(doc))
+		  {
+			  return doc;
+		  }
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(int target) throws java.io.IOException
+	  public override int advance(int target)
+	  {
+		// also works fine when target==NO_MORE_DOCS
+		doc = target - 1;
+		return nextDoc();
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float score() throws java.io.IOException
+	  public override float score()
+	  {
+		return values.floatVal(doc);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+	  public override int freq()
+	  {
+		return 1;
+	  }
+
+	  public override long cost()
+	  {
+		return maxDoc;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Lucene.Net.Queries.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Lucene.Net.Queries.csproj b/src/Lucene.Net.Queries/Lucene.Net.Queries.csproj
new file mode 100644
index 0000000..6856c74
--- /dev/null
+++ b/src/Lucene.Net.Queries/Lucene.Net.Queries.csproj
@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{69D7956C-C2CC-4708-B399-A188FEC384C4}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Queries</RootNamespace>
+    <AssemblyName>Lucene.Net.Queries</AssemblyName>
+    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="BooleanFilter.cs" />
+    <Compile Include="BoostingQuery.cs" />
+    <Compile Include="ChainedFilter.cs" />
+    <Compile Include="CommonTermsQuery.cs" />
+    <Compile Include="CustomScoreProvider.cs" />
+    <Compile Include="CustomScoreQuery.cs" />
+    <Compile Include="FilterClause.cs" />
+    <Compile Include="Function\BoostedQuery.cs" />
+    <Compile Include="Function\DocValues\BoolDocValues.cs" />
+    <Compile Include="Function\DocValues\DocTermsIndexDocValues.cs" />
+    <Compile Include="Function\DocValues\DoubleDocValues.cs" />
+    <Compile Include="Function\DocValues\FloatDocValues.cs" />
+    <Compile Include="Function\DocValues\IntDocValues.cs" />
+    <Compile Include="Function\DocValues\LongDocValues.cs" />
+    <Compile Include="Function\DocValues\StrDocValues.cs" />
+    <Compile Include="Function\FunctionQuery.cs" />
+    <Compile Include="Function\FunctionValues.cs" />
+    <Compile Include="Function\ValueSource.cs" />
+    <Compile Include="Function\ValueSourceScorer.cs" />
+    <Compile Include="Function\ValueSource\BoolFunction.cs" />
+    <Compile Include="Function\ValueSource\ByteFieldSource.cs" />
+    <Compile Include="Function\ValueSource\BytesRefFieldSource.cs" />
+    <Compile Include="Function\ValueSource\ConstNumberSource.cs" />
+    <Compile Include="Function\ValueSource\ConstValueSource.cs" />
+    <Compile Include="Function\ValueSource\DefFunction.cs" />
+    <Compile Include="Function\ValueSource\DivFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\DocFreqValueSource.cs" />
+    <Compile Include="Function\ValueSource\DoubleConstValueSource.cs" />
+    <Compile Include="Function\ValueSource\DoubleFieldSource.cs" />
+    <Compile Include="Function\ValueSource\DualFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\EnumFieldSource.cs" />
+    <Compile Include="Function\ValueSource\FieldCacheSource.cs" />
+    <Compile Include="Function\ValueSource\FloatFieldSource.cs" />
+    <Compile Include="Function\ValueSource\IDFValueSource.cs" />
+    <Compile Include="Function\ValueSource\IfFunction.cs" />
+    <Compile Include="Function\ValueSource\IntFieldSource.cs" />
+    <Compile Include="Function\ValueSource\JoinDocFreqValueSource.cs" />
+    <Compile Include="Function\ValueSource\LinearFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\LiteralValueSource.cs" />
+    <Compile Include="Function\ValueSource\LongFieldSource.cs" />
+    <Compile Include="Function\ValueSource\MaxDocValueSource.cs" />
+    <Compile Include="Function\ValueSource\MaxFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\MinFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\MultiBoolFunction.cs" />
+    <Compile Include="Function\ValueSource\MultiFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\MultiFunction.cs" />
+    <Compile Include="Function\ValueSource\MultiValueSource.cs" />
+    <Compile Include="Function\ValueSource\NormValueSource.cs" />
+    <Compile Include="Function\ValueSource\NumDocsValueSource.cs" />
+    <Compile Include="Function\ValueSource\OrdFieldSource.cs" />
+    <Compile Include="Function\ValueSource\PowFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\ProductFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\QueryValueSource.cs" />
+    <Compile Include="Function\ValueSource\RangeMapFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\ReciprocalFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\ReverseOrdFieldSource.cs" />
+    <Compile Include="Function\ValueSource\ScaleFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\ShortFieldSource.cs" />
+    <Compile Include="Function\ValueSource\SimpleBoolFunction.cs" />
+    <Compile Include="Function\ValueSource\SimpleFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\SingleFunction.cs" />
+    <Compile Include="Function\ValueSource\SumFloatFunction.cs" />
+    <Compile Include="Function\ValueSource\SumTotalTermFreqValueSource.cs" />
+    <Compile Include="Function\ValueSource\TermFreqValueSource.cs" />
+    <Compile Include="Function\ValueSource\TFValueSource.cs" />
+    <Compile Include="Function\ValueSource\TotalTermFreqValueSource.cs" />
+    <Compile Include="Function\ValueSource\VectorValueSource.cs" />
+    <Compile Include="Mlt\MoreLikeThis.cs" />
+    <Compile Include="Mlt\MoreLikeThisQuery.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TermFilter.cs" />
+    <Compile Include="TermsFilter.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Lucene.Net.Core\Lucene.Net.csproj">
+      <Project>{5d4ad9be-1ffb-41ab-9943-25737971bf57}</Project>
+      <Name>Lucene.Net</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Mlt/MoreLikeThis.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Mlt/MoreLikeThis.cs b/src/Lucene.Net.Queries/Mlt/MoreLikeThis.cs
new file mode 100644
index 0000000..1a25108
--- /dev/null
+++ b/src/Lucene.Net.Queries/Mlt/MoreLikeThis.cs
@@ -0,0 +1,981 @@
+using System.Collections.Generic;
+using System.Text;
+
+/// <summary>
+/// Copyright 2004-2005 The Apache Software Foundation.
+/// 
+/// Licensed 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.
+/// </summary>
+namespace org.apache.lucene.queries.mlt
+{
+
+
+	using Analyzer = org.apache.lucene.analysis.Analyzer;
+	using TokenStream = org.apache.lucene.analysis.TokenStream;
+	using CharTermAttribute = org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
+	using Document = org.apache.lucene.document.Document;
+	using Fields = org.apache.lucene.index.Fields;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using IndexableField = org.apache.lucene.index.IndexableField;
+	using MultiFields = org.apache.lucene.index.MultiFields;
+	using Term = org.apache.lucene.index.Term;
+	using Terms = org.apache.lucene.index.Terms;
+	using TermsEnum = org.apache.lucene.index.TermsEnum;
+	using org.apache.lucene.search;
+	using DefaultSimilarity = org.apache.lucene.search.similarities.DefaultSimilarity;
+	using TFIDFSimilarity = org.apache.lucene.search.similarities.TFIDFSimilarity;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+	using CharsRef = org.apache.lucene.util.CharsRef;
+	using IOUtils = org.apache.lucene.util.IOUtils;
+	using PriorityQueue = org.apache.lucene.util.PriorityQueue;
+	using UnicodeUtil = org.apache.lucene.util.UnicodeUtil;
+
+
+	/// <summary>
+	/// Generate "more like this" similarity queries.
+	/// Based on this mail:
+	/// <code><pre>
+	/// Lucene does let you access the document frequency of terms, with IndexReader.docFreq().
+	/// Term frequencies can be computed by re-tokenizing the text, which, for a single document,
+	/// is usually fast enough.  But looking up the docFreq() of every term in the document is
+	/// probably too slow.
+	/// <p/>
+	/// You can use some heuristics to prune the set of terms, to avoid calling docFreq() too much,
+	/// or at all.  Since you're trying to maximize a tf*idf score, you're probably most interested
+	/// in terms with a high tf. Choosing a tf threshold even as low as two or three will radically
+	/// reduce the number of terms under consideration.  Another heuristic is that terms with a
+	/// high idf (i.e., a low df) tend to be longer.  So you could threshold the terms by the
+	/// number of characters, not selecting anything less than, e.g., six or seven characters.
+	/// With these sorts of heuristics you can usually find small set of, e.g., ten or fewer terms
+	/// that do a pretty good job of characterizing a document.
+	/// <p/>
+	/// It all depends on what you're trying to do.  If you're trying to eek out that last percent
+	/// of precision and recall regardless of computational difficulty so that you can win a TREC
+	/// competition, then the techniques I mention above are useless.  But if you're trying to
+	/// provide a "more like this" button on a search results page that does a decent job and has
+	/// good performance, such techniques might be useful.
+	/// <p/>
+	/// An efficient, effective "more-like-this" query generator would be a great contribution, if
+	/// anyone's interested.  I'd imagine that it would take a Reader or a String (the document's
+	/// text), analyzer Analyzer, and return a set of representative terms using heuristics like those
+	/// above.  The frequency and length thresholds could be parameters, etc.
+	/// <p/>
+	/// Doug
+	/// </pre></code>
+	/// <p/>
+	/// <p/>
+	/// <p/>
+	/// <h3>Initial Usage</h3>
+	/// <p/>
+	/// This class has lots of options to try to make it efficient and flexible.
+	/// The simplest possible usage is as follows. The bold
+	/// fragment is specific to this class.
+	/// <p/>
+	/// <pre class="prettyprint">
+	/// <p/>
+	/// IndexReader ir = ...
+	/// IndexSearcher is = ...
+	/// <p/>
+	/// MoreLikeThis mlt = new MoreLikeThis(ir);
+	/// Reader target = ... // orig source of doc you want to find similarities to
+	/// Query query = mlt.like( target);
+	/// <p/>
+	/// Hits hits = is.search(query);
+	/// // now the usual iteration thru 'hits' - the only thing to watch for is to make sure
+	/// //you ignore the doc if it matches your 'target' document, as it should be similar to itself
+	/// <p/>
+	/// </pre>
+	/// <p/>
+	/// Thus you:
+	/// <ol>
+	/// <li> do your normal, Lucene setup for searching,
+	/// <li> create a MoreLikeThis,
+	/// <li> get the text of the doc you want to find similarities to
+	/// <li> then call one of the like() calls to generate a similarity query
+	/// <li> call the searcher to find the similar docs
+	/// </ol>
+	/// <p/>
+	/// <h3>More Advanced Usage</h3>
+	/// <p/>
+	/// You may want to use <seealso cref="#setFieldNames setFieldNames(...)"/> so you can examine
+	/// multiple fields (e.g. body and title) for similarity.
+	/// <p/>
+	/// <p/>
+	/// Depending on the size of your index and the size and makeup of your documents you
+	/// may want to call the other set methods to control how the similarity queries are
+	/// generated:
+	/// <ul>
+	/// <li> <seealso cref="#setMinTermFreq setMinTermFreq(...)"/>
+	/// <li> <seealso cref="#setMinDocFreq setMinDocFreq(...)"/>
+	/// <li> <seealso cref="#setMaxDocFreq setMaxDocFreq(...)"/>
+	/// <li> <seealso cref="#setMaxDocFreqPct setMaxDocFreqPct(...)"/>
+	/// <li> <seealso cref="#setMinWordLen setMinWordLen(...)"/>
+	/// <li> <seealso cref="#setMaxWordLen setMaxWordLen(...)"/>
+	/// <li> <seealso cref="#setMaxQueryTerms setMaxQueryTerms(...)"/>
+	/// <li> <seealso cref="#setMaxNumTokensParsed setMaxNumTokensParsed(...)"/>
+	/// <li> <seealso cref="#setStopWords setStopWord(...)"/>
+	/// </ul>
+	/// <p/>
+	/// <hr>
+	/// <pre>
+	/// Changes: Mark Harwood 29/02/04
+	/// Some bugfixing, some refactoring, some optimisation.
+	/// - bugfix: retrieveTerms(int docNum) was not working for indexes without a termvector -added missing code
+	/// - bugfix: No significant terms being created for fields with a termvector - because
+	/// was only counting one occurrence per term/field pair in calculations(ie not including frequency info from TermVector)
+	/// - refactor: moved common code into isNoiseWord()
+	/// - optimise: when no termvector support available - used maxNumTermsParsed to limit amount of tokenization
+	/// </pre>
+	/// </summary>
+	public sealed class MoreLikeThis
+	{
+
+	  /// <summary>
+	  /// Default maximum number of tokens to parse in each example doc field that is not stored with TermVector support.
+	  /// </summary>
+	  /// <seealso cref= #getMaxNumTokensParsed </seealso>
+	  public const int DEFAULT_MAX_NUM_TOKENS_PARSED = 5000;
+
+	  /// <summary>
+	  /// Ignore terms with less than this frequency in the source doc.
+	  /// </summary>
+	  /// <seealso cref= #getMinTermFreq </seealso>
+	  /// <seealso cref= #setMinTermFreq </seealso>
+	  public const int DEFAULT_MIN_TERM_FREQ = 2;
+
+	  /// <summary>
+	  /// Ignore words which do not occur in at least this many docs.
+	  /// </summary>
+	  /// <seealso cref= #getMinDocFreq </seealso>
+	  /// <seealso cref= #setMinDocFreq </seealso>
+	  public const int DEFAULT_MIN_DOC_FREQ = 5;
+
+	  /// <summary>
+	  /// Ignore words which occur in more than this many docs.
+	  /// </summary>
+	  /// <seealso cref= #getMaxDocFreq </seealso>
+	  /// <seealso cref= #setMaxDocFreq </seealso>
+	  /// <seealso cref= #setMaxDocFreqPct </seealso>
+	  public static readonly int DEFAULT_MAX_DOC_FREQ = int.MaxValue;
+
+	  /// <summary>
+	  /// Boost terms in query based on score.
+	  /// </summary>
+	  /// <seealso cref= #isBoost </seealso>
+	  /// <seealso cref= #setBoost </seealso>
+	  public const bool DEFAULT_BOOST = false;
+
+	  /// <summary>
+	  /// Default field names. Null is used to specify that the field names should be looked
+	  /// up at runtime from the provided reader.
+	  /// </summary>
+	  public static readonly string[] DEFAULT_FIELD_NAMES = new string[]{"contents"};
+
+	  /// <summary>
+	  /// Ignore words less than this length or if 0 then this has no effect.
+	  /// </summary>
+	  /// <seealso cref= #getMinWordLen </seealso>
+	  /// <seealso cref= #setMinWordLen </seealso>
+	  public const int DEFAULT_MIN_WORD_LENGTH = 0;
+
+	  /// <summary>
+	  /// Ignore words greater than this length or if 0 then this has no effect.
+	  /// </summary>
+	  /// <seealso cref= #getMaxWordLen </seealso>
+	  /// <seealso cref= #setMaxWordLen </seealso>
+	  public const int DEFAULT_MAX_WORD_LENGTH = 0;
+
+	  /// <summary>
+	  /// Default set of stopwords.
+	  /// If null means to allow stop words.
+	  /// </summary>
+	  /// <seealso cref= #setStopWords </seealso>
+	  /// <seealso cref= #getStopWords </seealso>
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: public static final Set<?> DEFAULT_STOP_WORDS = null;
+	  public const HashSet<?> DEFAULT_STOP_WORDS = null;
+
+	  /// <summary>
+	  /// Current set of stop words.
+	  /// </summary>
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: private Set<?> stopWords = DEFAULT_STOP_WORDS;
+	  private HashSet<?> stopWords = DEFAULT_STOP_WORDS;
+
+	  /// <summary>
+	  /// Return a Query with no more than this many terms.
+	  /// </summary>
+	  /// <seealso cref= BooleanQuery#getMaxClauseCount </seealso>
+	  /// <seealso cref= #getMaxQueryTerms </seealso>
+	  /// <seealso cref= #setMaxQueryTerms </seealso>
+	  public const int DEFAULT_MAX_QUERY_TERMS = 25;
+
+	  /// <summary>
+	  /// Analyzer that will be used to parse the doc.
+	  /// </summary>
+	  private Analyzer analyzer = null;
+
+	  /// <summary>
+	  /// Ignore words less frequent that this.
+	  /// </summary>
+	  private int minTermFreq = DEFAULT_MIN_TERM_FREQ;
+
+	  /// <summary>
+	  /// Ignore words which do not occur in at least this many docs.
+	  /// </summary>
+	  private int minDocFreq = DEFAULT_MIN_DOC_FREQ;
+
+	  /// <summary>
+	  /// Ignore words which occur in more than this many docs.
+	  /// </summary>
+	  private int maxDocFreq = DEFAULT_MAX_DOC_FREQ;
+
+	  /// <summary>
+	  /// Should we apply a boost to the Query based on the scores?
+	  /// </summary>
+	  private bool boost = DEFAULT_BOOST;
+
+	  /// <summary>
+	  /// Field name we'll analyze.
+	  /// </summary>
+	  private string[] fieldNames = DEFAULT_FIELD_NAMES;
+
+	  /// <summary>
+	  /// The maximum number of tokens to parse in each example doc field that is not stored with TermVector support
+	  /// </summary>
+	  private int maxNumTokensParsed = DEFAULT_MAX_NUM_TOKENS_PARSED;
+
+	  /// <summary>
+	  /// Ignore words if less than this len.
+	  /// </summary>
+	  private int minWordLen = DEFAULT_MIN_WORD_LENGTH;
+
+	  /// <summary>
+	  /// Ignore words if greater than this len.
+	  /// </summary>
+	  private int maxWordLen = DEFAULT_MAX_WORD_LENGTH;
+
+	  /// <summary>
+	  /// Don't return a query longer than this.
+	  /// </summary>
+	  private int maxQueryTerms = DEFAULT_MAX_QUERY_TERMS;
+
+	  /// <summary>
+	  /// For idf() calculations.
+	  /// </summary>
+	  private TFIDFSimilarity similarity; // = new DefaultSimilarity();
+
+	  /// <summary>
+	  /// IndexReader to use
+	  /// </summary>
+	  private readonly IndexReader ir;
+
+	  /// <summary>
+	  /// Boost factor to use when boosting the terms
+	  /// </summary>
+	  private float boostFactor = 1;
+
+	  /// <summary>
+	  /// Returns the boost factor used when boosting terms
+	  /// </summary>
+	  /// <returns> the boost factor used when boosting terms </returns>
+	  /// <seealso cref= #setBoostFactor(float) </seealso>
+	  public float BoostFactor
+	  {
+		  get
+		  {
+			return boostFactor;
+		  }
+		  set
+		  {
+			this.boostFactor = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Constructor requiring an IndexReader.
+	  /// </summary>
+	  public MoreLikeThis(IndexReader ir) : this(ir, new DefaultSimilarity())
+	  {
+	  }
+
+	  public MoreLikeThis(IndexReader ir, TFIDFSimilarity sim)
+	  {
+		this.ir = ir;
+		this.similarity = sim;
+	  }
+
+
+	  public TFIDFSimilarity Similarity
+	  {
+		  get
+		  {
+			return similarity;
+		  }
+		  set
+		  {
+			this.similarity = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns an analyzer that will be used to parse source doc with. The default analyzer
+	  /// is not set.
+	  /// </summary>
+	  /// <returns> the analyzer that will be used to parse source doc with. </returns>
+	  public Analyzer Analyzer
+	  {
+		  get
+		  {
+			return analyzer;
+		  }
+		  set
+		  {
+			this.analyzer = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns the frequency below which terms will be ignored in the source doc. The default
+	  /// frequency is the <seealso cref="#DEFAULT_MIN_TERM_FREQ"/>.
+	  /// </summary>
+	  /// <returns> the frequency below which terms will be ignored in the source doc. </returns>
+	  public int MinTermFreq
+	  {
+		  get
+		  {
+			return minTermFreq;
+		  }
+		  set
+		  {
+			this.minTermFreq = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns the frequency at which words will be ignored which do not occur in at least this
+	  /// many docs. The default frequency is <seealso cref="#DEFAULT_MIN_DOC_FREQ"/>.
+	  /// </summary>
+	  /// <returns> the frequency at which words will be ignored which do not occur in at least this
+	  ///         many docs. </returns>
+	  public int MinDocFreq
+	  {
+		  get
+		  {
+			return minDocFreq;
+		  }
+		  set
+		  {
+			this.minDocFreq = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns the maximum frequency in which words may still appear.
+	  /// Words that appear in more than this many docs will be ignored. The default frequency is
+	  /// <seealso cref="#DEFAULT_MAX_DOC_FREQ"/>.
+	  /// </summary>
+	  /// <returns> get the maximum frequency at which words are still allowed,
+	  ///         words which occur in more docs than this are ignored. </returns>
+	  public int MaxDocFreq
+	  {
+		  get
+		  {
+			return maxDocFreq;
+		  }
+		  set
+		  {
+			this.maxDocFreq = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Set the maximum percentage in which words may still appear. Words that appear
+	  /// in more than this many percent of all docs will be ignored.
+	  /// </summary>
+	  /// <param name="maxPercentage"> the maximum percentage of documents (0-100) that a term may appear
+	  /// in to be still considered relevant </param>
+	  public int MaxDocFreqPct
+	  {
+		  set
+		  {
+			this.maxDocFreq = value * ir.numDocs() / 100;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns whether to boost terms in query based on "score" or not. The default is
+	  /// <seealso cref="#DEFAULT_BOOST"/>.
+	  /// </summary>
+	  /// <returns> whether to boost terms in query based on "score" or not. </returns>
+	  /// <seealso cref= #setBoost </seealso>
+	  public bool Boost
+	  {
+		  get
+		  {
+			return boost;
+		  }
+		  set
+		  {
+			this.boost = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns the field names that will be used when generating the 'More Like This' query.
+	  /// The default field names that will be used is <seealso cref="#DEFAULT_FIELD_NAMES"/>.
+	  /// </summary>
+	  /// <returns> the field names that will be used when generating the 'More Like This' query. </returns>
+	  public string[] FieldNames
+	  {
+		  get
+		  {
+			return fieldNames;
+		  }
+		  set
+		  {
+			this.fieldNames = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns the minimum word length below which words will be ignored. Set this to 0 for no
+	  /// minimum word length. The default is <seealso cref="#DEFAULT_MIN_WORD_LENGTH"/>.
+	  /// </summary>
+	  /// <returns> the minimum word length below which words will be ignored. </returns>
+	  public int MinWordLen
+	  {
+		  get
+		  {
+			return minWordLen;
+		  }
+		  set
+		  {
+			this.minWordLen = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Returns the maximum word length above which words will be ignored. Set this to 0 for no
+	  /// maximum word length. The default is <seealso cref="#DEFAULT_MAX_WORD_LENGTH"/>.
+	  /// </summary>
+	  /// <returns> the maximum word length above which words will be ignored. </returns>
+	  public int MaxWordLen
+	  {
+		  get
+		  {
+			return maxWordLen;
+		  }
+		  set
+		  {
+			this.maxWordLen = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Set the set of stopwords.
+	  /// Any word in this set is considered "uninteresting" and ignored.
+	  /// Even if your Analyzer allows stopwords, you might want to tell the MoreLikeThis code to ignore them, as
+	  /// for the purposes of document similarity it seems reasonable to assume that "a stop word is never interesting".
+	  /// </summary>
+	  /// <param name="stopWords"> set of stopwords, if null it means to allow stop words </param>
+	  /// <seealso cref= #getStopWords </seealso>
+	  public HashSet<T1> StopWords<T1>
+	  {
+		  set
+		  {
+			this.stopWords = value;
+		  }
+		  get
+		  {
+			return stopWords;
+		  }
+	  }
+
+
+
+	  /// <summary>
+	  /// Returns the maximum number of query terms that will be included in any generated query.
+	  /// The default is <seealso cref="#DEFAULT_MAX_QUERY_TERMS"/>.
+	  /// </summary>
+	  /// <returns> the maximum number of query terms that will be included in any generated query. </returns>
+	  public int MaxQueryTerms
+	  {
+		  get
+		  {
+			return maxQueryTerms;
+		  }
+		  set
+		  {
+			this.maxQueryTerms = value;
+		  }
+	  }
+
+
+	  /// <returns> The maximum number of tokens to parse in each example doc field that is not stored with TermVector support </returns>
+	  /// <seealso cref= #DEFAULT_MAX_NUM_TOKENS_PARSED </seealso>
+	  public int MaxNumTokensParsed
+	  {
+		  get
+		  {
+			return maxNumTokensParsed;
+		  }
+		  set
+		  {
+			maxNumTokensParsed = value;
+		  }
+	  }
+
+
+
+	  /// <summary>
+	  /// Return a query that will return docs like the passed lucene document ID.
+	  /// </summary>
+	  /// <param name="docNum"> the documentID of the lucene doc to generate the 'More Like This" query for. </param>
+	  /// <returns> a query that will return docs like the passed lucene document ID. </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public Query like(int docNum) throws IOException
+	  public Query like(int docNum)
+	  {
+		if (fieldNames == null)
+		{
+		  // gather list of valid fields from lucene
+		  ICollection<string> fields = MultiFields.getIndexedFields(ir);
+		  fieldNames = fields.toArray(new string[fields.Count]);
+		}
+
+		return createQuery(retrieveTerms(docNum));
+	  }
+
+	  /// <summary>
+	  /// Return a query that will return docs like the passed Reader.
+	  /// </summary>
+	  /// <returns> a query that will return docs like the passed Reader. </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public Query like(Reader r, String fieldName) throws IOException
+	  public Query like(Reader r, string fieldName)
+	  {
+		return createQuery(retrieveTerms(r, fieldName));
+	  }
+
+	  /// <summary>
+	  /// Create the More like query from a PriorityQueue
+	  /// </summary>
+	  private Query createQuery(PriorityQueue<object[]> q)
+	  {
+		BooleanQuery query = new BooleanQuery();
+		object cur;
+		int qterms = 0;
+		float bestScore = 0;
+
+		while ((cur = q.pop()) != null)
+		{
+		  object[] ar = (object[]) cur;
+		  TermQuery tq = new TermQuery(new Term((string) ar[1], (string) ar[0]));
+
+		  if (boost)
+		  {
+			if (qterms == 0)
+			{
+			  bestScore = ((float?) ar[2]);
+			}
+			float myScore = ((float?) ar[2]);
+
+			tq.Boost = boostFactor * myScore / bestScore;
+		  }
+
+		  try
+		  {
+			query.add(tq, BooleanClause.Occur.SHOULD);
+		  }
+		  catch (BooleanQuery.TooManyClauses)
+		  {
+			break;
+		  }
+
+		  qterms++;
+		  if (maxQueryTerms > 0 && qterms >= maxQueryTerms)
+		  {
+			break;
+		  }
+		}
+
+		return query;
+	  }
+
+	  /// <summary>
+	  /// Create a PriorityQueue from a word->tf map.
+	  /// </summary>
+	  /// <param name="words"> a map of words keyed on the word(String) with Int objects as the values. </param>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private org.apache.lucene.util.PriorityQueue<Object[]> createQueue(Map<String, Int> words) throws IOException
+	  private PriorityQueue<object[]> createQueue(IDictionary<string, Int> words)
+	  {
+		// have collected all words in doc and their freqs
+		int numDocs = ir.numDocs();
+		FreqQ res = new FreqQ(words.Count); // will order words by score
+
+		foreach (string word in words.Keys) // for every word
+		{
+		  int tf = words[word].x; // term freq in the source doc
+		  if (minTermFreq > 0 && tf < minTermFreq)
+		  {
+			continue; // filter out words that don't occur enough times in the source
+		  }
+
+		  // go through all the fields and find the largest document frequency
+		  string topField = fieldNames[0];
+		  int docFreq = 0;
+		  foreach (string fieldName in fieldNames)
+		  {
+			int freq = ir.docFreq(new Term(fieldName, word));
+			topField = (freq > docFreq) ? fieldName : topField;
+			docFreq = (freq > docFreq) ? freq : docFreq;
+		  }
+
+		  if (minDocFreq > 0 && docFreq < minDocFreq)
+		  {
+			continue; // filter out words that don't occur in enough docs
+		  }
+
+		  if (docFreq > maxDocFreq)
+		  {
+			continue; // filter out words that occur in too many docs
+		  }
+
+		  if (docFreq == 0)
+		  {
+			continue; // index update problem?
+		  }
+
+		  float idf = similarity.idf(docFreq, numDocs);
+		  float score = tf * idf;
+
+		  // only really need 1st 3 entries, other ones are for troubleshooting
+		  res.insertWithOverflow(new object[]{word, topField, score, idf, docFreq, tf}); // freq in all docs -  idf -  overall score -  the top field -  the word
+		}
+		return res;
+	  }
+
+	  /// <summary>
+	  /// Describe the parameters that control how the "more like this" query is formed.
+	  /// </summary>
+	  public string describeParams()
+	  {
+		StringBuilder sb = new StringBuilder();
+		sb.Append("\t").Append("maxQueryTerms  : ").Append(maxQueryTerms).Append("\n");
+		sb.Append("\t").Append("minWordLen     : ").Append(minWordLen).Append("\n");
+		sb.Append("\t").Append("maxWordLen     : ").Append(maxWordLen).Append("\n");
+		sb.Append("\t").Append("fieldNames     : ");
+		string delim = "";
+		foreach (string fieldName in fieldNames)
+		{
+		  sb.Append(delim).Append(fieldName);
+		  delim = ", ";
+		}
+		sb.Append("\n");
+		sb.Append("\t").Append("boost          : ").Append(boost).Append("\n");
+		sb.Append("\t").Append("minTermFreq    : ").Append(minTermFreq).Append("\n");
+		sb.Append("\t").Append("minDocFreq     : ").Append(minDocFreq).Append("\n");
+		return sb.ToString();
+	  }
+
+	  /// <summary>
+	  /// Find words for a more-like-this query former.
+	  /// </summary>
+	  /// <param name="docNum"> the id of the lucene document from which to find terms </param>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public org.apache.lucene.util.PriorityQueue<Object[]> retrieveTerms(int docNum) throws IOException
+	  public PriorityQueue<object[]> retrieveTerms(int docNum)
+	  {
+		IDictionary<string, Int> termFreqMap = new Dictionary<string, Int>();
+		foreach (string fieldName in fieldNames)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.Fields vectors = ir.getTermVectors(docNum);
+		  Fields vectors = ir.getTermVectors(docNum);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.Terms vector;
+		  Terms vector;
+		  if (vectors != null)
+		  {
+			vector = vectors.terms(fieldName);
+		  }
+		  else
+		  {
+			vector = null;
+		  }
+
+		  // field does not store term vector info
+		  if (vector == null)
+		  {
+			Document d = ir.document(docNum);
+			IndexableField[] fields = d.getFields(fieldName);
+			foreach (IndexableField field in fields)
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final String stringValue = field.stringValue();
+			  string stringValue = field.stringValue();
+			  if (stringValue != null)
+			  {
+				addTermFrequencies(new StringReader(stringValue), termFreqMap, fieldName);
+			  }
+			}
+		  }
+		  else
+		  {
+			addTermFrequencies(termFreqMap, vector);
+		  }
+		}
+
+		return createQueue(termFreqMap);
+	  }
+
+	  /// <summary>
+	  /// Adds terms and frequencies found in vector into the Map termFreqMap
+	  /// </summary>
+	  /// <param name="termFreqMap"> a Map of terms and their frequencies </param>
+	  /// <param name="vector"> List of terms and their frequencies for a doc/field </param>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private void addTermFrequencies(Map<String, Int> termFreqMap, org.apache.lucene.index.Terms vector) throws IOException
+	  private void addTermFrequencies(IDictionary<string, Int> termFreqMap, Terms vector)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.TermsEnum termsEnum = vector.iterator(null);
+		TermsEnum termsEnum = vector.iterator(null);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.CharsRef spare = new org.apache.lucene.util.CharsRef();
+		CharsRef spare = new CharsRef();
+		BytesRef text;
+		while ((text = termsEnum.next()) != null)
+		{
+		  UnicodeUtil.UTF8toUTF16(text, spare);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final String term = spare.toString();
+		  string term = spare.ToString();
+		  if (isNoiseWord(term))
+		  {
+			continue;
+		  }
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int freq = (int) termsEnum.totalTermFreq();
+		  int freq = (int) termsEnum.totalTermFreq();
+
+		  // increment frequency
+		  Int cnt = termFreqMap[term];
+		  if (cnt == null)
+		  {
+			cnt = new Int();
+			termFreqMap[term] = cnt;
+			cnt.x = freq;
+		  }
+		  else
+		  {
+			cnt.x += freq;
+		  }
+		}
+	  }
+
+	  /// <summary>
+	  /// Adds term frequencies found by tokenizing text from reader into the Map words
+	  /// </summary>
+	  /// <param name="r"> a source of text to be tokenized </param>
+	  /// <param name="termFreqMap"> a Map of terms and their frequencies </param>
+	  /// <param name="fieldName"> Used by analyzer for any special per-field analysis </param>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private void addTermFrequencies(Reader r, Map<String, Int> termFreqMap, String fieldName) throws IOException
+	  private void addTermFrequencies(Reader r, IDictionary<string, Int> termFreqMap, string fieldName)
+	  {
+		if (analyzer == null)
+		{
+		  throw new System.NotSupportedException("To use MoreLikeThis without " + "term vectors, you must provide an Analyzer");
+		}
+		TokenStream ts = analyzer.tokenStream(fieldName, r);
+		try
+		{
+		  int tokenCount = 0;
+		  // for every token
+		  CharTermAttribute termAtt = ts.addAttribute(typeof(CharTermAttribute));
+		  ts.reset();
+		  while (ts.incrementToken())
+		  {
+			string word = termAtt.ToString();
+			tokenCount++;
+			if (tokenCount > maxNumTokensParsed)
+			{
+			  break;
+			}
+			if (isNoiseWord(word))
+			{
+			  continue;
+			}
+
+			// increment frequency
+			Int cnt = termFreqMap[word];
+			if (cnt == null)
+			{
+			  termFreqMap[word] = new Int();
+			}
+			else
+			{
+			  cnt.x++;
+			}
+		  }
+		  ts.end();
+		}
+		finally
+		{
+		  IOUtils.closeWhileHandlingException(ts);
+		}
+	  }
+
+
+	  /// <summary>
+	  /// determines if the passed term is likely to be of interest in "more like" comparisons
+	  /// </summary>
+	  /// <param name="term"> The word being considered </param>
+	  /// <returns> true if should be ignored, false if should be used in further analysis </returns>
+	  private bool isNoiseWord(string term)
+	  {
+		int len = term.Length;
+		if (minWordLen > 0 && len < minWordLen)
+		{
+		  return true;
+		}
+		if (maxWordLen > 0 && len > maxWordLen)
+		{
+		  return true;
+		}
+		return stopWords != null && stopWords.Contains(term);
+	  }
+
+
+	  /// <summary>
+	  /// Find words for a more-like-this query former.
+	  /// The result is a priority queue of arrays with one entry for <b>every word</b> in the document.
+	  /// Each array has 6 elements.
+	  /// The elements are:
+	  /// <ol>
+	  /// <li> The word (String)
+	  /// <li> The top field that this word comes from (String)
+	  /// <li> The score for this word (Float)
+	  /// <li> The IDF value (Float)
+	  /// <li> The frequency of this word in the index (Integer)
+	  /// <li> The frequency of this word in the source document (Integer)
+	  /// </ol>
+	  /// This is a somewhat "advanced" routine, and in general only the 1st entry in the array is of interest.
+	  /// This method is exposed so that you can identify the "interesting words" in a document.
+	  /// For an easier method to call see <seealso cref="#retrieveInterestingTerms retrieveInterestingTerms()"/>.
+	  /// </summary>
+	  /// <param name="r"> the reader that has the content of the document </param>
+	  /// <param name="fieldName"> field passed to the analyzer to use when analyzing the content </param>
+	  /// <returns> the most interesting words in the document ordered by score, with the highest scoring, or best entry, first </returns>
+	  /// <seealso cref= #retrieveInterestingTerms </seealso>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public org.apache.lucene.util.PriorityQueue<Object[]> retrieveTerms(Reader r, String fieldName) throws IOException
+	  public PriorityQueue<object[]> retrieveTerms(Reader r, string fieldName)
+	  {
+		IDictionary<string, Int> words = new Dictionary<string, Int>();
+		addTermFrequencies(r, words, fieldName);
+		return createQueue(words);
+	  }
+
+	  /// <seealso cref= #retrieveInterestingTerms(java.io.Reader, String) </seealso>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public String[] retrieveInterestingTerms(int docNum) throws IOException
+	  public string[] retrieveInterestingTerms(int docNum)
+	  {
+		List<object> al = new List<object>(maxQueryTerms);
+		PriorityQueue<object[]> pq = retrieveTerms(docNum);
+		object cur;
+		int lim = maxQueryTerms; // have to be careful, retrieveTerms returns all words but that's probably not useful to our caller...
+		// we just want to return the top words
+		while (((cur = pq.pop()) != null) && lim-- > 0)
+		{
+		  object[] ar = (object[]) cur;
+		  al.Add(ar[0]); // the 1st entry is the interesting word
+		}
+		string[] res = new string[al.Count];
+		return al.toArray(res);
+	  }
+
+	  /// <summary>
+	  /// Convenience routine to make it easy to return the most interesting words in a document.
+	  /// More advanced users will call <seealso cref="#retrieveTerms(Reader, String) retrieveTerms()"/> directly.
+	  /// </summary>
+	  /// <param name="r"> the source document </param>
+	  /// <param name="fieldName"> field passed to analyzer to use when analyzing the content </param>
+	  /// <returns> the most interesting words in the document </returns>
+	  /// <seealso cref= #retrieveTerms(java.io.Reader, String) </seealso>
+	  /// <seealso cref= #setMaxQueryTerms </seealso>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public String[] retrieveInterestingTerms(Reader r, String fieldName) throws IOException
+	  public string[] retrieveInterestingTerms(Reader r, string fieldName)
+	  {
+		List<object> al = new List<object>(maxQueryTerms);
+		PriorityQueue<object[]> pq = retrieveTerms(r, fieldName);
+		object cur;
+		int lim = maxQueryTerms; // have to be careful, retrieveTerms returns all words but that's probably not useful to our caller...
+		// we just want to return the top words
+		while (((cur = pq.pop()) != null) && lim-- > 0)
+		{
+		  object[] ar = (object[]) cur;
+		  al.Add(ar[0]); // the 1st entry is the interesting word
+		}
+		string[] res = new string[al.Count];
+		return al.toArray(res);
+	  }
+
+	  /// <summary>
+	  /// PriorityQueue that orders words by score.
+	  /// </summary>
+	  private class FreqQ : PriorityQueue<object[]>
+	  {
+		internal FreqQ(int s) : base(s)
+		{
+		}
+
+		protected internal override bool lessThan(object[] aa, object[] bb)
+		{
+		  float? fa = (float?) aa[2];
+		  float? fb = (float?) bb[2];
+		  return fa > fb;
+		}
+	  }
+
+	  /// <summary>
+	  /// Use for frequencies and to avoid renewing Integers.
+	  /// </summary>
+	  private class Int
+	  {
+		internal int x;
+
+		internal Int()
+		{
+		  x = 1;
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Mlt/MoreLikeThisQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Mlt/MoreLikeThisQuery.cs b/src/Lucene.Net.Queries/Mlt/MoreLikeThisQuery.cs
new file mode 100644
index 0000000..d397720
--- /dev/null
+++ b/src/Lucene.Net.Queries/Mlt/MoreLikeThisQuery.cs
@@ -0,0 +1,297 @@
+using System.Collections.Generic;
+
+/*
+ * Created on 25-Jan-2006
+ */
+namespace org.apache.lucene.queries.mlt
+{
+
+	/*
+	 * 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.
+	 */
+
+	using Analyzer = org.apache.lucene.analysis.Analyzer;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using BooleanClause = org.apache.lucene.search.BooleanClause;
+	using BooleanQuery = org.apache.lucene.search.BooleanQuery;
+	using Query = org.apache.lucene.search.Query;
+
+
+	/// <summary>
+	/// A simple wrapper for MoreLikeThis for use in scenarios where a Query object is required eg
+	/// in custom QueryParser extensions. At query.rewrite() time the reader is used to construct the
+	/// actual MoreLikeThis object and obtain the real Query object.
+	/// </summary>
+	public class MoreLikeThisQuery : Query
+	{
+
+	  private string likeText;
+	  private string[] moreLikeFields;
+	  private Analyzer analyzer;
+	  private readonly string fieldName;
+	  private float percentTermsToMatch = 0.3f;
+	  private int minTermFrequency = 1;
+	  private int maxQueryTerms = 5;
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: private java.util.Set<?> stopWords = null;
+	  private HashSet<?> stopWords = null;
+	  private int minDocFreq = -1;
+
+	  /// <param name="moreLikeFields"> fields used for similarity measure </param>
+	  public MoreLikeThisQuery(string likeText, string[] moreLikeFields, Analyzer analyzer, string fieldName)
+	  {
+		this.likeText = likeText;
+		this.moreLikeFields = moreLikeFields;
+		this.analyzer = analyzer;
+		this.fieldName = fieldName;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.Query rewrite(org.apache.lucene.index.IndexReader reader) throws java.io.IOException
+	  public override Query rewrite(IndexReader reader)
+	  {
+		MoreLikeThis mlt = new MoreLikeThis(reader);
+
+		mlt.FieldNames = moreLikeFields;
+		mlt.Analyzer = analyzer;
+		mlt.MinTermFreq = minTermFrequency;
+		if (minDocFreq >= 0)
+		{
+		  mlt.MinDocFreq = minDocFreq;
+		}
+		mlt.MaxQueryTerms = maxQueryTerms;
+		mlt.StopWords = stopWords;
+		BooleanQuery bq = (BooleanQuery) mlt.like(new StringReader(likeText), fieldName);
+		BooleanClause[] clauses = bq.Clauses;
+		//make at least half the terms match
+		bq.MinimumNumberShouldMatch = (int)(clauses.Length * percentTermsToMatch);
+		return bq;
+	  }
+
+	  /* (non-Javadoc)
+	  * @see org.apache.lucene.search.Query#toString(java.lang.String)
+	  */
+	  public override string ToString(string field)
+	  {
+		return "like:" + likeText;
+	  }
+
+	  public virtual float PercentTermsToMatch
+	  {
+		  get
+		  {
+			return percentTermsToMatch;
+		  }
+		  set
+		  {
+			this.percentTermsToMatch = value;
+		  }
+	  }
+
+
+	  public virtual Analyzer Analyzer
+	  {
+		  get
+		  {
+			return analyzer;
+		  }
+		  set
+		  {
+			this.analyzer = value;
+		  }
+	  }
+
+
+	  public virtual string LikeText
+	  {
+		  get
+		  {
+			return likeText;
+		  }
+		  set
+		  {
+			this.likeText = value;
+		  }
+	  }
+
+
+	  public virtual int MaxQueryTerms
+	  {
+		  get
+		  {
+			return maxQueryTerms;
+		  }
+		  set
+		  {
+			this.maxQueryTerms = value;
+		  }
+	  }
+
+
+	  public virtual int MinTermFrequency
+	  {
+		  get
+		  {
+			return minTermFrequency;
+		  }
+		  set
+		  {
+			this.minTermFrequency = value;
+		  }
+	  }
+
+
+	  public virtual string[] MoreLikeFields
+	  {
+		  get
+		  {
+			return moreLikeFields;
+		  }
+		  set
+		  {
+			this.moreLikeFields = value;
+		  }
+	  }
+
+
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: public java.util.Set<?> getStopWords()
+	  public virtual HashSet<?> StopWords
+	  {
+		  get
+		  {
+			return stopWords;
+		  }
+		  set
+		  {
+			this.stopWords = value;
+		  }
+	  }
+
+
+	  public virtual int MinDocFreq
+	  {
+		  get
+		  {
+			return minDocFreq;
+		  }
+		  set
+		  {
+			this.minDocFreq = value;
+		  }
+	  }
+
+
+	  public override int GetHashCode()
+	  {
+		const int prime = 31;
+		int result = base.GetHashCode();
+		result = prime * result + ((analyzer == null) ? 0 : analyzer.GetHashCode());
+		result = prime * result + ((fieldName == null) ? 0 : fieldName.GetHashCode());
+		result = prime * result + ((likeText == null) ? 0 : likeText.GetHashCode());
+		result = prime * result + maxQueryTerms;
+		result = prime * result + minDocFreq;
+		result = prime * result + minTermFrequency;
+		result = prime * result + Arrays.GetHashCode(moreLikeFields);
+		result = prime * result + float.floatToIntBits(percentTermsToMatch);
+		result = prime * result + ((stopWords == null) ? 0 : stopWords.GetHashCode());
+		return result;
+	  }
+
+	  public override bool Equals(object obj)
+	  {
+		if (this == obj)
+		{
+			return true;
+		}
+		if (!base.Equals(obj))
+		{
+			return false;
+		}
+		if (this.GetType() != obj.GetType())
+		{
+			return false;
+		}
+		MoreLikeThisQuery other = (MoreLikeThisQuery) obj;
+		if (analyzer == null)
+		{
+		  if (other.analyzer != null)
+		  {
+			  return false;
+		  }
+		}
+		else if (!analyzer.Equals(other.analyzer))
+		{
+			return false;
+		}
+		if (fieldName == null)
+		{
+		  if (other.fieldName != null)
+		  {
+			  return false;
+		  }
+		}
+		else if (!fieldName.Equals(other.fieldName))
+		{
+			return false;
+		}
+		if (likeText == null)
+		{
+		  if (other.likeText != null)
+		  {
+			  return false;
+		  }
+		}
+		else if (!likeText.Equals(other.likeText))
+		{
+			return false;
+		}
+		if (maxQueryTerms != other.maxQueryTerms)
+		{
+			return false;
+		}
+		if (minDocFreq != other.minDocFreq)
+		{
+			return false;
+		}
+		if (minTermFrequency != other.minTermFrequency)
+		{
+			return false;
+		}
+		if (!Arrays.Equals(moreLikeFields, other.moreLikeFields))
+		{
+			return false;
+		}
+		if (float.floatToIntBits(percentTermsToMatch) != float.floatToIntBits(other.percentTermsToMatch))
+		{
+			return false;
+		}
+		if (stopWords == null)
+		{
+		  if (other.stopWords != null)
+		  {
+			  return false;
+		  }
+		}
+		else if (!stopWords.Equals(other.stopWords))
+		{
+			return false;
+		}
+		return true;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Properties/AssemblyInfo.cs b/src/Lucene.Net.Queries/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..d8e310e
--- /dev/null
+++ b/src/Lucene.Net.Queries/Properties/AssemblyInfo.cs
@@ -0,0 +1,35 @@
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Lucene.Net.Queries")]
+[assembly: AssemblyDescription("Filters and Queries that add to core Lucene")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Lucene.Net.Queries")]
+[assembly: AssemblyCopyright("Copyright ©  2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("76a14bc5-8f0f-4de4-b501-423d4c1a20a5")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]


[07/11] git commit: Skeleton porting of Lucene.Net.Queries

Posted by sy...@apache.org.
Skeleton porting of Lucene.Net.Queries


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

Branch: refs/heads/master
Commit: 882f487db71361a68ed4c78308f02bd0f82cf75b
Parents: 895be41
Author: Itamar Syn-Hershko <it...@code972.com>
Authored: Tue Sep 16 01:34:54 2014 +0300
Committer: Itamar Syn-Hershko <it...@code972.com>
Committed: Tue Sep 16 01:34:54 2014 +0300

----------------------------------------------------------------------
 src/Lucene.Net.Queries/BooleanFilter.cs         | 204 ++++
 src/Lucene.Net.Queries/BoostingQuery.cs         | 178 ++++
 src/Lucene.Net.Queries/ChainedFilter.cs         | 285 ++++++
 src/Lucene.Net.Queries/CommonTermsQuery.cs      | 526 ++++++++++
 src/Lucene.Net.Queries/CustomScoreProvider.cs   | 192 ++++
 src/Lucene.Net.Queries/CustomScoreQuery.cs      | 490 +++++++++
 src/Lucene.Net.Queries/FilterClause.cs          |  97 ++
 src/Lucene.Net.Queries/Function/BoostedQuery.cs | 287 ++++++
 .../Function/DocValues/BoolDocValues.cs         | 122 +++
 .../DocValues/DocTermsIndexDocValues.cs         | 234 +++++
 .../Function/DocValues/DoubleDocValues.cs       | 256 +++++
 .../Function/DocValues/FloatDocValues.cs        | 117 +++
 .../Function/DocValues/IntDocValues.cs          | 183 ++++
 .../Function/DocValues/LongDocValues.cs         | 193 ++++
 .../Function/DocValues/StrDocValues.cs          |  89 ++
 .../Function/FunctionQuery.cs                   | 270 +++++
 .../Function/FunctionValues.cs                  | 362 +++++++
 src/Lucene.Net.Queries/Function/ValueSource.cs  | 223 +++++
 .../Function/ValueSource/BoolFunction.cs        |  30 +
 .../Function/ValueSource/ByteFieldSource.cs     | 142 +++
 .../Function/ValueSource/BytesRefFieldSource.cs | 140 +++
 .../Function/ValueSource/ConstNumberSource.cs   |  34 +
 .../Function/ValueSource/ConstValueSource.cs    | 156 +++
 .../Function/ValueSource/DefFunction.cs         | 153 +++
 .../Function/ValueSource/DivFloatFunction.cs    |  44 +
 .../Function/ValueSource/DocFreqValueSource.cs  | 186 ++++
 .../ValueSource/DoubleConstValueSource.cs       | 166 ++++
 .../Function/ValueSource/DoubleFieldSource.cs   | 149 +++
 .../Function/ValueSource/DualFloatFunction.cs   | 121 +++
 .../Function/ValueSource/EnumFieldSource.cs     | 343 +++++++
 .../Function/ValueSource/FieldCacheSource.cs    |  77 ++
 .../Function/ValueSource/FloatFieldSource.cs    | 152 +++
 .../Function/ValueSource/IDFValueSource.cs      |  85 ++
 .../Function/ValueSource/IfFunction.cs          | 186 ++++
 .../Function/ValueSource/IntFieldSource.cs      | 183 ++++
 .../ValueSource/JoinDocFreqValueSource.cs       | 134 +++
 .../Function/ValueSource/LinearFloatFunction.cs | 113 +++
 .../Function/ValueSource/LiteralValueSource.cs  | 117 +++
 .../Function/ValueSource/LongFieldSource.cs     | 184 ++++
 .../Function/ValueSource/MaxDocValueSource.cs   |  70 ++
 .../Function/ValueSource/MaxFloatFunction.cs    |  53 +
 .../Function/ValueSource/MinFloatFunction.cs    |  53 +
 .../Function/ValueSource/MultiBoolFunction.cs   | 148 +++
 .../Function/ValueSource/MultiFloatFunction.cs  | 146 +++
 .../Function/ValueSource/MultiFunction.cs       | 161 +++
 .../Function/ValueSource/MultiValueSource.cs    |  32 +
 .../Function/ValueSource/NormValueSource.cs     | 125 +++
 .../Function/ValueSource/NumDocsValueSource.cs  |  63 ++
 .../Function/ValueSource/OrdFieldSource.cs      | 175 ++++
 .../Function/ValueSource/PowFloatFunction.cs    |  48 +
 .../ValueSource/ProductFloatFunction.cs         |  47 +
 .../Function/ValueSource/QueryValueSource.cs    | 328 +++++++
 .../ValueSource/RangeMapFloatFunction.cs        | 138 +++
 .../ValueSource/ReciprocalFloatFunction.cs      | 130 +++
 .../ValueSource/ReverseOrdFieldSource.cs        | 135 +++
 .../Function/ValueSource/ScaleFloatFunction.cs  | 200 ++++
 .../Function/ValueSource/ShortFieldSource.cs    | 137 +++
 .../Function/ValueSource/SimpleBoolFunction.cs  | 108 ++
 .../Function/ValueSource/SimpleFloatFunction.cs |  71 ++
 .../Function/ValueSource/SingleFunction.cs      |  67 ++
 .../Function/ValueSource/SumFloatFunction.cs    |  46 +
 .../ValueSource/SumTotalTermFreqValueSource.cs  | 132 +++
 .../Function/ValueSource/TFValueSource.cs       | 197 ++++
 .../Function/ValueSource/TermFreqValueSource.cs | 186 ++++
 .../ValueSource/TotalTermFreqValueSource.cs     | 127 +++
 .../Function/ValueSource/VectorValueSource.cs   | 293 ++++++
 .../Function/ValueSourceScorer.cs               | 126 +++
 .../Lucene.Net.Queries.csproj                   | 129 +++
 src/Lucene.Net.Queries/Mlt/MoreLikeThis.cs      | 981 +++++++++++++++++++
 src/Lucene.Net.Queries/Mlt/MoreLikeThisQuery.cs | 297 ++++++
 .../Properties/AssemblyInfo.cs                  |  35 +
 src/Lucene.Net.Queries/TermFilter.cs            | 139 +++
 src/Lucene.Net.Queries/TermsFilter.cs           | 439 +++++++++
 73 files changed, 12765 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/BooleanFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/BooleanFilter.cs b/src/Lucene.Net.Queries/BooleanFilter.cs
new file mode 100644
index 0000000..bcbc6fb
--- /dev/null
+++ b/src/Lucene.Net.Queries/BooleanFilter.cs
@@ -0,0 +1,204 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Util;
+using org.apache.lucene.queries;
+
+namespace Lucene.Net.Queries
+{
+
+	/*
+	 * 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.
+	 */
+    /// <summary>
+	/// A container Filter that allows Boolean composition of Filters.
+	/// Filters are allocated into one of three logical constructs;
+	/// SHOULD, MUST NOT, MUST
+	/// The results Filter BitSet is constructed as follows:
+	/// SHOULD Filters are OR'd together
+	/// The resulting Filter is NOT'd with the NOT Filters
+	/// The resulting Filter is AND'd with the MUST Filters
+	/// </summary>
+	public class BooleanFilter : Filter, IEnumerable<FilterClause>
+	{
+
+	  private readonly IList<FilterClause> clauses_Renamed = new List<FilterClause>();
+
+	  /// <summary>
+	  /// Returns the a DocIdSetIterator representing the Boolean composition
+	  /// of the filters that have been added.
+	  /// </summary>
+	  public override DocIdSet GetDocIdSet(AtomicReaderContext context, Bits acceptDocs)
+	  {
+		FixedBitSet res = null;
+		AtomicReader reader = context.reader();
+
+		bool hasShouldClauses = false;
+		foreach (FilterClause fc in clauses_Renamed)
+		{
+		  if (fc.Occur == BooleanClause.Occur.SHOULD)
+		  {
+			hasShouldClauses = true;
+			DocIdSetIterator disi = getDISI(fc.Filter, context);
+			if (disi == null)
+			{
+				continue;
+			}
+			if (res == null)
+			{
+			  res = new FixedBitSet(reader.MaxDoc());
+			}
+			res.or(disi);
+		  }
+		}
+		if (hasShouldClauses && res == null)
+		{
+		  return null;
+		}
+
+		foreach (FilterClause fc in clauses_Renamed)
+		{
+		  if (fc.Occur == BooleanClause.Occur.MUST_NOT)
+		  {
+			if (res == null)
+			{
+			  Debug.Assert(!hasShouldClauses);
+			  res = new FixedBitSet(reader.MaxDoc());
+			  res.Set(0, reader.MaxDoc()); // NOTE: may set bits on deleted docs
+			}
+
+              DocIdSetIterator disi = GetDISI(fc.Filter, context);
+			if (disi != null)
+			{
+			  res.AndNot(disi);
+			}
+		  }
+		}
+
+		foreach (FilterClause fc in clauses_Renamed)
+		{
+		  if (fc.Occur == BooleanClause.Occur.MUST)
+		  {
+			DocIdSetIterator disi = GetDISI(fc.Filter, context);
+			if (disi == null)
+			{
+			  return null; // no documents can match
+			}
+			if (res == null)
+			{
+			  res = new FixedBitSet(reader.maxDoc());
+			  res.or(disi);
+			}
+			else
+			{
+			  res.and(disi);
+			}
+		  }
+		}
+
+		return BitsFilteredDocIdSet.wrap(res, acceptDocs);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private static org.apache.lucene.search.DocIdSetIterator getDISI(org.apache.lucene.search.Filter filter, org.apache.lucene.index.AtomicReaderContext context) throws java.io.IOException
+	  private static DocIdSetIterator GetDISI(Filter filter, AtomicReaderContext context)
+	  {
+		// we dont pass acceptDocs, we will filter at the end using an additional filter
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.DocIdSet set = filter.getDocIdSet(context, null);
+		DocIdSet set = filter.GetDocIdSet(context, null);
+		return set == null ? null : set.GetEnumerator();
+	  }
+
+	  /// <summary>
+	  /// Adds a new FilterClause to the Boolean Filter container </summary>
+	  /// <param name="filterClause"> A FilterClause object containing a Filter and an Occur parameter </param>
+	  public virtual void Add(FilterClause filterClause)
+	  {
+		clauses_Renamed.Add(filterClause);
+	  }
+
+	  public void Add(Filter filter, BooleanClause.Occur occur)
+	  {
+		Add(new FilterClause(filter, occur));
+	  }
+
+	  /// <summary>
+	  /// Returns the list of clauses
+	  /// </summary>
+	  public virtual IList<FilterClause> clauses()
+	  {
+		return clauses_Renamed;
+	  }
+
+	  /// <summary>
+	  /// Returns an iterator on the clauses in this query. It implements the <seealso cref="Iterable"/> interface to
+	  /// make it possible to do:
+	  /// <pre class="prettyprint">for (FilterClause clause : booleanFilter) {}</pre>
+	  /// </summary>
+	  public IEnumerator<FilterClause> GetEnumerator()
+	  {
+		return clauses().GetEnumerator();
+	  }
+
+	  public override bool Equals(object obj)
+	  {
+		if (this == obj)
+		{
+		  return true;
+		}
+
+		if ((obj == null) || (obj.GetType() != this.GetType()))
+		{
+		  return false;
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final BooleanFilter other = (BooleanFilter)obj;
+		BooleanFilter other = (BooleanFilter)obj;
+		return clauses_Renamed.Equals(other.clauses_Renamed);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return 657153718 ^ clauses_Renamed.GetHashCode();
+	  }
+
+	  /// <summary>
+	  /// Prints a user-readable version of this Filter. </summary>
+	  public override string ToString()
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final StringBuilder buffer = new StringBuilder("BooleanFilter(");
+		StringBuilder buffer = new StringBuilder("BooleanFilter(");
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int minLen = buffer.length();
+		int minLen = buffer.Length;
+		foreach (FilterClause c in clauses_Renamed)
+		{
+		  if (buffer.Length > minLen)
+		  {
+			buffer.Append(' ');
+		  }
+		  buffer.Append(c);
+		}
+		return buffer.Append(')').ToString();
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/BoostingQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/BoostingQuery.cs b/src/Lucene.Net.Queries/BoostingQuery.cs
new file mode 100644
index 0000000..203a2ae
--- /dev/null
+++ b/src/Lucene.Net.Queries/BoostingQuery.cs
@@ -0,0 +1,178 @@
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using org.apache.lucene.search;
+
+	/// <summary>
+	/// The BoostingQuery class can be used to effectively demote results that match a given query. 
+	/// Unlike the "NOT" clause, this still selects documents that contain undesirable terms, 
+	/// but reduces their overall score:
+	/// 
+	///     Query balancedQuery = new BoostingQuery(positiveQuery, negativeQuery, 0.01f);
+	/// In this scenario the positiveQuery contains the mandatory, desirable criteria which is used to 
+	/// select all matching documents, and the negativeQuery contains the undesirable elements which 
+	/// are simply used to lessen the scores. Documents that match the negativeQuery have their score 
+	/// multiplied by the supplied "boost" parameter, so this should be less than 1 to achieve a 
+	/// demoting effect
+	/// 
+	/// This code was originally made available here: [WWW] http://marc.theaimsgroup.com/?l=lucene-user&m=108058407130459&w=2
+	/// and is documented here: http://wiki.apache.org/lucene-java/CommunityContributions
+	/// </summary>
+	public class BoostingQuery : Query
+	{
+		private readonly float boost; // the amount to boost by
+		private readonly Query match; // query to match
+		private readonly Query context; // boost when matches too
+
+		public BoostingQuery(Query match, Query context, float boost)
+		{
+		  this.match = match;
+		  this.context = context.clone(); // clone before boost
+		  this.boost = boost;
+		  this.context.Boost = 0.0f; // ignore context-only matches
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Query rewrite(org.apache.lucene.index.IndexReader reader) throws java.io.IOException
+		public override Query rewrite(IndexReader reader)
+		{
+		  BooleanQuery result = new BooleanQueryAnonymousInnerClassHelper(this);
+
+		  result.add(match, BooleanClause.Occur.MUST);
+		  result.add(context, BooleanClause.Occur.SHOULD);
+
+		  return result;
+		}
+
+		private class BooleanQueryAnonymousInnerClassHelper : BooleanQuery
+		{
+			private readonly BoostingQuery outerInstance;
+
+			public BooleanQueryAnonymousInnerClassHelper(BoostingQuery outerInstance)
+			{
+				this.outerInstance = outerInstance;
+			}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Weight createWeight(IndexSearcher searcher) throws java.io.IOException
+			public override Weight createWeight(IndexSearcher searcher)
+			{
+			  return new BooleanWeightAnonymousInnerClassHelper(this, searcher);
+			}
+
+			private class BooleanWeightAnonymousInnerClassHelper : BooleanWeight
+			{
+				private readonly BooleanQueryAnonymousInnerClassHelper outerInstance;
+
+				public BooleanWeightAnonymousInnerClassHelper(BooleanQueryAnonymousInnerClassHelper outerInstance, IndexSearcher searcher) : base(searcher, false)
+				{
+					this.outerInstance = outerInstance;
+				}
+
+
+				public override float coord(int overlap, int max)
+				{
+				  switch (overlap)
+				  {
+
+				  case 1: // matched only one clause
+					return 1.0f; // use the score as-is
+
+				  case 2: // matched both clauses
+					return outerInstance.outerInstance.boost; // multiply by boost
+
+				  default:
+					return 0.0f;
+
+				  }
+				}
+			}
+		}
+
+		public override int GetHashCode()
+		{
+		  const int prime = 31;
+		  int result = base.GetHashCode();
+		  result = prime * result + float.floatToIntBits(boost);
+		  result = prime * result + ((context == null) ? 0 : context.GetHashCode());
+		  result = prime * result + ((match == null) ? 0 : match.GetHashCode());
+		  return result;
+		}
+
+		public override bool Equals(object obj)
+		{
+		  if (this == obj)
+		  {
+			return true;
+		  }
+		  if (obj == null)
+		  {
+			return false;
+		  }
+		  if (this.GetType() != obj.GetType())
+		  {
+			return false;
+		  }
+
+		  if (!base.Equals(obj))
+		  {
+			return false;
+		  }
+
+		  BoostingQuery other = (BoostingQuery) obj;
+		  if (float.floatToIntBits(boost) != float.floatToIntBits(other.boost))
+		  {
+			return false;
+		  }
+
+		  if (context == null)
+		  {
+			if (other.context != null)
+			{
+			  return false;
+			}
+		  }
+		  else if (!context.Equals(other.context))
+		  {
+			return false;
+		  }
+
+		  if (match == null)
+		  {
+			if (other.match != null)
+			{
+			  return false;
+			}
+		  }
+		  else if (!match.Equals(other.match))
+		  {
+			return false;
+		  }
+		  return true;
+		}
+
+		public override string ToString(string field)
+		{
+		  return match.ToString(field) + "/" + context.ToString(field);
+		}
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/ChainedFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/ChainedFilter.cs b/src/Lucene.Net.Queries/ChainedFilter.cs
new file mode 100644
index 0000000..c6aec63
--- /dev/null
+++ b/src/Lucene.Net.Queries/ChainedFilter.cs
@@ -0,0 +1,285 @@
+using System.Text;
+
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+
+	using AtomicReader = org.apache.lucene.index.AtomicReader;
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using BitsFilteredDocIdSet = org.apache.lucene.search.BitsFilteredDocIdSet;
+	using DocIdSet = org.apache.lucene.search.DocIdSet;
+	using DocIdSetIterator = org.apache.lucene.search.DocIdSetIterator;
+	using Filter = org.apache.lucene.search.Filter;
+	using Bits = org.apache.lucene.util.Bits;
+	using FixedBitSet = org.apache.lucene.util.FixedBitSet;
+
+	/// <summary>
+	/// <para>
+	/// Allows multiple <seealso cref="Filter"/>s to be chained.
+	/// Logical operations such as <b>NOT</b> and <b>XOR</b>
+	/// are applied between filters. One operation can be used
+	/// for all filters, or a specific operation can be declared
+	/// for each filter.
+	/// </para>
+	/// <para>
+	/// Order in which filters are called depends on
+	/// the position of the filter in the chain. It's probably
+	/// more efficient to place the most restrictive filters
+	/// /least computationally-intensive filters first.
+	/// </para>
+	/// </summary>
+	public class ChainedFilter : Filter
+	{
+
+	  public const int OR = 0;
+	  public const int AND = 1;
+	  public const int ANDNOT = 2;
+	  public const int XOR = 3;
+	  /// <summary>
+	  /// Logical operation when none is declared. Defaults to OR.
+	  /// </summary>
+	  public const int DEFAULT = OR;
+
+	  /// <summary>
+	  /// The filter chain
+	  /// </summary>
+	  private Filter[] chain = null;
+
+	  private int[] logicArray;
+
+	  private int logic = -1;
+
+	  /// <summary>
+	  /// Ctor.
+	  /// </summary>
+	  /// <param name="chain"> The chain of filters </param>
+	  public ChainedFilter(Filter[] chain)
+	  {
+		this.chain = chain;
+	  }
+
+	  /// <summary>
+	  /// Ctor.
+	  /// </summary>
+	  /// <param name="chain"> The chain of filters </param>
+	  /// <param name="logicArray"> Logical operations to apply between filters </param>
+	  public ChainedFilter(Filter[] chain, int[] logicArray)
+	  {
+		this.chain = chain;
+		this.logicArray = logicArray;
+	  }
+
+	  /// <summary>
+	  /// Ctor.
+	  /// </summary>
+	  /// <param name="chain"> The chain of filters </param>
+	  /// <param name="logic"> Logical operation to apply to ALL filters </param>
+	  public ChainedFilter(Filter[] chain, int logic)
+	  {
+		this.chain = chain;
+		this.logic = logic;
+	  }
+
+	  /// <summary>
+	  /// <seealso cref="Filter#getDocIdSet"/>.
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.DocIdSet getDocIdSet(org.apache.lucene.index.AtomicReaderContext context, org.apache.lucene.util.Bits acceptDocs) throws java.io.IOException
+	  public override DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs)
+	  {
+		int[] index = new int[1]; // use array as reference to modifiable int;
+		index[0] = 0; // an object attribute would not be thread safe.
+		if (logic != -1)
+		{
+		  return BitsFilteredDocIdSet.wrap(getDocIdSet(context, logic, index), acceptDocs);
+		}
+		else if (logicArray != null)
+		{
+		  return BitsFilteredDocIdSet.wrap(getDocIdSet(context, logicArray, index), acceptDocs);
+		}
+
+		return BitsFilteredDocIdSet.wrap(getDocIdSet(context, DEFAULT, index), acceptDocs);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private org.apache.lucene.search.DocIdSetIterator getDISI(org.apache.lucene.search.Filter filter, org.apache.lucene.index.AtomicReaderContext context) throws java.io.IOException
+	  private DocIdSetIterator getDISI(Filter filter, AtomicReaderContext context)
+	  {
+		// we dont pass acceptDocs, we will filter at the end using an additional filter
+		DocIdSet docIdSet = filter.getDocIdSet(context, null);
+		if (docIdSet == null)
+		{
+		  return DocIdSetIterator.empty();
+		}
+		else
+		{
+		  DocIdSetIterator iter = docIdSet.GetEnumerator();
+		  if (iter == null)
+		  {
+			return DocIdSetIterator.empty();
+		  }
+		  else
+		  {
+			return iter;
+		  }
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private org.apache.lucene.util.FixedBitSet initialResult(org.apache.lucene.index.AtomicReaderContext context, int logic, int[] index) throws java.io.IOException
+	  private FixedBitSet initialResult(AtomicReaderContext context, int logic, int[] index)
+	  {
+		AtomicReader reader = context.reader();
+		FixedBitSet result = new FixedBitSet(reader.maxDoc());
+		if (logic == AND)
+		{
+		  result.or(getDISI(chain[index[0]], context));
+		  ++index[0];
+		}
+		else if (logic == ANDNOT)
+		{
+		  result.or(getDISI(chain[index[0]], context));
+		  result.flip(0, reader.maxDoc()); // NOTE: may set bits for deleted docs.
+		  ++index[0];
+		}
+		return result;
+	  }
+
+	  /// <summary>
+	  /// Delegates to each filter in the chain.
+	  /// </summary>
+	  /// <param name="context"> AtomicReaderContext </param>
+	  /// <param name="logic"> Logical operation </param>
+	  /// <returns> DocIdSet </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private org.apache.lucene.search.DocIdSet getDocIdSet(org.apache.lucene.index.AtomicReaderContext context, int logic, int[] index) throws java.io.IOException
+	  private DocIdSet getDocIdSet(AtomicReaderContext context, int logic, int[] index)
+	  {
+		FixedBitSet result = initialResult(context, logic, index);
+		for (; index[0] < chain.Length; index[0]++)
+		{
+		  // we dont pass acceptDocs, we will filter at the end using an additional filter
+		  doChain(result, logic, chain[index[0]].getDocIdSet(context, null));
+		}
+		return result;
+	  }
+
+	  /// <summary>
+	  /// Delegates to each filter in the chain.
+	  /// </summary>
+	  /// <param name="context"> AtomicReaderContext </param>
+	  /// <param name="logic"> Logical operation </param>
+	  /// <returns> DocIdSet </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private org.apache.lucene.search.DocIdSet getDocIdSet(org.apache.lucene.index.AtomicReaderContext context, int[] logic, int[] index) throws java.io.IOException
+	  private DocIdSet getDocIdSet(AtomicReaderContext context, int[] logic, int[] index)
+	  {
+		if (logic.Length != chain.Length)
+		{
+		  throw new System.ArgumentException("Invalid number of elements in logic array");
+		}
+
+		FixedBitSet result = initialResult(context, logic[0], index);
+		for (; index[0] < chain.Length; index[0]++)
+		{
+		  // we dont pass acceptDocs, we will filter at the end using an additional filter
+		  doChain(result, logic[index[0]], chain[index[0]].getDocIdSet(context, null));
+		}
+		return result;
+	  }
+
+	  public override string ToString()
+	  {
+		StringBuilder sb = new StringBuilder();
+		sb.Append("ChainedFilter: [");
+		foreach (Filter aChain in chain)
+		{
+		  sb.Append(aChain);
+		  sb.Append(' ');
+		}
+		sb.Append(']');
+		return sb.ToString();
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private void doChain(org.apache.lucene.util.FixedBitSet result, int logic, org.apache.lucene.search.DocIdSet dis) throws java.io.IOException
+	  private void doChain(FixedBitSet result, int logic, DocIdSet dis)
+	  {
+		if (dis is FixedBitSet)
+		{
+		  // optimized case for FixedBitSets
+		  switch (logic)
+		  {
+			case OR:
+			  result.or((FixedBitSet) dis);
+			  break;
+			case AND:
+			  result.and((FixedBitSet) dis);
+			  break;
+			case ANDNOT:
+			  result.andNot((FixedBitSet) dis);
+			  break;
+			case XOR:
+			  result.xor((FixedBitSet) dis);
+			  break;
+			default:
+			  doChain(result, DEFAULT, dis);
+			  break;
+		  }
+		}
+		else
+		{
+		  DocIdSetIterator disi;
+		  if (dis == null)
+		  {
+			disi = DocIdSetIterator.empty();
+		  }
+		  else
+		  {
+			disi = dis.GetEnumerator();
+			if (disi == null)
+			{
+			  disi = DocIdSetIterator.empty();
+			}
+		  }
+
+		  switch (logic)
+		  {
+			case OR:
+			  result.or(disi);
+			  break;
+			case AND:
+			  result.and(disi);
+			  break;
+			case ANDNOT:
+			  result.andNot(disi);
+			  break;
+			case XOR:
+			  result.xor(disi);
+			  break;
+			default:
+			  doChain(result, DEFAULT, dis);
+			  break;
+		  }
+		}
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/CommonTermsQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/CommonTermsQuery.cs b/src/Lucene.Net.Queries/CommonTermsQuery.cs
new file mode 100644
index 0000000..0d78a68
--- /dev/null
+++ b/src/Lucene.Net.Queries/CommonTermsQuery.cs
@@ -0,0 +1,526 @@
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using Fields = org.apache.lucene.index.Fields;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using Term = org.apache.lucene.index.Term;
+	using TermContext = org.apache.lucene.index.TermContext;
+	using Terms = org.apache.lucene.index.Terms;
+	using TermsEnum = org.apache.lucene.index.TermsEnum;
+	using BooleanClause = org.apache.lucene.search.BooleanClause;
+	using Occur = org.apache.lucene.search.BooleanClause.Occur;
+	using BooleanQuery = org.apache.lucene.search.BooleanQuery;
+	using Query = org.apache.lucene.search.Query;
+	using TermQuery = org.apache.lucene.search.TermQuery;
+	using Similarity = org.apache.lucene.search.similarities.Similarity;
+	using ToStringUtils = org.apache.lucene.util.ToStringUtils;
+
+
+	/// <summary>
+	/// A query that executes high-frequency terms in a optional sub-query to prevent
+	/// slow queries due to "common" terms like stopwords. This query
+	/// builds 2 queries off the <seealso cref="#add(Term) added"/> terms: low-frequency
+	/// terms are added to a required boolean clause and high-frequency terms are
+	/// added to an optional boolean clause. The optional clause is only executed if
+	/// the required "low-frequency" clause matches. Scores produced by this query
+	/// will be slightly different than plain <seealso cref="BooleanQuery"/> scorer mainly due to
+	/// differences in the <seealso cref="Similarity#coord(int,int) number of leaf queries"/>
+	/// in the required boolean clause. In most cases, high-frequency terms are
+	/// unlikely to significantly contribute to the document score unless at least
+	/// one of the low-frequency terms are matched.  This query can improve
+	/// query execution times significantly if applicable.
+	/// <para>
+	/// <seealso cref="CommonTermsQuery"/> has several advantages over stopword filtering at
+	/// index or query time since a term can be "classified" based on the actual
+	/// document frequency in the index and can prevent slow queries even across
+	/// domains without specialized stopword files.
+	/// </para>
+	/// <para>
+	/// <b>Note:</b> if the query only contains high-frequency terms the query is
+	/// rewritten into a plain conjunction query ie. all high-frequency terms need to
+	/// match in order to match a document.
+	/// </para>
+	/// </summary>
+	public class CommonTermsQuery : Query
+	{
+	  /*
+	   * TODO maybe it would make sense to abstract this even further and allow to
+	   * rewrite to dismax rather than boolean. Yet, this can already be subclassed
+	   * to do so.
+	   */
+	  protected internal readonly IList<Term> terms = new List<Term>();
+	  protected internal readonly bool disableCoord;
+	  protected internal readonly float maxTermFrequency;
+	  protected internal readonly BooleanClause.Occur lowFreqOccur;
+	  protected internal readonly BooleanClause.Occur highFreqOccur;
+	  protected internal float lowFreqBoost = 1.0f;
+	  protected internal float highFreqBoost = 1.0f;
+	  protected internal float lowFreqMinNrShouldMatch = 0;
+	  protected internal float highFreqMinNrShouldMatch = 0;
+
+	  /// <summary>
+	  /// Creates a new <seealso cref="CommonTermsQuery"/>
+	  /// </summary>
+	  /// <param name="highFreqOccur">
+	  ///          <seealso cref="Occur"/> used for high frequency terms </param>
+	  /// <param name="lowFreqOccur">
+	  ///          <seealso cref="Occur"/> used for low frequency terms </param>
+	  /// <param name="maxTermFrequency">
+	  ///          a value in [0..1) (or absolute number >=1) representing the
+	  ///          maximum threshold of a terms document frequency to be considered a
+	  ///          low frequency term. </param>
+	  /// <exception cref="IllegalArgumentException">
+	  ///           if <seealso cref="Occur#MUST_NOT"/> is pass as lowFreqOccur or
+	  ///           highFreqOccur </exception>
+	  public CommonTermsQuery(BooleanClause.Occur highFreqOccur, BooleanClause.Occur lowFreqOccur, float maxTermFrequency) : this(highFreqOccur, lowFreqOccur, maxTermFrequency, false)
+	  {
+	  }
+
+	  /// <summary>
+	  /// Creates a new <seealso cref="CommonTermsQuery"/>
+	  /// </summary>
+	  /// <param name="highFreqOccur">
+	  ///          <seealso cref="Occur"/> used for high frequency terms </param>
+	  /// <param name="lowFreqOccur">
+	  ///          <seealso cref="Occur"/> used for low frequency terms </param>
+	  /// <param name="maxTermFrequency">
+	  ///          a value in [0..1) (or absolute number >=1) representing the
+	  ///          maximum threshold of a terms document frequency to be considered a
+	  ///          low frequency term. </param>
+	  /// <param name="disableCoord">
+	  ///          disables <seealso cref="Similarity#coord(int,int)"/> in scoring for the low
+	  ///          / high frequency sub-queries </param>
+	  /// <exception cref="IllegalArgumentException">
+	  ///           if <seealso cref="Occur#MUST_NOT"/> is pass as lowFreqOccur or
+	  ///           highFreqOccur </exception>
+	  public CommonTermsQuery(BooleanClause.Occur highFreqOccur, BooleanClause.Occur lowFreqOccur, float maxTermFrequency, bool disableCoord)
+	  {
+		if (highFreqOccur == BooleanClause.Occur.MUST_NOT)
+		{
+		  throw new System.ArgumentException("highFreqOccur should be MUST or SHOULD but was MUST_NOT");
+		}
+		if (lowFreqOccur == BooleanClause.Occur.MUST_NOT)
+		{
+		  throw new System.ArgumentException("lowFreqOccur should be MUST or SHOULD but was MUST_NOT");
+		}
+		this.disableCoord = disableCoord;
+		this.highFreqOccur = highFreqOccur;
+		this.lowFreqOccur = lowFreqOccur;
+		this.maxTermFrequency = maxTermFrequency;
+	  }
+
+	  /// <summary>
+	  /// Adds a term to the <seealso cref="CommonTermsQuery"/>
+	  /// </summary>
+	  /// <param name="term">
+	  ///          the term to add </param>
+	  public virtual void add(Term term)
+	  {
+		if (term == null)
+		{
+		  throw new System.ArgumentException("Term must not be null");
+		}
+		this.terms.Add(term);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.Query rewrite(org.apache.lucene.index.IndexReader reader) throws java.io.IOException
+	  public override Query rewrite(IndexReader reader)
+	  {
+		if (this.terms.Count == 0)
+		{
+		  return new BooleanQuery();
+		}
+		else if (this.terms.Count == 1)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.Query tq = newTermQuery(this.terms.get(0), null);
+		  Query tq = newTermQuery(this.terms[0], null);
+		  tq.Boost = Boost;
+		  return tq;
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.util.List<org.apache.lucene.index.AtomicReaderContext> leaves = reader.leaves();
+		IList<AtomicReaderContext> leaves = reader.leaves();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int maxDoc = reader.maxDoc();
+		int maxDoc = reader.maxDoc();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.TermContext[] contextArray = new org.apache.lucene.index.TermContext[terms.size()];
+		TermContext[] contextArray = new TermContext[terms.Count];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.Term[] queryTerms = this.terms.toArray(new org.apache.lucene.index.Term[0]);
+		Term[] queryTerms = this.terms.ToArray();
+		collectTermContext(reader, leaves, contextArray, queryTerms);
+		return buildQuery(maxDoc, contextArray, queryTerms);
+	  }
+
+	  protected internal virtual int calcLowFreqMinimumNumberShouldMatch(int numOptional)
+	  {
+		return minNrShouldMatch(lowFreqMinNrShouldMatch, numOptional);
+	  }
+
+	  protected internal virtual int calcHighFreqMinimumNumberShouldMatch(int numOptional)
+	  {
+		return minNrShouldMatch(highFreqMinNrShouldMatch, numOptional);
+	  }
+
+	  private int minNrShouldMatch(float minNrShouldMatch, int numOptional)
+	  {
+		if (minNrShouldMatch >= 1.0f || minNrShouldMatch == 0.0f)
+		{
+		  return (int) minNrShouldMatch;
+		}
+		return Math.Round(minNrShouldMatch * numOptional);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: protected org.apache.lucene.search.Query buildQuery(final int maxDoc, final org.apache.lucene.index.TermContext[] contextArray, final org.apache.lucene.index.Term[] queryTerms)
+	  protected internal virtual Query buildQuery(int maxDoc, TermContext[] contextArray, Term[] queryTerms)
+	  {
+		BooleanQuery lowFreq = new BooleanQuery(disableCoord);
+		BooleanQuery highFreq = new BooleanQuery(disableCoord);
+		highFreq.Boost = highFreqBoost;
+		lowFreq.Boost = lowFreqBoost;
+		BooleanQuery query = new BooleanQuery(true);
+		for (int i = 0; i < queryTerms.Length; i++)
+		{
+		  TermContext termContext = contextArray[i];
+		  if (termContext == null)
+		  {
+			lowFreq.add(newTermQuery(queryTerms[i], null), lowFreqOccur);
+		  }
+		  else
+		  {
+			if ((maxTermFrequency >= 1f && termContext.docFreq() > maxTermFrequency) || (termContext.docFreq() > (int) Math.Ceiling(maxTermFrequency * (float) maxDoc)))
+			{
+			  highFreq.add(newTermQuery(queryTerms[i], termContext), highFreqOccur);
+			}
+			else
+			{
+			  lowFreq.add(newTermQuery(queryTerms[i], termContext), lowFreqOccur);
+			}
+		  }
+
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int numLowFreqClauses = lowFreq.clauses().size();
+		int numLowFreqClauses = lowFreq.clauses().size();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int numHighFreqClauses = highFreq.clauses().size();
+		int numHighFreqClauses = highFreq.clauses().size();
+		if (lowFreqOccur == BooleanClause.Occur.SHOULD && numLowFreqClauses > 0)
+		{
+		  int minMustMatch = calcLowFreqMinimumNumberShouldMatch(numLowFreqClauses);
+		  lowFreq.MinimumNumberShouldMatch = minMustMatch;
+		}
+		if (highFreqOccur == BooleanClause.Occur.SHOULD && numHighFreqClauses > 0)
+		{
+		  int minMustMatch = calcHighFreqMinimumNumberShouldMatch(numHighFreqClauses);
+		  highFreq.MinimumNumberShouldMatch = minMustMatch;
+		}
+		if (lowFreq.clauses().Empty)
+		{
+		  /*
+		   * if lowFreq is empty we rewrite the high freq terms in a conjunction to
+		   * prevent slow queries.
+		   */
+		  if (highFreq.MinimumNumberShouldMatch == 0 && highFreqOccur != BooleanClause.Occur.MUST)
+		  {
+			foreach (BooleanClause booleanClause in highFreq)
+			{
+				booleanClause.Occur = BooleanClause.Occur.MUST;
+			}
+		  }
+		  highFreq.Boost = Boost;
+		  return highFreq;
+		}
+		else if (highFreq.clauses().Empty)
+		{
+		  // only do low freq terms - we don't have high freq terms
+		  lowFreq.Boost = Boost;
+		  return lowFreq;
+		}
+		else
+		{
+		  query.add(highFreq, BooleanClause.Occur.SHOULD);
+		  query.add(lowFreq, BooleanClause.Occur.MUST);
+		  query.Boost = Boost;
+		  return query;
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void collectTermContext(org.apache.lucene.index.IndexReader reader, java.util.List<org.apache.lucene.index.AtomicReaderContext> leaves, org.apache.lucene.index.TermContext[] contextArray, org.apache.lucene.index.Term[] queryTerms) throws java.io.IOException
+	  public virtual void collectTermContext(IndexReader reader, IList<AtomicReaderContext> leaves, TermContext[] contextArray, Term[] queryTerms)
+	  {
+		TermsEnum termsEnum = null;
+		foreach (AtomicReaderContext context in leaves)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.Fields fields = context.reader().fields();
+		  Fields fields = context.reader().fields();
+		  if (fields == null)
+		  {
+			// reader has no fields
+			continue;
+		  }
+		  for (int i = 0; i < queryTerms.Length; i++)
+		  {
+			Term term = queryTerms[i];
+			TermContext termContext = contextArray[i];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.Terms terms = fields.terms(term.field());
+			Terms terms = fields.terms(term.field());
+			if (terms == null)
+			{
+			  // field does not exist
+			  continue;
+			}
+			termsEnum = terms.iterator(termsEnum);
+			Debug.Assert(termsEnum != null);
+
+			if (termsEnum == TermsEnum.EMPTY)
+			{
+				continue;
+			}
+			if (termsEnum.seekExact(term.bytes()))
+			{
+			  if (termContext == null)
+			  {
+				contextArray[i] = new TermContext(reader.Context, termsEnum.termState(), context.ord, termsEnum.docFreq(), termsEnum.totalTermFreq());
+			  }
+			  else
+			  {
+				termContext.register(termsEnum.termState(), context.ord, termsEnum.docFreq(), termsEnum.totalTermFreq());
+			  }
+
+			}
+
+		  }
+		}
+	  }
+
+	  /// <summary>
+	  /// Returns true iff <seealso cref="Similarity#coord(int,int)"/> is disabled in scoring
+	  /// for the high and low frequency query instance. The top level query will
+	  /// always disable coords.
+	  /// </summary>
+	  public virtual bool CoordDisabled
+	  {
+		  get
+		  {
+			return disableCoord;
+		  }
+	  }
+
+	  /// <summary>
+	  /// Specifies a minimum number of the low frequent optional BooleanClauses which must be
+	  /// satisfied in order to produce a match on the low frequency terms query
+	  /// part. This method accepts a float value in the range [0..1) as a fraction
+	  /// of the actual query terms in the low frequent clause or a number
+	  /// <tt>&gt;=1</tt> as an absolut number of clauses that need to match.
+	  /// 
+	  /// <para>
+	  /// By default no optional clauses are necessary for a match (unless there are
+	  /// no required clauses). If this method is used, then the specified number of
+	  /// clauses is required.
+	  /// </para>
+	  /// </summary>
+	  /// <param name="min">
+	  ///          the number of optional clauses that must match </param>
+	  public virtual float LowFreqMinimumNumberShouldMatch
+	  {
+		  set
+		  {
+			this.lowFreqMinNrShouldMatch = value;
+		  }
+		  get
+		  {
+			return lowFreqMinNrShouldMatch;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// Specifies a minimum number of the high frequent optional BooleanClauses which must be
+	  /// satisfied in order to produce a match on the low frequency terms query
+	  /// part. This method accepts a float value in the range [0..1) as a fraction
+	  /// of the actual query terms in the low frequent clause or a number
+	  /// <tt>&gt;=1</tt> as an absolut number of clauses that need to match.
+	  /// 
+	  /// <para>
+	  /// By default no optional clauses are necessary for a match (unless there are
+	  /// no required clauses). If this method is used, then the specified number of
+	  /// clauses is required.
+	  /// </para>
+	  /// </summary>
+	  /// <param name="min">
+	  ///          the number of optional clauses that must match </param>
+	  public virtual float HighFreqMinimumNumberShouldMatch
+	  {
+		  set
+		  {
+			this.highFreqMinNrShouldMatch = value;
+		  }
+		  get
+		  {
+			return highFreqMinNrShouldMatch;
+		  }
+	  }
+
+
+	  public override void extractTerms(HashSet<Term> terms)
+	  {
+		terms.addAll(this.terms);
+	  }
+
+	  public override string ToString(string field)
+	  {
+		StringBuilder buffer = new StringBuilder();
+		bool needParens = (Boost != 1.0) || (LowFreqMinimumNumberShouldMatch > 0);
+		if (needParens)
+		{
+		  buffer.Append("(");
+		}
+		for (int i = 0; i < terms.Count; i++)
+		{
+		  Term t = terms[i];
+		  buffer.Append(newTermQuery(t, null).ToString());
+
+		  if (i != terms.Count - 1)
+		  {
+			  buffer.Append(", ");
+		  }
+		}
+		if (needParens)
+		{
+		  buffer.Append(")");
+		}
+		if (LowFreqMinimumNumberShouldMatch > 0 || HighFreqMinimumNumberShouldMatch > 0)
+		{
+		  buffer.Append('~');
+		  buffer.Append("(");
+		  buffer.Append(LowFreqMinimumNumberShouldMatch);
+		  buffer.Append(HighFreqMinimumNumberShouldMatch);
+		  buffer.Append(")");
+		}
+		if (Boost != 1.0f)
+		{
+		  buffer.Append(ToStringUtils.boost(Boost));
+		}
+		return buffer.ToString();
+	  }
+
+	  public override int GetHashCode()
+	  {
+		const int prime = 31;
+		int result = base.GetHashCode();
+		result = prime * result + (disableCoord ? 1231 : 1237);
+		result = prime * result + float.floatToIntBits(highFreqBoost);
+		result = prime * result + ((highFreqOccur == null) ? 0 : highFreqOccur.GetHashCode());
+		result = prime * result + float.floatToIntBits(lowFreqBoost);
+		result = prime * result + ((lowFreqOccur == null) ? 0 : lowFreqOccur.GetHashCode());
+		result = prime * result + float.floatToIntBits(maxTermFrequency);
+		result = prime * result + float.floatToIntBits(lowFreqMinNrShouldMatch);
+		result = prime * result + float.floatToIntBits(highFreqMinNrShouldMatch);
+		result = prime * result + ((terms == null) ? 0 : terms.GetHashCode());
+		return result;
+	  }
+
+	  public override bool Equals(object obj)
+	  {
+		if (this == obj)
+		{
+			return true;
+		}
+		if (!base.Equals(obj))
+		{
+			return false;
+		}
+		if (this.GetType() != obj.GetType())
+		{
+			return false;
+		}
+		CommonTermsQuery other = (CommonTermsQuery) obj;
+		if (disableCoord != other.disableCoord)
+		{
+			return false;
+		}
+		if (float.floatToIntBits(highFreqBoost) != float.floatToIntBits(other.highFreqBoost))
+		{
+			return false;
+		}
+		if (highFreqOccur != other.highFreqOccur)
+		{
+			return false;
+		}
+		if (float.floatToIntBits(lowFreqBoost) != float.floatToIntBits(other.lowFreqBoost))
+		{
+			return false;
+		}
+		if (lowFreqOccur != other.lowFreqOccur)
+		{
+			return false;
+		}
+		if (float.floatToIntBits(maxTermFrequency) != float.floatToIntBits(other.maxTermFrequency))
+		{
+			return false;
+		}
+		if (lowFreqMinNrShouldMatch != other.lowFreqMinNrShouldMatch)
+		{
+			return false;
+		}
+		if (highFreqMinNrShouldMatch != other.highFreqMinNrShouldMatch)
+		{
+			return false;
+		}
+		if (terms == null)
+		{
+		  if (other.terms != null)
+		  {
+			  return false;
+		  }
+		}
+		else if (!terms.Equals(other.terms))
+		{
+			return false;
+		}
+		return true;
+	  }
+
+	  /// <summary>
+	  /// Builds a new TermQuery instance.
+	  /// <para>This is intended for subclasses that wish to customize the generated queries.</para> </summary>
+	  /// <param name="term"> term </param>
+	  /// <param name="context"> the TermContext to be used to create the low level term query. Can be <code>null</code>. </param>
+	  /// <returns> new TermQuery instance </returns>
+	  protected internal virtual Query newTermQuery(Term term, TermContext context)
+	  {
+		return context == null ? new TermQuery(term) : new TermQuery(term, context);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/CustomScoreProvider.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/CustomScoreProvider.cs b/src/Lucene.Net.Queries/CustomScoreProvider.cs
new file mode 100644
index 0000000..5491c86
--- /dev/null
+++ b/src/Lucene.Net.Queries/CustomScoreProvider.cs
@@ -0,0 +1,192 @@
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader; // for javadocs
+	using FunctionQuery = org.apache.lucene.queries.function.FunctionQuery;
+	using Explanation = org.apache.lucene.search.Explanation;
+	using FieldCache = org.apache.lucene.search.FieldCache; // for javadocs
+
+	/// <summary>
+	/// An instance of this subclass should be returned by
+	/// <seealso cref="CustomScoreQuery#getCustomScoreProvider"/>, if you want
+	/// to modify the custom score calculation of a <seealso cref="CustomScoreQuery"/>.
+	/// <para>Since Lucene 2.9, queries operate on each segment of an index separately,
+	/// so the protected <seealso cref="#context"/> field can be used to resolve doc IDs,
+	/// as the supplied <code>doc</code> ID is per-segment and without knowledge
+	/// of the IndexReader you cannot access the document or <seealso cref="FieldCache"/>.
+	/// 
+	/// @lucene.experimental
+	/// @since 2.9.2
+	/// </para>
+	/// </summary>
+	public class CustomScoreProvider
+	{
+
+	  protected internal readonly AtomicReaderContext context;
+
+	  /// <summary>
+	  /// Creates a new instance of the provider class for the given <seealso cref="IndexReader"/>.
+	  /// </summary>
+	  public CustomScoreProvider(AtomicReaderContext context)
+	  {
+		this.context = context;
+	  }
+
+	  /// <summary>
+	  /// Compute a custom score by the subQuery score and a number of 
+	  /// <seealso cref="org.apache.lucene.queries.function.FunctionQuery"/> scores.
+	  /// <para> 
+	  /// Subclasses can override this method to modify the custom score.  
+	  /// </para>
+	  /// <para>
+	  /// If your custom scoring is different than the default herein you 
+	  /// should override at least one of the two customScore() methods.
+	  /// If the number of <seealso cref="FunctionQuery function queries"/> is always &lt; 2 it is 
+	  /// sufficient to override the other 
+	  /// <seealso cref="#customScore(int, float, float) customScore()"/> 
+	  /// method, which is simpler. 
+	  /// </para>
+	  /// <para>
+	  /// The default computation herein is a multiplication of given scores:
+	  /// <pre>
+	  ///     ModifiedScore = valSrcScore * valSrcScores[0] * valSrcScores[1] * ...
+	  /// </pre>
+	  /// 
+	  /// </para>
+	  /// </summary>
+	  /// <param name="doc"> id of scored doc. </param>
+	  /// <param name="subQueryScore"> score of that doc by the subQuery. </param>
+	  /// <param name="valSrcScores"> scores of that doc by the <seealso cref="FunctionQuery"/>. </param>
+	  /// <returns> custom score. </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public float customScore(int doc, float subQueryScore, float valSrcScores[]) throws java.io.IOException
+	  public virtual float customScore(int doc, float subQueryScore, float[] valSrcScores)
+	  {
+		if (valSrcScores.Length == 1)
+		{
+		  return customScore(doc, subQueryScore, valSrcScores[0]);
+		}
+		if (valSrcScores.Length == 0)
+		{
+		  return customScore(doc, subQueryScore, 1);
+		}
+		float score = subQueryScore;
+		foreach (float valSrcScore in valSrcScores)
+		{
+		  score *= valSrcScore;
+		}
+		return score;
+	  }
+
+	  /// <summary>
+	  /// Compute a custom score by the subQuery score and the <seealso cref="FunctionQuery"/> score.
+	  /// <para> 
+	  /// Subclasses can override this method to modify the custom score.
+	  /// </para>
+	  /// <para>
+	  /// If your custom scoring is different than the default herein you 
+	  /// should override at least one of the two customScore() methods.
+	  /// If the number of <seealso cref="FunctionQuery function queries"/> is always &lt; 2 it is 
+	  /// sufficient to override this customScore() method, which is simpler. 
+	  /// </para>
+	  /// <para>
+	  /// The default computation herein is a multiplication of the two scores:
+	  /// <pre>
+	  ///     ModifiedScore = subQueryScore * valSrcScore
+	  /// </pre>
+	  /// 
+	  /// </para>
+	  /// </summary>
+	  /// <param name="doc"> id of scored doc. </param>
+	  /// <param name="subQueryScore"> score of that doc by the subQuery. </param>
+	  /// <param name="valSrcScore"> score of that doc by the <seealso cref="FunctionQuery"/>. </param>
+	  /// <returns> custom score. </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public float customScore(int doc, float subQueryScore, float valSrcScore) throws java.io.IOException
+	  public virtual float customScore(int doc, float subQueryScore, float valSrcScore)
+	  {
+		return subQueryScore * valSrcScore;
+	  }
+
+	  /// <summary>
+	  /// Explain the custom score.
+	  /// Whenever overriding <seealso cref="#customScore(int, float, float[])"/>, 
+	  /// this method should also be overridden to provide the correct explanation
+	  /// for the part of the custom scoring.
+	  /// </summary>
+	  /// <param name="doc"> doc being explained. </param>
+	  /// <param name="subQueryExpl"> explanation for the sub-query part. </param>
+	  /// <param name="valSrcExpls"> explanation for the value source part. </param>
+	  /// <returns> an explanation for the custom score </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public org.apache.lucene.search.Explanation customExplain(int doc, org.apache.lucene.search.Explanation subQueryExpl, org.apache.lucene.search.Explanation valSrcExpls[]) throws java.io.IOException
+	  public virtual Explanation customExplain(int doc, Explanation subQueryExpl, Explanation[] valSrcExpls)
+	  {
+		if (valSrcExpls.Length == 1)
+		{
+		  return customExplain(doc, subQueryExpl, valSrcExpls[0]);
+		}
+		if (valSrcExpls.Length == 0)
+		{
+		  return subQueryExpl;
+		}
+		float valSrcScore = 1;
+		foreach (Explanation valSrcExpl in valSrcExpls)
+		{
+		  valSrcScore *= valSrcExpl.Value;
+		}
+		Explanation exp = new Explanation(valSrcScore * subQueryExpl.Value, "custom score: product of:");
+		exp.addDetail(subQueryExpl);
+		foreach (Explanation valSrcExpl in valSrcExpls)
+		{
+		  exp.addDetail(valSrcExpl);
+		}
+		return exp;
+	  }
+
+	  /// <summary>
+	  /// Explain the custom score.
+	  /// Whenever overriding <seealso cref="#customScore(int, float, float)"/>, 
+	  /// this method should also be overridden to provide the correct explanation
+	  /// for the part of the custom scoring.
+	  /// </summary>
+	  /// <param name="doc"> doc being explained. </param>
+	  /// <param name="subQueryExpl"> explanation for the sub-query part. </param>
+	  /// <param name="valSrcExpl"> explanation for the value source part. </param>
+	  /// <returns> an explanation for the custom score </returns>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public org.apache.lucene.search.Explanation customExplain(int doc, org.apache.lucene.search.Explanation subQueryExpl, org.apache.lucene.search.Explanation valSrcExpl) throws java.io.IOException
+	  public virtual Explanation customExplain(int doc, Explanation subQueryExpl, Explanation valSrcExpl)
+	  {
+		float valSrcScore = 1;
+		if (valSrcExpl != null)
+		{
+		  valSrcScore *= valSrcExpl.Value;
+		}
+		Explanation exp = new Explanation(valSrcScore * subQueryExpl.Value, "custom score: product of:");
+		exp.addDetail(subQueryExpl);
+		exp.addDetail(valSrcExpl);
+		return exp;
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/CustomScoreQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/CustomScoreQuery.cs b/src/Lucene.Net.Queries/CustomScoreQuery.cs
new file mode 100644
index 0000000..91c2597
--- /dev/null
+++ b/src/Lucene.Net.Queries/CustomScoreQuery.cs
@@ -0,0 +1,490 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using Term = org.apache.lucene.index.Term;
+	using FunctionQuery = org.apache.lucene.queries.function.FunctionQuery;
+	using ValueSource = org.apache.lucene.queries.function.ValueSource;
+	using ComplexExplanation = org.apache.lucene.search.ComplexExplanation;
+	using Explanation = org.apache.lucene.search.Explanation;
+	using Query = org.apache.lucene.search.Query;
+	using Weight = org.apache.lucene.search.Weight;
+	using Scorer = org.apache.lucene.search.Scorer;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using Bits = org.apache.lucene.util.Bits;
+	using ToStringUtils = org.apache.lucene.util.ToStringUtils;
+
+	/// <summary>
+	/// Query that sets document score as a programmatic function of several (sub) scores:
+	/// <ol>
+	///    <li>the score of its subQuery (any query)</li>
+	///    <li>(optional) the score of its <seealso cref="FunctionQuery"/> (or queries).</li>
+	/// </ol>
+	/// Subclasses can modify the computation by overriding <seealso cref="#getCustomScoreProvider"/>.
+	/// 
+	/// @lucene.experimental
+	/// </summary>
+	public class CustomScoreQuery : Query
+	{
+
+	  private Query subQuery;
+	  private Query[] scoringQueries; // never null (empty array if there are no valSrcQueries).
+	  private bool strict = false; // if true, valueSource part of query does not take part in weights normalization.
+
+	  /// <summary>
+	  /// Create a CustomScoreQuery over input subQuery. </summary>
+	  /// <param name="subQuery"> the sub query whose scored is being customized. Must not be null.  </param>
+	  public CustomScoreQuery(Query subQuery) : this(subQuery, new FunctionQuery[0])
+	  {
+	  }
+
+	  /// <summary>
+	  /// Create a CustomScoreQuery over input subQuery and a <seealso cref="org.apache.lucene.queries.function.FunctionQuery"/>. </summary>
+	  /// <param name="subQuery"> the sub query whose score is being customized. Must not be null. </param>
+	  /// <param name="scoringQuery"> a value source query whose scores are used in the custom score
+	  /// computation.  This parameter is optional - it can be null. </param>
+	  public CustomScoreQuery(Query subQuery, FunctionQuery scoringQuery) : this(subQuery, scoringQuery != null ? new FunctionQuery[] {scoringQuery} : new FunctionQuery[0]); / / don't want an array that contains a single null..
+	  {
+	  }
+
+	  /// <summary>
+	  /// Create a CustomScoreQuery over input subQuery and a <seealso cref="org.apache.lucene.queries.function.FunctionQuery"/>. </summary>
+	  /// <param name="subQuery"> the sub query whose score is being customized. Must not be null. </param>
+	  /// <param name="scoringQueries"> value source queries whose scores are used in the custom score
+	  /// computation.  This parameter is optional - it can be null or even an empty array. </param>
+	  public CustomScoreQuery(Query subQuery, params FunctionQuery[] scoringQueries)
+	  {
+		this.subQuery = subQuery;
+		this.scoringQueries = scoringQueries != null? scoringQueries : new Query[0];
+		if (subQuery == null)
+		{
+			throw new System.ArgumentException("<subquery> must not be null!");
+		}
+	  }
+
+	  /*(non-Javadoc) @see org.apache.lucene.search.Query#rewrite(org.apache.lucene.index.IndexReader) */
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.Query rewrite(org.apache.lucene.index.IndexReader reader) throws java.io.IOException
+	  public override Query rewrite(IndexReader reader)
+	  {
+		CustomScoreQuery clone = null;
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.Query sq = subQuery.rewrite(reader);
+		Query sq = subQuery.rewrite(reader);
+		if (sq != subQuery)
+		{
+		  clone = clone();
+		  clone.subQuery = sq;
+		}
+
+		for (int i = 0; i < scoringQueries.Length; i++)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.Query v = scoringQueries[i].rewrite(reader);
+		  Query v = scoringQueries[i].rewrite(reader);
+		  if (v != scoringQueries[i])
+		  {
+			if (clone == null)
+			{
+				clone = clone();
+			}
+			clone.scoringQueries[i] = v;
+		  }
+		}
+
+		return (clone == null) ? this : clone;
+	  }
+
+	  /*(non-Javadoc) @see org.apache.lucene.search.Query#extractTerms(java.util.Set) */
+	  public override void extractTerms(HashSet<Term> terms)
+	  {
+		subQuery.extractTerms(terms);
+		foreach (Query scoringQuery in scoringQueries)
+		{
+		  scoringQuery.extractTerms(terms);
+		}
+	  }
+
+	  /*(non-Javadoc) @see org.apache.lucene.search.Query#clone() */
+	  public override CustomScoreQuery clone()
+	  {
+		CustomScoreQuery clone = (CustomScoreQuery)base.clone();
+		clone.subQuery = subQuery.clone();
+		clone.scoringQueries = new Query[scoringQueries.Length];
+		for (int i = 0; i < scoringQueries.Length; i++)
+		{
+		  clone.scoringQueries[i] = scoringQueries[i].clone();
+		}
+		return clone;
+	  }
+
+	  /* (non-Javadoc) @see org.apache.lucene.search.Query#toString(java.lang.String) */
+	  public override string ToString(string field)
+	  {
+		StringBuilder sb = (new StringBuilder(name())).Append("(");
+		sb.Append(subQuery.ToString(field));
+		foreach (Query scoringQuery in scoringQueries)
+		{
+		  sb.Append(", ").Append(scoringQuery.ToString(field));
+		}
+		sb.Append(")");
+		sb.Append(strict?" STRICT" : "");
+		return sb.ToString() + ToStringUtils.boost(Boost);
+	  }
+
+	  /// <summary>
+	  /// Returns true if <code>o</code> is equal to this. </summary>
+	  public override bool Equals(object o)
+	  {
+		if (this == o)
+		{
+		  return true;
+		}
+		if (!base.Equals(o))
+		{
+		  return false;
+		}
+		if (this.GetType() != o.GetType())
+		{
+		  return false;
+		}
+		CustomScoreQuery other = (CustomScoreQuery)o;
+		if (this.Boost != other.Boost || !this.subQuery.Equals(other.subQuery) || this.strict != other.strict || this.scoringQueries.Length != other.scoringQueries.Length)
+		{
+		  return false;
+		}
+		return Arrays.Equals(scoringQueries, other.scoringQueries);
+	  }
+
+	  /// <summary>
+	  /// Returns a hash code value for this object. </summary>
+	  public override int GetHashCode()
+	  {
+		return (this.GetType().GetHashCode() + subQuery.GetHashCode() + Arrays.GetHashCode(scoringQueries)) ^ float.floatToIntBits(Boost) ^ (strict ? 1234 : 4321);
+	  }
+
+	  /// <summary>
+	  /// Returns a <seealso cref="CustomScoreProvider"/> that calculates the custom scores
+	  /// for the given <seealso cref="IndexReader"/>. The default implementation returns a default
+	  /// implementation as specified in the docs of <seealso cref="CustomScoreProvider"/>.
+	  /// @since 2.9.2
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: protected CustomScoreProvider getCustomScoreProvider(org.apache.lucene.index.AtomicReaderContext context) throws java.io.IOException
+	  protected internal virtual CustomScoreProvider getCustomScoreProvider(AtomicReaderContext context)
+	  {
+		return new CustomScoreProvider(context);
+	  }
+
+	  //=========================== W E I G H T ============================
+
+	  private class CustomWeight : Weight
+	  {
+		  private readonly CustomScoreQuery outerInstance;
+
+		internal Weight subQueryWeight;
+		internal Weight[] valSrcWeights;
+		internal bool qStrict;
+		internal float queryWeight;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public CustomWeight(org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+		public CustomWeight(CustomScoreQuery outerInstance, IndexSearcher searcher)
+		{
+			this.outerInstance = outerInstance;
+		  this.subQueryWeight = outerInstance.subQuery.createWeight(searcher);
+		  this.valSrcWeights = new Weight[outerInstance.scoringQueries.Length];
+		  for (int i = 0; i < outerInstance.scoringQueries.Length; i++)
+		  {
+			this.valSrcWeights[i] = outerInstance.scoringQueries[i].createWeight(searcher);
+		  }
+		  this.qStrict = outerInstance.strict;
+		}
+
+		/*(non-Javadoc) @see org.apache.lucene.search.Weight#getQuery() */
+		public override Query Query
+		{
+			get
+			{
+			  return outerInstance;
+			}
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float getValueForNormalization() throws java.io.IOException
+		public override float ValueForNormalization
+		{
+			get
+			{
+			  float sum = subQueryWeight.ValueForNormalization;
+			  foreach (Weight valSrcWeight in valSrcWeights)
+			  {
+				if (qStrict)
+				{
+				  valSrcWeight.ValueForNormalization; // do not include ValueSource part in the query normalization
+				}
+				else
+				{
+				  sum += valSrcWeight.ValueForNormalization;
+				}
+			  }
+			  return sum;
+			}
+		}
+
+		/*(non-Javadoc) @see org.apache.lucene.search.Weight#normalize(float) */
+		public override void normalize(float norm, float topLevelBoost)
+		{
+		  // note we DONT incorporate our boost, nor pass down any topLevelBoost 
+		  // (e.g. from outer BQ), as there is no guarantee that the CustomScoreProvider's 
+		  // function obeys the distributive law... it might call sqrt() on the subQuery score
+		  // or some other arbitrary function other than multiplication.
+		  // so, instead boosts are applied directly in score()
+		  subQueryWeight.normalize(norm, 1f);
+		  foreach (Weight valSrcWeight in valSrcWeights)
+		  {
+			if (qStrict)
+			{
+			  valSrcWeight.normalize(1, 1); // do not normalize the ValueSource part
+			}
+			else
+			{
+			  valSrcWeight.normalize(norm, 1f);
+			}
+		  }
+		  queryWeight = topLevelBoost * Boost;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.Scorer scorer(org.apache.lucene.index.AtomicReaderContext context, org.apache.lucene.util.Bits acceptDocs) throws java.io.IOException
+		public override Scorer scorer(AtomicReaderContext context, Bits acceptDocs)
+		{
+		  Scorer subQueryScorer = subQueryWeight.scorer(context, acceptDocs);
+		  if (subQueryScorer == null)
+		  {
+			return null;
+		  }
+		  Scorer[] valSrcScorers = new Scorer[valSrcWeights.Length];
+		  for (int i = 0; i < valSrcScorers.Length; i++)
+		  {
+			 valSrcScorers[i] = valSrcWeights[i].scorer(context, acceptDocs);
+		  }
+		  return new CustomScorer(outerInstance, outerInstance.getCustomScoreProvider(context), this, queryWeight, subQueryScorer, valSrcScorers);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.Explanation explain(org.apache.lucene.index.AtomicReaderContext context, int doc) throws java.io.IOException
+		public override Explanation explain(AtomicReaderContext context, int doc)
+		{
+		  Explanation explain = doExplain(context, doc);
+		  return explain == null ? new Explanation(0.0f, "no matching docs") : explain;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private org.apache.lucene.search.Explanation doExplain(org.apache.lucene.index.AtomicReaderContext info, int doc) throws java.io.IOException
+		internal virtual Explanation doExplain(AtomicReaderContext info, int doc)
+		{
+		  Explanation subQueryExpl = subQueryWeight.explain(info, doc);
+		  if (!subQueryExpl.Match)
+		  {
+			return subQueryExpl;
+		  }
+		  // match
+		  Explanation[] valSrcExpls = new Explanation[valSrcWeights.Length];
+		  for (int i = 0; i < valSrcWeights.Length; i++)
+		  {
+			valSrcExpls[i] = valSrcWeights[i].explain(info, doc);
+		  }
+		  Explanation customExp = outerInstance.getCustomScoreProvider(info).customExplain(doc,subQueryExpl,valSrcExpls);
+		  float sc = Boost * customExp.Value;
+		  Explanation res = new ComplexExplanation(true, sc, outerInstance.ToString() + ", product of:");
+		  res.addDetail(customExp);
+		  res.addDetail(new Explanation(Boost, "queryBoost")); // actually using the q boost as q weight (== weight value)
+		  return res;
+		}
+
+		public override bool scoresDocsOutOfOrder()
+		{
+		  return false;
+		}
+
+	  }
+
+
+	  //=========================== S C O R E R ============================
+
+	  /// <summary>
+	  /// A scorer that applies a (callback) function on scores of the subQuery.
+	  /// </summary>
+	  private class CustomScorer : Scorer
+	  {
+		  private readonly CustomScoreQuery outerInstance;
+
+		internal readonly float qWeight;
+		internal readonly Scorer subQueryScorer;
+		internal readonly Scorer[] valSrcScorers;
+		internal readonly CustomScoreProvider provider;
+		internal readonly float[] vScores; // reused in score() to avoid allocating this array for each doc
+
+		// constructor
+		internal CustomScorer(CustomScoreQuery outerInstance, CustomScoreProvider provider, CustomWeight w, float qWeight, Scorer subQueryScorer, Scorer[] valSrcScorers) : base(w)
+		{
+			this.outerInstance = outerInstance;
+		  this.qWeight = qWeight;
+		  this.subQueryScorer = subQueryScorer;
+		  this.valSrcScorers = valSrcScorers;
+		  this.vScores = new float[valSrcScorers.Length];
+		  this.provider = provider;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextDoc() throws java.io.IOException
+		public override int nextDoc()
+		{
+		  int doc = subQueryScorer.nextDoc();
+		  if (doc != NO_MORE_DOCS)
+		  {
+			foreach (Scorer valSrcScorer in valSrcScorers)
+			{
+			  valSrcScorer.advance(doc);
+			}
+		  }
+		  return doc;
+		}
+
+		public override int docID()
+		{
+		  return subQueryScorer.docID();
+		}
+
+		/*(non-Javadoc) @see org.apache.lucene.search.Scorer#score() */
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float score() throws java.io.IOException
+		public override float score()
+		{
+		  for (int i = 0; i < valSrcScorers.Length; i++)
+		  {
+			vScores[i] = valSrcScorers[i].score();
+		  }
+		  return qWeight * provider.customScore(subQueryScorer.docID(), subQueryScorer.score(), vScores);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		public override int freq()
+		{
+		  return subQueryScorer.freq();
+		}
+
+		public override ICollection<ChildScorer> Children
+		{
+			get
+			{
+			  return Collections.singleton(new ChildScorer(subQueryScorer, "CUSTOM"));
+			}
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(int target) throws java.io.IOException
+		public override int advance(int target)
+		{
+		  int doc = subQueryScorer.advance(target);
+		  if (doc != NO_MORE_DOCS)
+		  {
+			foreach (Scorer valSrcScorer in valSrcScorers)
+			{
+			  valSrcScorer.advance(doc);
+			}
+		  }
+		  return doc;
+		}
+
+		public override long cost()
+		{
+		  return subQueryScorer.cost();
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.Weight createWeight(org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override Weight createWeight(IndexSearcher searcher)
+	  {
+		return new CustomWeight(this, searcher);
+	  }
+
+	  /// <summary>
+	  /// Checks if this is strict custom scoring.
+	  /// In strict custom scoring, the <seealso cref="ValueSource"/> part does not participate in weight normalization.
+	  /// This may be useful when one wants full control over how scores are modified, and does 
+	  /// not care about normalizing by the <seealso cref="ValueSource"/> part.
+	  /// One particular case where this is useful if for testing this query.   
+	  /// <P>
+	  /// Note: only has effect when the <seealso cref="ValueSource"/> part is not null.
+	  /// </summary>
+	  public virtual bool Strict
+	  {
+		  get
+		  {
+			return strict;
+		  }
+		  set
+		  {
+			this.strict = value;
+		  }
+	  }
+
+
+	  /// <summary>
+	  /// The sub-query that CustomScoreQuery wraps, affecting both the score and which documents match. </summary>
+	  public virtual Query SubQuery
+	  {
+		  get
+		  {
+			return subQuery;
+		  }
+	  }
+
+	  /// <summary>
+	  /// The scoring queries that only affect the score of CustomScoreQuery. </summary>
+	  public virtual Query[] ScoringQueries
+	  {
+		  get
+		  {
+			return scoringQueries;
+		  }
+	  }
+
+	  /// <summary>
+	  /// A short name of this query, used in <seealso cref="#toString(String)"/>.
+	  /// </summary>
+	  public virtual string name()
+	  {
+		return "custom";
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/FilterClause.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/FilterClause.cs b/src/Lucene.Net.Queries/FilterClause.cs
new file mode 100644
index 0000000..cbfe284
--- /dev/null
+++ b/src/Lucene.Net.Queries/FilterClause.cs
@@ -0,0 +1,97 @@
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+
+	using Occur = org.apache.lucene.search.BooleanClause.Occur;
+	using Filter = org.apache.lucene.search.Filter;
+
+	/// <summary>
+	/// A Filter that wrapped with an indication of how that filter
+	/// is used when composed with another filter.
+	/// (Follows the boolean logic in BooleanClause for composition 
+	/// of queries.)
+	/// </summary>
+	public sealed class FilterClause
+	{
+
+	  private readonly Occur occur;
+	  private readonly Filter filter;
+
+	  /// <summary>
+	  /// Create a new FilterClause </summary>
+	  /// <param name="filter"> A Filter object containing a BitSet </param>
+	  /// <param name="occur"> A parameter implementation indicating SHOULD, MUST or MUST NOT </param>
+
+	  public FilterClause(Filter filter, Occur occur)
+	  {
+		this.occur = occur;
+		this.filter = filter;
+	  }
+
+	  /// <summary>
+	  /// Returns this FilterClause's filter </summary>
+	  /// <returns> A Filter object </returns>
+	  public Filter Filter
+	  {
+		  get
+		  {
+			return filter;
+		  }
+	  }
+
+	  /// <summary>
+	  /// Returns this FilterClause's occur parameter </summary>
+	  /// <returns> An Occur object </returns>
+	  public Occur Occur
+	  {
+		  get
+		  {
+			return occur;
+		  }
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o == this)
+		{
+		  return true;
+		}
+		if (o == null || !(o is FilterClause))
+		{
+		  return false;
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final FilterClause other = (FilterClause)o;
+		FilterClause other = (FilterClause)o;
+		return this.filter.Equals(other.filter) && this.occur == other.occur;
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return filter.GetHashCode() ^ occur.GetHashCode();
+	  }
+
+	  public override string ToString()
+	  {
+		return occur.ToString() + filter.ToString();
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/BoostedQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/BoostedQuery.cs b/src/Lucene.Net.Queries/Function/BoostedQuery.cs
new file mode 100644
index 0000000..928db91
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/BoostedQuery.cs
@@ -0,0 +1,287 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.lucene.queries.function
+{
+
+	/*
+	 * 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.
+	 */
+
+	using org.apache.lucene.search;
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using Term = org.apache.lucene.index.Term;
+	using Bits = org.apache.lucene.util.Bits;
+	using ToStringUtils = org.apache.lucene.util.ToStringUtils;
+
+
+	/// <summary>
+	/// Query that is boosted by a ValueSource
+	/// </summary>
+	// TODO: BoostedQuery and BoostingQuery in the same module? 
+	// something has to give
+	public class BoostedQuery : Query
+	{
+	  private Query q;
+	  private readonly ValueSource boostVal; // optional, can be null
+
+	  public BoostedQuery(Query subQuery, ValueSource boostVal)
+	  {
+		this.q = subQuery;
+		this.boostVal = boostVal;
+	  }
+
+	  public virtual Query Query
+	  {
+		  get
+		  {
+			  return q;
+		  }
+	  }
+	  public virtual ValueSource ValueSource
+	  {
+		  get
+		  {
+			  return boostVal;
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Query rewrite(org.apache.lucene.index.IndexReader reader) throws java.io.IOException
+	  public override Query rewrite(IndexReader reader)
+	  {
+		Query newQ = q.rewrite(reader);
+		if (newQ == q)
+		{
+			return this;
+		}
+		BoostedQuery bq = (BoostedQuery)this.MemberwiseClone();
+		bq.q = newQ;
+		return bq;
+	  }
+
+	  public override void extractTerms(HashSet<Term> terms)
+	  {
+		q.extractTerms(terms);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Weight createWeight(IndexSearcher searcher) throws java.io.IOException
+	  public override Weight createWeight(IndexSearcher searcher)
+	  {
+		return new BoostedQuery.BoostedWeight(this, searcher);
+	  }
+
+	  private class BoostedWeight : Weight
+	  {
+		  private readonly BoostedQuery outerInstance;
+
+		internal readonly IndexSearcher searcher;
+		internal Weight qWeight;
+		internal IDictionary fcontext;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public BoostedWeight(IndexSearcher searcher) throws java.io.IOException
+		public BoostedWeight(BoostedQuery outerInstance, IndexSearcher searcher)
+		{
+			this.outerInstance = outerInstance;
+		  this.searcher = searcher;
+		  this.qWeight = outerInstance.q.createWeight(searcher);
+		  this.fcontext = ValueSource.newContext(searcher);
+		  outerInstance.boostVal.createWeight(fcontext,searcher);
+		}
+
+		public override Query Query
+		{
+			get
+			{
+			  return outerInstance;
+			}
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float getValueForNormalization() throws java.io.IOException
+		public override float ValueForNormalization
+		{
+			get
+			{
+			  float sum = qWeight.ValueForNormalization;
+			  sum *= Boost * Boost;
+			  return sum;
+			}
+		}
+
+		public override void normalize(float norm, float topLevelBoost)
+		{
+		  topLevelBoost *= Boost;
+		  qWeight.normalize(norm, topLevelBoost);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Scorer scorer(org.apache.lucene.index.AtomicReaderContext context, org.apache.lucene.util.Bits acceptDocs) throws java.io.IOException
+		public override Scorer scorer(AtomicReaderContext context, Bits acceptDocs)
+		{
+		  Scorer subQueryScorer = qWeight.scorer(context, acceptDocs);
+		  if (subQueryScorer == null)
+		  {
+			return null;
+		  }
+		  return new BoostedQuery.CustomScorer(outerInstance, context, this, Boost, subQueryScorer, outerInstance.boostVal);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public Explanation explain(org.apache.lucene.index.AtomicReaderContext readerContext, int doc) throws java.io.IOException
+		public override Explanation explain(AtomicReaderContext readerContext, int doc)
+		{
+		  Explanation subQueryExpl = qWeight.explain(readerContext,doc);
+		  if (!subQueryExpl.Match)
+		  {
+			return subQueryExpl;
+		  }
+		  FunctionValues vals = outerInstance.boostVal.getValues(fcontext, readerContext);
+		  float sc = subQueryExpl.Value * vals.floatVal(doc);
+		  Explanation res = new ComplexExplanation(true, sc, outerInstance.ToString() + ", product of:");
+		  res.addDetail(subQueryExpl);
+		  res.addDetail(vals.explain(doc));
+		  return res;
+		}
+	  }
+
+
+	  private class CustomScorer : Scorer
+	  {
+		  private readonly BoostedQuery outerInstance;
+
+		internal readonly BoostedQuery.BoostedWeight weight;
+		internal readonly float qWeight;
+		internal readonly Scorer scorer;
+		internal readonly FunctionValues vals;
+		internal readonly AtomicReaderContext readerContext;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private CustomScorer(org.apache.lucene.index.AtomicReaderContext readerContext, BoostedQuery.BoostedWeight w, float qWeight, Scorer scorer, ValueSource vs) throws java.io.IOException
+		internal CustomScorer(BoostedQuery outerInstance, AtomicReaderContext readerContext, BoostedQuery.BoostedWeight w, float qWeight, Scorer scorer, ValueSource vs) : base(w)
+		{
+			this.outerInstance = outerInstance;
+		  this.weight = w;
+		  this.qWeight = qWeight;
+		  this.scorer = scorer;
+		  this.readerContext = readerContext;
+		  this.vals = vs.getValues(weight.fcontext, readerContext);
+		}
+
+		public override int docID()
+		{
+		  return scorer.docID();
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(int target) throws java.io.IOException
+		public override int advance(int target)
+		{
+		  return scorer.advance(target);
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextDoc() throws java.io.IOException
+		public override int nextDoc()
+		{
+		  return scorer.nextDoc();
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float score() throws java.io.IOException
+		public override float score()
+		{
+		  float score = qWeight * scorer.score() * vals.floatVal(scorer.docID());
+
+		  // Current Lucene priority queues can't handle NaN and -Infinity, so
+		  // map to -Float.MAX_VALUE. This conditional handles both -infinity
+		  // and NaN since comparisons with NaN are always false.
+		  return score > float.NegativeInfinity ? score : -float.MaxValue;
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		public override int freq()
+		{
+		  return scorer.freq();
+		}
+
+		public override ICollection<ChildScorer> Children
+		{
+			get
+			{
+			  return Collections.singleton(new ChildScorer(scorer, "CUSTOM"));
+			}
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public Explanation explain(int doc) throws java.io.IOException
+		public virtual Explanation explain(int doc)
+		{
+		  Explanation subQueryExpl = weight.qWeight.explain(readerContext,doc);
+		  if (!subQueryExpl.Match)
+		  {
+			return subQueryExpl;
+		  }
+		  float sc = subQueryExpl.Value * vals.floatVal(doc);
+		  Explanation res = new ComplexExplanation(true, sc, outerInstance.ToString() + ", product of:");
+		  res.addDetail(subQueryExpl);
+		  res.addDetail(vals.explain(doc));
+		  return res;
+		}
+
+		public override long cost()
+		{
+		  return scorer.cost();
+		}
+	  }
+
+
+	  public override string ToString(string field)
+	  {
+		StringBuilder sb = new StringBuilder();
+		sb.Append("boost(").Append(q.ToString(field)).Append(',').Append(boostVal).Append(')');
+		sb.Append(ToStringUtils.boost(Boost));
+		return sb.ToString();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+	  if (!base.Equals(o))
+	  {
+		  return false;
+	  }
+		BoostedQuery other = (BoostedQuery)o;
+		return this.q.Equals(other.q) && this.boostVal.Equals(other.boostVal);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = q.GetHashCode();
+		h ^= (h << 17) | ((int)((uint)h >> 16));
+		h += boostVal.GetHashCode();
+		h ^= (h << 8) | ((int)((uint)h >> 25));
+		h += float.floatToIntBits(Boost);
+		return h;
+	  }
+
+	}
+
+}
\ No newline at end of file


[10/11] git commit: Skeleton porting of Lucene.Net.Misc

Posted by sy...@apache.org.
Skeleton porting of Lucene.Net.Misc


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

Branch: refs/heads/master
Commit: 674f0cb97dfae0961d5f9622f49f17d891be08bc
Parents: 882f487
Author: Itamar Syn-Hershko <it...@code972.com>
Authored: Tue Sep 16 01:39:08 2014 +0300
Committer: Itamar Syn-Hershko <it...@code972.com>
Committed: Tue Sep 16 01:39:08 2014 +0300

----------------------------------------------------------------------
 src/Lucene.Net.Misc/ByteBuffer.cs               |  325 ++++++
 src/Lucene.Net.Misc/Document/LazyDocument.cs    |  226 ++++
 .../Index/CompoundFileExtractor.cs              |  165 +++
 src/Lucene.Net.Misc/Index/IndexSplitter.cs      |  200 ++++
 .../Index/MultiPassIndexSplitter.cs             |  329 ++++++
 src/Lucene.Net.Misc/Index/PKIndexSplitter.cs    |  220 ++++
 .../Index/Sorter/BlockJoinComparatorSource.cs   |  321 ++++++
 .../Sorter/EarlyTerminatingSortingCollector.cs  |  147 +++
 src/Lucene.Net.Misc/Index/Sorter/Sorter.cs      |  404 +++++++
 .../Index/Sorter/SortingAtomicReader.cs         | 1081 ++++++++++++++++++
 .../Index/Sorter/SortingMergePolicy.cs          |  309 +++++
 src/Lucene.Net.Misc/Lucene.Net.Misc.csproj      |   73 ++
 src/Lucene.Net.Misc/Misc/GetTermInfo.cs         |   74 ++
 src/Lucene.Net.Misc/Misc/HighFreqTerms.cs       |  230 ++++
 src/Lucene.Net.Misc/Misc/IndexMergeTool.cs      |   66 ++
 src/Lucene.Net.Misc/Misc/SweetSpotSimilarity.cs |  238 ++++
 src/Lucene.Net.Misc/Misc/TermStats.cs           |   55 +
 src/Lucene.Net.Misc/Properties/AssemblyInfo.cs  |   35 +
 src/Lucene.Net.Misc/Store/NativePosixUtil.cs    |   64 ++
 .../Store/NativeUnixDirectory.cs                |  527 +++++++++
 src/Lucene.Net.Misc/Store/WindowsDirectory.cs   |  181 +++
 src/Lucene.Net.Misc/Util/Fst/ListOfOutputs.cs   |  246 ++++
 .../Util/Fst/UpToTwoPositiveIntOutputs.cs       |  328 ++++++
 23 files changed, 5844 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/ByteBuffer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/ByteBuffer.cs b/src/Lucene.Net.Misc/ByteBuffer.cs
new file mode 100644
index 0000000..204f7de
--- /dev/null
+++ b/src/Lucene.Net.Misc/ByteBuffer.cs
@@ -0,0 +1,325 @@
+//-------------------------------------------------------------------------------------------
+//	Copyright © 2007 - 2014 Tangible Software Solutions Inc.
+//	This class can be used by anyone provided that the copyright notice remains intact.
+//
+//	This class is used to simulate the java.nio.ByteBuffer class in C#.
+//
+//	Instances are only obtainable via the static 'allocate' method.
+//
+//	Some methods are not available:
+//		Methods which create shared views of the buffer, such as: array,
+//		asCharBuffer, asDoubleBuffer, asFloatBuffer, asIntBuffer, asLongBuffer,
+//		asReadOnlyBuffer, asShortBuffer, duplicate, slice, & wrap.
+//
+//		Methods mark, reset, isReadOnly, order, compareTo, arrayOffset, & limit (setter).
+//-------------------------------------------------------------------------------------------
+public class ByteBuffer
+{
+	//'Mode' is only used to determine whether to return data length or capacity from the 'limit' method:
+	private enum Mode
+	{
+		Read,
+		Write
+	}
+	private Mode mode;
+
+	private System.IO.MemoryStream stream;
+	private System.IO.BinaryReader reader;
+	private System.IO.BinaryWriter writer;
+
+	private ByteBuffer()
+	{
+		stream = new System.IO.MemoryStream();
+		reader = new System.IO.BinaryReader(stream);
+		writer = new System.IO.BinaryWriter(stream);
+	}
+
+	~ByteBuffer()
+	{
+		reader.Close();
+		writer.Close();
+		stream.Close();
+		stream.Dispose();
+	}
+
+	public static ByteBuffer allocate(int capacity)
+	{
+		ByteBuffer buffer = new ByteBuffer();
+		buffer.stream.Capacity = capacity;
+		buffer.mode = Mode.Write;
+		return buffer;
+	}
+
+	public static ByteBuffer allocateDirect(int capacity)
+	{
+		//this wrapper class makes no distinction between 'allocate' & 'allocateDirect'
+		return allocate(capacity);
+	}
+
+	public int capacity()
+	{
+		return stream.Capacity;
+	}
+
+	public ByteBuffer flip()
+	{
+		mode = Mode.Read;
+		stream.SetLength(stream.Position);
+		stream.Position = 0;
+		return this;
+	}
+
+	public ByteBuffer clear()
+	{
+		mode = Mode.Write;
+		stream.Position = 0;
+		return this;
+	}
+
+	public ByteBuffer compact()
+	{
+		mode = Mode.Write;
+		System.IO.MemoryStream newStream = new System.IO.MemoryStream(stream.Capacity);
+		stream.CopyTo(newStream);
+		stream = newStream;
+		return this;
+	}
+
+	public ByteBuffer rewind()
+	{
+		stream.Position = 0;
+		return this;
+	}
+
+	public long limit()
+	{
+		if (mode == Mode.Write)
+			return stream.Capacity;
+		else
+			return stream.Length;
+	}
+
+	public long position()
+	{
+		return stream.Position;
+	}
+
+	public ByteBuffer position(long newPosition)
+	{
+		stream.Position = newPosition;
+		return this;
+	}
+
+	public long remaining()
+	{
+		return this.limit() - this.position();
+	}
+
+	public bool hasRemaining()
+	{
+		return this.remaining() > 0;
+	}
+
+	public int get()
+	{
+		return stream.ReadByte();
+	}
+
+	public ByteBuffer get(byte[] dst, int offset, int length)
+	{
+		stream.Read(dst, offset, length);
+		return this;
+	}
+
+	public ByteBuffer put(byte b)
+	{
+		stream.WriteByte(b);
+		return this;
+	}
+
+	public ByteBuffer put(byte[] src, int offset, int length)
+	{
+		stream.Write(src, offset, length);
+		return this;
+	}
+
+	public bool Equals(ByteBuffer other)
+	{
+		if (other != null && this.remaining() == other.remaining())
+		{
+			long thisOriginalPosition = this.position();
+			long otherOriginalPosition = other.position();
+
+			bool differenceFound = false;
+			while (stream.Position < stream.Length)
+			{
+				if (this.get() != other.get())
+				{
+					differenceFound = true;
+					break;
+				}
+			}
+
+			this.position(thisOriginalPosition);
+			other.position(otherOriginalPosition);
+
+			return ! differenceFound;
+		}
+		else
+			return false;
+	}
+
+	//methods using the internal BinaryReader:
+	public char getChar()
+	{
+		return reader.ReadChar();
+	}
+	public char getChar(int index)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		char value = reader.ReadChar();
+		stream.Position = originalPosition;
+		return value;
+	}
+	public double getDouble()
+	{
+		return reader.ReadDouble();
+	}
+	public double getDouble(int index)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		double value = reader.ReadDouble();
+		stream.Position = originalPosition;
+		return value;
+	}
+	public float getFloat()
+	{
+		return reader.ReadSingle();
+	}
+	public float getFloat(int index)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		float value = reader.ReadSingle();
+		stream.Position = originalPosition;
+		return value;
+	}
+	public int getInt()
+	{
+		return reader.ReadInt32();
+	}
+	public int getInt(int index)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		int value = reader.ReadInt32();
+		stream.Position = originalPosition;
+		return value;
+	}
+	public long getLong()
+	{
+		return reader.ReadInt64();
+	}
+	public long getLong(int index)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		long value = reader.ReadInt64();
+		stream.Position = originalPosition;
+		return value;
+	}
+	public short getShort()
+	{
+		return reader.ReadInt16();
+	}
+	public short getShort(int index)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		short value = reader.ReadInt16();
+		stream.Position = originalPosition;
+		return value;
+	}
+
+	//methods using the internal BinaryWriter:
+	public ByteBuffer putChar(char value)
+	{
+		writer.Write(value);
+		return this;
+	}
+	public ByteBuffer putChar(int index, char value)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		writer.Write(value);
+		stream.Position = originalPosition;
+		return this;
+	}
+	public ByteBuffer putDouble(double value)
+	{
+		writer.Write(value);
+		return this;
+	}
+	public ByteBuffer putDouble(int index, double value)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		writer.Write(value);
+		stream.Position = originalPosition;
+		return this;
+	}
+	public ByteBuffer putFloat(float value)
+	{
+		writer.Write(value);
+		return this;
+	}
+	public ByteBuffer putFloat(int index, float value)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		writer.Write(value);
+		stream.Position = originalPosition;
+		return this;
+	}
+	public ByteBuffer putInt(int value)
+	{
+		writer.Write(value);
+		return this;
+	}
+	public ByteBuffer putInt(int index, int value)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		writer.Write(value);
+		stream.Position = originalPosition;
+		return this;
+	}
+	public ByteBuffer putLong(long value)
+	{
+		writer.Write(value);
+		return this;
+	}
+	public ByteBuffer putLong(int index, long value)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		writer.Write(value);
+		stream.Position = originalPosition;
+		return this;
+	}
+	public ByteBuffer putShort(short value)
+	{
+		writer.Write(value);
+		return this;
+	}
+	public ByteBuffer putShort(int index, short value)
+	{
+		long originalPosition = stream.Position;
+		stream.Position = index;
+		writer.Write(value);
+		stream.Position = originalPosition;
+		return this;
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Document/LazyDocument.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Document/LazyDocument.cs b/src/Lucene.Net.Misc/Document/LazyDocument.cs
new file mode 100644
index 0000000..6faed94
--- /dev/null
+++ b/src/Lucene.Net.Misc/Document/LazyDocument.cs
@@ -0,0 +1,226 @@
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.document
+{
+
+	/// <summary>
+	/// Copyright 2004 The Apache Software Foundation
+	/// 
+	/// Licensed 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.
+	/// </summary>
+
+	using Analyzer = org.apache.lucene.analysis.Analyzer;
+	using TokenStream = org.apache.lucene.analysis.TokenStream;
+	using FieldInfo = org.apache.lucene.index.FieldInfo;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using IndexableField = org.apache.lucene.index.IndexableField;
+	using IndexableFieldType = org.apache.lucene.index.IndexableFieldType;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+	/// <summary>
+	/// Defers actually loading a field's value until you ask
+	///  for it.  You must not use the returned Field instances
+	///  after the provided reader has been closed. </summary>
+	/// <seealso cref= #getField </seealso>
+	public class LazyDocument
+	{
+	  private readonly IndexReader reader;
+	  private readonly int docID;
+
+	  // null until first field is loaded
+	  private Document doc;
+
+	  private IDictionary<int?, IList<LazyField>> fields = new Dictionary<int?, IList<LazyField>>();
+	  private HashSet<string> fieldNames = new HashSet<string>();
+
+	  public LazyDocument(IndexReader reader, int docID)
+	  {
+		this.reader = reader;
+		this.docID = docID;
+	  }
+
+	  /// <summary>
+	  /// Creates an IndexableField whose value will be lazy loaded if and 
+	  /// when it is used. 
+	  /// <para>
+	  /// <b>NOTE:</b> This method must be called once for each value of the field 
+	  /// name specified in sequence that the values exist.  This method may not be 
+	  /// used to generate multiple, lazy, IndexableField instances refering to 
+	  /// the same underlying IndexableField instance.
+	  /// </para>
+	  /// <para>
+	  /// The lazy loading of field values from all instances of IndexableField 
+	  /// objects returned by this method are all backed by a single Document 
+	  /// per LazyDocument instance.
+	  /// </para>
+	  /// </summary>
+	  public virtual IndexableField getField(FieldInfo fieldInfo)
+	  {
+
+		fieldNames.Add(fieldInfo.name);
+		IList<LazyField> values = fields[fieldInfo.number];
+		if (null == values)
+		{
+		  values = new List<>();
+		  fields[fieldInfo.number] = values;
+		}
+
+		LazyField value = new LazyField(this, fieldInfo.name, fieldInfo.number);
+		values.Add(value);
+
+		lock (this)
+		{
+		  // edge case: if someone asks this LazyDoc for more LazyFields
+		  // after other LazyFields from the same LazyDoc have been
+		  // actuallized, we need to force the doc to be re-fetched
+		  // so the new LazyFields are also populated.
+		  doc = null;
+		}
+		return value;
+	  }
+
+	  /// <summary>
+	  /// non-private for test only access
+	  /// @lucene.internal 
+	  /// </summary>
+	  internal virtual Document Document
+	  {
+		  get
+		  {
+			  lock (this)
+			  {
+				if (doc == null)
+				{
+				  try
+				  {
+					doc = reader.document(docID, fieldNames);
+				  }
+				  catch (IOException ioe)
+				  {
+					throw new IllegalStateException("unable to load document", ioe);
+				  }
+				}
+				return doc;
+			  }
+		  }
+	  }
+
+	  // :TODO: synchronize to prevent redundent copying? (sync per field name?)
+	  private void fetchRealValues(string name, int fieldNum)
+	  {
+		Document d = Document;
+
+		IList<LazyField> lazyValues = fields[fieldNum];
+		IndexableField[] realValues = d.getFields(name);
+
+		Debug.Assert(realValues.Length <= lazyValues.Count, "More lazy values then real values for field: " + name);
+
+		for (int i = 0; i < lazyValues.Count; i++)
+		{
+		  LazyField f = lazyValues[i];
+		  if (null != f)
+		  {
+			f.realValue = realValues[i];
+		  }
+		}
+	  }
+
+
+	  /// <summary>
+	  /// @lucene.internal 
+	  /// </summary>
+	  public class LazyField : IndexableField
+	  {
+		  private readonly LazyDocument outerInstance;
+
+		internal string name_Renamed;
+		internal int fieldNum;
+		internal volatile IndexableField realValue = null;
+
+		internal LazyField(LazyDocument outerInstance, string name, int fieldNum)
+		{
+			this.outerInstance = outerInstance;
+		  this.name_Renamed = name;
+		  this.fieldNum = fieldNum;
+		}
+
+		/// <summary>
+		/// non-private for test only access
+		/// @lucene.internal 
+		/// </summary>
+		public virtual bool hasBeenLoaded()
+		{
+		  return null != realValue;
+		}
+
+		internal virtual IndexableField RealValue
+		{
+			get
+			{
+			  if (null == realValue)
+			  {
+				outerInstance.fetchRealValues(name_Renamed, fieldNum);
+			  }
+			  Debug.Assert(hasBeenLoaded(), "field value was not lazy loaded");
+			  Debug.Assert(realValue.name().Equals(name()), "realvalue name != name: " + realValue.name() + " != " + name());
+    
+			  return realValue;
+			}
+		}
+
+		public override string name()
+		{
+		  return name_Renamed;
+		}
+
+		public override float boost()
+		{
+		  return 1.0f;
+		}
+
+		public override BytesRef binaryValue()
+		{
+		  return RealValue.binaryValue();
+		}
+
+		public override string stringValue()
+		{
+		  return RealValue.stringValue();
+		}
+
+		public override Reader readerValue()
+		{
+		  return RealValue.readerValue();
+		}
+
+		public override Number numericValue()
+		{
+		  return RealValue.numericValue();
+		}
+
+		public override IndexableFieldType fieldType()
+		{
+		  return RealValue.fieldType();
+		}
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.analysis.TokenStream tokenStream(org.apache.lucene.analysis.Analyzer analyzer) throws java.io.IOException
+		public override TokenStream tokenStream(Analyzer analyzer)
+		{
+		  return RealValue.tokenStream(analyzer);
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/CompoundFileExtractor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/CompoundFileExtractor.cs b/src/Lucene.Net.Misc/Index/CompoundFileExtractor.cs
new file mode 100644
index 0000000..855b6f3
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/CompoundFileExtractor.cs
@@ -0,0 +1,165 @@
+using System;
+
+namespace org.apache.lucene.index
+{
+
+	/*
+	 * 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.
+	 */
+
+	/// <summary>
+	/// Prints the filename and size of each file within a given compound file.
+	/// Add the -extract flag to extract files to the current working directory.
+	/// In order to make the extracted version of the index work, you have to copy
+	/// the segments file from the compound index into the directory where the extracted files are stored. </summary>
+	/// <param name="args"> Usage: org.apache.lucene.index.IndexReader [-extract] &lt;cfsfile&gt; </param>
+
+
+	using CompoundFileDirectory = org.apache.lucene.store.CompoundFileDirectory;
+	using Directory = org.apache.lucene.store.Directory;
+	using FSDirectory = org.apache.lucene.store.FSDirectory;
+	using IOContext = org.apache.lucene.store.IOContext;
+	using IndexInput = org.apache.lucene.store.IndexInput;
+	using ArrayUtil = org.apache.lucene.util.ArrayUtil;
+	using CommandLineUtil = org.apache.lucene.util.CommandLineUtil;
+
+	/// <summary>
+	/// Command-line tool for extracting sub-files out of a compound file.
+	/// </summary>
+	public class CompoundFileExtractor
+	{
+
+	  public static void Main(string[] args)
+	  {
+		string filename = null;
+		bool extract = false;
+		string dirImpl = null;
+
+		int j = 0;
+		while (j < args.Length)
+		{
+		  string arg = args[j];
+		  if ("-extract".Equals(arg))
+		  {
+			extract = true;
+		  }
+		  else if ("-dir-impl".Equals(arg))
+		  {
+			if (j == args.Length - 1)
+			{
+			  Console.WriteLine("ERROR: missing value for -dir-impl option");
+			  Environment.Exit(1);
+			}
+			j++;
+			dirImpl = args[j];
+		  }
+		  else if (filename == null)
+		  {
+			filename = arg;
+		  }
+		  j++;
+		}
+
+		if (filename == null)
+		{
+		  Console.WriteLine("Usage: org.apache.lucene.index.CompoundFileExtractor [-extract] [-dir-impl X] <cfsfile>");
+		  return;
+		}
+
+		Directory dir = null;
+		CompoundFileDirectory cfr = null;
+		IOContext context = IOContext.READ;
+
+		try
+		{
+		  File file = new File(filename);
+		  string dirname = file.AbsoluteFile.Parent;
+		  filename = file.Name;
+		  if (dirImpl == null)
+		  {
+			dir = FSDirectory.open(new File(dirname));
+		  }
+		  else
+		  {
+			dir = CommandLineUtil.newFSDirectory(dirImpl, new File(dirname));
+		  }
+
+		  cfr = new CompoundFileDirectory(dir, filename, IOContext.DEFAULT, false);
+
+		  string[] files = cfr.listAll();
+		  ArrayUtil.timSort(files); // sort the array of filename so that the output is more readable
+
+		  for (int i = 0; i < files.Length; ++i)
+		  {
+			long len = cfr.fileLength(files[i]);
+
+			if (extract)
+			{
+			  Console.WriteLine("extract " + files[i] + " with " + len + " bytes to local directory...");
+			  IndexInput ii = cfr.openInput(files[i], context);
+
+			  FileOutputStream f = new FileOutputStream(files[i]);
+
+			  // read and write with a small buffer, which is more effective than reading byte by byte
+			  sbyte[] buffer = new sbyte[1024];
+			  int chunk = buffer.Length;
+			  while (len > 0)
+			  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int bufLen = (int) Math.min(chunk, len);
+				int bufLen = (int) Math.Min(chunk, len);
+				ii.readBytes(buffer, 0, bufLen);
+				f.write(buffer, 0, bufLen);
+				len -= bufLen;
+			  }
+
+			  f.close();
+			  ii.close();
+			}
+			else
+			{
+			  Console.WriteLine(files[i] + ": " + len + " bytes");
+			}
+		  }
+		}
+		catch (IOException ioe)
+		{
+		  Console.WriteLine(ioe.ToString());
+		  Console.Write(ioe.StackTrace);
+		}
+		finally
+		{
+		  try
+		  {
+			if (dir != null)
+			{
+			  dir.close();
+			}
+			if (cfr != null)
+			{
+			  cfr.close();
+			}
+		  }
+		  catch (IOException ioe)
+		  {
+			Console.WriteLine(ioe.ToString());
+			Console.Write(ioe.StackTrace);
+		  }
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/IndexSplitter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/IndexSplitter.cs b/src/Lucene.Net.Misc/Index/IndexSplitter.cs
new file mode 100644
index 0000000..a0e9946
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/IndexSplitter.cs
@@ -0,0 +1,200 @@
+using System;
+using System.Collections.Generic;
+
+/*
+ * 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.
+ */
+namespace org.apache.lucene.index
+{
+
+
+	using FSDirectory = org.apache.lucene.store.FSDirectory;
+
+	/// <summary>
+	/// Command-line tool that enables listing segments in an
+	/// index, copying specific segments to another index, and
+	/// deleting segments from an index.
+	/// 
+	/// <para>This tool does file-level copying of segments files.
+	/// This means it's unable to split apart a single segment
+	/// into multiple segments.  For example if your index is a
+	/// single segment, this tool won't help.  Also, it does basic
+	/// file-level copying (using simple
+	/// File{In,Out}putStream) so it will not work with non
+	/// FSDirectory Directory impls.</para>
+	/// 
+	/// @lucene.experimental You can easily
+	/// accidentally remove segments from your index so be
+	/// careful!
+	/// </summary>
+	public class IndexSplitter
+	{
+	  public SegmentInfos infos;
+
+	  internal FSDirectory fsDir;
+
+	  internal File dir;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static void main(String[] args) throws Exception
+	  public static void Main(string[] args)
+	  {
+		if (args.Length < 2)
+		{
+		  Console.Error.WriteLine("Usage: IndexSplitter <srcDir> -l (list the segments and their sizes)");
+		  Console.Error.WriteLine("IndexSplitter <srcDir> <destDir> <segments>+");
+		  Console.Error.WriteLine("IndexSplitter <srcDir> -d (delete the following segments)");
+		  return;
+		}
+		File srcDir = new File(args[0]);
+		IndexSplitter @is = new IndexSplitter(srcDir);
+		if (!srcDir.exists())
+		{
+		  throw new Exception("srcdir:" + srcDir.AbsolutePath + " doesn't exist");
+		}
+		if (args[1].Equals("-l"))
+		{
+		  @is.listSegments();
+		}
+		else if (args[1].Equals("-d"))
+		{
+		  IList<string> segs = new List<string>();
+		  for (int x = 2; x < args.Length; x++)
+		  {
+			segs.Add(args[x]);
+		  }
+		  @is.remove(segs.ToArray());
+		}
+		else
+		{
+		  File targetDir = new File(args[1]);
+		  IList<string> segs = new List<string>();
+		  for (int x = 2; x < args.Length; x++)
+		  {
+			segs.Add(args[x]);
+		  }
+		  @is.Split(targetDir, segs.ToArray());
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public IndexSplitter(java.io.File dir) throws java.io.IOException
+	  public IndexSplitter(File dir)
+	  {
+		this.dir = dir;
+		fsDir = FSDirectory.open(dir);
+		infos = new SegmentInfos();
+		infos.read(fsDir);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void listSegments() throws java.io.IOException
+	  public virtual void listSegments()
+	  {
+		DecimalFormat formatter = new DecimalFormat("###,###.###", DecimalFormatSymbols.getInstance(Locale.ROOT));
+		for (int x = 0; x < infos.size(); x++)
+		{
+		  SegmentCommitInfo info = infos.info(x);
+		  string sizeStr = formatter.format(info.sizeInBytes());
+		  Console.WriteLine(info.info.name + " " + sizeStr);
+		}
+	  }
+
+	  private int getIdx(string name)
+	  {
+		for (int x = 0; x < infos.size(); x++)
+		{
+		  if (name.Equals(infos.info(x).info.name))
+		  {
+			return x;
+		  }
+		}
+		return -1;
+	  }
+
+	  private SegmentCommitInfo getInfo(string name)
+	  {
+		for (int x = 0; x < infos.size(); x++)
+		{
+		  if (name.Equals(infos.info(x).info.name))
+		  {
+			return infos.info(x);
+		  }
+		}
+		return null;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void remove(String[] segs) throws java.io.IOException
+	  public virtual void remove(string[] segs)
+	  {
+		foreach (string n in segs)
+		{
+		  int idx = getIdx(n);
+		  infos.remove(idx);
+		}
+		infos.changed();
+		infos.commit(fsDir);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void split(java.io.File destDir, String[] segs) throws java.io.IOException
+	  public virtual void Split(File destDir, string[] segs)
+	  {
+		destDir.mkdirs();
+		FSDirectory destFSDir = FSDirectory.open(destDir);
+		SegmentInfos destInfos = new SegmentInfos();
+		destInfos.counter = infos.counter;
+		foreach (string n in segs)
+		{
+		  SegmentCommitInfo infoPerCommit = getInfo(n);
+		  SegmentInfo info = infoPerCommit.info;
+		  // Same info just changing the dir:
+		  SegmentInfo newInfo = new SegmentInfo(destFSDir, info.Version, info.name, info.DocCount, info.UseCompoundFile, info.Codec, info.Diagnostics);
+		  destInfos.add(new SegmentCommitInfo(newInfo, infoPerCommit.DelCount, infoPerCommit.DelGen, infoPerCommit.FieldInfosGen));
+		  // now copy files over
+		  ICollection<string> files = infoPerCommit.files();
+		  foreach (String srcName in files)
+		  {
+			File srcFile = new File(dir, srcName);
+			File destFile = new File(destDir, srcName);
+			copyFile(srcFile, destFile);
+		  }
+		}
+		destInfos.changed();
+		destInfos.commit(destFSDir);
+		// System.out.println("destDir:"+destDir.getAbsolutePath());
+	  }
+
+	  private static readonly sbyte[] copyBuffer = new sbyte[32 * 1024];
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private static void copyFile(java.io.File src, java.io.File dst) throws java.io.IOException
+	  private static void copyFile(File src, File dst)
+	  {
+		InputStream @in = new FileInputStream(src);
+		OutputStream @out = new FileOutputStream(dst);
+		int len;
+		while ((len = @in.read(copyBuffer)) > 0)
+		{
+		  @out.write(copyBuffer, 0, len);
+		}
+		@in.close();
+		@out.close();
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/MultiPassIndexSplitter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/MultiPassIndexSplitter.cs b/src/Lucene.Net.Misc/Index/MultiPassIndexSplitter.cs
new file mode 100644
index 0000000..1e03fed
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/MultiPassIndexSplitter.cs
@@ -0,0 +1,329 @@
+using System;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.index
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using OpenMode = org.apache.lucene.index.IndexWriterConfig.OpenMode;
+	using Directory = org.apache.lucene.store.Directory;
+	using FSDirectory = org.apache.lucene.store.FSDirectory;
+	using FixedBitSet = org.apache.lucene.util.FixedBitSet;
+	using Bits = org.apache.lucene.util.Bits;
+	using Version = org.apache.lucene.util.Version;
+
+	/// <summary>
+	/// This tool splits input index into multiple equal parts. The method employed
+	/// here uses <seealso cref="IndexWriter#addIndexes(IndexReader[])"/> where the input data
+	/// comes from the input index with artificially applied deletes to the document
+	/// id-s that fall outside the selected partition.
+	/// <para>Note 1: Deletes are only applied to a buffered list of deleted docs and
+	/// don't affect the source index - this tool works also with read-only indexes.
+	/// </para>
+	/// <para>Note 2: the disadvantage of this tool is that source index needs to be
+	/// read as many times as there are parts to be created, hence the name of this
+	/// tool.
+	/// 
+	/// </para>
+	/// <para><b>NOTE</b>: this tool is unaware of documents added
+	/// atomically via <seealso cref="IndexWriter#addDocuments"/> or {@link
+	/// IndexWriter#updateDocuments}, which means it can easily
+	/// break up such document groups.
+	/// </para>
+	/// </summary>
+	public class MultiPassIndexSplitter
+	{
+
+	  /// <summary>
+	  /// Split source index into multiple parts. </summary>
+	  /// <param name="in"> source index, can have deletions, can have
+	  /// multiple segments (or multiple readers). </param>
+	  /// <param name="outputs"> list of directories where the output parts will be stored. </param>
+	  /// <param name="seq"> if true, then the source index will be split into equal
+	  /// increasing ranges of document id-s. If false, source document id-s will be
+	  /// assigned in a deterministic round-robin fashion to one of the output splits. </param>
+	  /// <exception cref="IOException"> If there is a low-level I/O error </exception>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void split(org.apache.lucene.util.Version version, IndexReader in, org.apache.lucene.store.Directory[] outputs, boolean seq) throws java.io.IOException
+	  public virtual void Split(Version version, IndexReader @in, Directory[] outputs, bool seq)
+	  {
+		if (outputs == null || outputs.Length < 2)
+		{
+		  throw new IOException("Invalid number of outputs.");
+		}
+		if (@in == null || @in.numDocs() < 2)
+		{
+		  throw new IOException("Not enough documents for splitting");
+		}
+		int numParts = outputs.Length;
+		// wrap a potentially read-only input
+		// this way we don't have to preserve original deletions because neither
+		// deleteDocument(int) or undeleteAll() is applied to the wrapped input index.
+		FakeDeleteIndexReader input = new FakeDeleteIndexReader(@in);
+		int maxDoc = input.maxDoc();
+		int partLen = maxDoc / numParts;
+		for (int i = 0; i < numParts; i++)
+		{
+		  input.undeleteAll();
+		  if (seq) // sequential range
+		  {
+			int lo = partLen * i;
+			int hi = lo + partLen;
+			// below range
+			for (int j = 0; j < lo; j++)
+			{
+			  input.deleteDocument(j);
+			}
+			// above range - last part collects all id-s that remained due to
+			// integer rounding errors
+			if (i < numParts - 1)
+			{
+			  for (int j = hi; j < maxDoc; j++)
+			  {
+				input.deleteDocument(j);
+			  }
+			}
+		  }
+		  else
+		  {
+			// round-robin
+			for (int j = 0; j < maxDoc; j++)
+			{
+			  if ((j + numParts - i) % numParts != 0)
+			  {
+				input.deleteDocument(j);
+			  }
+			}
+		  }
+		  IndexWriter w = new IndexWriter(outputs[i], new IndexWriterConfig(version, null)
+			 .setOpenMode(OpenMode.CREATE));
+		  Console.Error.WriteLine("Writing part " + (i + 1) + " ...");
+		  // pass the subreaders directly, as our wrapper's numDocs/hasDeletetions are not up-to-date
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.util.List<? extends FakeDeleteAtomicIndexReader> sr = input.getSequentialSubReaders();
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+		  IList<?> sr = input.SequentialSubReaders;
+		  w.addIndexes(sr.ToArray()); // TODO: maybe take List<IR> here?
+		  w.close();
+		}
+		Console.Error.WriteLine("Done.");
+	  }
+
+//JAVA TO C# CONVERTER TODO TASK: Most Java annotations will not have direct .NET equivalent attributes:
+//ORIGINAL LINE: @SuppressWarnings("deprecation") public static void main(String[] args) throws Exception
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+	  public static void Main(string[] args)
+	  {
+		if (args.Length < 5)
+		{
+		  Console.Error.WriteLine("Usage: MultiPassIndexSplitter -out <outputDir> -num <numParts> [-seq] <inputIndex1> [<inputIndex2 ...]");
+		  Console.Error.WriteLine("\tinputIndex\tpath to input index, multiple values are ok");
+		  Console.Error.WriteLine("\t-out ouputDir\tpath to output directory to contain partial indexes");
+		  Console.Error.WriteLine("\t-num numParts\tnumber of parts to produce");
+		  Console.Error.WriteLine("\t-seq\tsequential docid-range split (default is round-robin)");
+		  Environment.Exit(-1);
+		}
+		List<IndexReader> indexes = new List<IndexReader>();
+		string outDir = null;
+		int numParts = -1;
+		bool seq = false;
+		for (int i = 0; i < args.Length; i++)
+		{
+		  if (args[i].Equals("-out"))
+		  {
+			outDir = args[++i];
+		  }
+		  else if (args[i].Equals("-num"))
+		  {
+			numParts = Convert.ToInt32(args[++i]);
+		  }
+		  else if (args[i].Equals("-seq"))
+		  {
+			seq = true;
+		  }
+		  else
+		  {
+			File file = new File(args[i]);
+			if (!file.exists() || !file.Directory)
+			{
+			  Console.Error.WriteLine("Invalid input path - skipping: " + file);
+			  continue;
+			}
+			Directory dir = FSDirectory.open(new File(args[i]));
+			try
+			{
+			  if (!DirectoryReader.indexExists(dir))
+			  {
+				Console.Error.WriteLine("Invalid input index - skipping: " + file);
+				continue;
+			  }
+			}
+			catch (Exception)
+			{
+			  Console.Error.WriteLine("Invalid input index - skipping: " + file);
+			  continue;
+			}
+			indexes.Add(DirectoryReader.open(dir));
+		  }
+		}
+		if (outDir == null)
+		{
+		  throw new Exception("Required argument missing: -out outputDir");
+		}
+		if (numParts < 2)
+		{
+		  throw new Exception("Invalid value of required argument: -num numParts");
+		}
+		if (indexes.Count == 0)
+		{
+		  throw new Exception("No input indexes to process");
+		}
+		File @out = new File(outDir);
+		if (!@out.mkdirs())
+		{
+		  throw new Exception("Can't create output directory: " + @out);
+		}
+		Directory[] dirs = new Directory[numParts];
+		for (int i = 0; i < numParts; i++)
+		{
+		  dirs[i] = FSDirectory.open(new File(@out, "part-" + i));
+		}
+		MultiPassIndexSplitter splitter = new MultiPassIndexSplitter();
+		IndexReader input;
+		if (indexes.Count == 1)
+		{
+		  input = indexes[0];
+		}
+		else
+		{
+		  input = new MultiReader(indexes.ToArray());
+		}
+		splitter.Split(Version.LUCENE_CURRENT, input, dirs, seq);
+	  }
+
+	  /// <summary>
+	  /// This class emulates deletions on the underlying index.
+	  /// </summary>
+	  private sealed class FakeDeleteIndexReader : BaseCompositeReader<FakeDeleteAtomicIndexReader>
+	  {
+
+		public FakeDeleteIndexReader(IndexReader reader) : base(initSubReaders(reader))
+		{
+		}
+
+		internal static FakeDeleteAtomicIndexReader[] initSubReaders(IndexReader reader)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.util.List<AtomicReaderContext> leaves = reader.leaves();
+		  IList<AtomicReaderContext> leaves = reader.leaves();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final FakeDeleteAtomicIndexReader[] subs = new FakeDeleteAtomicIndexReader[leaves.size()];
+		  FakeDeleteAtomicIndexReader[] subs = new FakeDeleteAtomicIndexReader[leaves.Count];
+		  int i = 0;
+		  foreach (AtomicReaderContext ctx in leaves)
+		  {
+			subs[i++] = new FakeDeleteAtomicIndexReader(ctx.reader());
+		  }
+		  return subs;
+		}
+
+		public void deleteDocument(int docID)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int i = readerIndex(docID);
+		  int i = readerIndex(docID);
+		  SequentialSubReaders.get(i).deleteDocument(docID - readerBase(i));
+		}
+
+		public void undeleteAll()
+		{
+		  foreach (FakeDeleteAtomicIndexReader r in SequentialSubReaders)
+		  {
+			r.undeleteAll();
+		  }
+		}
+
+		protected internal override void doClose()
+		{
+		}
+
+		// no need to override numDocs/hasDeletions,
+		// as we pass the subreaders directly to IW.addIndexes().
+	  }
+
+	  private sealed class FakeDeleteAtomicIndexReader : FilterAtomicReader
+	  {
+		internal FixedBitSet liveDocs;
+
+		public FakeDeleteAtomicIndexReader(AtomicReader reader) : base(reader)
+		{
+		  undeleteAll(); // initialize main bitset
+		}
+
+		public override int numDocs()
+		{
+		  return liveDocs.cardinality();
+		}
+
+		public void undeleteAll()
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int maxDoc = in.maxDoc();
+		  int maxDoc = @in.maxDoc();
+		  liveDocs = new FixedBitSet(@in.maxDoc());
+		  if (@in.hasDeletions())
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits oldLiveDocs = in.getLiveDocs();
+			Bits oldLiveDocs = @in.LiveDocs;
+			Debug.Assert(oldLiveDocs != null);
+			// this loop is a little bit ineffective, as Bits has no nextSetBit():
+			for (int i = 0; i < maxDoc; i++)
+			{
+			  if (oldLiveDocs.get(i))
+			  {
+				  liveDocs.set(i);
+			  }
+			}
+		  }
+		  else
+		  {
+			// mark all docs as valid
+			liveDocs.set(0, maxDoc);
+		  }
+		}
+
+		public void deleteDocument(int n)
+		{
+		  liveDocs.clear(n);
+		}
+
+		public override Bits LiveDocs
+		{
+			get
+			{
+			  return liveDocs;
+			}
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/PKIndexSplitter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/PKIndexSplitter.cs b/src/Lucene.Net.Misc/Index/PKIndexSplitter.cs
new file mode 100644
index 0000000..f3e7ed4
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/PKIndexSplitter.cs
@@ -0,0 +1,220 @@
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.index
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using OpenMode = org.apache.lucene.index.IndexWriterConfig.OpenMode;
+	using DocIdSet = org.apache.lucene.search.DocIdSet;
+	using DocIdSetIterator = org.apache.lucene.search.DocIdSetIterator;
+	using Filter = org.apache.lucene.search.Filter;
+	using TermRangeFilter = org.apache.lucene.search.TermRangeFilter;
+	using Directory = org.apache.lucene.store.Directory;
+	using Bits = org.apache.lucene.util.Bits;
+	using FixedBitSet = org.apache.lucene.util.FixedBitSet;
+	using IOUtils = org.apache.lucene.util.IOUtils;
+	using Version = org.apache.lucene.util.Version;
+
+	/// <summary>
+	/// Split an index based on a <seealso cref="Filter"/>.
+	/// </summary>
+
+	public class PKIndexSplitter
+	{
+	  private readonly Filter docsInFirstIndex;
+	  private readonly Directory input;
+	  private readonly Directory dir1;
+	  private readonly Directory dir2;
+	  private readonly IndexWriterConfig config1;
+	  private readonly IndexWriterConfig config2;
+
+	  /// <summary>
+	  /// Split an index based on a <seealso cref="Filter"/>. All documents that match the filter
+	  /// are sent to dir1, remaining ones to dir2.
+	  /// </summary>
+	  public PKIndexSplitter(Version version, Directory input, Directory dir1, Directory dir2, Filter docsInFirstIndex) : this(input, dir1, dir2, docsInFirstIndex, newDefaultConfig(version), newDefaultConfig(version))
+	  {
+	  }
+
+	  private static IndexWriterConfig newDefaultConfig(Version version)
+	  {
+		return (new IndexWriterConfig(version, null)).setOpenMode(OpenMode.CREATE);
+	  }
+
+	  public PKIndexSplitter(Directory input, Directory dir1, Directory dir2, Filter docsInFirstIndex, IndexWriterConfig config1, IndexWriterConfig config2)
+	  {
+		this.input = input;
+		this.dir1 = dir1;
+		this.dir2 = dir2;
+		this.docsInFirstIndex = docsInFirstIndex;
+		this.config1 = config1;
+		this.config2 = config2;
+	  }
+
+	  /// <summary>
+	  /// Split an index based on a  given primary key term 
+	  /// and a 'middle' term.  If the middle term is present, it's
+	  /// sent to dir2.
+	  /// </summary>
+	  public PKIndexSplitter(Version version, Directory input, Directory dir1, Directory dir2, Term midTerm) : this(version, input, dir1, dir2, new TermRangeFilter(midTerm.field(), null, midTerm.bytes(), true, false))
+	  {
+	  }
+
+	  public PKIndexSplitter(Directory input, Directory dir1, Directory dir2, Term midTerm, IndexWriterConfig config1, IndexWriterConfig config2) : this(input, dir1, dir2, new TermRangeFilter(midTerm.field(), null, midTerm.bytes(), true, false), config1, config2)
+	  {
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public void split() throws java.io.IOException
+	  public virtual void Split()
+	  {
+		bool success = false;
+		DirectoryReader reader = DirectoryReader.open(input);
+		try
+		{
+		  // pass an individual config in here since one config can not be reused!
+		  createIndex(config1, dir1, reader, docsInFirstIndex, false);
+		  createIndex(config2, dir2, reader, docsInFirstIndex, true);
+		  success = true;
+		}
+		finally
+		{
+		  if (success)
+		  {
+			IOUtils.close(reader);
+		  }
+		  else
+		  {
+			IOUtils.closeWhileHandlingException(reader);
+		  }
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private void createIndex(IndexWriterConfig config, org.apache.lucene.store.Directory target, IndexReader reader, org.apache.lucene.search.Filter preserveFilter, boolean negateFilter) throws java.io.IOException
+	  private void createIndex(IndexWriterConfig config, Directory target, IndexReader reader, Filter preserveFilter, bool negateFilter)
+	  {
+		bool success = false;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final IndexWriter w = new IndexWriter(target, config);
+		IndexWriter w = new IndexWriter(target, config);
+		try
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.util.List<AtomicReaderContext> leaves = reader.leaves();
+		  IList<AtomicReaderContext> leaves = reader.leaves();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final IndexReader[] subReaders = new IndexReader[leaves.size()];
+		  IndexReader[] subReaders = new IndexReader[leaves.Count];
+		  int i = 0;
+		  foreach (AtomicReaderContext ctx in leaves)
+		  {
+			subReaders[i++] = new DocumentFilteredAtomicIndexReader(ctx, preserveFilter, negateFilter);
+		  }
+		  w.addIndexes(subReaders);
+		  success = true;
+		}
+		finally
+		{
+		  if (success)
+		  {
+			IOUtils.close(w);
+		  }
+		  else
+		  {
+			IOUtils.closeWhileHandlingException(w);
+		  }
+		}
+	  }
+
+	  private class DocumentFilteredAtomicIndexReader : FilterAtomicReader
+	  {
+		internal readonly Bits liveDocs;
+		internal readonly int numDocs_Renamed;
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public DocumentFilteredAtomicIndexReader(AtomicReaderContext context, org.apache.lucene.search.Filter preserveFilter, boolean negateFilter) throws java.io.IOException
+		public DocumentFilteredAtomicIndexReader(AtomicReaderContext context, Filter preserveFilter, bool negateFilter) : base(context.reader())
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int maxDoc = in.maxDoc();
+		  int maxDoc = @in.maxDoc();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.FixedBitSet bits = new org.apache.lucene.util.FixedBitSet(maxDoc);
+		  FixedBitSet bits = new FixedBitSet(maxDoc);
+		  // ignore livedocs here, as we filter them later:
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.DocIdSet docs = preserveFilter.getDocIdSet(context, null);
+		  DocIdSet docs = preserveFilter.getDocIdSet(context, null);
+		  if (docs != null)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.DocIdSetIterator it = docs.iterator();
+			DocIdSetIterator it = docs.GetEnumerator();
+			if (it != null)
+			{
+			  bits.or(it);
+			}
+		  }
+		  if (negateFilter)
+		  {
+			bits.flip(0, maxDoc);
+		  }
+
+		  if (@in.hasDeletions())
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits oldLiveDocs = in.getLiveDocs();
+			Bits oldLiveDocs = @in.LiveDocs;
+			Debug.Assert(oldLiveDocs != null);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.DocIdSetIterator it = bits.iterator();
+			DocIdSetIterator it = bits.GetEnumerator();
+			for (int i = it.nextDoc(); i < maxDoc; i = it.nextDoc())
+			{
+			  if (!oldLiveDocs.get(i))
+			  {
+				// we can safely modify the current bit, as the iterator already stepped over it:
+				bits.clear(i);
+			  }
+			}
+		  }
+
+		  this.liveDocs = bits;
+		  this.numDocs_Renamed = bits.cardinality();
+		}
+
+		public override int numDocs()
+		{
+		  return numDocs_Renamed;
+		}
+
+		public override Bits LiveDocs
+		{
+			get
+			{
+			  return liveDocs;
+			}
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs b/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs
new file mode 100644
index 0000000..70ad20a
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/Sorter/BlockJoinComparatorSource.cs
@@ -0,0 +1,321 @@
+using System;
+
+namespace org.apache.lucene.index.sorter
+{
+
+	/*
+	 * 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.
+	 */
+
+	using DocIdSet = org.apache.lucene.search.DocIdSet;
+	using FieldComparator = org.apache.lucene.search.FieldComparator;
+	using FieldComparatorSource = org.apache.lucene.search.FieldComparatorSource;
+	using Filter = org.apache.lucene.search.Filter;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher; // javadocs
+	using Query = org.apache.lucene.search.Query; // javadocs
+	using ScoreDoc = org.apache.lucene.search.ScoreDoc; // javadocs
+	using Scorer = org.apache.lucene.search.Scorer;
+	using Sort = org.apache.lucene.search.Sort;
+	using SortField = org.apache.lucene.search.SortField;
+	using FixedBitSet = org.apache.lucene.util.FixedBitSet;
+
+	/// <summary>
+	/// Helper class to sort readers that contain blocks of documents.
+	/// <para>
+	/// Note that this class is intended to used with <seealso cref="SortingMergePolicy"/>,
+	/// and for other purposes has some limitations:
+	/// <ul>
+	///    <li>Cannot yet be used with <seealso cref="IndexSearcher#searchAfter(ScoreDoc, Query, int, Sort) IndexSearcher.searchAfter"/>
+	///    <li>Filling sort field values is not yet supported.
+	/// </ul>
+	/// @lucene.experimental
+	/// </para>
+	/// </summary>
+	// TODO: can/should we clean this thing up (e.g. return a proper sort value)
+	// and move to the join/ module?
+	public class BlockJoinComparatorSource : FieldComparatorSource
+	{
+	  internal readonly Filter parentsFilter;
+	  internal readonly Sort parentSort;
+	  internal readonly Sort childSort;
+
+	  /// <summary>
+	  /// Create a new BlockJoinComparatorSource, sorting only blocks of documents
+	  /// with {@code parentSort} and not reordering children with a block.
+	  /// </summary>
+	  /// <param name="parentsFilter"> Filter identifying parent documents </param>
+	  /// <param name="parentSort"> Sort for parent documents </param>
+	  public BlockJoinComparatorSource(Filter parentsFilter, Sort parentSort) : this(parentsFilter, parentSort, new Sort(SortField.FIELD_DOC))
+	  {
+	  }
+
+	  /// <summary>
+	  /// Create a new BlockJoinComparatorSource, specifying the sort order for both
+	  /// blocks of documents and children within a block.
+	  /// </summary>
+	  /// <param name="parentsFilter"> Filter identifying parent documents </param>
+	  /// <param name="parentSort"> Sort for parent documents </param>
+	  /// <param name="childSort"> Sort for child documents in the same block </param>
+	  public BlockJoinComparatorSource(Filter parentsFilter, Sort parentSort, Sort childSort)
+	  {
+		this.parentsFilter = parentsFilter;
+		this.parentSort = parentSort;
+		this.childSort = childSort;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.FieldComparator<Integer> newComparator(String fieldname, int numHits, int sortPos, boolean reversed) throws java.io.IOException
+	  public override FieldComparator<int?> newComparator(string fieldname, int numHits, int sortPos, bool reversed)
+	  {
+		// we keep parallel slots: the parent ids and the child ids
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int parentSlots[] = new int[numHits];
+		int[] parentSlots = new int[numHits];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int childSlots[] = new int[numHits];
+		int[] childSlots = new int[numHits];
+
+		SortField[] parentFields = parentSort.Sort;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int parentReverseMul[] = new int[parentFields.length];
+		int[] parentReverseMul = new int[parentFields.Length];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldComparator<?> parentComparators[] = new org.apache.lucene.search.FieldComparator[parentFields.length];
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+		FieldComparator<?>[] parentComparators = new FieldComparator[parentFields.Length];
+		for (int i = 0; i < parentFields.Length; i++)
+		{
+		  parentReverseMul[i] = parentFields[i].Reverse ? - 1 : 1;
+		  parentComparators[i] = parentFields[i].getComparator(1, i);
+		}
+
+		SortField[] childFields = childSort.Sort;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int childReverseMul[] = new int[childFields.length];
+		int[] childReverseMul = new int[childFields.Length];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldComparator<?> childComparators[] = new org.apache.lucene.search.FieldComparator[childFields.length];
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+		FieldComparator<?>[] childComparators = new FieldComparator[childFields.Length];
+		for (int i = 0; i < childFields.Length; i++)
+		{
+		  childReverseMul[i] = childFields[i].Reverse ? - 1 : 1;
+		  childComparators[i] = childFields[i].getComparator(1, i);
+		}
+
+		// NOTE: we could return parent ID as value but really our sort "value" is more complex...
+		// So we throw UOE for now. At the moment you really should only use this at indexing time.
+		return new FieldComparatorAnonymousInnerClassHelper(this, parentSlots, childSlots, parentReverseMul, parentComparators, childReverseMul, childComparators);
+	  }
+
+	  private class FieldComparatorAnonymousInnerClassHelper : FieldComparator<int?>
+	  {
+		  private readonly BlockJoinComparatorSource outerInstance;
+
+		  private int[] parentSlots;
+		  private int[] childSlots;
+		  private int[] parentReverseMul;
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: private org.apache.lucene.search.FieldComparator<JavaToDotNetGenericWildcard>[] parentComparators;
+		  private FieldComparator<?>[] parentComparators;
+		  private int[] childReverseMul;
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: private org.apache.lucene.search.FieldComparator<JavaToDotNetGenericWildcard>[] childComparators;
+		  private FieldComparator<?>[] childComparators;
+
+		  public FieldComparatorAnonymousInnerClassHelper<T1, T2>(BlockJoinComparatorSource outerInstance, int[] parentSlots, int[] childSlots, int[] parentReverseMul, FieldComparator<T1>[] parentComparators, int[] childReverseMul, FieldComparator<T2>[] childComparators)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.parentSlots = parentSlots;
+			  this.childSlots = childSlots;
+			  this.parentReverseMul = parentReverseMul;
+			  this.parentComparators = parentComparators;
+			  this.childReverseMul = childReverseMul;
+			  this.childComparators = childComparators;
+		  }
+
+		  internal int bottomParent;
+		  internal int bottomChild;
+		  internal FixedBitSet parentBits;
+
+		  public override int compare(int slot1, int slot2)
+		  {
+			try
+			{
+			  return compare(childSlots[slot1], parentSlots[slot1], childSlots[slot2], parentSlots[slot2]);
+			}
+			catch (IOException e)
+			{
+			  throw new Exception(e);
+			}
+		  }
+
+		  public override int Bottom
+		  {
+			  set
+			  {
+				bottomParent = parentSlots[value];
+				bottomChild = childSlots[value];
+			  }
+		  }
+
+		  public override int? TopValue
+		  {
+			  set
+			  {
+				// we dont have enough information (the docid is needed)
+				throw new System.NotSupportedException("this comparator cannot be used with deep paging");
+			  }
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int compareBottom(int doc) throws java.io.IOException
+		  public override int compareBottom(int doc)
+		  {
+			return compare(bottomChild, bottomParent, doc, parent(doc));
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int compareTop(int doc) throws java.io.IOException
+		  public override int compareTop(int doc)
+		  {
+			// we dont have enough information (the docid is needed)
+			throw new System.NotSupportedException("this comparator cannot be used with deep paging");
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void copy(int slot, int doc) throws java.io.IOException
+		  public override void copy(int slot, int doc)
+		  {
+			childSlots[slot] = doc;
+			parentSlots[slot] = parent(doc);
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.FieldComparator<Integer> setNextReader(org.apache.lucene.index.AtomicReaderContext context) throws java.io.IOException
+		  public override FieldComparator<int?> setNextReader(AtomicReaderContext context)
+		  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.DocIdSet parents = parentsFilter.getDocIdSet(context, null);
+			DocIdSet parents = outerInstance.parentsFilter.getDocIdSet(context, null);
+			if (parents == null)
+			{
+			  throw new IllegalStateException("AtomicReader " + context.reader() + " contains no parents!");
+			}
+			if (!(parents is FixedBitSet))
+			{
+			  throw new IllegalStateException("parentFilter must return FixedBitSet; got " + parents);
+			}
+			parentBits = (FixedBitSet) parents;
+			for (int i = 0; i < parentComparators.Length; i++)
+			{
+			  parentComparators[i] = parentComparators[i].setNextReader(context);
+			}
+			for (int i = 0; i < childComparators.Length; i++)
+			{
+			  childComparators[i] = childComparators[i].setNextReader(context);
+			}
+			return this;
+		  }
+
+		  public override int? value(int slot)
+		  {
+			// really our sort "value" is more complex...
+			throw new System.NotSupportedException("filling sort field values is not yet supported");
+		  }
+
+		  public override Scorer Scorer
+		  {
+			  set
+			  {
+				base.Scorer = value;
+	//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+	//ORIGINAL LINE: for (org.apache.lucene.search.FieldComparator<?> comp : parentComparators)
+				foreach (FieldComparator<?> comp in parentComparators)
+				{
+				  comp.Scorer = value;
+				}
+	//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+	//ORIGINAL LINE: for (org.apache.lucene.search.FieldComparator<?> comp : childComparators)
+				foreach (FieldComparator<?> comp in childComparators)
+				{
+				  comp.Scorer = value;
+				}
+			  }
+		  }
+
+		  internal virtual int parent(int doc)
+		  {
+			return parentBits.nextSetBit(doc);
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: int compare(int docID1, int parent1, int docID2, int parent2) throws java.io.IOException
+		  internal virtual int compare(int docID1, int parent1, int docID2, int parent2)
+		  {
+			if (parent1 == parent2) // both are in the same block
+			{
+			  if (docID1 == parent1 || docID2 == parent2)
+			  {
+				// keep parents at the end of blocks
+				return docID1 - docID2;
+			  }
+			  else
+			  {
+				return compare(docID1, docID2, childComparators, childReverseMul);
+			  }
+			}
+			else
+			{
+			  int cmp = compare(parent1, parent2, parentComparators, parentReverseMul);
+			  if (cmp == 0)
+			  {
+				return parent1 - parent2;
+			  }
+			  else
+			  {
+				return cmp;
+			  }
+			}
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: int compare(int docID1, int docID2, org.apache.lucene.search.FieldComparator<?> comparators[] , int reverseMul[]) throws java.io.IOException
+		  internal virtual int compare<T1>(int docID1, int docID2, FieldComparator<T1>[] comparators, int[] reverseMul)
+		  {
+			for (int i = 0; i < comparators.Length; i++)
+			{
+			  // TODO: would be better if copy() didnt cause a term lookup in TermOrdVal & co,
+			  // the segments are always the same here...
+			  comparators[i].copy(0, docID1);
+			  comparators[i].Bottom = 0;
+			  int comp = reverseMul[i] * comparators[i].compareBottom(docID2);
+			  if (comp != 0)
+			  {
+				return comp;
+			  }
+			}
+			return 0; // no need to docid tiebreak
+		  }
+	  }
+
+	  public override string ToString()
+	  {
+		return "blockJoin(parentSort=" + parentSort + ",childSort=" + childSort + ")";
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/Sorter/EarlyTerminatingSortingCollector.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/Sorter/EarlyTerminatingSortingCollector.cs b/src/Lucene.Net.Misc/Index/Sorter/EarlyTerminatingSortingCollector.cs
new file mode 100644
index 0000000..654ba85
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/Sorter/EarlyTerminatingSortingCollector.cs
@@ -0,0 +1,147 @@
+namespace org.apache.lucene.index.sorter
+{
+
+	/*
+	 * 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.
+	 */
+
+	using CollectionTerminatedException = org.apache.lucene.search.CollectionTerminatedException;
+	using Collector = org.apache.lucene.search.Collector;
+	using Scorer = org.apache.lucene.search.Scorer;
+	using Sort = org.apache.lucene.search.Sort;
+	using TopDocsCollector = org.apache.lucene.search.TopDocsCollector;
+	using TotalHitCountCollector = org.apache.lucene.search.TotalHitCountCollector;
+
+	/// <summary>
+	/// A <seealso cref="Collector"/> that early terminates collection of documents on a
+	/// per-segment basis, if the segment was sorted according to the given
+	/// <seealso cref="Sort"/>.
+	/// 
+	/// <para>
+	/// <b>NOTE:</b> the {@code Collector} detects sorted segments according to
+	/// <seealso cref="SortingMergePolicy"/>, so it's best used in conjunction with it. Also,
+	/// it collects up to a specified {@code numDocsToCollect} from each segment, 
+	/// and therefore is mostly suitable for use in conjunction with collectors such as
+	/// <seealso cref="TopDocsCollector"/>, and not e.g. <seealso cref="TotalHitCountCollector"/>.
+	/// </para>
+	/// <para>
+	/// <b>NOTE</b>: If you wrap a {@code TopDocsCollector} that sorts in the same
+	/// order as the index order, the returned <seealso cref="TopDocsCollector#topDocs() TopDocs"/>
+	/// will be correct. However the total of {@link TopDocsCollector#getTotalHits()
+	/// hit count} will be underestimated since not all matching documents will have
+	/// been collected.
+	/// </para>
+	/// <para>
+	/// <b>NOTE</b>: This {@code Collector} uses <seealso cref="Sort#toString()"/> to detect
+	/// whether a segment was sorted with the same {@code Sort}. This has
+	/// two implications:
+	/// <ul>
+	/// <li>if a custom comparator is not implemented correctly and returns
+	/// different identifiers for equivalent instances, this collector will not
+	/// detect sorted segments,</li>
+	/// <li>if you suddenly change the <seealso cref="IndexWriter"/>'s
+	/// {@code SortingMergePolicy} to sort according to another criterion and if both
+	/// the old and the new {@code Sort}s have the same identifier, this
+	/// {@code Collector} will incorrectly detect sorted segments.</li>
+	/// </ul>
+	/// 
+	/// @lucene.experimental
+	/// </para>
+	/// </summary>
+	public class EarlyTerminatingSortingCollector : Collector
+	{
+	  /// <summary>
+	  /// The wrapped Collector </summary>
+	  protected internal readonly Collector @in;
+	  /// <summary>
+	  /// Sort used to sort the search results </summary>
+	  protected internal readonly Sort sort;
+	  /// <summary>
+	  /// Number of documents to collect in each segment </summary>
+	  protected internal readonly int numDocsToCollect;
+	  /// <summary>
+	  /// Number of documents to collect in the current segment being processed </summary>
+	  protected internal int segmentTotalCollect;
+	  /// <summary>
+	  /// True if the current segment being processed is sorted by <seealso cref="#sort"/> </summary>
+	  protected internal bool segmentSorted;
+
+	  private int numCollected;
+
+	  /// <summary>
+	  /// Create a new <seealso cref="EarlyTerminatingSortingCollector"/> instance.
+	  /// </summary>
+	  /// <param name="in">
+	  ///          the collector to wrap </param>
+	  /// <param name="sort">
+	  ///          the sort you are sorting the search results on </param>
+	  /// <param name="numDocsToCollect">
+	  ///          the number of documents to collect on each segment. When wrapping
+	  ///          a <seealso cref="TopDocsCollector"/>, this number should be the number of
+	  ///          hits. </param>
+	  public EarlyTerminatingSortingCollector(Collector @in, Sort sort, int numDocsToCollect)
+	  {
+		if (numDocsToCollect <= 0)
+		{
+		  throw new IllegalStateException("numDocsToCollect must always be > 0, got " + segmentTotalCollect);
+		}
+		this.@in = @in;
+		this.sort = sort;
+		this.numDocsToCollect = numDocsToCollect;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void setScorer(org.apache.lucene.search.Scorer scorer) throws java.io.IOException
+	  public override Scorer Scorer
+	  {
+		  set
+		  {
+			@in.Scorer = value;
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void collect(int doc) throws java.io.IOException
+	  public override void collect(int doc)
+	  {
+		@in.collect(doc);
+		if (++numCollected >= segmentTotalCollect)
+		{
+		  throw new CollectionTerminatedException();
+		}
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void setNextReader(org.apache.lucene.index.AtomicReaderContext context) throws java.io.IOException
+	  public override AtomicReaderContext NextReader
+	  {
+		  set
+		  {
+			@in.NextReader = value;
+			segmentSorted = SortingMergePolicy.isSorted(value.reader(), sort);
+			segmentTotalCollect = segmentSorted ? numDocsToCollect : int.MaxValue;
+			numCollected = 0;
+		  }
+	  }
+
+	  public override bool acceptsDocsOutOfOrder()
+	  {
+		return !segmentSorted && @in.acceptsDocsOutOfOrder();
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/674f0cb9/src/Lucene.Net.Misc/Index/Sorter/Sorter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Misc/Index/Sorter/Sorter.cs b/src/Lucene.Net.Misc/Index/Sorter/Sorter.cs
new file mode 100644
index 0000000..f315b9c
--- /dev/null
+++ b/src/Lucene.Net.Misc/Index/Sorter/Sorter.cs
@@ -0,0 +1,404 @@
+using System;
+using System.Diagnostics;
+
+namespace org.apache.lucene.index.sorter
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using FieldComparator = org.apache.lucene.search.FieldComparator;
+	using Scorer = org.apache.lucene.search.Scorer;
+	using Sort = org.apache.lucene.search.Sort;
+	using SortField = org.apache.lucene.search.SortField;
+	using TimSorter = org.apache.lucene.util.TimSorter;
+	using MonotonicAppendingLongBuffer = org.apache.lucene.util.packed.MonotonicAppendingLongBuffer;
+
+	/// <summary>
+	/// Sorts documents of a given index by returning a permutation on the document
+	/// IDs.
+	/// @lucene.experimental
+	/// </summary>
+	internal sealed class Sorter
+	{
+	  internal readonly Sort sort_Renamed;
+
+	  /// <summary>
+	  /// Creates a new Sorter to sort the index with {@code sort} </summary>
+	  internal Sorter(Sort sort)
+	  {
+		if (sort.needsScores())
+		{
+		  throw new System.ArgumentException("Cannot sort an index with a Sort that refers to the relevance score");
+		}
+		this.sort_Renamed = sort;
+	  }
+
+	  /// <summary>
+	  /// A permutation of doc IDs. For every document ID between <tt>0</tt> and
+	  /// <seealso cref="IndexReader#maxDoc()"/>, <code>oldToNew(newToOld(docID))</code> must
+	  /// return <code>docID</code>.
+	  /// </summary>
+	  internal abstract class DocMap
+	  {
+
+		/// <summary>
+		/// Given a doc ID from the original index, return its ordinal in the
+		///  sorted index. 
+		/// </summary>
+		internal abstract int oldToNew(int docID);
+
+		/// <summary>
+		/// Given the ordinal of a doc ID, return its doc ID in the original index. </summary>
+		internal abstract int newToOld(int docID);
+
+		/// <summary>
+		/// Return the number of documents in this map. This must be equal to the
+		///  <seealso cref="AtomicReader#maxDoc() number of documents"/> of the
+		///  <seealso cref="AtomicReader"/> which is sorted. 
+		/// </summary>
+		internal abstract int size();
+	  }
+
+	  /// <summary>
+	  /// Check consistency of a <seealso cref="DocMap"/>, useful for assertions. </summary>
+	  internal static bool isConsistent(DocMap docMap)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int maxDoc = docMap.size();
+		int maxDoc = docMap.size();
+		for (int i = 0; i < maxDoc; ++i)
+		{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int newID = docMap.oldToNew(i);
+		  int newID = docMap.oldToNew(i);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int oldID = docMap.newToOld(newID);
+		  int oldID = docMap.newToOld(newID);
+		  Debug.Assert(newID >= 0 && newID < maxDoc, "doc IDs must be in [0-" + maxDoc + "[, got " + newID);
+		  Debug.Assert(i == oldID, "mapping is inconsistent: " + i + " --oldToNew--> " + newID + " --newToOld--> " + oldID);
+		  if (i != oldID || newID < 0 || newID >= maxDoc)
+		  {
+			return false;
+		  }
+		}
+		return true;
+	  }
+
+	  /// <summary>
+	  /// A comparator of doc IDs. </summary>
+	  internal abstract class DocComparator
+	  {
+
+		/// <summary>
+		/// Compare docID1 against docID2. The contract for the return value is the
+		///  same as <seealso cref="Comparator#compare(Object, Object)"/>. 
+		/// </summary>
+		public abstract int compare(int docID1, int docID2);
+
+	  }
+
+	  private sealed class DocValueSorter : TimSorter
+	  {
+
+		internal readonly int[] docs;
+		internal readonly Sorter.DocComparator comparator;
+		internal readonly int[] tmp;
+
+		internal DocValueSorter(int[] docs, Sorter.DocComparator comparator) : base(docs.Length / 64)
+		{
+		  this.docs = docs;
+		  this.comparator = comparator;
+		  tmp = new int[docs.Length / 64];
+		}
+
+		protected internal override int compare(int i, int j)
+		{
+		  return comparator.compare(docs[i], docs[j]);
+		}
+
+		protected internal override void swap(int i, int j)
+		{
+		  int tmpDoc = docs[i];
+		  docs[i] = docs[j];
+		  docs[j] = tmpDoc;
+		}
+
+		protected internal override void copy(int src, int dest)
+		{
+		  docs[dest] = docs[src];
+		}
+
+		protected internal override void save(int i, int len)
+		{
+		  Array.Copy(docs, i, tmp, 0, len);
+		}
+
+		protected internal override void restore(int i, int j)
+		{
+		  docs[j] = tmp[i];
+		}
+
+		protected internal override int compareSaved(int i, int j)
+		{
+		  return comparator.compare(tmp[i], docs[j]);
+		}
+	  }
+
+	  /// <summary>
+	  /// Computes the old-to-new permutation over the given comparator. </summary>
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: private static Sorter.DocMap sort(final int maxDoc, DocComparator comparator)
+	  private static Sorter.DocMap sort(int maxDoc, DocComparator comparator)
+	  {
+		// check if the index is sorted
+		bool sorted = true;
+		for (int i = 1; i < maxDoc; ++i)
+		{
+		  if (comparator.compare(i - 1, i) > 0)
+		  {
+			sorted = false;
+			break;
+		  }
+		}
+		if (sorted)
+		{
+		  return null;
+		}
+
+		// sort doc IDs
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int[] docs = new int[maxDoc];
+		int[] docs = new int[maxDoc];
+		for (int i = 0; i < maxDoc; i++)
+		{
+		  docs[i] = i;
+		}
+
+		DocValueSorter sorter = new DocValueSorter(docs, comparator);
+		// It can be common to sort a reader, add docs, sort it again, ... and in
+		// that case timSort can save a lot of time
+		sorter.sort(0, docs.Length); // docs is now the newToOld mapping
+
+		// The reason why we use MonotonicAppendingLongBuffer here is that it
+		// wastes very little memory if the index is in random order but can save
+		// a lot of memory if the index is already "almost" sorted
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.packed.MonotonicAppendingLongBuffer newToOld = new org.apache.lucene.util.packed.MonotonicAppendingLongBuffer();
+		MonotonicAppendingLongBuffer newToOld = new MonotonicAppendingLongBuffer();
+		for (int i = 0; i < maxDoc; ++i)
+		{
+		  newToOld.add(docs[i]);
+		}
+		newToOld.freeze();
+
+		for (int i = 0; i < maxDoc; ++i)
+		{
+		  docs[(int) newToOld.get(i)] = i;
+		} // docs is now the oldToNew mapping
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.packed.MonotonicAppendingLongBuffer oldToNew = new org.apache.lucene.util.packed.MonotonicAppendingLongBuffer();
+		MonotonicAppendingLongBuffer oldToNew = new MonotonicAppendingLongBuffer();
+		for (int i = 0; i < maxDoc; ++i)
+		{
+		  oldToNew.add(docs[i]);
+		}
+		oldToNew.freeze();
+
+		return new DocMapAnonymousInnerClassHelper(maxDoc, newToOld, oldToNew);
+	  }
+
+	  private class DocMapAnonymousInnerClassHelper : Sorter.DocMap
+	  {
+		  private int maxDoc;
+		  private MonotonicAppendingLongBuffer newToOld;
+		  private MonotonicAppendingLongBuffer oldToNew;
+
+		  public DocMapAnonymousInnerClassHelper(int maxDoc, MonotonicAppendingLongBuffer newToOld, MonotonicAppendingLongBuffer oldToNew)
+		  {
+			  this.maxDoc = maxDoc;
+			  this.newToOld = newToOld;
+			  this.oldToNew = oldToNew;
+		  }
+
+
+		  public override int oldToNew(int docID)
+		  {
+			return (int) oldToNew.get(docID);
+		  }
+
+		  public override int newToOld(int docID)
+		  {
+			return (int) newToOld.get(docID);
+		  }
+
+		  public override int size()
+		  {
+			return maxDoc;
+		  }
+	  }
+
+	  /// <summary>
+	  /// Returns a mapping from the old document ID to its new location in the
+	  /// sorted index. Implementations can use the auxiliary
+	  /// <seealso cref="#sort(int, DocComparator)"/> to compute the old-to-new permutation
+	  /// given a list of documents and their corresponding values.
+	  /// <para>
+	  /// A return value of <tt>null</tt> is allowed and means that
+	  /// <code>reader</code> is already sorted.
+	  /// </para>
+	  /// <para>
+	  /// <b>NOTE:</b> deleted documents are expected to appear in the mapping as
+	  /// well, they will however be marked as deleted in the sorted view.
+	  /// </para>
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: DocMap sort(org.apache.lucene.index.AtomicReader reader) throws java.io.IOException
+	  internal DocMap sort(AtomicReader reader)
+	  {
+		SortField[] fields = sort_Renamed.Sort;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int reverseMul[] = new int[fields.length];
+		int[] reverseMul = new int[fields.Length];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldComparator<?> comparators[] = new org.apache.lucene.search.FieldComparator[fields.length];
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+		FieldComparator<?>[] comparators = new FieldComparator[fields.Length];
+
+		for (int i = 0; i < fields.Length; i++)
+		{
+		  reverseMul[i] = fields[i].Reverse ? - 1 : 1;
+		  comparators[i] = fields[i].getComparator(1, i);
+		  comparators[i].NextReader = reader.Context;
+		  comparators[i].Scorer = FAKESCORER;
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final DocComparator comparator = new DocComparator()
+		DocComparator comparator = new DocComparatorAnonymousInnerClassHelper(this, reverseMul, comparators);
+		return sort(reader.maxDoc(), comparator);
+	  }
+
+	  private class DocComparatorAnonymousInnerClassHelper : DocComparator
+	  {
+		  private readonly Sorter outerInstance;
+
+		  private int[] reverseMul;
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: private org.apache.lucene.search.FieldComparator<JavaToDotNetGenericWildcard>[] comparators;
+		  private FieldComparator<?>[] comparators;
+
+		  public DocComparatorAnonymousInnerClassHelper<T1>(Sorter outerInstance, int[] reverseMul, FieldComparator<T1>[] comparators)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.reverseMul = reverseMul;
+			  this.comparators = comparators;
+		  }
+
+		  public override int compare(int docID1, int docID2)
+		  {
+			try
+			{
+			  for (int i = 0; i < comparators.Length; i++)
+			  {
+				// TODO: would be better if copy() didnt cause a term lookup in TermOrdVal & co,
+				// the segments are always the same here...
+				comparators[i].copy(0, docID1);
+				comparators[i].Bottom = 0;
+				int comp = reverseMul[i] * comparators[i].compareBottom(docID2);
+				if (comp != 0)
+				{
+				  return comp;
+				}
+			  }
+			  return int.compare(docID1, docID2); // docid order tiebreak
+			}
+			catch (IOException e)
+			{
+			  throw new Exception(e);
+			}
+		  }
+	  }
+
+	  /// <summary>
+	  /// Returns the identifier of this <seealso cref="Sorter"/>.
+	  /// <para>This identifier is similar to <seealso cref="Object#hashCode()"/> and should be
+	  /// chosen so that two instances of this class that sort documents likewise
+	  /// will have the same identifier. On the contrary, this identifier should be
+	  /// different on different <seealso cref="Sort sorts"/>.
+	  /// </para>
+	  /// </summary>
+	  public string ID
+	  {
+		  get
+		  {
+			return sort_Renamed.ToString();
+		  }
+	  }
+
+	  public override string ToString()
+	  {
+		return ID;
+	  }
+
+	  internal static readonly Scorer FAKESCORER = new ScorerAnonymousInnerClassHelper();
+
+	  private class ScorerAnonymousInnerClassHelper : Scorer
+	  {
+		  public ScorerAnonymousInnerClassHelper() : base(null)
+		  {
+		  }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public float score() throws java.io.IOException
+		  public override float score()
+		  {
+			  throw new System.NotSupportedException();
+		  }
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int freq() throws java.io.IOException
+		  public override int freq()
+		  {
+			  throw new System.NotSupportedException();
+		  }
+		  public override int docID()
+		  {
+			  throw new System.NotSupportedException();
+		  }
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int nextDoc() throws java.io.IOException
+		  public override int nextDoc()
+		  {
+			  throw new System.NotSupportedException();
+		  }
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public int advance(int target) throws java.io.IOException
+		  public override int advance(int target)
+		  {
+			  throw new System.NotSupportedException();
+		  }
+		  public override long cost()
+		  {
+			  throw new System.NotSupportedException();
+		  }
+	  }
+
+	}
+
+}
\ No newline at end of file


[04/11] Skeleton porting of Lucene.Net.Queries

Posted by sy...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/MultiBoolFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/MultiBoolFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/MultiBoolFunction.cs
new file mode 100644
index 0000000..56810a3
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/MultiBoolFunction.cs
@@ -0,0 +1,148 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using BoolDocValues = org.apache.lucene.queries.function.docvalues.BoolDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// Abstract <seealso cref="ValueSource"/> implementation which wraps multiple ValueSources
+	/// and applies an extendible boolean function to their values.
+	/// 
+	/// </summary>
+	public abstract class MultiBoolFunction : BoolFunction
+	{
+	  protected internal readonly IList<ValueSource> sources;
+
+	  public MultiBoolFunction(IList<ValueSource> sources)
+	  {
+		this.sources = sources;
+	  }
+
+	  protected internal abstract string name();
+
+	  protected internal abstract bool func(int doc, FunctionValues[] vals);
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.docvalues.BoolDocValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override BoolDocValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues[] vals = new org.apache.lucene.queries.function.FunctionValues[sources.size()];
+		FunctionValues[] vals = new FunctionValues[sources.Count];
+		int i = 0;
+		foreach (ValueSource source in sources)
+		{
+		  vals[i++] = source.getValues(context, readerContext);
+		}
+
+		return new BoolDocValuesAnonymousInnerClassHelper(this, this, vals);
+	  }
+
+	  private class BoolDocValuesAnonymousInnerClassHelper : BoolDocValues
+	  {
+		  private readonly MultiBoolFunction outerInstance;
+
+		  private FunctionValues[] vals;
+
+		  public BoolDocValuesAnonymousInnerClassHelper(MultiBoolFunction outerInstance, org.apache.lucene.queries.function.valuesource.MultiBoolFunction this, FunctionValues[] vals) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.vals = vals;
+		  }
+
+		  public override bool boolVal(int doc)
+		  {
+			return outerInstance.func(doc, vals);
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			StringBuilder sb = new StringBuilder(outerInstance.name());
+			sb.Append('(');
+			bool first = true;
+			foreach (FunctionValues dv in vals)
+			{
+			  if (first)
+			  {
+				first = false;
+			  }
+			  else
+			  {
+				sb.Append(',');
+			  }
+			  sb.Append(dv.ToString(doc));
+			}
+			return sb.ToString();
+		  }
+	  }
+
+	  public override string description()
+	  {
+		StringBuilder sb = new StringBuilder(name());
+		sb.Append('(');
+		bool first = true;
+		foreach (ValueSource source in sources)
+		{
+		  if (first)
+		  {
+			first = false;
+		  }
+		  else
+		  {
+			sb.Append(',');
+		  }
+		  sb.Append(source.description());
+		}
+		return sb.ToString();
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return sources.GetHashCode() + name().GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		MultiBoolFunction other = (MultiBoolFunction)o;
+		return this.sources.Equals(other.sources);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		foreach (ValueSource source in sources)
+		{
+		  source.createWeight(context, searcher);
+		}
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/MultiFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/MultiFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/MultiFloatFunction.cs
new file mode 100644
index 0000000..90b56ff
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/MultiFloatFunction.cs
@@ -0,0 +1,146 @@
+using System.Collections;
+using System.Text;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+
+	/// <summary>
+	/// Abstract <seealso cref="ValueSource"/> implementation which wraps multiple ValueSources
+	/// and applies an extendible float function to their values.
+	/// 
+	/// </summary>
+	public abstract class MultiFloatFunction : ValueSource
+	{
+	  protected internal readonly ValueSource[] sources;
+
+	  public MultiFloatFunction(ValueSource[] sources)
+	  {
+		this.sources = sources;
+	  }
+
+	  protected internal abstract string name();
+	  protected internal abstract float func(int doc, FunctionValues[] valsArr);
+
+	  public override string description()
+	  {
+		StringBuilder sb = new StringBuilder();
+		sb.Append(name()).Append('(');
+		bool firstTime = true;
+		foreach (ValueSource source in sources)
+		{
+		  if (firstTime)
+		  {
+			firstTime = false;
+		  }
+		  else
+		  {
+			sb.Append(',');
+		  }
+		  sb.Append(source);
+		}
+		sb.Append(')');
+		return sb.ToString();
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues[] valsArr = new org.apache.lucene.queries.function.FunctionValues[sources.length];
+		FunctionValues[] valsArr = new FunctionValues[sources.Length];
+		for (int i = 0; i < sources.Length; i++)
+		{
+		  valsArr[i] = sources[i].getValues(context, readerContext);
+		}
+
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, valsArr);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly MultiFloatFunction outerInstance;
+
+		  private FunctionValues[] valsArr;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(MultiFloatFunction outerInstance, org.apache.lucene.queries.function.valuesource.MultiFloatFunction this, FunctionValues[] valsArr) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.valsArr = valsArr;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return outerInstance.func(doc, valsArr);
+		  }
+		   public override string ToString(int doc)
+		   {
+			StringBuilder sb = new StringBuilder();
+			sb.Append(outerInstance.name()).Append('(');
+			bool firstTime = true;
+			foreach (FunctionValues vals in valsArr)
+			{
+			  if (firstTime)
+			  {
+				firstTime = false;
+			  }
+			  else
+			  {
+				sb.Append(',');
+			  }
+			  sb.Append(vals.ToString(doc));
+			}
+			sb.Append(')');
+			return sb.ToString();
+		   }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		foreach (ValueSource source in sources)
+		{
+		  source.createWeight(context, searcher);
+		}
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return Arrays.GetHashCode(sources) + name().GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		MultiFloatFunction other = (MultiFloatFunction)o;
+		return this.name().Equals(other.name()) && Arrays.Equals(this.sources, other.sources);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/MultiFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/MultiFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/MultiFunction.cs
new file mode 100644
index 0000000..089d21c
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/MultiFunction.cs
@@ -0,0 +1,161 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// Abstract parent class for <seealso cref="ValueSource"/> implementations that wrap multiple
+	/// ValueSources and apply their own logic.
+	/// </summary>
+	public abstract class MultiFunction : ValueSource
+	{
+	  protected internal readonly IList<ValueSource> sources;
+
+	  public MultiFunction(IList<ValueSource> sources)
+	  {
+		this.sources = sources;
+	  }
+
+	  protected internal abstract string name();
+
+	  public override string description()
+	  {
+		return description(name(), sources);
+	  }
+
+	  public static string description(string name, IList<ValueSource> sources)
+	  {
+		StringBuilder sb = new StringBuilder();
+		sb.Append(name).Append('(');
+		bool firstTime = true;
+		foreach (ValueSource source in sources)
+		{
+		  if (firstTime)
+		  {
+			firstTime = false;
+		  }
+		  else
+		  {
+			sb.Append(',');
+		  }
+		  sb.Append(source);
+		}
+		sb.Append(')');
+		return sb.ToString();
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public static org.apache.lucene.queries.function.FunctionValues[] valsArr(java.util.List<org.apache.lucene.queries.function.ValueSource> sources, java.util.Map fcontext, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public static FunctionValues[] valsArr(IList<ValueSource> sources, IDictionary fcontext, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues[] valsArr = new org.apache.lucene.queries.function.FunctionValues[sources.size()];
+		FunctionValues[] valsArr = new FunctionValues[sources.Count];
+		int i = 0;
+		foreach (ValueSource source in sources)
+		{
+		  valsArr[i++] = source.getValues(fcontext, readerContext);
+		}
+		return valsArr;
+	  }
+
+	  public class Values : FunctionValues
+	  {
+		  private readonly MultiFunction outerInstance;
+
+		internal readonly FunctionValues[] valsArr;
+
+		public Values(MultiFunction outerInstance, FunctionValues[] valsArr)
+		{
+			this.outerInstance = outerInstance;
+		  this.valsArr = valsArr;
+		}
+
+		public override string ToString(int doc)
+		{
+		  return MultiFunction.ToString(outerInstance.name(), valsArr, doc);
+		}
+
+		public override ValueFiller ValueFiller
+		{
+			get
+			{
+			  // TODO: need ValueSource.type() to determine correct type
+			  return base.ValueFiller;
+			}
+		}
+	  }
+
+
+	  public static string ToString(string name, FunctionValues[] valsArr, int doc)
+	  {
+		StringBuilder sb = new StringBuilder();
+		sb.Append(name).Append('(');
+		bool firstTime = true;
+		foreach (FunctionValues vals in valsArr)
+		{
+		  if (firstTime)
+		  {
+			firstTime = false;
+		  }
+		  else
+		  {
+			sb.Append(',');
+		  }
+		  sb.Append(vals.ToString(doc));
+		}
+		sb.Append(')');
+		return sb.ToString();
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		foreach (ValueSource source in sources)
+		{
+		  source.createWeight(context, searcher);
+		}
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return sources.GetHashCode() + name().GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		MultiFunction other = (MultiFunction)o;
+		return this.sources.Equals(other.sources);
+	  }
+	}
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/MultiValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/MultiValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/MultiValueSource.cs
new file mode 100644
index 0000000..908eae9
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/MultiValueSource.cs
@@ -0,0 +1,32 @@
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+
+	/// <summary>
+	/// A <seealso cref="ValueSource"/> that abstractly represents <seealso cref="ValueSource"/>s for
+	/// poly fields, and other things.
+	/// 
+	/// </summary>
+	public abstract class MultiValueSource : ValueSource
+	{
+
+	  public abstract int dimension();
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/NormValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/NormValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/NormValueSource.cs
new file mode 100644
index 0000000..d0de6c1
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/NormValueSource.cs
@@ -0,0 +1,125 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using NumericDocValues = org.apache.lucene.index.NumericDocValues;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using TFIDFSimilarity = org.apache.lucene.search.similarities.TFIDFSimilarity;
+
+
+	/// <summary>
+	/// Function that returns <seealso cref="TFIDFSimilarity#decodeNormValue(long)"/>
+	/// for every document.
+	/// <para>
+	/// Note that the configured Similarity for the field must be
+	/// a subclass of <seealso cref="TFIDFSimilarity"/>
+	/// @lucene.internal 
+	/// </para>
+	/// </summary>
+	public class NormValueSource : ValueSource
+	{
+	  protected internal readonly string field;
+	  public NormValueSource(string field)
+	  {
+		this.field = field;
+	  }
+
+	  public virtual string name()
+	  {
+		return "norm";
+	  }
+
+	  public override string description()
+	  {
+		return name() + '(' + field + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		context["searcher"] = searcher;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		IndexSearcher searcher = (IndexSearcher)context["searcher"];
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.similarities.TFIDFSimilarity similarity = IDFValueSource.asTFIDF(searcher.getSimilarity(), field);
+		TFIDFSimilarity similarity = IDFValueSource.asTFIDF(searcher.Similarity, field);
+		if (similarity == null)
+		{
+		  throw new System.NotSupportedException("requires a TFIDFSimilarity (such as DefaultSimilarity)");
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.NumericDocValues norms = readerContext.reader().getNormValues(field);
+		NumericDocValues norms = readerContext.reader().getNormValues(field);
+
+		if (norms == null)
+		{
+		  return new ConstDoubleDocValues(0.0, this);
+		}
+
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, similarity, norms);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly NormValueSource outerInstance;
+
+		  private TFIDFSimilarity similarity;
+		  private NumericDocValues norms;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(NormValueSource outerInstance, org.apache.lucene.queries.function.valuesource.NormValueSource this, TFIDFSimilarity similarity, NumericDocValues norms) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.similarity = similarity;
+			  this.norms = norms;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return similarity.decodeNormValue(norms.get(doc));
+		  }
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+		  return false;
+		}
+		return this.field.Equals(((NormValueSource)o).field);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return this.GetType().GetHashCode() + field.GetHashCode();
+	  }
+	}
+
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/NumDocsValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/NumDocsValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/NumDocsValueSource.cs
new file mode 100644
index 0000000..b5e6669
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/NumDocsValueSource.cs
@@ -0,0 +1,63 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using ReaderUtil = org.apache.lucene.index.ReaderUtil;
+
+
+	/// <summary>
+	/// Returns the value of <seealso cref="IndexReader#numDocs()"/>
+	/// for every document. This is the number of documents
+	/// excluding deletions.
+	/// </summary>
+	public class NumDocsValueSource : ValueSource
+	{
+	  public virtual string name()
+	  {
+		return "numdocs";
+	  }
+
+	  public override string description()
+	  {
+		return name() + "()";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		// Searcher has no numdocs so we must use the reader instead
+		return new ConstIntDocValues(ReaderUtil.getTopLevelContext(readerContext).reader().numDocs(), this);
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		return this.GetType() == o.GetType();
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return this.GetType().GetHashCode();
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/OrdFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/OrdFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/OrdFieldSource.cs
new file mode 100644
index 0000000..123327f
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/OrdFieldSource.cs
@@ -0,0 +1,175 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	using AtomicReader = org.apache.lucene.index.AtomicReader;
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using CompositeReader = org.apache.lucene.index.CompositeReader;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using ReaderUtil = org.apache.lucene.index.ReaderUtil;
+	using SlowCompositeReaderWrapper = org.apache.lucene.index.SlowCompositeReaderWrapper;
+	using SortedDocValues = org.apache.lucene.index.SortedDocValues;
+	using IntDocValues = org.apache.lucene.queries.function.docvalues.IntDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueInt = org.apache.lucene.util.mutable.MutableValueInt;
+
+	/// <summary>
+	/// Obtains the ordinal of the field value from the default Lucene <seealso cref="org.apache.lucene.search.FieldCache"/> using getStringIndex().
+	/// <br>
+	/// The native lucene index order is used to assign an ordinal value for each field value.
+	/// <br>Field values (terms) are lexicographically ordered by unicode value, and numbered starting at 1.
+	/// <br>
+	/// Example:<br>
+	///  If there were only three field values: "apple","banana","pear"
+	/// <br>then ord("apple")=1, ord("banana")=2, ord("pear")=3
+	/// <para>
+	/// WARNING: ord() depends on the position in an index and can thus change when other documents are inserted or deleted,
+	///  or if a MultiSearcher is used.
+	/// <br>WARNING: as of Solr 1.4, ord() and rord() can cause excess memory use since they must use a FieldCache entry
+	/// at the top level reader, while sorting and function queries now use entries at the segment level.  Hence sorting
+	/// or using a different function query, in addition to ord()/rord() will double memory use.
+	/// 
+	/// </para>
+	/// </summary>
+
+	public class OrdFieldSource : ValueSource
+	{
+	  protected internal readonly string field;
+
+	  public OrdFieldSource(string field)
+	  {
+		this.field = field;
+	  }
+
+	  public override string description()
+	  {
+		return "ord(" + field + ')';
+	  }
+
+
+	  // TODO: this is trappy? perhaps this query instead should make you pass a slow reader yourself?
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int off = readerContext.docBase;
+		int off = readerContext.docBase;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.IndexReader topReader = org.apache.lucene.index.ReaderUtil.getTopLevelContext(readerContext).reader();
+		IndexReader topReader = ReaderUtil.getTopLevelContext(readerContext).reader();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.AtomicReader r = org.apache.lucene.index.SlowCompositeReaderWrapper.wrap(topReader);
+		AtomicReader r = SlowCompositeReaderWrapper.wrap(topReader);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.SortedDocValues sindex = org.apache.lucene.search.FieldCache.DEFAULT.getTermsIndex(r, field);
+		SortedDocValues sindex = FieldCache.DEFAULT.getTermsIndex(r, field);
+		return new IntDocValuesAnonymousInnerClassHelper(this, this, off, sindex);
+	  }
+
+	  private class IntDocValuesAnonymousInnerClassHelper : IntDocValues
+	  {
+		  private readonly OrdFieldSource outerInstance;
+
+		  private int off;
+		  private SortedDocValues sindex;
+
+		  public IntDocValuesAnonymousInnerClassHelper(OrdFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.OrdFieldSource this, int off, SortedDocValues sindex) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.off = off;
+			  this.sindex = sindex;
+		  }
+
+		  protected internal virtual string toTerm(string readableValue)
+		  {
+			return readableValue;
+		  }
+		  public override int intVal(int doc)
+		  {
+			return sindex.getOrd(doc + off);
+		  }
+		  public override int ordVal(int doc)
+		  {
+			return sindex.getOrd(doc + off);
+		  }
+		  public override int numOrd()
+		  {
+			return sindex.ValueCount;
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			return sindex.getOrd(doc + off) != 0;
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				return new ValueFillerAnonymousInnerClassHelper(this);
+			  }
+		  }
+
+		  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+		  {
+			  private readonly IntDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public ValueFillerAnonymousInnerClassHelper(IntDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+				  mval = new MutableValueInt();
+			  }
+
+			  private readonly MutableValueInt mval;
+
+			  public override MutableValue Value
+			  {
+				  get
+				  {
+					return mval;
+				  }
+			  }
+
+			  public override void fillValue(int doc)
+			  {
+				mval.value = outerInstance.sindex.getOrd(doc);
+				mval.exists = mval.value != 0;
+			  }
+		  }
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		return o != null && o.GetType() == typeof(OrdFieldSource) && this.field.Equals(((OrdFieldSource)o).field);
+	  }
+
+	  private static readonly int hcode = typeof(OrdFieldSource).GetHashCode();
+	  public override int GetHashCode()
+	  {
+		return hcode + field.GetHashCode();
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/PowFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/PowFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/PowFloatFunction.cs
new file mode 100644
index 0000000..99b4c42
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/PowFloatFunction.cs
@@ -0,0 +1,48 @@
+using System;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	/// <summary>
+	/// Function to raise the base "a" to the power "b"
+	/// </summary>
+	public class PowFloatFunction : DualFloatFunction
+	{
+	 /// <param name="a">  the base. </param>
+	 /// <param name="b">  the exponent. </param>
+	  public PowFloatFunction(ValueSource a, ValueSource b) : base(a,b)
+	  {
+	  }
+
+	  protected internal override string name()
+	  {
+		return "pow";
+	  }
+
+	  protected internal override float func(int doc, FunctionValues aVals, FunctionValues bVals)
+	  {
+		return (float)Math.Pow(aVals.floatVal(doc), bVals.floatVal(doc));
+	  }
+	}
+
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ProductFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ProductFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/ProductFloatFunction.cs
new file mode 100644
index 0000000..92cc4d7
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ProductFloatFunction.cs
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	/// <summary>
+	/// <code>ProductFloatFunction</code> returns the product of it's components.
+	/// </summary>
+	public class ProductFloatFunction : MultiFloatFunction
+	{
+	  public ProductFloatFunction(ValueSource[] sources) : base(sources)
+	  {
+	  }
+
+	  protected internal override string name()
+	  {
+		return "product";
+	  }
+
+	  protected internal override float func(int doc, FunctionValues[] valsArr)
+	  {
+		float val = 1.0f;
+		foreach (FunctionValues vals in valsArr)
+		{
+		  val *= vals.floatVal(doc);
+		}
+		return val;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/QueryValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/QueryValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/QueryValueSource.cs
new file mode 100644
index 0000000..9abc198
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/QueryValueSource.cs
@@ -0,0 +1,328 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using ReaderUtil = org.apache.lucene.index.ReaderUtil;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using org.apache.lucene.search;
+	using Bits = org.apache.lucene.util.Bits;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueFloat = org.apache.lucene.util.mutable.MutableValueFloat;
+
+
+	/// <summary>
+	/// <code>QueryValueSource</code> returns the relevance score of the query
+	/// </summary>
+	public class QueryValueSource : ValueSource
+	{
+	  internal readonly Query q;
+	  internal readonly float defVal;
+
+	  public QueryValueSource(Query q, float defVal)
+	  {
+		this.q = q;
+		this.defVal = defVal;
+	  }
+
+	  public virtual Query Query
+	  {
+		  get
+		  {
+			  return q;
+		  }
+	  }
+	  public virtual float DefaultValue
+	  {
+		  get
+		  {
+			  return defVal;
+		  }
+	  }
+
+	  public override string description()
+	  {
+		return "query(" + q + ",def=" + defVal + ")";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map fcontext, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary fcontext, AtomicReaderContext readerContext)
+	  {
+		return new QueryDocValues(this, readerContext, fcontext);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return q.GetHashCode() * 29;
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (typeof(QueryValueSource) != o.GetType())
+		{
+			return false;
+		}
+		QueryValueSource other = (QueryValueSource)o;
+		return this.q.Equals(other.q) && this.defVal == other.defVal;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		Weight w = searcher.createNormalizedWeight(q);
+		context[this] = w;
+	  }
+	}
+
+
+	internal class QueryDocValues : FloatDocValues
+	{
+	  internal readonly AtomicReaderContext readerContext;
+	  internal readonly Bits acceptDocs;
+	  internal readonly Weight weight;
+	  internal readonly float defVal;
+	  internal readonly IDictionary fcontext;
+	  internal readonly Query q;
+
+	  internal Scorer scorer;
+	  internal int scorerDoc; // the document the scorer is on
+	  internal bool noMatches = false;
+
+	  // the last document requested... start off with high value
+	  // to trigger a scorer reset on first access.
+	  internal int lastDocRequested = int.MaxValue;
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: public QueryDocValues(QueryValueSource vs, org.apache.lucene.index.AtomicReaderContext readerContext, java.util.Map fcontext) throws java.io.IOException
+	  public QueryDocValues(QueryValueSource vs, AtomicReaderContext readerContext, IDictionary fcontext) : base(vs)
+	  {
+
+		this.readerContext = readerContext;
+		this.acceptDocs = readerContext.reader().LiveDocs;
+		this.defVal = vs.defVal;
+		this.q = vs.q;
+		this.fcontext = fcontext;
+
+		Weight w = fcontext == null ? null : (Weight)fcontext[vs];
+		if (w == null)
+		{
+		  IndexSearcher weightSearcher;
+		  if (fcontext == null)
+		  {
+			weightSearcher = new IndexSearcher(ReaderUtil.getTopLevelContext(readerContext));
+		  }
+		  else
+		  {
+			weightSearcher = (IndexSearcher)fcontext["searcher"];
+			if (weightSearcher == null)
+			{
+			  weightSearcher = new IndexSearcher(ReaderUtil.getTopLevelContext(readerContext));
+			}
+		  }
+		  vs.createWeight(fcontext, weightSearcher);
+		  w = (Weight)fcontext[vs];
+		}
+		weight = w;
+	  }
+
+	  public override float floatVal(int doc)
+	  {
+		try
+		{
+		  if (doc < lastDocRequested)
+		  {
+			if (noMatches)
+			{
+				return defVal;
+			}
+			scorer = weight.scorer(readerContext, acceptDocs);
+			if (scorer == null)
+			{
+			  noMatches = true;
+			  return defVal;
+			}
+			scorerDoc = -1;
+		  }
+		  lastDocRequested = doc;
+
+		  if (scorerDoc < doc)
+		  {
+			scorerDoc = scorer.advance(doc);
+		  }
+
+		  if (scorerDoc > doc)
+		  {
+			// query doesn't match this document... either because we hit the
+			// end, or because the next doc is after this doc.
+			return defVal;
+		  }
+
+		  // a match!
+		  return scorer.score();
+		}
+		catch (IOException e)
+		{
+		  throw new Exception("caught exception in QueryDocVals(" + q + ") doc=" + doc, e);
+		}
+	  }
+
+	  public override bool exists(int doc)
+	  {
+		try
+		{
+		  if (doc < lastDocRequested)
+		  {
+			if (noMatches)
+			{
+				return false;
+			}
+			scorer = weight.scorer(readerContext, acceptDocs);
+			scorerDoc = -1;
+			if (scorer == null)
+			{
+			  noMatches = true;
+			  return false;
+			}
+		  }
+		  lastDocRequested = doc;
+
+		  if (scorerDoc < doc)
+		  {
+			scorerDoc = scorer.advance(doc);
+		  }
+
+		  if (scorerDoc > doc)
+		  {
+			// query doesn't match this document... either because we hit the
+			// end, or because the next doc is after this doc.
+			return false;
+		  }
+
+		  // a match!
+		  return true;
+		}
+		catch (IOException e)
+		{
+		  throw new Exception("caught exception in QueryDocVals(" + q + ") doc=" + doc, e);
+		}
+	  }
+
+	   public override object objectVal(int doc)
+	   {
+		 try
+		 {
+		   return exists(doc) ? scorer.score() : null;
+		 }
+		 catch (IOException e)
+		 {
+		   throw new Exception("caught exception in QueryDocVals(" + q + ") doc=" + doc, e);
+		 }
+	   }
+
+	  public override ValueFiller ValueFiller
+	  {
+		  get
+		  {
+			//
+			// TODO: if we want to support more than one value-filler or a value-filler in conjunction with
+			// the FunctionValues, then members like "scorer" should be per ValueFiller instance.
+			// Or we can say that the user should just instantiate multiple FunctionValues.
+			//
+			return new ValueFillerAnonymousInnerClassHelper(this);
+		  }
+	  }
+
+	  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+	  {
+		  private readonly QueryDocValues outerInstance;
+
+		  public ValueFillerAnonymousInnerClassHelper(QueryDocValues outerInstance)
+		  {
+			  this.outerInstance = outerInstance;
+			  mval = new MutableValueFloat();
+		  }
+
+		  private readonly MutableValueFloat mval;
+
+		  public override MutableValue Value
+		  {
+			  get
+			  {
+				return mval;
+			  }
+		  }
+
+		  public override void fillValue(int doc)
+		  {
+			try
+			{
+			  if (outerInstance.noMatches)
+			  {
+				mval.value = outerInstance.defVal;
+				mval.exists = false;
+				return;
+			  }
+			  outerInstance.scorer = outerInstance.weight.scorer(outerInstance.readerContext, outerInstance.acceptDocs);
+			  outerInstance.scorerDoc = -1;
+			  if (outerInstance.scorer == null)
+			  {
+				outerInstance.noMatches = true;
+				mval.value = outerInstance.defVal;
+				mval.exists = false;
+				return;
+			  }
+			  outerInstance.lastDocRequested = doc;
+
+			  if (outerInstance.scorerDoc < doc)
+			  {
+				outerInstance.scorerDoc = outerInstance.scorer.advance(doc);
+			  }
+
+			  if (outerInstance.scorerDoc > doc)
+			  {
+				// query doesn't match this document... either because we hit the
+				// end, or because the next doc is after this doc.
+				mval.value = outerInstance.defVal;
+				mval.exists = false;
+				return;
+			  }
+
+			  // a match!
+			  mval.value = outerInstance.scorer.score();
+			  mval.exists = true;
+			}
+			catch (IOException e)
+			{
+			  throw new Exception("caught exception in QueryDocVals(" + outerInstance.q + ") doc=" + doc, e);
+			}
+		  }
+	  }
+
+	  public override string ToString(int doc)
+	  {
+		return "query(" + q + ",def=" + defVal + ")=" + floatVal(doc);
+	  }
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/RangeMapFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/RangeMapFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/RangeMapFloatFunction.cs
new file mode 100644
index 0000000..d6cf6df
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/RangeMapFloatFunction.cs
@@ -0,0 +1,138 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// <code>RangeMapFloatFunction</code> implements a map function over
+	/// another <seealso cref="ValueSource"/> whose values fall within min and max inclusive to target.
+	/// <br>
+	/// Normally Used as an argument to a <seealso cref="org.apache.lucene.queries.function.FunctionQuery"/>
+	/// 
+	/// 
+	/// </summary>
+	public class RangeMapFloatFunction : ValueSource
+	{
+	  protected internal readonly ValueSource source;
+	  protected internal readonly float min;
+	  protected internal readonly float max;
+	  protected internal readonly ValueSource target;
+	  protected internal readonly ValueSource defaultVal;
+
+	  public RangeMapFloatFunction(ValueSource source, float min, float max, float target, float? def) : this(source, min, max, new ConstValueSource(target), def == null ? null : new ConstValueSource(def.Value))
+	  {
+	  }
+
+	  public RangeMapFloatFunction(ValueSource source, float min, float max, ValueSource target, ValueSource def)
+	  {
+		this.source = source;
+		this.min = min;
+		this.max = max;
+		this.target = target;
+		this.defaultVal = def;
+	  }
+
+	  public override string description()
+	  {
+		return "map(" + source.description() + "," + min + "," + max + "," + target.description() + ")";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues vals = source.getValues(context, readerContext);
+		FunctionValues vals = source.getValues(context, readerContext);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues targets = target.getValues(context, readerContext);
+		FunctionValues targets = target.getValues(context, readerContext);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues defaults = (this.defaultVal == null) ? null : defaultVal.getValues(context, readerContext);
+		FunctionValues defaults = (this.defaultVal == null) ? null : defaultVal.getValues(context, readerContext);
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, vals, targets, defaults);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly RangeMapFloatFunction outerInstance;
+
+		  private FunctionValues vals;
+		  private FunctionValues targets;
+		  private FunctionValues defaults;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(RangeMapFloatFunction outerInstance, org.apache.lucene.queries.function.valuesource.RangeMapFloatFunction this, FunctionValues vals, FunctionValues targets, FunctionValues defaults) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.vals = vals;
+			  this.targets = targets;
+			  this.defaults = defaults;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			float val = vals.floatVal(doc);
+			return (val >= outerInstance.min && val <= outerInstance.max) ? targets.floatVal(doc) : (outerInstance.defaultVal == null ? val : defaults.floatVal(doc));
+		  }
+		  public override string ToString(int doc)
+		  {
+			return "map(" + vals.ToString(doc) + ",min=" + outerInstance.min + ",max=" + outerInstance.max + ",target=" + targets.ToString(doc) + ")";
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		source.createWeight(context, searcher);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = source.GetHashCode();
+		h ^= (h << 10) | ((int)((uint)h >> 23));
+		h += float.floatToIntBits(min);
+		h ^= (h << 14) | ((int)((uint)h >> 19));
+		h += float.floatToIntBits(max);
+		h += target.GetHashCode();
+		if (defaultVal != null)
+		{
+		  h += defaultVal.GetHashCode();
+		}
+		return h;
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (typeof(RangeMapFloatFunction) != o.GetType())
+		{
+			return false;
+		}
+		RangeMapFloatFunction other = (RangeMapFloatFunction)o;
+		return this.min == other.min && this.max == other.max && this.target.Equals(other.target) && this.source.Equals(other.source) && (this.defaultVal == other.defaultVal || (this.defaultVal != null && this.defaultVal.Equals(other.defaultVal)));
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ReciprocalFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ReciprocalFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/ReciprocalFloatFunction.cs
new file mode 100644
index 0000000..9fcf24c
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ReciprocalFloatFunction.cs
@@ -0,0 +1,130 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// <code>ReciprocalFloatFunction</code> implements a reciprocal function f(x) = a/(mx+b), based on
+	/// the float value of a field or function as exported by <seealso cref="org.apache.lucene.queries.function.ValueSource"/>.
+	/// <br>
+	/// 
+	/// When a and b are equal, and x>=0, this function has a maximum value of 1 that drops as x increases.
+	/// Increasing the value of a and b together results in a movement of the entire function to a flatter part of the curve.
+	/// <para>These properties make this an idea function for boosting more recent documents.
+	/// </para>
+	/// <para>Example:<code>  recip(ms(NOW,mydatefield),3.16e-11,1,1)</code>
+	/// </para>
+	/// <para>A multiplier of 3.16e-11 changes the units from milliseconds to years (since there are about 3.16e10 milliseconds
+	/// per year).  Thus, a very recent date will yield a value close to 1/(0+1) or 1,
+	/// a date a year in the past will get a multiplier of about 1/(1+1) or 1/2,
+	/// and date two years old will yield 1/(2+1) or 1/3.
+	/// 
+	/// </para>
+	/// </summary>
+	/// <seealso cref= org.apache.lucene.queries.function.FunctionQuery
+	/// 
+	///  </seealso>
+	public class ReciprocalFloatFunction : ValueSource
+	{
+	  protected internal readonly ValueSource source;
+	  protected internal readonly float m;
+	  protected internal readonly float a;
+	  protected internal readonly float b;
+
+	  /// <summary>
+	  ///  f(source) = a/(m*float(source)+b)
+	  /// </summary>
+	  public ReciprocalFloatFunction(ValueSource source, float m, float a, float b)
+	  {
+		this.source = source;
+		this.m = m;
+		this.a = a;
+		this.b = b;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues vals = source.getValues(context, readerContext);
+		FunctionValues vals = source.getValues(context, readerContext);
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, vals);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly ReciprocalFloatFunction outerInstance;
+
+		  private FunctionValues vals;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(ReciprocalFloatFunction outerInstance, org.apache.lucene.queries.function.valuesource.ReciprocalFloatFunction this, FunctionValues vals) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.vals = vals;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return outerInstance.a / (outerInstance.m * vals.floatVal(doc) + outerInstance.b);
+		  }
+		  public override string ToString(int doc)
+		  {
+			return Convert.ToString(outerInstance.a) + "/(" + outerInstance.m + "*float(" + vals.ToString(doc) + ')' + '+' + outerInstance.b + ')';
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		source.createWeight(context, searcher);
+	  }
+
+	  public override string description()
+	  {
+		return Convert.ToString(a) + "/(" + m + "*float(" + source.description() + ")" + "+" + b + ')';
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = float.floatToIntBits(a) + float.floatToIntBits(m);
+		h ^= (h << 13) | ((int)((uint)h >> 20));
+		return h + (float.floatToIntBits(b)) + source.GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (typeof(ReciprocalFloatFunction) != o.GetType())
+		{
+			return false;
+		}
+		ReciprocalFloatFunction other = (ReciprocalFloatFunction)o;
+		return this.m == other.m && this.a == other.a && this.b == other.b && this.source.Equals(other.source);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ReverseOrdFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ReverseOrdFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/ReverseOrdFieldSource.cs
new file mode 100644
index 0000000..b509dde
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ReverseOrdFieldSource.cs
@@ -0,0 +1,135 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	using AtomicReader = org.apache.lucene.index.AtomicReader;
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using CompositeReader = org.apache.lucene.index.CompositeReader;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using ReaderUtil = org.apache.lucene.index.ReaderUtil;
+	using SlowCompositeReaderWrapper = org.apache.lucene.index.SlowCompositeReaderWrapper;
+	using SortedDocValues = org.apache.lucene.index.SortedDocValues;
+	using IntDocValues = org.apache.lucene.queries.function.docvalues.IntDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+
+	/// <summary>
+	/// Obtains the ordinal of the field value from the default Lucene <seealso cref="org.apache.lucene.search.FieldCache"/> using getTermsIndex()
+	/// and reverses the order.
+	/// <br>
+	/// The native lucene index order is used to assign an ordinal value for each field value.
+	/// <br>Field values (terms) are lexicographically ordered by unicode value, and numbered starting at 1.
+	/// <br>
+	/// Example of reverse ordinal (rord):<br>
+	///  If there were only three field values: "apple","banana","pear"
+	/// <br>then rord("apple")=3, rord("banana")=2, ord("pear")=1
+	/// <para>
+	///  WARNING: ord() depends on the position in an index and can thus change when other documents are inserted or deleted,
+	///  or if a MultiSearcher is used.
+	/// <br>
+	///  WARNING: as of Solr 1.4, ord() and rord() can cause excess memory use since they must use a FieldCache entry
+	/// at the top level reader, while sorting and function queries now use entries at the segment level.  Hence sorting
+	/// or using a different function query, in addition to ord()/rord() will double memory use.
+	/// 
+	/// 
+	/// </para>
+	/// </summary>
+
+	public class ReverseOrdFieldSource : ValueSource
+	{
+	  public readonly string field;
+
+	  public ReverseOrdFieldSource(string field)
+	  {
+		this.field = field;
+	  }
+
+	  public override string description()
+	  {
+		return "rord(" + field + ')';
+	  }
+
+	  // TODO: this is trappy? perhaps this query instead should make you pass a slow reader yourself?
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.IndexReader topReader = org.apache.lucene.index.ReaderUtil.getTopLevelContext(readerContext).reader();
+		IndexReader topReader = ReaderUtil.getTopLevelContext(readerContext).reader();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.AtomicReader r = org.apache.lucene.index.SlowCompositeReaderWrapper.wrap(topReader);
+		AtomicReader r = SlowCompositeReaderWrapper.wrap(topReader);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int off = readerContext.docBase;
+		int off = readerContext.docBase;
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.SortedDocValues sindex = org.apache.lucene.search.FieldCache.DEFAULT.getTermsIndex(r, field);
+		SortedDocValues sindex = FieldCache.DEFAULT.getTermsIndex(r, field);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int end = sindex.getValueCount();
+		int end = sindex.ValueCount;
+
+		return new IntDocValuesAnonymousInnerClassHelper(this, this, off, sindex, end);
+	  }
+
+	  private class IntDocValuesAnonymousInnerClassHelper : IntDocValues
+	  {
+		  private readonly ReverseOrdFieldSource outerInstance;
+
+		  private int off;
+		  private SortedDocValues sindex;
+		  private int end;
+
+		  public IntDocValuesAnonymousInnerClassHelper(ReverseOrdFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.ReverseOrdFieldSource this, int off, SortedDocValues sindex, int end) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.off = off;
+			  this.sindex = sindex;
+			  this.end = end;
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			 return (end - sindex.getOrd(doc + off) - 1);
+		  }
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o == null || (o.GetType() != typeof(ReverseOrdFieldSource)))
+		{
+			return false;
+		}
+		ReverseOrdFieldSource other = (ReverseOrdFieldSource)o;
+		return this.field.Equals(other.field);
+	  }
+
+	  private static readonly int hcode = typeof(ReverseOrdFieldSource).GetHashCode();
+	  public override int GetHashCode()
+	  {
+		return hcode + field.GetHashCode();
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ScaleFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ScaleFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/ScaleFloatFunction.cs
new file mode 100644
index 0000000..4d27585
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ScaleFloatFunction.cs
@@ -0,0 +1,200 @@
+using System.Collections;
+using System.Collections.Generic;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using ReaderUtil = org.apache.lucene.index.ReaderUtil;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// Scales values to be between min and max.
+	/// <para>This implementation currently traverses all of the source values to obtain
+	/// their min and max.
+	/// </para>
+	/// <para>This implementation currently cannot distinguish when documents have been
+	/// deleted or documents that have no value, and 0.0 values will be used for
+	/// these cases.  This means that if values are normally all greater than 0.0, one can
+	/// still end up with 0.0 as the min value to map from.  In these cases, an
+	/// appropriate map() function could be used as a workaround to change 0.0
+	/// to a value in the real range.
+	/// </para>
+	/// </summary>
+	public class ScaleFloatFunction : ValueSource
+	{
+	  protected internal readonly ValueSource source;
+	  protected internal readonly float min;
+	  protected internal readonly float max;
+
+	  public ScaleFloatFunction(ValueSource source, float min, float max)
+	  {
+		this.source = source;
+		this.min = min;
+		this.max = max;
+	  }
+
+	  public override string description()
+	  {
+		return "scale(" + source.description() + "," + min + "," + max + ")";
+	  }
+
+	  private class ScaleInfo
+	  {
+		internal float minVal;
+		internal float maxVal;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: private ScaleInfo createScaleInfo(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  private ScaleInfo createScaleInfo(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final java.util.List<org.apache.lucene.index.AtomicReaderContext> leaves = org.apache.lucene.index.ReaderUtil.getTopLevelContext(readerContext).leaves();
+		IList<AtomicReaderContext> leaves = ReaderUtil.getTopLevelContext(readerContext).leaves();
+
+		float minVal = float.PositiveInfinity;
+		float maxVal = float.NegativeInfinity;
+
+		foreach (AtomicReaderContext leaf in leaves)
+		{
+		  int maxDoc = leaf.reader().maxDoc();
+		  FunctionValues vals = source.getValues(context, leaf);
+		  for (int i = 0; i < maxDoc; i++)
+		  {
+
+		  float val = vals.floatVal(i);
+		  if ((float.floatToRawIntBits(val) & (0xff << 23)) == 0xff << 23)
+		  {
+			// if the exponent in the float is all ones, then this is +Inf, -Inf or NaN
+			// which don't make sense to factor into the scale function
+			continue;
+		  }
+		  if (val < minVal)
+		  {
+			minVal = val;
+		  }
+		  if (val > maxVal)
+		  {
+			maxVal = val;
+		  }
+		  }
+		}
+
+		if (minVal == float.PositiveInfinity)
+		{
+		// must have been an empty index
+		  minVal = maxVal = 0;
+		}
+
+		ScaleInfo scaleInfo = new ScaleInfo();
+		scaleInfo.minVal = minVal;
+		scaleInfo.maxVal = maxVal;
+		context[ScaleFloatFunction.this] = scaleInfo;
+		return scaleInfo;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+
+		ScaleInfo scaleInfo = (ScaleInfo)context[ScaleFloatFunction.this];
+		if (scaleInfo == null)
+		{
+		  scaleInfo = createScaleInfo(context, readerContext);
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float scale = (scaleInfo.maxVal-scaleInfo.minVal==0) ? 0 : (max-min)/(scaleInfo.maxVal-scaleInfo.minVal);
+		float scale = (scaleInfo.maxVal - scaleInfo.minVal == 0) ? 0 : (max - min) / (scaleInfo.maxVal - scaleInfo.minVal);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float minSource = scaleInfo.minVal;
+		float minSource = scaleInfo.minVal;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final float maxSource = scaleInfo.maxVal;
+		float maxSource = scaleInfo.maxVal;
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues vals = source.getValues(context, readerContext);
+		FunctionValues vals = source.getValues(context, readerContext);
+
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, scale, minSource, maxSource, vals);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly ScaleFloatFunction outerInstance;
+
+		  private float scale;
+		  private float minSource;
+		  private float maxSource;
+		  private FunctionValues vals;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(ScaleFloatFunction outerInstance, org.apache.lucene.queries.function.valuesource.ScaleFloatFunction this, float scale, float minSource, float maxSource, FunctionValues vals) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.scale = scale;
+			  this.minSource = minSource;
+			  this.maxSource = maxSource;
+			  this.vals = vals;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return (vals.floatVal(doc) - minSource) * scale + outerInstance.min;
+		  }
+		  public override string ToString(int doc)
+		  {
+			return "scale(" + vals.ToString(doc) + ",toMin=" + outerInstance.min + ",toMax=" + outerInstance.max + ",fromMin=" + minSource + ",fromMax=" + maxSource + ")";
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		source.createWeight(context, searcher);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = float.floatToIntBits(min);
+		h = h * 29;
+		h += float.floatToIntBits(max);
+		h = h * 29;
+		h += source.GetHashCode();
+		return h;
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (typeof(ScaleFloatFunction) != o.GetType())
+		{
+			return false;
+		}
+		ScaleFloatFunction other = (ScaleFloatFunction)o;
+		return this.min == other.min && this.max == other.max && this.source.Equals(other.source);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/ShortFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/ShortFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/ShortFieldSource.cs
new file mode 100644
index 0000000..6240253
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/ShortFieldSource.cs
@@ -0,0 +1,137 @@
+using System;
+using System.Collections;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+
+
+	/// <summary>
+	/// Obtains short field values from the <seealso cref="org.apache.lucene.search.FieldCache"/>
+	/// using <code>getShorts()</code>
+	/// and makes those values available as other numeric types, casting as needed.
+	/// 
+	/// </summary>
+	[Obsolete]
+	public class ShortFieldSource : FieldCacheSource
+	{
+
+	  internal readonly FieldCache.ShortParser parser;
+
+	  public ShortFieldSource(string field) : this(field, null)
+	  {
+	  }
+
+	  public ShortFieldSource(string field, FieldCache.ShortParser parser) : base(field)
+	  {
+		this.parser = parser;
+	  }
+
+	  public override string description()
+	  {
+		return "short(" + field + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldCache.Shorts arr = cache.getShorts(readerContext.reader(), field, parser, false);
+		FieldCache.Shorts arr = cache.getShorts(readerContext.reader(), field, parser, false);
+
+		return new FunctionValuesAnonymousInnerClassHelper(this, arr);
+	  }
+
+	  private class FunctionValuesAnonymousInnerClassHelper : FunctionValues
+	  {
+		  private readonly ShortFieldSource outerInstance;
+
+		  private FieldCache.Shorts arr;
+
+		  public FunctionValuesAnonymousInnerClassHelper(ShortFieldSource outerInstance, FieldCache.Shorts arr)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.arr = arr;
+		  }
+
+		  public override sbyte byteVal(int doc)
+		  {
+			return (sbyte) arr.get(doc);
+		  }
+
+		  public override short shortVal(int doc)
+		  {
+			return arr.get(doc);
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return (float) arr.get(doc);
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			return (int) arr.get(doc);
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return (long) arr.get(doc);
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return (double) arr.get(doc);
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return Convert.ToString(arr.get(doc));
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description() + '=' + shortVal(doc);
+		  }
+
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o.GetType() != typeof(ShortFieldSource))
+		{
+			return false;
+		}
+		ShortFieldSource other = (ShortFieldSource) o;
+		return base.Equals(other) && (this.parser == null ? other.parser == null : this.parser.GetType() == other.parser.GetType());
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = parser == null ? typeof(short?).GetHashCode() : parser.GetType().GetHashCode();
+		h += base.GetHashCode();
+		return h;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/SimpleBoolFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/SimpleBoolFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/SimpleBoolFunction.cs
new file mode 100644
index 0000000..01349f6
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/SimpleBoolFunction.cs
@@ -0,0 +1,108 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using BoolDocValues = org.apache.lucene.queries.function.docvalues.BoolDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// <seealso cref="BoolFunction"/> implementation which applies an extendible boolean
+	/// function to the values of a single wrapped <seealso cref="ValueSource"/>.
+	/// 
+	/// Functions this can be used for include whether a field has a value or not,
+	/// or inverting the boolean value of the wrapped ValueSource.
+	/// </summary>
+	public abstract class SimpleBoolFunction : BoolFunction
+	{
+	  protected internal readonly ValueSource source;
+
+	  public SimpleBoolFunction(ValueSource source)
+	  {
+		this.source = source;
+	  }
+
+	  protected internal abstract string name();
+
+	  protected internal abstract bool func(int doc, FunctionValues vals);
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.docvalues.BoolDocValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override BoolDocValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues vals = source.getValues(context, readerContext);
+		FunctionValues vals = source.getValues(context, readerContext);
+		return new BoolDocValuesAnonymousInnerClassHelper(this, this, vals);
+	  }
+
+	  private class BoolDocValuesAnonymousInnerClassHelper : BoolDocValues
+	  {
+		  private readonly SimpleBoolFunction outerInstance;
+
+		  private FunctionValues vals;
+
+		  public BoolDocValuesAnonymousInnerClassHelper(SimpleBoolFunction outerInstance, org.apache.lucene.queries.function.valuesource.SimpleBoolFunction this, FunctionValues vals) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.vals = vals;
+		  }
+
+		  public override bool boolVal(int doc)
+		  {
+			return outerInstance.func(doc, vals);
+		  }
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.name() + '(' + vals.ToString(doc) + ')';
+		  }
+	  }
+
+	  public override string description()
+	  {
+		return name() + '(' + source.description() + ')';
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return source.GetHashCode() + name().GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		SimpleBoolFunction other = (SimpleBoolFunction)o;
+		return this.source.Equals(other.source);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		source.createWeight(context, searcher);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/SimpleFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/SimpleFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/SimpleFloatFunction.cs
new file mode 100644
index 0000000..4cc6f29
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/SimpleFloatFunction.cs
@@ -0,0 +1,71 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+
+
+	/// <summary>
+	/// A simple float function with a single argument
+	/// </summary>
+	 public abstract class SimpleFloatFunction : SingleFunction
+	 {
+	  public SimpleFloatFunction(ValueSource source) : base(source)
+	  {
+	  }
+
+	  protected internal abstract float func(int doc, FunctionValues vals);
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues vals = source.getValues(context, readerContext);
+		FunctionValues vals = source.getValues(context, readerContext);
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, vals);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly SimpleFloatFunction outerInstance;
+
+		  private FunctionValues vals;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(SimpleFloatFunction outerInstance, org.apache.lucene.queries.function.valuesource.SimpleFloatFunction this, FunctionValues vals) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.vals = vals;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return outerInstance.func(doc, vals);
+		  }
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.name() + '(' + vals.ToString(doc) + ')';
+		  }
+	  }
+	 }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/SingleFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/SingleFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/SingleFunction.cs
new file mode 100644
index 0000000..15084be
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/SingleFunction.cs
@@ -0,0 +1,67 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// A function with a single argument
+	/// </summary>
+	 public abstract class SingleFunction : ValueSource
+	 {
+	  protected internal readonly ValueSource source;
+
+	  public SingleFunction(ValueSource source)
+	  {
+		this.source = source;
+	  }
+
+	  protected internal abstract string name();
+
+	  public override string description()
+	  {
+		return name() + '(' + source.description() + ')';
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return source.GetHashCode() + name().GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		SingleFunction other = (SingleFunction)o;
+		return this.name().Equals(other.name()) && this.source.Equals(other.source);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		source.createWeight(context, searcher);
+	  }
+	 }
+}
\ No newline at end of file


[05/11] Skeleton porting of Lucene.Net.Queries

Posted by sy...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/DivFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/DivFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/DivFloatFunction.cs
new file mode 100644
index 0000000..08912e5
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/DivFloatFunction.cs
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	/// <summary>
+	/// Function to divide "a" by "b"
+	/// </summary>
+	public class DivFloatFunction : DualFloatFunction
+	{
+	 /// <param name="a">  the numerator. </param>
+	 /// <param name="b">  the denominator. </param>
+	  public DivFloatFunction(ValueSource a, ValueSource b) : base(a,b)
+	  {
+	  }
+
+	  protected internal override string name()
+	  {
+		return "div";
+	  }
+
+	  protected internal override float func(int doc, FunctionValues aVals, FunctionValues bVals)
+	  {
+		return aVals.floatVal(doc) / bVals.floatVal(doc);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/DocFreqValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/DocFreqValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/DocFreqValueSource.cs
new file mode 100644
index 0000000..56ea07d
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/DocFreqValueSource.cs
@@ -0,0 +1,186 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using Term = org.apache.lucene.index.Term;
+	using DoubleDocValues = org.apache.lucene.queries.function.docvalues.DoubleDocValues;
+	using IntDocValues = org.apache.lucene.queries.function.docvalues.IntDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+
+	internal class ConstIntDocValues : IntDocValues
+	{
+	  internal readonly int ival;
+	  internal readonly float fval;
+	  internal readonly double dval;
+	  internal readonly long lval;
+	  internal readonly string sval;
+	  internal readonly ValueSource parent;
+
+	  internal ConstIntDocValues(int val, ValueSource parent) : base(parent)
+	  {
+		ival = val;
+		fval = val;
+		dval = val;
+		lval = val;
+		sval = Convert.ToString(val);
+		this.parent = parent;
+	  }
+
+	  public override float floatVal(int doc)
+	  {
+		return fval;
+	  }
+	  public override int intVal(int doc)
+	  {
+		return ival;
+	  }
+	  public override long longVal(int doc)
+	  {
+		return lval;
+	  }
+	  public override double doubleVal(int doc)
+	  {
+		return dval;
+	  }
+	  public override string strVal(int doc)
+	  {
+		return sval;
+	  }
+	  public override string ToString(int doc)
+	  {
+		return parent.description() + '=' + sval;
+	  }
+	}
+
+	internal class ConstDoubleDocValues : DoubleDocValues
+	{
+	  internal readonly int ival;
+	  internal readonly float fval;
+	  internal readonly double dval;
+	  internal readonly long lval;
+	  internal readonly string sval;
+	  internal readonly ValueSource parent;
+
+	  internal ConstDoubleDocValues(double val, ValueSource parent) : base(parent)
+	  {
+		ival = (int)val;
+		fval = (float)val;
+		dval = val;
+		lval = (long)val;
+		sval = Convert.ToString(val);
+		this.parent = parent;
+	  }
+
+	  public override float floatVal(int doc)
+	  {
+		return fval;
+	  }
+	  public override int intVal(int doc)
+	  {
+		return ival;
+	  }
+	  public override long longVal(int doc)
+	  {
+		return lval;
+	  }
+	  public override double doubleVal(int doc)
+	  {
+		return dval;
+	  }
+	  public override string strVal(int doc)
+	  {
+		return sval;
+	  }
+	  public override string ToString(int doc)
+	  {
+		return parent.description() + '=' + sval;
+	  }
+	}
+
+
+	/// <summary>
+	/// <code>DocFreqValueSource</code> returns the number of documents containing the term.
+	/// @lucene.internal
+	/// </summary>
+	public class DocFreqValueSource : ValueSource
+	{
+	  protected internal readonly string field;
+	  protected internal readonly string indexedField;
+	  protected internal readonly string val;
+	  protected internal readonly BytesRef indexedBytes;
+
+	  public DocFreqValueSource(string field, string val, string indexedField, BytesRef indexedBytes)
+	  {
+		this.field = field;
+		this.val = val;
+		this.indexedField = indexedField;
+		this.indexedBytes = indexedBytes;
+	  }
+
+	  public virtual string name()
+	  {
+		return "docfreq";
+	  }
+
+	  public override string description()
+	  {
+		return name() + '(' + field + ',' + val + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		IndexSearcher searcher = (IndexSearcher)context["searcher"];
+		int docfreq = searcher.IndexReader.docFreq(new Term(indexedField, indexedBytes));
+		return new ConstIntDocValues(docfreq, this);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		context["searcher"] = searcher;
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return this.GetType().GetHashCode() + indexedField.GetHashCode() * 29 + indexedBytes.GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		DocFreqValueSource other = (DocFreqValueSource)o;
+		return this.indexedField.Equals(other.indexedField) && this.indexedBytes.Equals(other.indexedBytes);
+	  }
+	}
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/DoubleConstValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/DoubleConstValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/DoubleConstValueSource.cs
new file mode 100644
index 0000000..e21be0c
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/DoubleConstValueSource.cs
@@ -0,0 +1,166 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using DoubleDocValues = org.apache.lucene.queries.function.docvalues.DoubleDocValues;
+
+
+	/// <summary>
+	/// Function that returns a constant double value for every document.
+	/// </summary>
+	public class DoubleConstValueSource : ConstNumberSource
+	{
+	  internal readonly double constant;
+	  private readonly float fv;
+	  private readonly long lv;
+
+	  public DoubleConstValueSource(double constant)
+	  {
+		this.constant = constant;
+		this.fv = (float)constant;
+		this.lv = (long)constant;
+	  }
+
+	  public override string description()
+	  {
+		return "const(" + constant + ")";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		return new DoubleDocValuesAnonymousInnerClassHelper(this, this);
+	  }
+
+	  private class DoubleDocValuesAnonymousInnerClassHelper : DoubleDocValues
+	  {
+		  private readonly DoubleConstValueSource outerInstance;
+
+		  public DoubleDocValuesAnonymousInnerClassHelper(DoubleConstValueSource outerInstance, org.apache.lucene.queries.function.valuesource.DoubleConstValueSource this) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return outerInstance.fv;
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			return (int) outerInstance.lv;
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return outerInstance.lv;
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return outerInstance.constant;
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return Convert.ToString(outerInstance.constant);
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return outerInstance.constant;
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description();
+		  }
+	  }
+
+	  public override int GetHashCode()
+	  {
+		long bits = double.doubleToRawLongBits(constant);
+		return (int)(bits ^ ((long)((ulong)bits >> 32)));
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (!(o is DoubleConstValueSource))
+		{
+			return false;
+		}
+		DoubleConstValueSource other = (DoubleConstValueSource) o;
+		return this.constant == other.constant;
+	  }
+
+	  public override int Int
+	  {
+		  get
+		  {
+			return (int)lv;
+		  }
+	  }
+
+	  public override long Long
+	  {
+		  get
+		  {
+			return lv;
+		  }
+	  }
+
+	  public override float Float
+	  {
+		  get
+		  {
+			return fv;
+		  }
+	  }
+
+	  public override double Double
+	  {
+		  get
+		  {
+			return constant;
+		  }
+	  }
+
+	  public override Number Number
+	  {
+		  get
+		  {
+			return constant;
+		  }
+	  }
+
+	  public override bool Bool
+	  {
+		  get
+		  {
+			return constant != 0;
+		  }
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/DoubleFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/DoubleFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/DoubleFieldSource.cs
new file mode 100644
index 0000000..188974f
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/DoubleFieldSource.cs
@@ -0,0 +1,149 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using DoubleDocValues = org.apache.lucene.queries.function.docvalues.DoubleDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using Bits = org.apache.lucene.util.Bits;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueDouble = org.apache.lucene.util.mutable.MutableValueDouble;
+
+	/// <summary>
+	/// Obtains double field values from <seealso cref="FieldCache#getDoubles"/> and makes
+	/// those values available as other numeric types, casting as needed.
+	/// </summary>
+	public class DoubleFieldSource : FieldCacheSource
+	{
+
+	  protected internal readonly FieldCache.DoubleParser parser;
+
+	  public DoubleFieldSource(string field) : this(field, null)
+	  {
+	  }
+
+	  public DoubleFieldSource(string field, FieldCache.DoubleParser parser) : base(field)
+	  {
+		this.parser = parser;
+	  }
+
+	  public override string description()
+	  {
+		return "double(" + field + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldCache.Doubles arr = cache.getDoubles(readerContext.reader(), field, parser, true);
+		FieldCache.Doubles arr = cache.getDoubles(readerContext.reader(), field, parser, true);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+		Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+		return new DoubleDocValuesAnonymousInnerClassHelper(this, this, arr, valid);
+
+	  }
+
+	  private class DoubleDocValuesAnonymousInnerClassHelper : DoubleDocValues
+	  {
+		  private readonly DoubleFieldSource outerInstance;
+
+		  private FieldCache.Doubles arr;
+		  private Bits valid;
+
+		  public DoubleDocValuesAnonymousInnerClassHelper(DoubleFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.DoubleFieldSource this, FieldCache.Doubles arr, Bits valid) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.arr = arr;
+			  this.valid = valid;
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return arr.get(doc);
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			return arr.get(doc) != 0 || valid.get(doc);
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				return new ValueFillerAnonymousInnerClassHelper(this);
+			  }
+		  }
+
+		  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+		  {
+			  private readonly DoubleDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public ValueFillerAnonymousInnerClassHelper(DoubleDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+				  mval = new MutableValueDouble();
+			  }
+
+			  private readonly MutableValueDouble mval;
+
+			  public override MutableValue Value
+			  {
+				  get
+				  {
+					return mval;
+				  }
+			  }
+
+			  public override void fillValue(int doc)
+			  {
+				mval.value = outerInstance.arr.get(doc);
+				mval.exists = mval.value != 0 || outerInstance.valid.get(doc);
+			  }
+		  }
+
+
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o.GetType() != typeof(DoubleFieldSource))
+		{
+			return false;
+		}
+		DoubleFieldSource other = (DoubleFieldSource) o;
+		return base.Equals(other) && (this.parser == null ? other.parser == null : this.parser.GetType() == other.parser.GetType());
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = parser == null ? typeof(double?).GetHashCode() : parser.GetType().GetHashCode();
+		h += base.GetHashCode();
+		return h;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/DualFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/DualFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/DualFloatFunction.cs
new file mode 100644
index 0000000..9a9c069
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/DualFloatFunction.cs
@@ -0,0 +1,121 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// Abstract <seealso cref="ValueSource"/> implementation which wraps two ValueSources
+	/// and applies an extendible float function to their values.
+	/// 
+	/// </summary>
+	public abstract class DualFloatFunction : ValueSource
+	{
+	  protected internal readonly ValueSource a;
+	  protected internal readonly ValueSource b;
+
+	 /// <param name="a">  the base. </param>
+	 /// <param name="b">  the exponent. </param>
+	  public DualFloatFunction(ValueSource a, ValueSource b)
+	  {
+		this.a = a;
+		this.b = b;
+	  }
+
+	  protected internal abstract string name();
+	  protected internal abstract float func(int doc, FunctionValues aVals, FunctionValues bVals);
+
+	  public override string description()
+	  {
+		return name() + "(" + a.description() + "," + b.description() + ")";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues aVals = a.getValues(context, readerContext);
+		FunctionValues aVals = a.getValues(context, readerContext);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues bVals = b.getValues(context, readerContext);
+		FunctionValues bVals = b.getValues(context, readerContext);
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, aVals, bVals);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly DualFloatFunction outerInstance;
+
+		  private FunctionValues aVals;
+		  private FunctionValues bVals;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(DualFloatFunction outerInstance, org.apache.lucene.queries.function.valuesource.DualFloatFunction this, FunctionValues aVals, FunctionValues bVals) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.aVals = aVals;
+			  this.bVals = bVals;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return outerInstance.func(doc, aVals, bVals);
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.name() + '(' + aVals.ToString(doc) + ',' + bVals.ToString(doc) + ')';
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		a.createWeight(context,searcher);
+		b.createWeight(context,searcher);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = a.GetHashCode();
+		h ^= (h << 13) | ((int)((uint)h >> 20));
+		h += b.GetHashCode();
+		h ^= (h << 23) | ((int)((uint)h >> 10));
+		h += name().GetHashCode();
+		return h;
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		DualFloatFunction other = (DualFloatFunction)o;
+		return this.a.Equals(other.a) && this.b.Equals(other.b);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/EnumFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/EnumFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/EnumFieldSource.cs
new file mode 100644
index 0000000..cbdf2cb
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/EnumFieldSource.cs
@@ -0,0 +1,343 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	/*
+	 * 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.
+	 */
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using IntDocValues = org.apache.lucene.queries.function.docvalues.IntDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using Bits = org.apache.lucene.util.Bits;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueInt = org.apache.lucene.util.mutable.MutableValueInt;
+
+	/// <summary>
+	/// Obtains int field values from <seealso cref="FieldCache#getInts"/> and makes
+	/// those values available as other numeric types, casting as needed.
+	/// strVal of the value is not the int value, but its string (displayed) value
+	/// </summary>
+	public class EnumFieldSource : FieldCacheSource
+	{
+	  internal const int? DEFAULT_VALUE = -1;
+
+	  internal readonly FieldCache.IntParser parser;
+	  internal readonly IDictionary<int?, string> enumIntToStringMap;
+	  internal readonly IDictionary<string, int?> enumStringToIntMap;
+
+	  public EnumFieldSource(string field, FieldCache.IntParser parser, IDictionary<int?, string> enumIntToStringMap, IDictionary<string, int?> enumStringToIntMap) : base(field)
+	  {
+		this.parser = parser;
+		this.enumIntToStringMap = enumIntToStringMap;
+		this.enumStringToIntMap = enumStringToIntMap;
+	  }
+
+	  private static int? tryParseInt(string valueStr)
+	  {
+		int? intValue = null;
+		try
+		{
+		  intValue = Convert.ToInt32(valueStr);
+		}
+		catch (NumberFormatException)
+		{
+		}
+		return intValue;
+	  }
+
+	  private string intValueToStringValue(int? intVal)
+	  {
+		if (intVal == null)
+		{
+		  return null;
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final String enumString = enumIntToStringMap.get(intVal);
+		string enumString = enumIntToStringMap[intVal];
+		if (enumString != null)
+		{
+		  return enumString;
+		}
+		// can't find matching enum name - return DEFAULT_VALUE.toString()
+		return DEFAULT_VALUE.ToString();
+	  }
+
+	  private int? stringValueToIntValue(string stringVal)
+	  {
+		if (stringVal == null)
+		{
+		  return null;
+		}
+
+		int? intValue;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Integer enumInt = enumStringToIntMap.get(stringVal);
+		int? enumInt = enumStringToIntMap[stringVal];
+		if (enumInt != null) //enum int found for string
+		{
+		  return enumInt;
+		}
+
+		//enum int not found for string
+		intValue = tryParseInt(stringVal);
+		if (intValue == null) //not Integer
+		{
+		  intValue = DEFAULT_VALUE;
+		}
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final String enumString = enumIntToStringMap.get(intValue);
+		string enumString = enumIntToStringMap[intValue];
+		if (enumString != null) //has matching string
+		{
+		  return intValue;
+		}
+
+		return DEFAULT_VALUE;
+	  }
+
+	  public override string description()
+	  {
+		return "enum(" + field + ')';
+	  }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldCache.Ints arr = cache.getInts(readerContext.reader(), field, parser, true);
+		FieldCache.Ints arr = cache.getInts(readerContext.reader(), field, parser, true);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+		Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+
+		return new IntDocValuesAnonymousInnerClassHelper(this, this, arr, valid);
+	  }
+
+	  private class IntDocValuesAnonymousInnerClassHelper : IntDocValues
+	  {
+		  private readonly EnumFieldSource outerInstance;
+
+		  private FieldCache.Ints arr;
+		  private Bits valid;
+
+		  public IntDocValuesAnonymousInnerClassHelper(EnumFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.EnumFieldSource this, FieldCache.Ints arr, Bits valid) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.arr = arr;
+			  this.valid = valid;
+			  val = new MutableValueInt();
+		  }
+
+		  internal readonly MutableValueInt val;
+
+		  public override float floatVal(int doc)
+		  {
+			return (float) arr.get(doc);
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			return arr.get(doc);
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return (long) arr.get(doc);
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return (double) arr.get(doc);
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			int? intValue = arr.get(doc);
+			return outerInstance.intValueToStringValue(intValue);
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return valid.get(doc) ? arr.get(doc) : null;
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			return valid.get(doc);
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description() + '=' + strVal(doc);
+		  }
+
+
+		  public override ValueSourceScorer getRangeScorer(IndexReader reader, string lowerVal, string upperVal, bool includeLower, bool includeUpper)
+		  {
+			int? lower = outerInstance.stringValueToIntValue(lowerVal);
+			int? upper = outerInstance.stringValueToIntValue(upperVal);
+
+			// instead of using separate comparison functions, adjust the endpoints.
+
+			if (lower == null)
+			{
+			  lower = int.MinValue;
+			}
+			else
+			{
+			  if (!includeLower && lower < int.MaxValue)
+			  {
+				  lower++;
+			  }
+			}
+
+			if (upper == null)
+			{
+			  upper = int.MaxValue;
+			}
+			else
+			{
+			  if (!includeUpper && upper > int.MinValue)
+			  {
+				  upper--;
+			  }
+			}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int ll = lower;
+			int ll = lower.Value;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int uu = upper;
+			int uu = upper.Value;
+
+			return new ValueSourceScorerAnonymousInnerClassHelper(this, reader, this, ll, uu);
+		  }
+
+		  private class ValueSourceScorerAnonymousInnerClassHelper : ValueSourceScorer
+		  {
+			  private readonly IntDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  private int ll;
+			  private int uu;
+
+			  public ValueSourceScorerAnonymousInnerClassHelper(IntDocValuesAnonymousInnerClassHelper outerInstance, IndexReader reader, org.apache.lucene.queries.function.valuesource.EnumFieldSource this, int ll, int uu) : base(reader, this)
+			  {
+				  this.outerInstance = outerInstance;
+				  this.ll = ll;
+				  this.uu = uu;
+			  }
+
+			  public override bool matchesValue(int doc)
+			  {
+				int val = outerInstance.arr.get(doc);
+				// only check for deleted if it's the default value
+				// if (val==0 && reader.isDeleted(doc)) return false;
+				return val >= ll && val <= uu;
+			  }
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				return new ValueFillerAnonymousInnerClassHelper(this);
+			  }
+		  }
+
+		  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+		  {
+			  private readonly IntDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public ValueFillerAnonymousInnerClassHelper(IntDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+				  mval = new MutableValueInt();
+			  }
+
+			  private readonly MutableValueInt mval;
+
+			  public override MutableValue Value
+			  {
+				  get
+				  {
+					return mval;
+				  }
+			  }
+
+			  public override void fillValue(int doc)
+			  {
+				mval.value = outerInstance.arr.get(doc);
+				mval.exists = outerInstance.valid.get(doc);
+			  }
+		  }
+
+
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this == o)
+		{
+			return true;
+		}
+		if (o == null || this.GetType() != o.GetType())
+		{
+			return false;
+		}
+		if (!base.Equals(o))
+		{
+			return false;
+		}
+
+		EnumFieldSource that = (EnumFieldSource) o;
+
+		if (!enumIntToStringMap.Equals(that.enumIntToStringMap))
+		{
+			return false;
+		}
+		if (!enumStringToIntMap.Equals(that.enumStringToIntMap))
+		{
+			return false;
+		}
+		if (!parser.Equals(that.parser))
+		{
+			return false;
+		}
+
+		return true;
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int result = base.GetHashCode();
+		result = 31 * result + parser.GetHashCode();
+		result = 31 * result + enumIntToStringMap.GetHashCode();
+		result = 31 * result + enumStringToIntMap.GetHashCode();
+		return result;
+	  }
+	}
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/FieldCacheSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/FieldCacheSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/FieldCacheSource.cs
new file mode 100644
index 0000000..92c2cb4
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/FieldCacheSource.cs
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using FieldCache = org.apache.lucene.search.FieldCache;
+
+	/// <summary>
+	/// A base class for ValueSource implementations that retrieve values for
+	/// a single field from the <seealso cref="org.apache.lucene.search.FieldCache"/>.
+	/// 
+	/// 
+	/// </summary>
+	public abstract class FieldCacheSource : ValueSource
+	{
+	  protected internal readonly string field;
+	  protected internal readonly FieldCache cache = FieldCache.DEFAULT;
+
+	  public FieldCacheSource(string field)
+	  {
+		this.field = field;
+	  }
+
+	  public virtual FieldCache FieldCache
+	  {
+		  get
+		  {
+			return cache;
+		  }
+	  }
+
+	  public virtual string Field
+	  {
+		  get
+		  {
+			return field;
+		  }
+	  }
+
+	  public override string description()
+	  {
+		return field;
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (!(o is FieldCacheSource))
+		{
+			return false;
+		}
+		FieldCacheSource other = (FieldCacheSource)o;
+		return this.field.Equals(other.field) && this.cache == other.cache;
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return cache.GetHashCode() + field.GetHashCode();
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/FloatFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/FloatFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/FloatFieldSource.cs
new file mode 100644
index 0000000..c60d99f
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/FloatFieldSource.cs
@@ -0,0 +1,152 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using Bits = org.apache.lucene.util.Bits;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueFloat = org.apache.lucene.util.mutable.MutableValueFloat;
+
+	/// <summary>
+	/// Obtains float field values from <seealso cref="FieldCache#getFloats"/> and makes those
+	/// values available as other numeric types, casting as needed.
+	/// </summary>
+	public class FloatFieldSource : FieldCacheSource
+	{
+
+	  protected internal readonly FieldCache.FloatParser parser;
+
+	  public FloatFieldSource(string field) : this(field, null)
+	  {
+	  }
+
+	  public FloatFieldSource(string field, FieldCache.FloatParser parser) : base(field)
+	  {
+		this.parser = parser;
+	  }
+
+	  public override string description()
+	  {
+		return "float(" + field + ')';
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldCache.Floats arr = cache.getFloats(readerContext.reader(), field, parser, true);
+		FieldCache.Floats arr = cache.getFloats(readerContext.reader(), field, parser, true);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+		Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, arr, valid);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly FloatFieldSource outerInstance;
+
+		  private FieldCache.Floats arr;
+		  private Bits valid;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(FloatFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.FloatFieldSource this, FieldCache.Floats arr, Bits valid) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.arr = arr;
+			  this.valid = valid;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return arr.get(doc);
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return valid.get(doc) ? arr.get(doc) : null;
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			return arr.get(doc) != 0 || valid.get(doc);
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				return new ValueFillerAnonymousInnerClassHelper(this);
+			  }
+		  }
+
+		  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+		  {
+			  private readonly FloatDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public ValueFillerAnonymousInnerClassHelper(FloatDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+				  mval = new MutableValueFloat();
+			  }
+
+			  private readonly MutableValueFloat mval;
+
+			  public override MutableValue Value
+			  {
+				  get
+				  {
+					return mval;
+				  }
+			  }
+
+			  public override void fillValue(int doc)
+			  {
+				mval.value = outerInstance.arr.get(doc);
+				mval.exists = mval.value != 0 || outerInstance.valid.get(doc);
+			  }
+		  }
+
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o.GetType() != typeof(FloatFieldSource))
+		{
+			return false;
+		}
+		FloatFieldSource other = (FloatFieldSource)o;
+		return base.Equals(other) && (this.parser == null ? other.parser == null : this.parser.GetType() == other.parser.GetType());
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = parser == null ? typeof(float?).GetHashCode() : parser.GetType().GetHashCode();
+		h += base.GetHashCode();
+		return h;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/IDFValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/IDFValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/IDFValueSource.cs
new file mode 100644
index 0000000..13456ff
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/IDFValueSource.cs
@@ -0,0 +1,85 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using org.apache.lucene.index;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using PerFieldSimilarityWrapper = org.apache.lucene.search.similarities.PerFieldSimilarityWrapper;
+	using Similarity = org.apache.lucene.search.similarities.Similarity;
+	using TFIDFSimilarity = org.apache.lucene.search.similarities.TFIDFSimilarity;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+	/// <summary>
+	/// Function that returns <seealso cref="TFIDFSimilarity #idf(long, long)"/>
+	/// for every document.
+	/// <para>
+	/// Note that the configured Similarity for the field must be
+	/// a subclass of <seealso cref="TFIDFSimilarity"/>
+	/// @lucene.internal 
+	/// </para>
+	/// </summary>
+	public class IDFValueSource : DocFreqValueSource
+	{
+	  public IDFValueSource(string field, string val, string indexedField, BytesRef indexedBytes) : base(field, val, indexedField, indexedBytes)
+	  {
+	  }
+
+	  public override string name()
+	  {
+		return "idf";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		IndexSearcher searcher = (IndexSearcher)context["searcher"];
+		TFIDFSimilarity sim = asTFIDF(searcher.Similarity, field);
+		if (sim == null)
+		{
+		  throw new System.NotSupportedException("requires a TFIDFSimilarity (such as DefaultSimilarity)");
+		}
+		int docfreq = searcher.IndexReader.docFreq(new Term(indexedField, indexedBytes));
+		float idf = sim.idf(docfreq, searcher.IndexReader.maxDoc());
+		return new ConstDoubleDocValues(idf, this);
+	  }
+
+	  // tries extra hard to cast the sim to TFIDFSimilarity
+	  internal static TFIDFSimilarity asTFIDF(Similarity sim, string field)
+	  {
+		while (sim is PerFieldSimilarityWrapper)
+		{
+		  sim = ((PerFieldSimilarityWrapper)sim).get(field);
+		}
+		if (sim is TFIDFSimilarity)
+		{
+		  return (TFIDFSimilarity)sim;
+		}
+		else
+		{
+		  return null;
+		}
+	  }
+	}
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/IfFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/IfFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/IfFunction.cs
new file mode 100644
index 0000000..a62c801
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/IfFunction.cs
@@ -0,0 +1,186 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using Explanation = org.apache.lucene.search.Explanation;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+
+	/// <summary>
+	/// Depending on the boolean value of the <code>ifSource</code> function,
+	/// returns the value of the <code>trueSource</code> or <code>falseSource</code> function.
+	/// </summary>
+	public class IfFunction : BoolFunction
+	{
+	  private readonly ValueSource ifSource;
+	  private readonly ValueSource trueSource;
+	  private readonly ValueSource falseSource;
+
+
+	  public IfFunction(ValueSource ifSource, ValueSource trueSource, ValueSource falseSource)
+	  {
+		this.ifSource = ifSource;
+		this.trueSource = trueSource;
+		this.falseSource = falseSource;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues ifVals = ifSource.getValues(context, readerContext);
+		FunctionValues ifVals = ifSource.getValues(context, readerContext);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues trueVals = trueSource.getValues(context, readerContext);
+		FunctionValues trueVals = trueSource.getValues(context, readerContext);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues falseVals = falseSource.getValues(context, readerContext);
+		FunctionValues falseVals = falseSource.getValues(context, readerContext);
+
+		return new FunctionValuesAnonymousInnerClassHelper(this, ifVals, trueVals, falseVals);
+
+	  }
+
+	  private class FunctionValuesAnonymousInnerClassHelper : FunctionValues
+	  {
+		  private readonly IfFunction outerInstance;
+
+		  private FunctionValues ifVals;
+		  private FunctionValues trueVals;
+		  private FunctionValues falseVals;
+
+		  public FunctionValuesAnonymousInnerClassHelper(IfFunction outerInstance, FunctionValues ifVals, FunctionValues trueVals, FunctionValues falseVals)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.ifVals = ifVals;
+			  this.trueVals = trueVals;
+			  this.falseVals = falseVals;
+		  }
+
+		  public override sbyte byteVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.byteVal(doc) : falseVals.byteVal(doc);
+		  }
+
+		  public override short shortVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.shortVal(doc) : falseVals.shortVal(doc);
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.floatVal(doc) : falseVals.floatVal(doc);
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.intVal(doc) : falseVals.intVal(doc);
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.longVal(doc) : falseVals.longVal(doc);
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.doubleVal(doc) : falseVals.doubleVal(doc);
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.strVal(doc) : falseVals.strVal(doc);
+		  }
+
+		  public override bool boolVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.boolVal(doc) : falseVals.boolVal(doc);
+		  }
+
+		  public override bool bytesVal(int doc, BytesRef target)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.bytesVal(doc, target) : falseVals.bytesVal(doc, target);
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return ifVals.boolVal(doc) ? trueVals.objectVal(doc) : falseVals.objectVal(doc);
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			return true; // TODO: flow through to any sub-sources?
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				// TODO: we need types of trueSource / falseSource to handle this
+				// for now, use float.
+				return base.ValueFiller;
+			  }
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return "if(" + ifVals.ToString(doc) + ',' + trueVals.ToString(doc) + ',' + falseVals.ToString(doc) + ')';
+		  }
+	  }
+
+	  public override string description()
+	  {
+		return "if(" + ifSource.description() + ',' + trueSource.description() + ',' + falseSource + ')';
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = ifSource.GetHashCode();
+		h = h * 31 + trueSource.GetHashCode();
+		h = h * 31 + falseSource.GetHashCode();
+		return h;
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (!(o is IfFunction))
+		{
+			return false;
+		}
+		IfFunction other = (IfFunction)o;
+		return ifSource.Equals(other.ifSource) && trueSource.Equals(other.trueSource) && falseSource.Equals(other.falseSource);
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		ifSource.createWeight(context, searcher);
+		trueSource.createWeight(context, searcher);
+		falseSource.createWeight(context, searcher);
+	  }
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/IntFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/IntFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/IntFieldSource.cs
new file mode 100644
index 0000000..bb6cf35
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/IntFieldSource.cs
@@ -0,0 +1,183 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using IntDocValues = org.apache.lucene.queries.function.docvalues.IntDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using Bits = org.apache.lucene.util.Bits;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueInt = org.apache.lucene.util.mutable.MutableValueInt;
+
+	/// <summary>
+	/// Obtains int field values from <seealso cref="FieldCache#getInts"/> and makes those
+	/// values available as other numeric types, casting as needed.
+	/// </summary>
+	public class IntFieldSource : FieldCacheSource
+	{
+	  internal readonly FieldCache.IntParser parser;
+
+	  public IntFieldSource(string field) : this(field, null)
+	  {
+	  }
+
+	  public IntFieldSource(string field, FieldCache.IntParser parser) : base(field)
+	  {
+		this.parser = parser;
+	  }
+
+	  public override string description()
+	  {
+		return "int(" + field + ')';
+	  }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldCache.Ints arr = cache.getInts(readerContext.reader(), field, parser, true);
+		FieldCache.Ints arr = cache.getInts(readerContext.reader(), field, parser, true);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+		Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+
+		return new IntDocValuesAnonymousInnerClassHelper(this, this, arr, valid);
+	  }
+
+	  private class IntDocValuesAnonymousInnerClassHelper : IntDocValues
+	  {
+		  private readonly IntFieldSource outerInstance;
+
+		  private FieldCache.Ints arr;
+		  private Bits valid;
+
+		  public IntDocValuesAnonymousInnerClassHelper(IntFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.IntFieldSource this, FieldCache.Ints arr, Bits valid) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.arr = arr;
+			  this.valid = valid;
+			  val = new MutableValueInt();
+		  }
+
+		  internal readonly MutableValueInt val;
+
+		  public override float floatVal(int doc)
+		  {
+			return (float)arr.get(doc);
+		  }
+
+		  public override int intVal(int doc)
+		  {
+			return arr.get(doc);
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return (long)arr.get(doc);
+		  }
+
+		  public override double doubleVal(int doc)
+		  {
+			return (double)arr.get(doc);
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return Convert.ToString(arr.get(doc));
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return valid.get(doc) ? arr.get(doc) : null;
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			return arr.get(doc) != 0 || valid.get(doc);
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.description() + '=' + intVal(doc);
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				return new ValueFillerAnonymousInnerClassHelper(this);
+			  }
+		  }
+
+		  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+		  {
+			  private readonly IntDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public ValueFillerAnonymousInnerClassHelper(IntDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+				  mval = new MutableValueInt();
+			  }
+
+			  private readonly MutableValueInt mval;
+
+			  public override MutableValue Value
+			  {
+				  get
+				  {
+					return mval;
+				  }
+			  }
+
+			  public override void fillValue(int doc)
+			  {
+				mval.value = outerInstance.arr.get(doc);
+				mval.exists = mval.value != 0 || outerInstance.valid.get(doc);
+			  }
+		  }
+
+
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o.GetType() != typeof(IntFieldSource))
+		{
+			return false;
+		}
+		IntFieldSource other = (IntFieldSource)o;
+		return base.Equals(other) && (this.parser == null ? other.parser == null : this.parser.GetType() == other.parser.GetType());
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = parser == null ? typeof(int?).GetHashCode() : parser.GetType().GetHashCode();
+		h += base.GetHashCode();
+		return h;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/JoinDocFreqValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/JoinDocFreqValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/JoinDocFreqValueSource.cs
new file mode 100644
index 0000000..46cc5c7
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/JoinDocFreqValueSource.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using BinaryDocValues = org.apache.lucene.index.BinaryDocValues;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using MultiFields = org.apache.lucene.index.MultiFields;
+	using ReaderUtil = org.apache.lucene.index.ReaderUtil;
+	using Terms = org.apache.lucene.index.Terms;
+	using TermsEnum = org.apache.lucene.index.TermsEnum;
+	using IntDocValues = org.apache.lucene.queries.function.docvalues.IntDocValues;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+	using PackedInts = org.apache.lucene.util.packed.PackedInts;
+
+	/// <summary>
+	/// Use a field value and find the Document Frequency within another field.
+	/// 
+	/// @since solr 4.0
+	/// </summary>
+	public class JoinDocFreqValueSource : FieldCacheSource
+	{
+
+	  public const string NAME = "joindf";
+
+	  protected internal readonly string qfield;
+
+	  public JoinDocFreqValueSource(string field, string qfield) : base(field)
+	  {
+		this.qfield = qfield;
+	  }
+
+	  public override string description()
+	  {
+		return NAME + "(" + field + ":(" + qfield + "))";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.BinaryDocValues terms = cache.getTerms(readerContext.reader(), field, false, org.apache.lucene.util.packed.PackedInts.FAST);
+		BinaryDocValues terms = cache.getTerms(readerContext.reader(), field, false, PackedInts.FAST);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.IndexReader top = org.apache.lucene.index.ReaderUtil.getTopLevelContext(readerContext).reader();
+		IndexReader top = ReaderUtil.getTopLevelContext(readerContext).reader();
+		Terms t = MultiFields.getTerms(top, qfield);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.TermsEnum termsEnum = t == null ? org.apache.lucene.index.TermsEnum.EMPTY : t.iterator(null);
+		TermsEnum termsEnum = t == null ? TermsEnum.EMPTY : t.iterator(null);
+
+		return new IntDocValuesAnonymousInnerClassHelper(this, this, terms, termsEnum);
+	  }
+
+	  private class IntDocValuesAnonymousInnerClassHelper : IntDocValues
+	  {
+		  private readonly JoinDocFreqValueSource outerInstance;
+
+		  private BinaryDocValues terms;
+		  private TermsEnum termsEnum;
+
+		  public IntDocValuesAnonymousInnerClassHelper(JoinDocFreqValueSource outerInstance, org.apache.lucene.queries.function.valuesource.JoinDocFreqValueSource this, BinaryDocValues terms, TermsEnum termsEnum) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.terms = terms;
+			  this.termsEnum = termsEnum;
+			  @ref = new BytesRef();
+		  }
+
+		  internal readonly BytesRef @ref;
+
+		  public override int intVal(int doc)
+		  {
+			try
+			{
+			  terms.get(doc, @ref);
+			  if (termsEnum.seekExact(@ref))
+			  {
+				return termsEnum.docFreq();
+			  }
+			  else
+			  {
+				return 0;
+			  }
+			}
+			catch (IOException e)
+			{
+			  throw new Exception("caught exception in function " + outerInstance.description() + " : doc=" + doc, e);
+			}
+		  }
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o.GetType() != typeof(JoinDocFreqValueSource))
+		{
+			return false;
+		}
+		JoinDocFreqValueSource other = (JoinDocFreqValueSource)o;
+		if (!qfield.Equals(other.qfield))
+		{
+			return false;
+		}
+		return base.Equals(other);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return qfield.GetHashCode() + base.GetHashCode();
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/LinearFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/LinearFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/LinearFloatFunction.cs
new file mode 100644
index 0000000..a03268c
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/LinearFloatFunction.cs
@@ -0,0 +1,113 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using FloatDocValues = org.apache.lucene.queries.function.docvalues.FloatDocValues;
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// <code>LinearFloatFunction</code> implements a linear function over
+	/// another <seealso cref="ValueSource"/>.
+	/// <br>
+	/// Normally Used as an argument to a <seealso cref="org.apache.lucene.queries.function.FunctionQuery"/>
+	/// 
+	/// 
+	/// </summary>
+	public class LinearFloatFunction : ValueSource
+	{
+	  protected internal readonly ValueSource source;
+	  protected internal readonly float slope;
+	  protected internal readonly float intercept;
+
+	  public LinearFloatFunction(ValueSource source, float slope, float intercept)
+	  {
+		this.source = source;
+		this.slope = slope;
+		this.intercept = intercept;
+	  }
+
+	  public override string description()
+	  {
+		return slope + "*float(" + source.description() + ")+" + intercept;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.queries.function.FunctionValues vals = source.getValues(context, readerContext);
+		FunctionValues vals = source.getValues(context, readerContext);
+		return new FloatDocValuesAnonymousInnerClassHelper(this, this, vals);
+	  }
+
+	  private class FloatDocValuesAnonymousInnerClassHelper : FloatDocValues
+	  {
+		  private readonly LinearFloatFunction outerInstance;
+
+		  private FunctionValues vals;
+
+		  public FloatDocValuesAnonymousInnerClassHelper(LinearFloatFunction outerInstance, org.apache.lucene.queries.function.valuesource.LinearFloatFunction this, FunctionValues vals) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.vals = vals;
+		  }
+
+		  public override float floatVal(int doc)
+		  {
+			return vals.floatVal(doc) * outerInstance.slope + outerInstance.intercept;
+		  }
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.slope + "*float(" + vals.ToString(doc) + ")+" + outerInstance.intercept;
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		source.createWeight(context, searcher);
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = float.floatToIntBits(slope);
+		h = ((int)((uint)h >> 2)) | (h << 30);
+		h += float.floatToIntBits(intercept);
+		h ^= (h << 14) | ((int)((uint)h >> 19));
+		return h + source.GetHashCode();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (typeof(LinearFloatFunction) != o.GetType())
+		{
+			return false;
+		}
+		LinearFloatFunction other = (LinearFloatFunction)o;
+		return this.slope == other.slope && this.intercept == other.intercept && this.source.Equals(other.source);
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/LiteralValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/LiteralValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/LiteralValueSource.cs
new file mode 100644
index 0000000..6107a28
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/LiteralValueSource.cs
@@ -0,0 +1,117 @@
+using System.Collections;
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using StrDocValues = org.apache.lucene.queries.function.docvalues.StrDocValues;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+
+
+
+	/// <summary>
+	/// Pass a the field value through as a String, no matter the type // Q: doesn't this mean it's a "string"?
+	/// 
+	/// 
+	/// </summary>
+	public class LiteralValueSource : ValueSource
+	{
+	  protected internal readonly string @string;
+	  protected internal readonly BytesRef bytesRef;
+
+	  public LiteralValueSource(string @string)
+	  {
+		this.@string = @string;
+		this.bytesRef = new BytesRef(@string);
+	  }
+
+	  /// <summary>
+	  /// returns the literal value </summary>
+	  public virtual string Value
+	  {
+		  get
+		  {
+			return @string;
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+
+		return new StrDocValuesAnonymousInnerClassHelper(this, this);
+	  }
+
+	  private class StrDocValuesAnonymousInnerClassHelper : StrDocValues
+	  {
+		  private readonly LiteralValueSource outerInstance;
+
+		  public StrDocValuesAnonymousInnerClassHelper(LiteralValueSource outerInstance, org.apache.lucene.queries.function.valuesource.LiteralValueSource this) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return outerInstance.@string;
+		  }
+
+		  public override bool bytesVal(int doc, BytesRef target)
+		  {
+			target.copyBytes(outerInstance.bytesRef);
+			return true;
+		  }
+
+		  public override string ToString(int doc)
+		  {
+			return outerInstance.@string;
+		  }
+	  }
+
+	  public override string description()
+	  {
+		return "literal(" + @string + ")";
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this == o)
+		{
+			return true;
+		}
+		if (!(o is LiteralValueSource))
+		{
+			return false;
+		}
+
+		LiteralValueSource that = (LiteralValueSource) o;
+
+		return @string.Equals(that.@string);
+
+	  }
+
+	  public static readonly int hash = typeof(LiteralValueSource).GetHashCode();
+	  public override int GetHashCode()
+	  {
+		return hash + @string.GetHashCode();
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/LongFieldSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/LongFieldSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/LongFieldSource.cs
new file mode 100644
index 0000000..d831ebd
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/LongFieldSource.cs
@@ -0,0 +1,184 @@
+using System;
+using System.Collections;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader;
+	using LongDocValues = org.apache.lucene.queries.function.docvalues.LongDocValues;
+	using FieldCache = org.apache.lucene.search.FieldCache;
+	using Bits = org.apache.lucene.util.Bits;
+	using MutableValue = org.apache.lucene.util.mutable.MutableValue;
+	using MutableValueLong = org.apache.lucene.util.mutable.MutableValueLong;
+
+	/// <summary>
+	/// Obtains long field values from <seealso cref="FieldCache#getLongs"/> and makes those
+	/// values available as other numeric types, casting as needed.
+	/// </summary>
+	public class LongFieldSource : FieldCacheSource
+	{
+
+	  protected internal readonly FieldCache.LongParser parser;
+
+	  public LongFieldSource(string field) : this(field, null)
+	  {
+	  }
+
+	  public LongFieldSource(string field, FieldCache.LongParser parser) : base(field)
+	  {
+		this.parser = parser;
+	  }
+
+	  public override string description()
+	  {
+		return "long(" + field + ')';
+	  }
+
+	  public virtual long externalToLong(string extVal)
+	  {
+		return Convert.ToInt64(extVal);
+	  }
+
+	  public virtual object longToObject(long val)
+	  {
+		return val;
+	  }
+
+	  public virtual string longToString(long val)
+	  {
+		return longToObject(val).ToString();
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.search.FieldCache.Longs arr = cache.getLongs(readerContext.reader(), field, parser, true);
+		FieldCache.Longs arr = cache.getLongs(readerContext.reader(), field, parser, true);
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+		Bits valid = cache.getDocsWithField(readerContext.reader(), field);
+
+		return new LongDocValuesAnonymousInnerClassHelper(this, this, arr, valid);
+	  }
+
+	  private class LongDocValuesAnonymousInnerClassHelper : LongDocValues
+	  {
+		  private readonly LongFieldSource outerInstance;
+
+		  private FieldCache.Longs arr;
+		  private Bits valid;
+
+		  public LongDocValuesAnonymousInnerClassHelper(LongFieldSource outerInstance, org.apache.lucene.queries.function.valuesource.LongFieldSource this, FieldCache.Longs arr, Bits valid) : base(this)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.arr = arr;
+			  this.valid = valid;
+		  }
+
+		  public override long longVal(int doc)
+		  {
+			return arr.get(doc);
+		  }
+
+		  public override bool exists(int doc)
+		  {
+			return arr.get(doc) != 0 || valid.get(doc);
+		  }
+
+		  public override object objectVal(int doc)
+		  {
+			return valid.get(doc) ? outerInstance.longToObject(arr.get(doc)) : null;
+		  }
+
+		  public override string strVal(int doc)
+		  {
+			return valid.get(doc) ? outerInstance.longToString(arr.get(doc)) : null;
+		  }
+
+		  protected internal override long externalToLong(string extVal)
+		  {
+			return outerInstance.externalToLong(extVal);
+		  }
+
+		  public override ValueFiller ValueFiller
+		  {
+			  get
+			  {
+				return new ValueFillerAnonymousInnerClassHelper(this);
+			  }
+		  }
+
+		  private class ValueFillerAnonymousInnerClassHelper : ValueFiller
+		  {
+			  private readonly LongDocValuesAnonymousInnerClassHelper outerInstance;
+
+			  public ValueFillerAnonymousInnerClassHelper(LongDocValuesAnonymousInnerClassHelper outerInstance)
+			  {
+				  this.outerInstance = outerInstance;
+				  mval = outerInstance.outerInstance.newMutableValueLong();
+			  }
+
+			  private readonly MutableValueLong mval;
+
+			  public override MutableValue Value
+			  {
+				  get
+				  {
+					return mval;
+				  }
+			  }
+
+			  public override void fillValue(int doc)
+			  {
+				mval.value = outerInstance.arr.get(doc);
+				mval.exists = mval.value != 0 || outerInstance.valid.get(doc);
+			  }
+		  }
+
+	  }
+
+	  protected internal virtual MutableValueLong newMutableValueLong()
+	  {
+		return new MutableValueLong();
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (o.GetType() != this.GetType())
+		{
+			return false;
+		}
+		LongFieldSource other = (LongFieldSource) o;
+		return base.Equals(other) && (this.parser == null ? other.parser == null : this.parser.GetType() == other.parser.GetType());
+	  }
+
+	  public override int GetHashCode()
+	  {
+		int h = parser == null ? this.GetType().GetHashCode() : parser.GetType().GetHashCode();
+		h += base.GetHashCode();
+		return h;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/MaxDocValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/MaxDocValueSource.cs b/src/Lucene.Net.Queries/Function/ValueSource/MaxDocValueSource.cs
new file mode 100644
index 0000000..0e00953
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/MaxDocValueSource.cs
@@ -0,0 +1,70 @@
+using System.Collections;
+
+/*
+ * 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.
+ */
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using IndexReader = org.apache.lucene.index.IndexReader; // javadocs
+	using IndexSearcher = org.apache.lucene.search.IndexSearcher;
+
+
+	/// <summary>
+	/// Returns the value of <seealso cref="IndexReader#maxDoc()"/>
+	/// for every document. This is the number of documents
+	/// including deletions.
+	/// </summary>
+	public class MaxDocValueSource : ValueSource
+	{
+	  public virtual string name()
+	  {
+		return "maxdoc";
+	  }
+
+	  public override string description()
+	  {
+		return name() + "()";
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public void createWeight(java.util.Map context, org.apache.lucene.search.IndexSearcher searcher) throws java.io.IOException
+	  public override void createWeight(IDictionary context, IndexSearcher searcher)
+	  {
+		context["searcher"] = searcher;
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.queries.function.FunctionValues getValues(java.util.Map context, org.apache.lucene.index.AtomicReaderContext readerContext) throws java.io.IOException
+	  public override FunctionValues getValues(IDictionary context, AtomicReaderContext readerContext)
+	  {
+		IndexSearcher searcher = (IndexSearcher)context["searcher"];
+		return new ConstIntDocValues(searcher.IndexReader.maxDoc(), this);
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		return this.GetType() == o.GetType();
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return this.GetType().GetHashCode();
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/MaxFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/MaxFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/MaxFloatFunction.cs
new file mode 100644
index 0000000..24034c3
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/MaxFloatFunction.cs
@@ -0,0 +1,53 @@
+using System;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	/// <summary>
+	/// <code>MaxFloatFunction</code> returns the max of it's components.
+	/// </summary>
+	public class MaxFloatFunction : MultiFloatFunction
+	{
+	  public MaxFloatFunction(ValueSource[] sources) : base(sources)
+	  {
+	  }
+
+	  protected internal override string name()
+	  {
+		return "max";
+	  }
+
+	  protected internal override float func(int doc, FunctionValues[] valsArr)
+	  {
+		if (valsArr.Length == 0)
+		{
+			return 0.0f;
+		}
+		float val = float.NegativeInfinity;
+		foreach (FunctionValues vals in valsArr)
+		{
+		  val = Math.Max(vals.floatVal(doc), val);
+		}
+		return val;
+	  }
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/Function/ValueSource/MinFloatFunction.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/Function/ValueSource/MinFloatFunction.cs b/src/Lucene.Net.Queries/Function/ValueSource/MinFloatFunction.cs
new file mode 100644
index 0000000..f4abce7
--- /dev/null
+++ b/src/Lucene.Net.Queries/Function/ValueSource/MinFloatFunction.cs
@@ -0,0 +1,53 @@
+using System;
+
+/*
+ * 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.
+ */
+
+namespace org.apache.lucene.queries.function.valuesource
+{
+
+
+	/// <summary>
+	/// <code>MinFloatFunction</code> returns the min of it's components.
+	/// </summary>
+	public class MinFloatFunction : MultiFloatFunction
+	{
+	  public MinFloatFunction(ValueSource[] sources) : base(sources)
+	  {
+	  }
+
+	  protected internal override string name()
+	  {
+		return "min";
+	  }
+
+	  protected internal override float func(int doc, FunctionValues[] valsArr)
+	  {
+		if (valsArr.Length == 0)
+		{
+			return 0.0f;
+		}
+		float val = float.PositiveInfinity;
+		foreach (FunctionValues vals in valsArr)
+		{
+		  val = Math.Min(vals.floatVal(doc), val);
+		}
+		return val;
+	  }
+	}
+
+}
\ No newline at end of file


[02/11] Skeleton porting of Lucene.Net.Queries

Posted by sy...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/TermFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/TermFilter.cs b/src/Lucene.Net.Queries/TermFilter.cs
new file mode 100644
index 0000000..1e4ffd0
--- /dev/null
+++ b/src/Lucene.Net.Queries/TermFilter.cs
@@ -0,0 +1,139 @@
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+
+	using AtomicReaderContext = org.apache.lucene.index.AtomicReaderContext;
+	using DocsEnum = org.apache.lucene.index.DocsEnum;
+	using Term = org.apache.lucene.index.Term;
+	using Terms = org.apache.lucene.index.Terms;
+	using TermsEnum = org.apache.lucene.index.TermsEnum;
+	using DocIdSet = org.apache.lucene.search.DocIdSet;
+	using DocIdSetIterator = org.apache.lucene.search.DocIdSetIterator;
+	using Filter = org.apache.lucene.search.Filter;
+	using Bits = org.apache.lucene.util.Bits;
+
+	/// <summary>
+	/// A filter that includes documents that match with a specific term.
+	/// </summary>
+	public sealed class TermFilter : Filter
+	{
+
+	  private readonly Term term;
+
+	  /// <param name="term"> The term documents need to have in order to be a match for this filter. </param>
+	  public TermFilter(Term term)
+	  {
+		if (term == null)
+		{
+		  throw new System.ArgumentException("Term must not be null");
+		}
+		else if (term.field() == null)
+		{
+		  throw new System.ArgumentException("Field must not be null");
+		}
+		this.term = term;
+	  }
+
+	  /// <returns> The term this filter includes documents with. </returns>
+	  public Term Term
+	  {
+		  get
+		  {
+			return term;
+		  }
+	  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.DocIdSet getDocIdSet(org.apache.lucene.index.AtomicReaderContext context, final org.apache.lucene.util.Bits acceptDocs) throws java.io.IOException
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+	  public override DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs)
+	  {
+		Terms terms = context.reader().terms(term.field());
+		if (terms == null)
+		{
+		  return null;
+		}
+
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.index.TermsEnum termsEnum = terms.iterator(null);
+		TermsEnum termsEnum = terms.iterator(null);
+		if (!termsEnum.seekExact(term.bytes()))
+		{
+		  return null;
+		}
+		return new DocIdSetAnonymousInnerClassHelper(this, acceptDocs, termsEnum);
+	  }
+
+	  private class DocIdSetAnonymousInnerClassHelper : DocIdSet
+	  {
+		  private readonly TermFilter outerInstance;
+
+		  private Bits acceptDocs;
+		  private TermsEnum termsEnum;
+
+		  public DocIdSetAnonymousInnerClassHelper(TermFilter outerInstance, Bits acceptDocs, TermsEnum termsEnum)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.acceptDocs = acceptDocs;
+			  this.termsEnum = termsEnum;
+		  }
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.DocIdSetIterator iterator() throws java.io.IOException
+		  public override DocIdSetIterator iterator()
+		  {
+			return termsEnum.docs(acceptDocs, null, DocsEnum.FLAG_NONE);
+		  }
+
+	  }
+
+	  public override bool Equals(object o)
+	  {
+		if (this == o)
+		{
+			return true;
+		}
+		if (o == null || this.GetType() != o.GetType())
+		{
+			return false;
+		}
+
+		TermFilter that = (TermFilter) o;
+
+		if (term != null ?!term.Equals(that.term) : that.term != null)
+		{
+			return false;
+		}
+
+		return true;
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return term != null ? term.GetHashCode() : 0;
+	  }
+
+	  public override string ToString()
+	  {
+		return term.field() + ":" + term.text();
+	  }
+
+	}
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/882f487d/src/Lucene.Net.Queries/TermsFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Queries/TermsFilter.cs b/src/Lucene.Net.Queries/TermsFilter.cs
new file mode 100644
index 0000000..be418fb
--- /dev/null
+++ b/src/Lucene.Net.Queries/TermsFilter.cs
@@ -0,0 +1,439 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace org.apache.lucene.queries
+{
+
+	/*
+	 * 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.
+	 */
+
+	using org.apache.lucene.index;
+	using DocIdSet = org.apache.lucene.search.DocIdSet;
+	using DocIdSetIterator = org.apache.lucene.search.DocIdSetIterator;
+	using Filter = org.apache.lucene.search.Filter;
+	using ArrayUtil = org.apache.lucene.util.ArrayUtil;
+	using Bits = org.apache.lucene.util.Bits;
+	using BytesRef = org.apache.lucene.util.BytesRef;
+	using FixedBitSet = org.apache.lucene.util.FixedBitSet;
+
+
+	/// <summary>
+	/// Constructs a filter for docs matching any of the terms added to this class.
+	/// Unlike a RangeFilter this can be used for filtering on multiple terms that are not necessarily in
+	/// a sequence. An example might be a collection of primary keys from a database query result or perhaps
+	/// a choice of "category" labels picked by the end user. As a filter, this is much faster than the
+	/// equivalent query (a BooleanQuery with many "should" TermQueries)
+	/// </summary>
+	public sealed class TermsFilter : Filter
+	{
+
+	  /*
+	   * this class is often used for large number of terms in a single field.
+	   * to optimize for this case and to be filter-cache friendly we 
+	   * serialize all terms into a single byte array and store offsets
+	   * in a parallel array to keep the # of object constant and speed up
+	   * equals / hashcode.
+	   * 
+	   * This adds quite a bit of complexity but allows large term filters to
+	   * be efficient for GC and cache-lookups
+	   */
+	  private readonly int[] offsets;
+	  private readonly sbyte[] termsBytes;
+	  private readonly TermsAndField[] termsAndFields;
+	  private readonly int hashCode_Renamed; // cached hashcode for fast cache lookups
+	  private const int PRIME = 31;
+
+	  /// <summary>
+	  /// Creates a new <seealso cref="TermsFilter"/> from the given list. The list
+	  /// can contain duplicate terms and multiple fields.
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public TermsFilter(final java.util.List<Term> terms)
+	  public TermsFilter(IList<Term> terms) : this(new FieldAndTermEnumAnonymousInnerClassHelper(this, terms), terms.Count)
+	  {
+	  }
+
+	  private class FieldAndTermEnumAnonymousInnerClassHelper : FieldAndTermEnum
+	  {
+		  private readonly TermsFilter outerInstance;
+
+		  private IList<Term> terms;
+
+		  public FieldAndTermEnumAnonymousInnerClassHelper(TermsFilter outerInstance, IList<Term> terms)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.terms = terms;
+			  iter = sort(terms).GetEnumerator();
+		  }
+
+			// we need to sort for deduplication and to have a common cache key
+		  internal readonly IEnumerator<Term> iter;
+		  public override BytesRef next()
+		  {
+			if (iter.hasNext())
+			{
+			  Term next = iter.next();
+			  field = next.field();
+			  return next.bytes();
+			}
+			return null;
+		  }
+	  }
+
+	  /// <summary>
+	  /// Creates a new <seealso cref="TermsFilter"/> from the given <seealso cref="BytesRef"/> list for
+	  /// a single field.
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public TermsFilter(final String field, final java.util.List<org.apache.lucene.util.BytesRef> terms)
+	  public TermsFilter(string field, IList<BytesRef> terms) : this(new FieldAndTermEnumAnonymousInnerClassHelper2(this, field, terms), terms.Count)
+	  {
+	  }
+
+	  private class FieldAndTermEnumAnonymousInnerClassHelper2 : FieldAndTermEnum
+	  {
+		  private readonly TermsFilter outerInstance;
+
+		  private IList<BytesRef> terms;
+
+		  public FieldAndTermEnumAnonymousInnerClassHelper2(TermsFilter outerInstance, string field, IList<BytesRef> terms) : base(field)
+		  {
+			  this.outerInstance = outerInstance;
+			  this.terms = terms;
+			  iter = sort(terms).GetEnumerator();
+		  }
+
+			// we need to sort for deduplication and to have a common cache key
+		  internal readonly IEnumerator<BytesRef> iter;
+		  public override BytesRef next()
+		  {
+			if (iter.hasNext())
+			{
+			  return iter.next();
+			}
+			return null;
+		  }
+	  }
+
+	  /// <summary>
+	  /// Creates a new <seealso cref="TermsFilter"/> from the given <seealso cref="BytesRef"/> array for
+	  /// a single field.
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public TermsFilter(final String field, final org.apache.lucene.util.BytesRef...terms)
+	  public TermsFilter(string field, params BytesRef[] terms) : this(field, Arrays.asList(terms))
+	  {
+		// this ctor prevents unnecessary Term creations
+	  }
+
+	  /// <summary>
+	  /// Creates a new <seealso cref="TermsFilter"/> from the given array. The array can
+	  /// contain duplicate terms and multiple fields.
+	  /// </summary>
+//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
+//ORIGINAL LINE: public TermsFilter(final Term... terms)
+	  public TermsFilter(params Term[] terms) : this(Arrays.asList(terms))
+	  {
+	  }
+
+
+	  private TermsFilter(FieldAndTermEnum iter, int length)
+	  {
+		// TODO: maybe use oal.index.PrefixCodedTerms instead?
+		// If number of terms is more than a few hundred it
+		// should be a win
+
+		// TODO: we also pack terms in FieldCache/DocValues
+		// ... maybe we can refactor to share that code
+
+		// TODO: yet another option is to build the union of the terms in
+		// an automaton an call intersect on the termsenum if the density is high
+
+		int hash = 9;
+		sbyte[] serializedTerms = new sbyte[0];
+		this.offsets = new int[length + 1];
+		int lastEndOffset = 0;
+		int index = 0;
+		List<TermsAndField> termsAndFields = new List<TermsAndField>();
+		TermsAndField lastTermsAndField = null;
+		BytesRef previousTerm = null;
+		string previousField = null;
+		BytesRef currentTerm;
+		string currentField;
+		while ((currentTerm = iter.next()) != null)
+		{
+		  currentField = iter.field();
+		  if (currentField == null)
+		  {
+			throw new System.ArgumentException("Field must not be null");
+		  }
+		  if (previousField != null)
+		  {
+			// deduplicate
+			if (previousField.Equals(currentField))
+			{
+			  if (previousTerm.bytesEquals(currentTerm))
+			  {
+				continue;
+			  }
+			}
+			else
+			{
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int start = lastTermsAndField == null ? 0 : lastTermsAndField.end;
+			  int start = lastTermsAndField == null ? 0 : lastTermsAndField.end;
+			  lastTermsAndField = new TermsAndField(start, index, previousField);
+			  termsAndFields.Add(lastTermsAndField);
+			}
+		  }
+		  hash = PRIME * hash + currentField.GetHashCode();
+		  hash = PRIME * hash + currentTerm.GetHashCode();
+		  if (serializedTerms.Length < lastEndOffset + currentTerm.length)
+		  {
+			serializedTerms = ArrayUtil.grow(serializedTerms, lastEndOffset + currentTerm.length);
+		  }
+		  Array.Copy(currentTerm.bytes, currentTerm.offset, serializedTerms, lastEndOffset, currentTerm.length);
+		  offsets[index] = lastEndOffset;
+		  lastEndOffset += currentTerm.length;
+		  index++;
+		  previousTerm = currentTerm;
+		  previousField = currentField;
+		}
+		offsets[index] = lastEndOffset;
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final int start = lastTermsAndField == null ? 0 : lastTermsAndField.end;
+		int start = lastTermsAndField == null ? 0 : lastTermsAndField.end;
+		lastTermsAndField = new TermsAndField(start, index, previousField);
+		termsAndFields.Add(lastTermsAndField);
+		this.termsBytes = ArrayUtil.shrink(serializedTerms, lastEndOffset);
+		this.termsAndFields = termsAndFields.ToArray();
+		this.hashCode_Renamed = hash;
+
+	  }
+
+
+//JAVA TO C# CONVERTER WARNING: Method 'throws' clauses are not available in .NET:
+//ORIGINAL LINE: @Override public org.apache.lucene.search.DocIdSet getDocIdSet(AtomicReaderContext context, org.apache.lucene.util.Bits acceptDocs) throws java.io.IOException
+	  public override DocIdSet getDocIdSet(AtomicReaderContext context, Bits acceptDocs)
+	  {
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final AtomicReader reader = context.reader();
+		AtomicReader reader = context.reader();
+		FixedBitSet result = null; // lazy init if needed - no need to create a big bitset ahead of time
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final Fields fields = reader.fields();
+		Fields fields = reader.fields();
+//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
+//ORIGINAL LINE: final org.apache.lucene.util.BytesRef spare = new org.apache.lucene.util.BytesRef(this.termsBytes);
+		BytesRef spare = new BytesRef(this.termsBytes);
+		if (fields == null)
+		{
+		  return result;
+		}
+		Terms terms = null;
+		TermsEnum termsEnum = null;
+		DocsEnum docs = null;
+		foreach (TermsAndField termsAndField in this.termsAndFields)
+		{
+		  if ((terms = fields.terms(termsAndField.field)) != null)
+		  {
+			termsEnum = terms.iterator(termsEnum); // this won't return null
+			for (int i = termsAndField.start; i < termsAndField.end; i++)
+			{
+			  spare.offset = offsets[i];
+			  spare.length = offsets[i + 1] - offsets[i];
+			  if (termsEnum.seekExact(spare))
+			  {
+				docs = termsEnum.docs(acceptDocs, docs, DocsEnum.FLAG_NONE); // no freq since we don't need them
+				if (result == null)
+				{
+				  if (docs.nextDoc() != DocIdSetIterator.NO_MORE_DOCS)
+				  {
+					result = new FixedBitSet(reader.maxDoc());
+					// lazy init but don't do it in the hot loop since we could read many docs
+					result.set(docs.docID());
+				  }
+				}
+				while (docs.nextDoc() != DocIdSetIterator.NO_MORE_DOCS)
+				{
+				  result.set(docs.docID());
+				}
+			  }
+			}
+		  }
+		}
+		return result;
+	  }
+
+	  public override bool Equals(object obj)
+	  {
+		if (this == obj)
+		{
+		  return true;
+		}
+		if ((obj == null) || (obj.GetType() != this.GetType()))
+		{
+		  return false;
+		}
+
+		TermsFilter test = (TermsFilter) obj;
+		// first check the fields before even comparing the bytes
+		if (test.hashCode_Renamed == hashCode_Renamed && Arrays.Equals(termsAndFields, test.termsAndFields))
+		{
+		  int lastOffset = termsAndFields[termsAndFields.Length - 1].end;
+		  // compare offsets since we sort they must be identical
+		  if (ArrayUtil.Equals(offsets, 0, test.offsets, 0, lastOffset + 1))
+		  {
+			// straight byte comparison since we sort they must be identical
+			return ArrayUtil.Equals(termsBytes, 0, test.termsBytes, 0, offsets[lastOffset]);
+		  }
+		}
+		return false;
+	  }
+
+	  public override int GetHashCode()
+	  {
+		return hashCode_Renamed;
+	  }
+
+	  public override string ToString()
+	  {
+		StringBuilder builder = new StringBuilder();
+		BytesRef spare = new BytesRef(termsBytes);
+		bool first = true;
+		for (int i = 0; i < termsAndFields.Length; i++)
+		{
+		  TermsAndField current = termsAndFields[i];
+		  for (int j = current.start; j < current.end; j++)
+		  {
+			spare.offset = offsets[j];
+			spare.length = offsets[j + 1] - offsets[j];
+			if (!first)
+			{
+			  builder.Append(' ');
+			}
+			first = false;
+			builder.Append(current.field).Append(':');
+			builder.Append(spare.utf8ToString());
+		  }
+		}
+
+		return builder.ToString();
+	  }
+
+	  private sealed class TermsAndField
+	  {
+		internal readonly int start;
+		internal readonly int end;
+		internal readonly string field;
+
+
+		internal TermsAndField(int start, int end, string field) : base()
+		{
+		  this.start = start;
+		  this.end = end;
+		  this.field = field;
+		}
+
+		public override int GetHashCode()
+		{
+		  const int prime = 31;
+		  int result = 1;
+		  result = prime * result + ((field == null) ? 0 : field.GetHashCode());
+		  result = prime * result + end;
+		  result = prime * result + start;
+		  return result;
+		}
+
+		public override bool Equals(object obj)
+		{
+		  if (this == obj)
+		  {
+			  return true;
+		  }
+		  if (obj == null)
+		  {
+			  return false;
+		  }
+		  if (this.GetType() != obj.GetType())
+		  {
+			  return false;
+		  }
+		  TermsAndField other = (TermsAndField) obj;
+		  if (field == null)
+		  {
+			if (other.field != null)
+			{
+				return false;
+			}
+		  }
+		  else if (!field.Equals(other.field))
+		  {
+			  return false;
+		  }
+		  if (end != other.end)
+		  {
+			  return false;
+		  }
+		  if (start != other.start)
+		  {
+			  return false;
+		  }
+		  return true;
+		}
+
+	  }
+
+	  private abstract class FieldAndTermEnum
+	  {
+		protected internal string field_Renamed;
+
+		public abstract BytesRef next();
+
+		public FieldAndTermEnum()
+		{
+		}
+
+		public FieldAndTermEnum(string field)
+		{
+			this.field_Renamed = field;
+		}
+
+		public virtual string field()
+		{
+		  return field_Renamed;
+		}
+	  }
+
+	  /*
+	   * simple utility that returns the in-place sorted list
+	   */
+//JAVA TO C# CONVERTER TODO TASK: Java wildcard generics are not converted to .NET:
+//ORIGINAL LINE: private static <T extends Comparable<? base T>> java.util.List<T> sort(java.util.List<T> toSort)
+	  private static IList<T> sort<T>(IList<T> toSort) where T : Comparable<? base T>
+	  {
+		if (toSort.Count == 0)
+		{
+		  throw new System.ArgumentException("no terms provided");
+		}
+		toSort.Sort();
+		return toSort;
+	  }
+	}
+
+}
\ No newline at end of file