lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From nightowl...@apache.org
Subject [07/72] [abbrv] [partial] lucenenet git commit: Lucene.Net.Tests: Removed \core directory and put its contents in root directory
Date Sun, 26 Feb 2017 23:36:55 GMT
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs b/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs
new file mode 100644
index 0000000..0511e75
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestCustomSearcherSort.cs
@@ -0,0 +1,262 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Text;
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    using NUnit.Framework;
+
+    /// <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 DateTools = DateTools;
+    using Directory = Lucene.Net.Store.Directory;
+    using Document = Documents.Document;
+    using Field = Field;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using Term = Lucene.Net.Index.Term;
+
+    /// <summary>
+    /// Unit test for sorting code. </summary>
+    [TestFixture]
+    public class TestCustomSearcherSort : LuceneTestCase
+    {
+        private Directory Index = null;
+        private IndexReader Reader;
+        private Query Query = null;
+
+        // reduced from 20000 to 2000 to speed up test...
+        private int INDEX_SIZE;
+
+        /// <summary>
+        /// Create index and query for test cases.
+        /// </summary>
+        [SetUp]
+        public override void SetUp()
+        {
+            base.SetUp();
+            INDEX_SIZE = AtLeast(2000);
+            Index = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), Index, Similarity, TimeZone);
+            RandomGen random = new RandomGen(this, Random());
+            for (int i = 0; i < INDEX_SIZE; ++i) // don't decrease; if to low the
+            {
+                // problem doesn't show up
+                Document doc = new Document();
+                if ((i % 5) != 0) // some documents must not have an entry in the first
+                {
+                    // sort field
+                    doc.Add(NewStringField("publicationDate_", random.LuceneDate, Field.Store.YES));
+                }
+                if ((i % 7) == 0) // some documents to match the query (see below)
+                {
+                    doc.Add(NewTextField("content", "test", Field.Store.YES));
+                }
+                // every document has a defined 'mandant' field
+                doc.Add(NewStringField("mandant", Convert.ToString(i % 3), Field.Store.YES));
+                writer.AddDocument(doc);
+            }
+            Reader = writer.Reader;
+            writer.Dispose();
+            Query = new TermQuery(new Term("content", "test"));
+        }
+
+        [TearDown]
+        public override void TearDown()
+        {
+            Reader.Dispose();
+            Index.Dispose();
+            base.TearDown();
+        }
+
+        /// <summary>
+        /// Run the test using two CustomSearcher instances.
+        /// </summary>
+        [Test]
+        public virtual void TestFieldSortCustomSearcher()
+        {
+            // log("Run testFieldSortCustomSearcher");
+            // define the sort criteria
+            Sort custSort = new Sort(new SortField("publicationDate_", SortFieldType.STRING), SortField.FIELD_SCORE);
+            IndexSearcher searcher = new CustomSearcher(this, Reader, 2);
+            // search and check hits
+            MatchHits(searcher, custSort);
+        }
+
+        /// <summary>
+        /// Run the test using one CustomSearcher wrapped by a MultiSearcher.
+        /// </summary>
+        [Test]
+        public virtual void TestFieldSortSingleSearcher()
+        {
+            // log("Run testFieldSortSingleSearcher");
+            // define the sort criteria
+            Sort custSort = new Sort(new SortField("publicationDate_", SortFieldType.STRING), SortField.FIELD_SCORE);
+            IndexSearcher searcher = new CustomSearcher(this, Reader, 2);
+            // search and check hits
+            MatchHits(searcher, custSort);
+        }
+
+        // make sure the documents returned by the search match the expected list
+        private void MatchHits(IndexSearcher searcher, Sort sort)
+        {
+            // make a query without sorting first
+            ScoreDoc[] hitsByRank = searcher.Search(Query, null, int.MaxValue).ScoreDocs;
+            CheckHits(hitsByRank, "Sort by rank: "); // check for duplicates
+            IDictionary<int?, int?> resultMap = new SortedDictionary<int?, int?>();
+            // store hits in TreeMap - TreeMap does not allow duplicates; existing
+            // entries are silently overwritten
+            for (int hitid = 0; hitid < hitsByRank.Length; ++hitid)
+            {
+                resultMap[Convert.ToInt32(hitsByRank[hitid].Doc)] = Convert.ToInt32(hitid); // Value: Hits-Objekt Index -  Key: Lucene
+                // Document ID
+            }
+
+            // now make a query using the sort criteria
+            ScoreDoc[] resultSort = searcher.Search(Query, null, int.MaxValue, sort).ScoreDocs;
+            CheckHits(resultSort, "Sort by custom criteria: "); // check for duplicates
+
+            // besides the sorting both sets of hits must be identical
+            for (int hitid = 0; hitid < resultSort.Length; ++hitid)
+            {
+                int? idHitDate = Convert.ToInt32(resultSort[hitid].Doc); // document ID
+                // from sorted
+                // search
+                if (!resultMap.ContainsKey(idHitDate))
+                {
+                    Log("ID " + idHitDate + " not found. Possibliy a duplicate.");
+                }
+                Assert.IsTrue(resultMap.ContainsKey(idHitDate)); // same ID must be in the
+                // Map from the rank-sorted
+                // search
+                // every hit must appear once in both result sets --> remove it from the
+                // Map.
+                // At the end the Map must be empty!
+                resultMap.Remove(idHitDate);
+            }
+            if (resultMap.Count == 0)
+            {
+                // log("All hits matched");
+            }
+            else
+            {
+                Log("Couldn't match " + resultMap.Count + " hits.");
+            }
+            Assert.AreEqual(resultMap.Count, 0);
+        }
+
+        /// <summary>
+        /// Check the hits for duplicates.
+        /// </summary>
+        private void CheckHits(ScoreDoc[] hits, string prefix)
+        {
+            if (hits != null)
+            {
+                IDictionary<int?, int?> idMap = new SortedDictionary<int?, int?>();
+                for (int docnum = 0; docnum < hits.Length; ++docnum)
+                {
+                    int? luceneId = null;
+
+                    luceneId = Convert.ToInt32(hits[docnum].Doc);
+                    if (idMap.ContainsKey(luceneId))
+                    {
+                        StringBuilder message = new StringBuilder(prefix);
+                        message.Append("Duplicate key for hit index = ");
+                        message.Append(docnum);
+                        message.Append(", previous index = ");
+                        message.Append((idMap[luceneId]).ToString());
+                        message.Append(", Lucene ID = ");
+                        message.Append(luceneId);
+                        Log(message.ToString());
+                    }
+                    else
+                    {
+                        idMap[luceneId] = Convert.ToInt32(docnum);
+                    }
+                }
+            }
+        }
+
+        // Simply write to console - choosen to be independant of log4j etc
+        private void Log(string message)
+        {
+            if (VERBOSE)
+            {
+                Console.WriteLine(message);
+            }
+        }
+
+        public class CustomSearcher : IndexSearcher
+        {
+            private readonly TestCustomSearcherSort OuterInstance;
+
+            internal int Switcher;
+
+            public CustomSearcher(TestCustomSearcherSort outerInstance, IndexReader r, int switcher)
+                : base(r)
+            {
+                this.OuterInstance = outerInstance;
+                this.Switcher = switcher;
+            }
+
+            public override TopFieldDocs Search(Query query, Filter filter, int nDocs, Sort sort)
+            {
+                BooleanQuery bq = new BooleanQuery();
+                bq.Add(query, Occur.MUST);
+                bq.Add(new TermQuery(new Term("mandant", Convert.ToString(Switcher))), Occur.MUST);
+                return base.Search(bq, filter, nDocs, sort);
+            }
+
+            public override TopDocs Search(Query query, Filter filter, int nDocs)
+            {
+                BooleanQuery bq = new BooleanQuery();
+                bq.Add(query, Occur.MUST);
+                bq.Add(new TermQuery(new Term("mandant", Convert.ToString(Switcher))), Occur.MUST);
+                return base.Search(bq, filter, nDocs);
+            }
+        }
+
+        private class RandomGen
+        {
+            private readonly TestCustomSearcherSort OuterInstance;
+
+            internal RandomGen(TestCustomSearcherSort outerInstance, Random random)
+            {
+                this.OuterInstance = outerInstance;
+                this.Random = random;
+                @base = new DateTime(1980, 1, 1);
+            }
+
+            internal Random Random;
+
+            // we use the default Locale/TZ since LuceneTestCase randomizes it
+            internal DateTime @base;
+
+            // Just to generate some different Lucene Date strings
+            internal virtual string LuceneDate
+            {
+                get
+                {
+                    return DateTools.TimeToString((DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond) + Random.Next() - int.MinValue, DateTools.Resolution.DAY);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDateFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDateFilter.cs b/src/Lucene.Net.Tests/Search/TestDateFilter.cs
new file mode 100644
index 0000000..11e62e1
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDateFilter.cs
@@ -0,0 +1,165 @@
+using System;
+using Lucene.Net.Attributes;
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    using NUnit.Framework;
+    using DateTools = DateTools;
+    using Directory = Lucene.Net.Store.Directory;
+    using Document = Documents.Document;
+
+    /*
+         * 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 Field = Field;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using Term = Lucene.Net.Index.Term;
+
+    /// <summary>
+    /// DateFilter JUnit tests.
+    ///
+    ///
+    /// </summary>
+    [TestFixture]
+    public class TestDateFilter : LuceneTestCase
+    {
+        ///
+        [OneTimeSetUp]
+        public virtual void TestBefore()
+        {
+            // create an index
+            Directory indexStore = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), indexStore, Similarity, TimeZone);
+
+            long now = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
+
+            Document doc = new Document();
+            // add time that is in the past
+            doc.Add(NewStringField("datefield", DateTools.TimeToString(now - 1000, DateTools.Resolution.MILLISECOND), Field.Store.YES));
+            doc.Add(NewTextField("body", "Today is a very sunny day in New York City", Field.Store.YES));
+            writer.AddDocument(doc);
+
+            IndexReader reader = writer.Reader;
+            writer.Dispose();
+            IndexSearcher searcher = NewSearcher(reader);
+
+            // filter that should preserve matches
+            // DateFilter df1 = DateFilter.Before("datefield", now);
+            TermRangeFilter df1 = TermRangeFilter.NewStringRange("datefield", DateTools.TimeToString(now - 2000, DateTools.Resolution.MILLISECOND), DateTools.TimeToString(now, DateTools.Resolution.MILLISECOND), false, true);
+            // filter that should discard matches
+            // DateFilter df2 = DateFilter.Before("datefield", now - 999999);
+            TermRangeFilter df2 = TermRangeFilter.NewStringRange("datefield", DateTools.TimeToString(0, DateTools.Resolution.MILLISECOND), DateTools.TimeToString(now - 2000, DateTools.Resolution.MILLISECOND), true, false);
+
+            // search something that doesn't exist with DateFilter
+            Query query1 = new TermQuery(new Term("body", "NoMatchForthis"));
+
+            // search for something that does exists
+            Query query2 = new TermQuery(new Term("body", "sunny"));
+
+            ScoreDoc[] result;
+
+            // ensure that queries return expected results without DateFilter first
+            result = searcher.Search(query1, null, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+
+            result = searcher.Search(query2, null, 1000).ScoreDocs;
+            Assert.AreEqual(1, result.Length);
+
+            // run queries with DateFilter
+            result = searcher.Search(query1, df1, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+
+            result = searcher.Search(query1, df2, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+
+            result = searcher.Search(query2, df1, 1000).ScoreDocs;
+            Assert.AreEqual(1, result.Length);
+
+            result = searcher.Search(query2, df2, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+            reader.Dispose();
+            indexStore.Dispose();
+        }
+
+        [Test, LuceneNetSpecific]
+        public void Test()
+        {
+            // noop, required for the before and after tests to run
+        }
+
+        ///
+        [OneTimeTearDown]
+        public virtual void TestAfter()
+        {
+            // create an index
+            Directory indexStore = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), indexStore, Similarity, TimeZone);
+
+            long now = DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond;
+
+            Document doc = new Document();
+            // add time that is in the future
+            doc.Add(NewStringField("datefield", DateTools.TimeToString(now + 888888, DateTools.Resolution.MILLISECOND), Field.Store.YES));
+            doc.Add(NewTextField("body", "Today is a very sunny day in New York City", Field.Store.YES));
+            writer.AddDocument(doc);
+
+            IndexReader reader = writer.Reader;
+            writer.Dispose();
+            IndexSearcher searcher = NewSearcher(reader);
+
+            // filter that should preserve matches
+            // DateFilter df1 = DateFilter.After("datefield", now);
+            TermRangeFilter df1 = TermRangeFilter.NewStringRange("datefield", DateTools.TimeToString(now, DateTools.Resolution.MILLISECOND), DateTools.TimeToString(now + 999999, DateTools.Resolution.MILLISECOND), true, false);
+            // filter that should discard matches
+            // DateFilter df2 = DateFilter.After("datefield", now + 999999);
+            TermRangeFilter df2 = TermRangeFilter.NewStringRange("datefield", DateTools.TimeToString(now + 999999, DateTools.Resolution.MILLISECOND), DateTools.TimeToString(now + 999999999, DateTools.Resolution.MILLISECOND), false, true);
+
+            // search something that doesn't exist with DateFilter
+            Query query1 = new TermQuery(new Term("body", "NoMatchForthis"));
+
+            // search for something that does exists
+            Query query2 = new TermQuery(new Term("body", "sunny"));
+
+            ScoreDoc[] result;
+
+            // ensure that queries return expected results without DateFilter first
+            result = searcher.Search(query1, null, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+
+            result = searcher.Search(query2, null, 1000).ScoreDocs;
+            Assert.AreEqual(1, result.Length);
+
+            // run queries with DateFilter
+            result = searcher.Search(query1, df1, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+
+            result = searcher.Search(query1, df2, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+
+            result = searcher.Search(query2, df1, 1000).ScoreDocs;
+            Assert.AreEqual(1, result.Length);
+
+            result = searcher.Search(query2, df2, 1000).ScoreDocs;
+            Assert.AreEqual(0, result.Length);
+            reader.Dispose();
+            indexStore.Dispose();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDateSort.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDateSort.cs b/src/Lucene.Net.Tests/Search/TestDateSort.cs
new file mode 100644
index 0000000..3c45c9b
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDateSort.cs
@@ -0,0 +1,125 @@
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    using Lucene.Net.Support;
+    using NUnit.Framework;
+    using DateTools = DateTools;
+    using Directory = Lucene.Net.Store.Directory;
+    using Document = Documents.Document;
+    using Field = Field;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+
+    /*
+         * 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 Term = Lucene.Net.Index.Term;
+
+    /// <summary>
+    /// Test date sorting, i.e. auto-sorting of fields with type "long".
+    /// See http://issues.apache.org/jira/browse/LUCENE-1045
+    /// </summary>
+    [TestFixture]
+    public class TestDateSort : LuceneTestCase
+    {
+        private const string TEXT_FIELD = "text";
+        private const string DATE_TIME_FIELD = "dateTime";
+
+        private Directory Directory;
+        private IndexReader Reader;
+
+        [SetUp]
+        public override void SetUp()
+        {
+            base.SetUp();
+            // Create an index writer.
+            Directory = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), Directory, Similarity, TimeZone);
+
+            // oldest doc:
+            // Add the first document.  text = "Document 1"  dateTime = Oct 10 03:25:22 EDT 2007
+            writer.AddDocument(CreateDocument("Document 1", 1192001122000L));
+            // Add the second document.  text = "Document 2"  dateTime = Oct 10 03:25:26 EDT 2007
+            writer.AddDocument(CreateDocument("Document 2", 1192001126000L));
+            // Add the third document.  text = "Document 3"  dateTime = Oct 11 07:12:13 EDT 2007
+            writer.AddDocument(CreateDocument("Document 3", 1192101133000L));
+            // Add the fourth document.  text = "Document 4"  dateTime = Oct 11 08:02:09 EDT 2007
+            writer.AddDocument(CreateDocument("Document 4", 1192104129000L));
+            // latest doc:
+            // Add the fifth document.  text = "Document 5"  dateTime = Oct 12 13:25:43 EDT 2007
+            writer.AddDocument(CreateDocument("Document 5", 1192209943000L));
+
+            Reader = writer.Reader;
+            writer.Dispose();
+        }
+
+        [TearDown]
+        public override void TearDown()
+        {
+            Reader.Dispose();
+            Directory.Dispose();
+            base.TearDown();
+        }
+
+        [Test]
+        public virtual void TestReverseDateSort()
+        {
+            IndexSearcher searcher = NewSearcher(Reader);
+
+            Sort sort = new Sort(new SortField(DATE_TIME_FIELD, SortFieldType.STRING, true));
+            Query query = new TermQuery(new Term(TEXT_FIELD, "document"));
+
+            // Execute the search and process the search results.
+            string[] actualOrder = new string[5];
+            ScoreDoc[] hits = searcher.Search(query, null, 1000, sort).ScoreDocs;
+            for (int i = 0; i < hits.Length; i++)
+            {
+                Document document = searcher.Doc(hits[i].Doc);
+                string text = document.Get(TEXT_FIELD);
+                actualOrder[i] = text;
+            }
+
+            // Set up the expected order (i.e. Document 5, 4, 3, 2, 1).
+            string[] expectedOrder = new string[5];
+            expectedOrder[0] = "Document 5";
+            expectedOrder[1] = "Document 4";
+            expectedOrder[2] = "Document 3";
+            expectedOrder[3] = "Document 2";
+            expectedOrder[4] = "Document 1";
+
+            Assert.AreEqual(Arrays.AsList(expectedOrder), Arrays.AsList(actualOrder));
+        }
+
+        private Document CreateDocument(string text, long time)
+        {
+            Document document = new Document();
+
+            // Add the text field.
+            Field textField = NewTextField(TEXT_FIELD, text, Field.Store.YES);
+            document.Add(textField);
+
+            // Add the date/time field.
+            string dateTimeString = DateTools.TimeToString(time, DateTools.Resolution.SECOND);
+            Field dateTimeField = NewStringField(DATE_TIME_FIELD, dateTimeString, Field.Store.YES);
+            document.Add(dateTimeField);
+
+            return document;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDisjunctionMaxQuery.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDisjunctionMaxQuery.cs b/src/Lucene.Net.Tests/Search/TestDisjunctionMaxQuery.cs
new file mode 100644
index 0000000..18db902
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDisjunctionMaxQuery.cs
@@ -0,0 +1,570 @@
+using System;
+using System.Globalization;
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    using Lucene.Net.Index;
+    using NUnit.Framework;
+    using Analyzer = Lucene.Net.Analysis.Analyzer;
+    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
+    using DefaultSimilarity = Lucene.Net.Search.Similarities.DefaultSimilarity;
+    using Directory = Lucene.Net.Store.Directory;
+    using DirectoryReader = Lucene.Net.Index.DirectoryReader;
+    using Document = Documents.Document;
+
+    /*
+         * 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 Field = Field;
+    using FieldInvertState = Lucene.Net.Index.FieldInvertState;
+    using FieldType = FieldType;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using IndexWriter = Lucene.Net.Index.IndexWriter;
+    using IndexWriterConfig = Lucene.Net.Index.IndexWriterConfig;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using Similarity = Lucene.Net.Search.Similarities.Similarity;
+    using SlowCompositeReaderWrapper = Lucene.Net.Index.SlowCompositeReaderWrapper;
+    using SpanQuery = Lucene.Net.Search.Spans.SpanQuery;
+    using SpanTermQuery = Lucene.Net.Search.Spans.SpanTermQuery;
+    using Term = Lucene.Net.Index.Term;
+    using TextField = TextField;
+
+    /// <summary>
+    /// Test of the DisjunctionMaxQuery.
+    ///
+    /// </summary>
+    [TestFixture]
+    public class TestDisjunctionMaxQuery : LuceneTestCase
+    {
+        /// <summary>
+        /// threshold for comparing floats </summary>
+        public static readonly float SCORE_COMP_THRESH = 0.0000f;
+
+        /// <summary>
+        /// Similarity to eliminate tf, idf and lengthNorm effects to isolate test
+        /// case.
+        ///
+        /// <p>
+        /// same as TestRankingSimilarity in TestRanking.zip from
+        /// http://issues.apache.org/jira/browse/LUCENE-323
+        /// </p>
+        /// </summary>
+        private class TestSimilarity : DefaultSimilarity
+        {
+            public TestSimilarity()
+            {
+            }
+
+            public override float Tf(float freq)
+            {
+                if (freq > 0.0f)
+                {
+                    return 1.0f;
+                }
+                else
+                {
+                    return 0.0f;
+                }
+            }
+
+            public override float LengthNorm(FieldInvertState state)
+            {
+                // Disable length norm
+                return state.Boost;
+            }
+
+            public override float Idf(long docFreq, long numDocs)
+            {
+                return 1.0f;
+            }
+        }
+
+        public Similarity Sim = new TestSimilarity();
+        public Directory Index;
+        public IndexReader r;
+        public IndexSearcher s;
+
+        private static readonly FieldType NonAnalyzedType = new FieldType(TextField.TYPE_STORED);
+
+        static TestDisjunctionMaxQuery()
+        {
+            NonAnalyzedType.IsTokenized = false;
+        }
+
+        [SetUp]
+        public override void SetUp()
+        {
+            base.SetUp();
+
+            Index = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), Index, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetSimilarity(Sim).SetMergePolicy(NewLogMergePolicy()));
+
+            // hed is the most important field, dek is secondary
+
+            // d1 is an "ok" match for: albino elephant
+            {
+                Document d1 = new Document();
+                d1.Add(NewField("id", "d1", NonAnalyzedType)); // Field.Keyword("id",
+                // "d1"));
+                d1.Add(NewTextField("hed", "elephant", Field.Store.YES)); // Field.Text("hed", "elephant"));
+                d1.Add(NewTextField("dek", "elephant", Field.Store.YES)); // Field.Text("dek", "elephant"));
+                writer.AddDocument(d1);
+            }
+
+            // d2 is a "good" match for: albino elephant
+            {
+                Document d2 = new Document();
+                d2.Add(NewField("id", "d2", NonAnalyzedType)); // Field.Keyword("id",
+                // "d2"));
+                d2.Add(NewTextField("hed", "elephant", Field.Store.YES)); // Field.Text("hed", "elephant"));
+                d2.Add(NewTextField("dek", "albino", Field.Store.YES)); // Field.Text("dek",
+                // "albino"));
+                d2.Add(NewTextField("dek", "elephant", Field.Store.YES)); // Field.Text("dek", "elephant"));
+                writer.AddDocument(d2);
+            }
+
+            // d3 is a "better" match for: albino elephant
+            {
+                Document d3 = new Document();
+                d3.Add(NewField("id", "d3", NonAnalyzedType)); // Field.Keyword("id",
+                // "d3"));
+                d3.Add(NewTextField("hed", "albino", Field.Store.YES)); // Field.Text("hed",
+                // "albino"));
+                d3.Add(NewTextField("hed", "elephant", Field.Store.YES)); // Field.Text("hed", "elephant"));
+                writer.AddDocument(d3);
+            }
+
+            // d4 is the "best" match for: albino elephant
+            {
+                Document d4 = new Document();
+                d4.Add(NewField("id", "d4", NonAnalyzedType)); // Field.Keyword("id",
+                // "d4"));
+                d4.Add(NewTextField("hed", "albino", Field.Store.YES)); // Field.Text("hed",
+                // "albino"));
+                d4.Add(NewField("hed", "elephant", NonAnalyzedType)); // Field.Text("hed", "elephant"));
+                d4.Add(NewTextField("dek", "albino", Field.Store.YES)); // Field.Text("dek",
+                // "albino"));
+                writer.AddDocument(d4);
+            }
+
+            r = SlowCompositeReaderWrapper.Wrap(writer.Reader);
+            writer.Dispose();
+            s = NewSearcher(r);
+            s.Similarity = Sim;
+        }
+
+        [TearDown]
+        public override void TearDown()
+        {
+            r.Dispose();
+            Index.Dispose();
+            base.TearDown();
+        }
+
+        [Test]
+        public virtual void TestSkipToFirsttimeMiss()
+        {
+            DisjunctionMaxQuery dq = new DisjunctionMaxQuery(0.0f);
+            dq.Add(Tq("id", "d1"));
+            dq.Add(Tq("dek", "DOES_NOT_EXIST"));
+
+            QueryUtils.Check(Random(), dq, s, Similarity);
+            Assert.IsTrue(s.TopReaderContext is AtomicReaderContext);
+            Weight dw = s.CreateNormalizedWeight(dq);
+            AtomicReaderContext context = (AtomicReaderContext)s.TopReaderContext;
+            Scorer ds = dw.GetScorer(context, (context.AtomicReader).LiveDocs);
+            bool skipOk = ds.Advance(3) != DocIdSetIterator.NO_MORE_DOCS;
+            if (skipOk)
+            {
+                Assert.Fail("firsttime skipTo found a match? ... " + r.Document(ds.DocID).Get("id"));
+            }
+        }
+
+        [Test]
+        public virtual void TestSkipToFirsttimeHit()
+        {
+            DisjunctionMaxQuery dq = new DisjunctionMaxQuery(0.0f);
+            dq.Add(Tq("dek", "albino"));
+            dq.Add(Tq("dek", "DOES_NOT_EXIST"));
+            Assert.IsTrue(s.TopReaderContext is AtomicReaderContext);
+            QueryUtils.Check(Random(), dq, s, Similarity);
+            Weight dw = s.CreateNormalizedWeight(dq);
+            AtomicReaderContext context = (AtomicReaderContext)s.TopReaderContext;
+            Scorer ds = dw.GetScorer(context, (context.AtomicReader).LiveDocs);
+            Assert.IsTrue(ds.Advance(3) != DocIdSetIterator.NO_MORE_DOCS, "firsttime skipTo found no match");
+            Assert.AreEqual("d4", r.Document(ds.DocID).Get("id"), "found wrong docid");
+        }
+
+        [Test]
+        public virtual void TestSimpleEqualScores1()
+        {
+            DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.0f);
+            q.Add(Tq("hed", "albino"));
+            q.Add(Tq("hed", "elephant"));
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(4, h.Length, "all docs should match " + q.ToString());
+
+                float score = h[0].Score;
+                for (int i = 1; i < h.Length; i++)
+                {
+                    Assert.AreEqual(score, h[i].Score, SCORE_COMP_THRESH, "score #" + i + " is not the same");
+                }
+            }
+            catch (Exception e)
+            {
+                PrintHits("testSimpleEqualScores1", h, s);
+                throw e;
+            }
+        }
+
+        [Test]
+        public virtual void TestSimpleEqualScores2()
+        {
+            DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.0f);
+            q.Add(Tq("dek", "albino"));
+            q.Add(Tq("dek", "elephant"));
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(3, h.Length, "3 docs should match " + q.ToString());
+                float score = h[0].Score;
+                for (int i = 1; i < h.Length; i++)
+                {
+                    Assert.AreEqual(score, h[i].Score, SCORE_COMP_THRESH, "score #" + i + " is not the same");
+                }
+            }
+            catch (Exception e)
+            {
+                PrintHits("testSimpleEqualScores2", h, s);
+                throw e;
+            }
+        }
+
+        [Test]
+        public virtual void TestSimpleEqualScores3()
+        {
+            DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.0f);
+            q.Add(Tq("hed", "albino"));
+            q.Add(Tq("hed", "elephant"));
+            q.Add(Tq("dek", "albino"));
+            q.Add(Tq("dek", "elephant"));
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(4, h.Length, "all docs should match " + q.ToString());
+                float score = h[0].Score;
+                for (int i = 1; i < h.Length; i++)
+                {
+                    Assert.AreEqual(score, h[i].Score, SCORE_COMP_THRESH, "score #" + i + " is not the same");
+                }
+            }
+            catch (Exception e)
+            {
+                PrintHits("testSimpleEqualScores3", h, s);
+                throw e;
+            }
+        }
+
+        [Test]
+        public virtual void TestSimpleTiebreaker()
+        {
+            DisjunctionMaxQuery q = new DisjunctionMaxQuery(0.01f);
+            q.Add(Tq("dek", "albino"));
+            q.Add(Tq("dek", "elephant"));
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(3, h.Length, "3 docs should match " + q.ToString());
+                Assert.AreEqual("d2", s.Doc(h[0].Doc).Get("id"), "wrong first");
+                float score0 = h[0].Score;
+                float score1 = h[1].Score;
+                float score2 = h[2].Score;
+                Assert.IsTrue(score0 > score1, "d2 does not have better score then others: " + score0 + " >? " + score1);
+                Assert.AreEqual(score1, score2, SCORE_COMP_THRESH, "d4 and d1 don't have equal scores");
+            }
+            catch (Exception e)
+            {
+                PrintHits("testSimpleTiebreaker", h, s);
+                throw e;
+            }
+        }
+
+        [Test]
+        public virtual void TestBooleanRequiredEqualScores()
+        {
+            BooleanQuery q = new BooleanQuery();
+            {
+                DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.0f);
+                q1.Add(Tq("hed", "albino"));
+                q1.Add(Tq("dek", "albino"));
+                q.Add(q1, Occur.MUST); // true,false);
+                QueryUtils.Check(Random(), q1, s, Similarity);
+            }
+            {
+                DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.0f);
+                q2.Add(Tq("hed", "elephant"));
+                q2.Add(Tq("dek", "elephant"));
+                q.Add(q2, Occur.MUST); // true,false);
+                QueryUtils.Check(Random(), q2, s, Similarity);
+            }
+
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(3, h.Length, "3 docs should match " + q.ToString());
+                float score = h[0].Score;
+                for (int i = 1; i < h.Length; i++)
+                {
+                    Assert.AreEqual(score, h[i].Score, SCORE_COMP_THRESH, "score #" + i + " is not the same");
+                }
+            }
+            catch (Exception e)
+            {
+                PrintHits("testBooleanRequiredEqualScores1", h, s);
+                throw e;
+            }
+        }
+
+        [Test]
+        public virtual void TestBooleanOptionalNoTiebreaker()
+        {
+            BooleanQuery q = new BooleanQuery();
+            {
+                DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.0f);
+                q1.Add(Tq("hed", "albino"));
+                q1.Add(Tq("dek", "albino"));
+                q.Add(q1, Occur.SHOULD); // false,false);
+            }
+            {
+                DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.0f);
+                q2.Add(Tq("hed", "elephant"));
+                q2.Add(Tq("dek", "elephant"));
+                q.Add(q2, Occur.SHOULD); // false,false);
+            }
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(4, h.Length, "4 docs should match " + q.ToString());
+                float score = h[0].Score;
+                for (int i = 1; i < h.Length - 1; i++) // note: -1
+                {
+                    Assert.AreEqual(score, h[i].Score, SCORE_COMP_THRESH, "score #" + i + " is not the same");
+                }
+                Assert.AreEqual("d1", s.Doc(h[h.Length - 1].Doc).Get("id"), "wrong last");
+                float score1 = h[h.Length - 1].Score;
+                Assert.IsTrue(score > score1, "d1 does not have worse score then others: " + score + " >? " + score1);
+            }
+            catch (Exception e)
+            {
+                PrintHits("testBooleanOptionalNoTiebreaker", h, s);
+                throw e;
+            }
+        }
+
+        [Test]
+        public virtual void TestBooleanOptionalWithTiebreaker()
+        {
+            BooleanQuery q = new BooleanQuery();
+            {
+                DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.01f);
+                q1.Add(Tq("hed", "albino"));
+                q1.Add(Tq("dek", "albino"));
+                q.Add(q1, Occur.SHOULD); // false,false);
+            }
+            {
+                DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.01f);
+                q2.Add(Tq("hed", "elephant"));
+                q2.Add(Tq("dek", "elephant"));
+                q.Add(q2, Occur.SHOULD); // false,false);
+            }
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(4, h.Length, "4 docs should match " + q.ToString());
+
+                float score0 = h[0].Score;
+                float score1 = h[1].Score;
+                float score2 = h[2].Score;
+                float score3 = h[3].Score;
+
+                string doc0 = s.Doc(h[0].Doc).Get("id");
+                string doc1 = s.Doc(h[1].Doc).Get("id");
+                string doc2 = s.Doc(h[2].Doc).Get("id");
+                string doc3 = s.Doc(h[3].Doc).Get("id");
+
+                Assert.IsTrue(doc0.Equals("d2") || doc0.Equals("d4"), "doc0 should be d2 or d4: " + doc0);
+                Assert.IsTrue(doc1.Equals("d2") || doc1.Equals("d4"), "doc1 should be d2 or d4: " + doc0);
+                Assert.AreEqual(score0, score1, SCORE_COMP_THRESH, "score0 and score1 should match");
+                Assert.AreEqual("d3", doc2, "wrong third");
+                Assert.IsTrue(score1 > score2, "d3 does not have worse score then d2 and d4: " + score1 + " >? " + score2);
+
+                Assert.AreEqual("d1", doc3, "wrong fourth");
+                Assert.IsTrue(score2 > score3, "d1 does not have worse score then d3: " + score2 + " >? " + score3);
+            }
+            catch (Exception e)
+            {
+                PrintHits("testBooleanOptionalWithTiebreaker", h, s);
+                throw e;
+            }
+        }
+
+        [Test]
+        public virtual void TestBooleanOptionalWithTiebreakerAndBoost()
+        {
+            BooleanQuery q = new BooleanQuery();
+            {
+                DisjunctionMaxQuery q1 = new DisjunctionMaxQuery(0.01f);
+                q1.Add(Tq("hed", "albino", 1.5f));
+                q1.Add(Tq("dek", "albino"));
+                q.Add(q1, Occur.SHOULD); // false,false);
+            }
+            {
+                DisjunctionMaxQuery q2 = new DisjunctionMaxQuery(0.01f);
+                q2.Add(Tq("hed", "elephant", 1.5f));
+                q2.Add(Tq("dek", "elephant"));
+                q.Add(q2, Occur.SHOULD); // false,false);
+            }
+            QueryUtils.Check(Random(), q, s, Similarity);
+
+            ScoreDoc[] h = s.Search(q, null, 1000).ScoreDocs;
+
+            try
+            {
+                Assert.AreEqual(4, h.Length, "4 docs should match " + q.ToString());
+
+                float score0 = h[0].Score;
+                float score1 = h[1].Score;
+                float score2 = h[2].Score;
+                float score3 = h[3].Score;
+
+                string doc0 = s.Doc(h[0].Doc).Get("id");
+                string doc1 = s.Doc(h[1].Doc).Get("id");
+                string doc2 = s.Doc(h[2].Doc).Get("id");
+                string doc3 = s.Doc(h[3].Doc).Get("id");
+
+                Assert.AreEqual("d4", doc0, "doc0 should be d4: ");
+                Assert.AreEqual("d3", doc1, "doc1 should be d3: ");
+                Assert.AreEqual("d2", doc2, "doc2 should be d2: ");
+                Assert.AreEqual("d1", doc3, "doc3 should be d1: ");
+
+                Assert.IsTrue(score0 > score1, "d4 does not have a better score then d3: " + score0 + " >? " + score1);
+                Assert.IsTrue(score1 > score2, "d3 does not have a better score then d2: " + score1 + " >? " + score2);
+                Assert.IsTrue(score2 > score3, "d3 does not have a better score then d1: " + score2 + " >? " + score3);
+            }
+            catch (Exception e)
+            {
+                PrintHits("TestBooleanOptionalWithTiebreakerAndBoost", h, s);
+                throw e;
+            }
+        }
+
+        // LUCENE-4477 / LUCENE-4401:
+        [Test]
+        public virtual void TestBooleanSpanQuery()
+        {
+            int hits = 0;
+            Directory directory = NewDirectory();
+            Analyzer indexerAnalyzer = new MockAnalyzer(Random());
+
+            IndexWriterConfig config = new IndexWriterConfig(TEST_VERSION_CURRENT, indexerAnalyzer);
+            IndexWriter writer = new IndexWriter(directory, config);
+            string FIELD = "content";
+            Document d = new Document();
+            d.Add(new TextField(FIELD, "clockwork orange", Field.Store.YES));
+            writer.AddDocument(d);
+            writer.Dispose();
+
+            IndexReader indexReader = DirectoryReader.Open(directory);
+            IndexSearcher searcher = NewSearcher(indexReader);
+
+            DisjunctionMaxQuery query = new DisjunctionMaxQuery(1.0f);
+            SpanQuery sq1 = new SpanTermQuery(new Term(FIELD, "clockwork"));
+            SpanQuery sq2 = new SpanTermQuery(new Term(FIELD, "clckwork"));
+            query.Add(sq1);
+            query.Add(sq2);
+            TopScoreDocCollector collector = TopScoreDocCollector.Create(1000, true);
+            searcher.Search(query, collector);
+            hits = collector.GetTopDocs().ScoreDocs.Length;
+            foreach (ScoreDoc scoreDoc in collector.GetTopDocs().ScoreDocs)
+            {
+                Console.WriteLine(scoreDoc.Doc);
+            }
+            indexReader.Dispose();
+            Assert.AreEqual(hits, 1);
+            directory.Dispose();
+        }
+
+        /// <summary>
+        /// macro </summary>
+        protected internal virtual Query Tq(string f, string t)
+        {
+            return new TermQuery(new Term(f, t));
+        }
+
+        /// <summary>
+        /// macro </summary>
+        protected internal virtual Query Tq(string f, string t, float b)
+        {
+            Query q = Tq(f, t);
+            q.Boost = b;
+            return q;
+        }
+
+        protected internal virtual void PrintHits(string test, ScoreDoc[] h, IndexSearcher searcher)
+        {
+            Console.Error.WriteLine("------- " + test + " -------");
+
+            //DecimalFormat f = new DecimalFormat("0.000000000", DecimalFormatSymbols.getInstance(Locale.ROOT));
+
+            NumberFormatInfo f = new NumberFormatInfo();
+            f.NumberDecimalSeparator = ".";
+
+            for (int i = 0; i < h.Length; i++)
+            {
+                Document d = searcher.Doc(h[i].Doc);
+                decimal score = (decimal)h[i].Score;
+                Console.Error.WriteLine("#" + i + ": " + score.ToString(f) + " - " + d.Get("id"));
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDocBoost.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDocBoost.cs b/src/Lucene.Net.Tests/Search/TestDocBoost.cs
new file mode 100644
index 0000000..29fe7d6
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDocBoost.cs
@@ -0,0 +1,122 @@
+using System;
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    
+    using NUnit.Framework;
+    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
+    using Directory = Lucene.Net.Store.Directory;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+
+    /*
+         * 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 MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using Term = Lucene.Net.Index.Term;
+
+    /// <summary>
+    /// Document boost unit test.
+    ///
+    ///
+    /// </summary>
+    [TestFixture]
+    public class TestDocBoost : LuceneTestCase
+    {
+        [Test]
+        public virtual void TestDocBoost_Mem()
+        {
+            Directory store = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), store, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetMergePolicy(NewLogMergePolicy()));
+
+            Field f1 = NewTextField("field", "word", Field.Store.YES);
+            Field f2 = NewTextField("field", "word", Field.Store.YES);
+            f2.Boost = 2.0f;
+
+            Documents.Document d1 = new Documents.Document();
+            Documents.Document d2 = new Documents.Document();
+
+            d1.Add(f1); // boost = 1
+            d2.Add(f2); // boost = 2
+
+            writer.AddDocument(d1);
+            writer.AddDocument(d2);
+
+            IndexReader reader = writer.Reader;
+            writer.Dispose();
+
+            float[] scores = new float[4];
+
+            IndexSearcher searcher = NewSearcher(reader);
+            searcher.Search(new TermQuery(new Term("field", "word")), new CollectorAnonymousInnerClassHelper(this, scores));
+
+            float lastScore = 0.0f;
+
+            for (int i = 0; i < 2; i++)
+            {
+                if (VERBOSE)
+                {
+                    Console.WriteLine(searcher.Explain(new TermQuery(new Term("field", "word")), i));
+                }
+                Assert.IsTrue(scores[i] > lastScore, "score: " + scores[i] + " should be > lastScore: " + lastScore);
+                lastScore = scores[i];
+            }
+
+            reader.Dispose();
+            store.Dispose();
+        }
+
+        private class CollectorAnonymousInnerClassHelper : ICollector
+        {
+            private readonly TestDocBoost OuterInstance;
+
+            private float[] Scores;
+
+            public CollectorAnonymousInnerClassHelper(TestDocBoost outerInstance, float[] scores)
+            {
+                this.OuterInstance = outerInstance;
+                this.Scores = scores;
+                @base = 0;
+            }
+
+            private int @base;
+            private Scorer scorer;
+
+            public virtual void SetScorer(Scorer scorer)
+            {
+                this.scorer = scorer;
+            }
+
+            public virtual void Collect(int doc)
+            {
+                Scores[doc + @base] = scorer.GetScore();
+            }
+
+            public virtual void SetNextReader(AtomicReaderContext context)
+            {
+                @base = context.DocBase;
+            }
+
+            public virtual bool AcceptsDocsOutOfOrder
+            {
+                get { return true; }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDocIdSet.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDocIdSet.cs b/src/Lucene.Net.Tests/Search/TestDocIdSet.cs
new file mode 100644
index 0000000..440fe7d
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDocIdSet.cs
@@ -0,0 +1,254 @@
+using System;
+using System.Collections.Generic;
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    using Lucene.Net.Support;
+    using NUnit.Framework;
+    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
+    using IBits = Lucene.Net.Util.IBits;
+    using Directory = Lucene.Net.Store.Directory;
+
+    /*
+         * 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 Document = Documents.Document;
+    using Field = Field;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+
+    [TestFixture]
+    public class TestDocIdSet : LuceneTestCase
+    {
+        [Test]
+        public virtual void TestFilteredDocIdSet()
+        {
+            const int maxdoc = 10;
+            DocIdSet innerSet = new DocIdSetAnonymousInnerClassHelper(this, maxdoc);
+
+            DocIdSet filteredSet = new FilteredDocIdSetAnonymousInnerClassHelper(this, innerSet);
+
+            DocIdSetIterator iter = filteredSet.GetIterator();
+            List<int?> list = new List<int?>();
+            int doc = iter.Advance(3);
+            if (doc != DocIdSetIterator.NO_MORE_DOCS)
+            {
+                list.Add(Convert.ToInt32(doc));
+                while ((doc = iter.NextDoc()) != DocIdSetIterator.NO_MORE_DOCS)
+                {
+                    list.Add(Convert.ToInt32(doc));
+                }
+            }
+
+            int[] docs = new int[list.Count];
+            int c = 0;
+            IEnumerator<int?> intIter = list.GetEnumerator();
+            while (intIter.MoveNext())
+            {
+                docs[c++] = (int)intIter.Current;
+            }
+            int[] answer = new int[] { 4, 6, 8 };
+            bool same = Arrays.Equals(answer, docs);
+            if (!same)
+            {
+                Console.WriteLine("answer: " + Arrays.ToString(answer));
+                Console.WriteLine("gotten: " + Arrays.ToString(docs));
+                Assert.Fail();
+            }
+        }
+
+        private class DocIdSetAnonymousInnerClassHelper : DocIdSet
+        {
+            private readonly TestDocIdSet OuterInstance;
+
+            private int Maxdoc;
+
+            public DocIdSetAnonymousInnerClassHelper(TestDocIdSet outerInstance, int maxdoc)
+            {
+                this.OuterInstance = outerInstance;
+                this.Maxdoc = maxdoc;
+            }
+
+            public override DocIdSetIterator GetIterator()
+            {
+                return new DocIdSetIteratorAnonymousInnerClassHelper(this);
+            }
+
+            private class DocIdSetIteratorAnonymousInnerClassHelper : DocIdSetIterator
+            {
+                private readonly DocIdSetAnonymousInnerClassHelper OuterInstance;
+
+                public DocIdSetIteratorAnonymousInnerClassHelper(DocIdSetAnonymousInnerClassHelper outerInstance)
+                {
+                    this.OuterInstance = outerInstance;
+                    docid = -1;
+                }
+
+                internal int docid;
+
+                public override int DocID
+                {
+                    get { return docid; }
+                }
+
+                public override int NextDoc()
+                {
+                    docid++;
+                    return docid < OuterInstance.Maxdoc ? docid : (docid = NO_MORE_DOCS);
+                }
+
+                public override int Advance(int target)
+                {
+                    return SlowAdvance(target);
+                }
+
+                public override long GetCost()
+                {
+                    return 1;
+                }
+            }
+        }
+
+        private class FilteredDocIdSetAnonymousInnerClassHelper : FilteredDocIdSet
+        {
+            private readonly TestDocIdSet OuterInstance;
+
+            public FilteredDocIdSetAnonymousInnerClassHelper(TestDocIdSet outerInstance, DocIdSet innerSet)
+                : base(innerSet)
+            {
+                this.OuterInstance = outerInstance;
+            }
+
+            protected override bool Match(int docid)
+            {
+                return docid % 2 == 0; //validate only even docids
+            }
+        }
+
+        [Test]
+        public virtual void TestNullDocIdSet()
+        {
+            // Tests that if a Filter produces a null DocIdSet, which is given to
+            // IndexSearcher, everything works fine. this came up in LUCENE-1754.
+            Directory dir = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), dir, Similarity, TimeZone);
+            Document doc = new Document();
+            doc.Add(NewStringField("c", "val", Field.Store.NO));
+            writer.AddDocument(doc);
+            IndexReader reader = writer.Reader;
+            writer.Dispose();
+
+            // First verify the document is searchable.
+            IndexSearcher searcher = NewSearcher(reader);
+            Assert.AreEqual(1, searcher.Search(new MatchAllDocsQuery(), 10).TotalHits);
+
+            // Now search w/ a Filter which returns a null DocIdSet
+            Filter f = new FilterAnonymousInnerClassHelper(this);
+
+            Assert.AreEqual(0, searcher.Search(new MatchAllDocsQuery(), f, 10).TotalHits);
+            reader.Dispose();
+            dir.Dispose();
+        }
+
+        private class FilterAnonymousInnerClassHelper : Filter
+        {
+            private readonly TestDocIdSet OuterInstance;
+
+            public FilterAnonymousInnerClassHelper(TestDocIdSet outerInstance)
+            {
+                this.OuterInstance = outerInstance;
+            }
+
+            public override DocIdSet GetDocIdSet(AtomicReaderContext context, IBits acceptDocs)
+            {
+                return null;
+            }
+        }
+
+        [Test]
+        public virtual void TestNullIteratorFilteredDocIdSet()
+        {
+            Directory dir = NewDirectory();
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), dir, Similarity, TimeZone);
+            Document doc = new Document();
+            doc.Add(NewStringField("c", "val", Field.Store.NO));
+            writer.AddDocument(doc);
+            IndexReader reader = writer.Reader;
+            writer.Dispose();
+
+            // First verify the document is searchable.
+            IndexSearcher searcher = NewSearcher(reader);
+            Assert.AreEqual(1, searcher.Search(new MatchAllDocsQuery(), 10).TotalHits);
+
+            // Now search w/ a Filter which returns a null DocIdSet
+            Filter f = new FilterAnonymousInnerClassHelper2(this);
+
+            Assert.AreEqual(0, searcher.Search(new MatchAllDocsQuery(), f, 10).TotalHits);
+            reader.Dispose();
+            dir.Dispose();
+        }
+
+        private class FilterAnonymousInnerClassHelper2 : Filter
+        {
+            private readonly TestDocIdSet OuterInstance;
+
+            public FilterAnonymousInnerClassHelper2(TestDocIdSet outerInstance)
+            {
+                this.OuterInstance = outerInstance;
+            }
+
+            public override DocIdSet GetDocIdSet(AtomicReaderContext context, IBits acceptDocs)
+            {
+                DocIdSet innerNullIteratorSet = new DocIdSetAnonymousInnerClassHelper2(this);
+                return new FilteredDocIdSetAnonymousInnerClassHelper2(this, innerNullIteratorSet);
+            }
+
+            private class DocIdSetAnonymousInnerClassHelper2 : DocIdSet
+            {
+                private readonly FilterAnonymousInnerClassHelper2 OuterInstance;
+
+                public DocIdSetAnonymousInnerClassHelper2(FilterAnonymousInnerClassHelper2 outerInstance)
+                {
+                    this.OuterInstance = outerInstance;
+                }
+
+                public override DocIdSetIterator GetIterator()
+                {
+                    return null;
+                }
+            }
+
+            private class FilteredDocIdSetAnonymousInnerClassHelper2 : FilteredDocIdSet
+            {
+                private readonly FilterAnonymousInnerClassHelper2 OuterInstance;
+
+                public FilteredDocIdSetAnonymousInnerClassHelper2(FilterAnonymousInnerClassHelper2 outerInstance, DocIdSet innerNullIteratorSet)
+                    : base(innerNullIteratorSet)
+                {
+                    this.OuterInstance = outerInstance;
+                }
+
+                protected override bool Match(int docid)
+                {
+                    return true;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDocTermOrdsRangeFilter.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDocTermOrdsRangeFilter.cs b/src/Lucene.Net.Tests/Search/TestDocTermOrdsRangeFilter.cs
new file mode 100644
index 0000000..f6b2706
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDocTermOrdsRangeFilter.cs
@@ -0,0 +1,149 @@
+using Lucene.Net.Documents;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Search
+{
+    using Lucene.Net.Randomized.Generators;
+    using BytesRef = Lucene.Net.Util.BytesRef;
+    using Directory = Lucene.Net.Store.Directory;
+    using Document = Documents.Document;
+    using Field = Field;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+
+    /*
+         * 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 MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using MockTokenizer = Lucene.Net.Analysis.MockTokenizer;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using SortedSetDocValuesField = SortedSetDocValuesField;
+    using Term = Lucene.Net.Index.Term;
+    using TestUtil = Lucene.Net.Util.TestUtil;
+    using UnicodeUtil = Lucene.Net.Util.UnicodeUtil;
+
+    /// <summary>
+    /// Tests the DocTermOrdsRangeFilter
+    /// </summary>
+    [TestFixture]
+    public class TestDocTermOrdsRangeFilter : LuceneTestCase
+    {
+        protected internal IndexSearcher Searcher1;
+        protected internal IndexSearcher Searcher2;
+        private IndexReader Reader;
+        private Directory Dir;
+        protected internal string FieldName;
+
+        [SetUp]
+        public override void SetUp()
+        {
+            base.SetUp();
+            Dir = NewDirectory();
+            FieldName = Random().NextBoolean() ? "field" : ""; // sometimes use an empty string as field name
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), Dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.KEYWORD, false)).SetMaxBufferedDocs(TestUtil.NextInt(Random(), 50, 1000)));
+            List<string> terms = new List<string>();
+            int num = AtLeast(200);
+            for (int i = 0; i < num; i++)
+            {
+                Document doc = new Document();
+                doc.Add(NewStringField("id", Convert.ToString(i), Field.Store.NO));
+                int numTerms = Random().Next(4);
+                for (int j = 0; j < numTerms; j++)
+                {
+                    string s = TestUtil.RandomUnicodeString(Random());
+                    doc.Add(NewStringField(FieldName, s, Field.Store.NO));
+                    // if the default codec doesn't support sortedset, we will uninvert at search time
+                    if (DefaultCodecSupportsSortedSet())
+                    {
+                        doc.Add(new SortedSetDocValuesField(FieldName, new BytesRef(s)));
+                    }
+                    terms.Add(s);
+                }
+                writer.AddDocument(doc);
+            }
+
+            if (VERBOSE)
+            {
+                // utf16 order
+                terms.Sort();
+                Console.WriteLine("UTF16 order:");
+                foreach (string s in terms)
+                {
+                    Console.WriteLine("  " + UnicodeUtil.ToHexString(s));
+                }
+            }
+
+            int numDeletions = Random().Next(num / 10);
+            for (int i = 0; i < numDeletions; i++)
+            {
+                writer.DeleteDocuments(new Term("id", Convert.ToString(Random().Next(num))));
+            }
+
+            Reader = writer.Reader;
+            Searcher1 = NewSearcher(Reader);
+            Searcher2 = NewSearcher(Reader);
+            writer.Dispose();
+        }
+
+        [TearDown]
+        public override void TearDown()
+        {
+            Reader.Dispose();
+            Dir.Dispose();
+            base.TearDown();
+        }
+
+        /// <summary>
+        /// test a bunch of random ranges </summary>
+        [Test]
+        public virtual void TestRanges()
+        {
+            int num = AtLeast(1000);
+            for (int i = 0; i < num; i++)
+            {
+                BytesRef lowerVal = new BytesRef(TestUtil.RandomUnicodeString(Random()));
+                BytesRef upperVal = new BytesRef(TestUtil.RandomUnicodeString(Random()));
+                if (upperVal.CompareTo(lowerVal) < 0)
+                {
+                    AssertSame(upperVal, lowerVal, Random().NextBoolean(), Random().NextBoolean());
+                }
+                else
+                {
+                    AssertSame(lowerVal, upperVal, Random().NextBoolean(), Random().NextBoolean());
+                }
+            }
+        }
+
+        /// <summary>
+        /// check that the # of hits is the same as if the query
+        /// is run against the inverted index
+        /// </summary>
+        protected internal virtual void AssertSame(BytesRef lowerVal, BytesRef upperVal, bool includeLower, bool includeUpper)
+        {
+            Query docValues = new ConstantScoreQuery(DocTermOrdsRangeFilter.NewBytesRefRange(FieldName, lowerVal, upperVal, includeLower, includeUpper));
+            MultiTermQuery inverted = new TermRangeQuery(FieldName, lowerVal, upperVal, includeLower, includeUpper);
+            inverted.MultiTermRewriteMethod = (MultiTermQuery.CONSTANT_SCORE_FILTER_REWRITE);
+
+            TopDocs invertedDocs = Searcher1.Search(inverted, 25);
+            TopDocs docValuesDocs = Searcher2.Search(docValues, 25);
+
+            CheckHits.CheckEqual(inverted, invertedDocs.ScoreDocs, docValuesDocs.ScoreDocs);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDocTermOrdsRewriteMethod.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDocTermOrdsRewriteMethod.cs b/src/Lucene.Net.Tests/Search/TestDocTermOrdsRewriteMethod.cs
new file mode 100644
index 0000000..7389e9e
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDocTermOrdsRewriteMethod.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    using Lucene.Net.Randomized.Generators;
+    using NUnit.Framework;
+    using AutomatonTestUtil = Lucene.Net.Util.Automaton.AutomatonTestUtil;
+    using BytesRef = Lucene.Net.Util.BytesRef;
+    using Directory = Lucene.Net.Store.Directory;
+    using Document = Documents.Document;
+    using Field = Field;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+
+    /*
+         * 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 MockAnalyzer = Lucene.Net.Analysis.MockAnalyzer;
+    using MockTokenizer = Lucene.Net.Analysis.MockTokenizer;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using RegExp = Lucene.Net.Util.Automaton.RegExp;
+    using SortedSetDocValuesField = SortedSetDocValuesField;
+    using Term = Lucene.Net.Index.Term;
+    using TestUtil = Lucene.Net.Util.TestUtil;
+    using UnicodeUtil = Lucene.Net.Util.UnicodeUtil;
+
+    /// <summary>
+    /// Tests the DocTermOrdsRewriteMethod
+    /// </summary>
+    [TestFixture]
+    public class TestDocTermOrdsRewriteMethod : LuceneTestCase
+    {
+        protected internal IndexSearcher Searcher1;
+        protected internal IndexSearcher Searcher2;
+        private IndexReader Reader;
+        private Directory Dir;
+        protected internal string FieldName;
+
+        [SetUp]
+        public override void SetUp()
+        {
+            base.SetUp();
+            Dir = NewDirectory();
+            FieldName = Random().NextBoolean() ? "field" : ""; // sometimes use an empty string as field name
+            RandomIndexWriter writer = new RandomIndexWriter(Random(), Dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.KEYWORD, false)).SetMaxBufferedDocs(TestUtil.NextInt(Random(), 50, 1000)));
+            List<string> terms = new List<string>();
+            int num = AtLeast(200);
+            for (int i = 0; i < num; i++)
+            {
+                Document doc = new Document();
+                doc.Add(NewStringField("id", Convert.ToString(i), Field.Store.NO));
+                int numTerms = Random().Next(4);
+                for (int j = 0; j < numTerms; j++)
+                {
+                    string s = TestUtil.RandomUnicodeString(Random());
+                    doc.Add(NewStringField(FieldName, s, Field.Store.NO));
+                    // if the default codec doesn't support sortedset, we will uninvert at search time
+                    if (DefaultCodecSupportsSortedSet())
+                    {
+                        doc.Add(new SortedSetDocValuesField(FieldName, new BytesRef(s)));
+                    }
+                    terms.Add(s);
+                }
+                writer.AddDocument(doc);
+            }
+
+            if (VERBOSE)
+            {
+                // utf16 order
+                terms.Sort();
+                Console.WriteLine("UTF16 order:");
+                foreach (string s in terms)
+                {
+                    Console.WriteLine("  " + UnicodeUtil.ToHexString(s));
+                }
+            }
+
+            int numDeletions = Random().Next(num / 10);
+            for (int i = 0; i < numDeletions; i++)
+            {
+                writer.DeleteDocuments(new Term("id", Convert.ToString(Random().Next(num))));
+            }
+
+            Reader = writer.Reader;
+            Searcher1 = NewSearcher(Reader);
+            Searcher2 = NewSearcher(Reader);
+            writer.Dispose();
+        }
+
+        [TearDown]
+        public override void TearDown()
+        {
+            Reader.Dispose();
+            Dir.Dispose();
+            base.TearDown();
+        }
+
+        /// <summary>
+        /// test a bunch of random regular expressions </summary>
+        [Test]
+        public virtual void TestRegexps()
+        {
+            int num = AtLeast(1000);
+            for (int i = 0; i < num; i++)
+            {
+                string reg = AutomatonTestUtil.RandomRegexp(Random());
+                if (VERBOSE)
+                {
+                    Console.WriteLine("TEST: regexp=" + reg);
+                }
+                AssertSame(reg);
+            }
+        }
+
+        /// <summary>
+        /// check that the # of hits is the same as if the query
+        /// is run against the inverted index
+        /// </summary>
+        protected internal virtual void AssertSame(string regexp)
+        {
+            RegexpQuery docValues = new RegexpQuery(new Term(FieldName, regexp), RegExp.NONE);
+            docValues.MultiTermRewriteMethod = (new DocTermOrdsRewriteMethod());
+            RegexpQuery inverted = new RegexpQuery(new Term(FieldName, regexp), RegExp.NONE);
+
+            TopDocs invertedDocs = Searcher1.Search(inverted, 25);
+            TopDocs docValuesDocs = Searcher2.Search(docValues, 25);
+
+            CheckHits.CheckEqual(inverted, invertedDocs.ScoreDocs, docValuesDocs.ScoreDocs);
+        }
+
+        [Test]
+        public virtual void TestEquals()
+        {
+            RegexpQuery a1 = new RegexpQuery(new Term(FieldName, "[aA]"), RegExp.NONE);
+            RegexpQuery a2 = new RegexpQuery(new Term(FieldName, "[aA]"), RegExp.NONE);
+            RegexpQuery b = new RegexpQuery(new Term(FieldName, "[bB]"), RegExp.NONE);
+            Assert.AreEqual(a1, a2);
+            Assert.IsFalse(a1.Equals(b));
+
+            a1.MultiTermRewriteMethod = (new DocTermOrdsRewriteMethod());
+            a2.MultiTermRewriteMethod = (new DocTermOrdsRewriteMethod());
+            b.MultiTermRewriteMethod = (new DocTermOrdsRewriteMethod());
+            Assert.AreEqual(a1, a2);
+            Assert.IsFalse(a1.Equals(b));
+            QueryUtils.Check(a1);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/96822396/src/Lucene.Net.Tests/Search/TestDocValuesScoring.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests/Search/TestDocValuesScoring.cs b/src/Lucene.Net.Tests/Search/TestDocValuesScoring.cs
new file mode 100644
index 0000000..ebd3e72
--- /dev/null
+++ b/src/Lucene.Net.Tests/Search/TestDocValuesScoring.cs
@@ -0,0 +1,233 @@
+using Lucene.Net.Documents;
+
+namespace Lucene.Net.Search
+{
+    using Lucene.Net.Index;
+    using NUnit.Framework;
+    using AtomicReaderContext = Lucene.Net.Index.AtomicReaderContext;
+    using BytesRef = Lucene.Net.Util.BytesRef;
+    using Directory = Lucene.Net.Store.Directory;
+
+    /*
+         * 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 Document = Documents.Document;
+    using Field = Field;
+    using FieldInvertState = Lucene.Net.Index.FieldInvertState;
+    using SingleDocValuesField = SingleDocValuesField;
+    using IndexReader = Lucene.Net.Index.IndexReader;
+    using LuceneTestCase = Lucene.Net.Util.LuceneTestCase;
+    using PerFieldSimilarityWrapper = Lucene.Net.Search.Similarities.PerFieldSimilarityWrapper;
+    using RandomIndexWriter = Lucene.Net.Index.RandomIndexWriter;
+    using Similarity = Lucene.Net.Search.Similarities.Similarity;
+    using Term = Lucene.Net.Index.Term;
+
+    /// <summary>
+    /// Tests the use of indexdocvalues in scoring.
+    ///
+    /// In the example, a docvalues field is used as a per-document boost (separate from the norm)
+    /// @lucene.experimental
+    /// </summary>
+    [SuppressCodecs("Lucene3x")]
+    [TestFixture]
+    public class TestDocValuesScoring : LuceneTestCase
+    {
+        private const float SCORE_EPSILON = 0.001f; // for comparing floats
+
+        [Test]
+        public virtual void TestSimple()
+        {
+            Directory dir = NewDirectory();
+            RandomIndexWriter iw = new RandomIndexWriter(Random(), dir, Similarity, TimeZone);
+            Document doc = new Document();
+            Field field = NewTextField("foo", "", Field.Store.NO);
+            doc.Add(field);
+            Field dvField = new SingleDocValuesField("foo_boost", 0.0F);
+            doc.Add(dvField);
+            Field field2 = NewTextField("bar", "", Field.Store.NO);
+            doc.Add(field2);
+
+            field.SetStringValue("quick brown fox");
+            field2.SetStringValue("quick brown fox");
+            dvField.SetSingleValue(2f); // boost x2
+            iw.AddDocument(doc);
+            field.SetStringValue("jumps over lazy brown dog");
+            field2.SetStringValue("jumps over lazy brown dog");
+            dvField.SetSingleValue(4f); // boost x4
+            iw.AddDocument(doc);
+            IndexReader ir = iw.Reader;
+            iw.Dispose();
+
+            // no boosting
+            IndexSearcher searcher1 = NewSearcher(ir, false, Similarity);
+            Similarity @base = searcher1.Similarity;
+            // boosting
+            IndexSearcher searcher2 = NewSearcher(ir, false, Similarity);
+            searcher2.Similarity = new PerFieldSimilarityWrapperAnonymousInnerClassHelper(this, field, @base);
+
+            // in this case, we searched on field "foo". first document should have 2x the score.
+            TermQuery tq = new TermQuery(new Term("foo", "quick"));
+            QueryUtils.Check(Random(), tq, searcher1, Similarity);
+            QueryUtils.Check(Random(), tq, searcher2, Similarity);
+
+            TopDocs noboost = searcher1.Search(tq, 10);
+            TopDocs boost = searcher2.Search(tq, 10);
+            Assert.AreEqual(1, noboost.TotalHits);
+            Assert.AreEqual(1, boost.TotalHits);
+
+            //System.out.println(searcher2.Explain(tq, boost.ScoreDocs[0].Doc));
+            Assert.AreEqual(boost.ScoreDocs[0].Score, noboost.ScoreDocs[0].Score * 2f, SCORE_EPSILON);
+
+            // this query matches only the second document, which should have 4x the score.
+            tq = new TermQuery(new Term("foo", "jumps"));
+            QueryUtils.Check(Random(), tq, searcher1, Similarity);
+            QueryUtils.Check(Random(), tq, searcher2, Similarity);
+
+            noboost = searcher1.Search(tq, 10);
+            boost = searcher2.Search(tq, 10);
+            Assert.AreEqual(1, noboost.TotalHits);
+            Assert.AreEqual(1, boost.TotalHits);
+
+            Assert.AreEqual(boost.ScoreDocs[0].Score, noboost.ScoreDocs[0].Score * 4f, SCORE_EPSILON);
+
+            // search on on field bar just for kicks, nothing should happen, since we setup
+            // our sim provider to only use foo_boost for field foo.
+            tq = new TermQuery(new Term("bar", "quick"));
+            QueryUtils.Check(Random(), tq, searcher1, Similarity);
+            QueryUtils.Check(Random(), tq, searcher2, Similarity);
+
+            noboost = searcher1.Search(tq, 10);
+            boost = searcher2.Search(tq, 10);
+            Assert.AreEqual(1, noboost.TotalHits);
+            Assert.AreEqual(1, boost.TotalHits);
+
+            Assert.AreEqual(boost.ScoreDocs[0].Score, noboost.ScoreDocs[0].Score, SCORE_EPSILON);
+
+            ir.Dispose();
+            dir.Dispose();
+        }
+
+        private class PerFieldSimilarityWrapperAnonymousInnerClassHelper : PerFieldSimilarityWrapper
+        {
+            private readonly TestDocValuesScoring OuterInstance;
+
+            private Field Field;
+            private Similarity @base;
+
+            public PerFieldSimilarityWrapperAnonymousInnerClassHelper(TestDocValuesScoring outerInstance, Field field, Similarity @base)
+            {
+                this.OuterInstance = outerInstance;
+                this.Field = field;
+                this.@base = @base;
+                fooSim = new BoostingSimilarity(@base, "foo_boost");
+            }
+
+            internal readonly Similarity fooSim;
+
+            public override Similarity Get(string field)
+            {
+                return "foo".Equals(field) ? fooSim : @base;
+            }
+
+            public override float Coord(int overlap, int maxOverlap)
+            {
+                return @base.Coord(overlap, maxOverlap);
+            }
+
+            public override float QueryNorm(float sumOfSquaredWeights)
+            {
+                return @base.QueryNorm(sumOfSquaredWeights);
+            }
+        }
+
+        /// <summary>
+        /// Similarity that wraps another similarity and boosts the final score
+        /// according to whats in a docvalues field.
+        ///
+        /// @lucene.experimental
+        /// </summary>
+        internal class BoostingSimilarity : Similarity
+        {
+            internal readonly Similarity Sim;
+            internal readonly string BoostField;
+
+            public BoostingSimilarity(Similarity sim, string boostField)
+            {
+                this.Sim = sim;
+                this.BoostField = boostField;
+            }
+
+            public override long ComputeNorm(FieldInvertState state)
+            {
+                return Sim.ComputeNorm(state);
+            }
+
+            public override SimWeight ComputeWeight(float queryBoost, CollectionStatistics collectionStats, params TermStatistics[] termStats)
+            {
+                return Sim.ComputeWeight(queryBoost, collectionStats, termStats);
+            }
+
+            public override SimScorer GetSimScorer(SimWeight stats, AtomicReaderContext context)
+            {
+                SimScorer sub = Sim.GetSimScorer(stats, context);
+                FieldCache.Singles values = FieldCache.DEFAULT.GetSingles(context.AtomicReader, BoostField, false);
+
+                return new SimScorerAnonymousInnerClassHelper(this, sub, values);
+            }
+
+            private class SimScorerAnonymousInnerClassHelper : SimScorer
+            {
+                private readonly BoostingSimilarity OuterInstance;
+
+                private SimScorer Sub;
+                private FieldCache.Singles Values;
+
+                public SimScorerAnonymousInnerClassHelper(BoostingSimilarity outerInstance, SimScorer sub, FieldCache.Singles values)
+                {
+                    this.OuterInstance = outerInstance;
+                    this.Sub = sub;
+                    this.Values = values;
+                }
+
+                public override float Score(int doc, float freq)
+                {
+                    return Values.Get(doc) * Sub.Score(doc, freq);
+                }
+
+                public override float ComputeSlopFactor(int distance)
+                {
+                    return Sub.ComputeSlopFactor(distance);
+                }
+
+                public override float ComputePayloadFactor(int doc, int start, int end, BytesRef payload)
+                {
+                    return Sub.ComputePayloadFactor(doc, start, end, payload);
+                }
+
+                public override Explanation Explain(int doc, Explanation freq)
+                {
+                    Explanation boostExplanation = new Explanation(Values.Get(doc), "indexDocValue(" + OuterInstance.BoostField + ")");
+                    Explanation simExplanation = Sub.Explain(doc, freq);
+                    Explanation expl = new Explanation(boostExplanation.Value * simExplanation.Value, "product of:");
+                    expl.AddDetail(boostExplanation);
+                    expl.AddDetail(simExplanation);
+                    return expl;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file


Mime
View raw message