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 2015/08/24 00:34:12 UTC

[13/17] lucenenet git commit: Lucene.Net.Join tests now passing

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4820f236/Lucene.Net.Tests.Join/TestBlockJoinSorting.cs
----------------------------------------------------------------------
diff --git a/Lucene.Net.Tests.Join/TestBlockJoinSorting.cs b/Lucene.Net.Tests.Join/TestBlockJoinSorting.cs
deleted file mode 100644
index c2df0df..0000000
--- a/Lucene.Net.Tests.Join/TestBlockJoinSorting.cs
+++ /dev/null
@@ -1,277 +0,0 @@
-using System.Collections.Generic;
-using Lucene.Net.Analysis;
-using Lucene.Net.Documents;
-using Lucene.Net.Index;
-using Lucene.Net.Join;
-using Lucene.Net.Randomized.Generators;
-using Lucene.Net.Search;
-using Lucene.Net.Store;
-using Lucene.Net.Util;
-using NUnit.Framework;
-
-namespace Lucene.Net.Tests.Join
-{
-    /*
-	 * 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.
-	 */
-
-    public class TestBlockJoinSorting : LuceneTestCase
-    {
-        [Test]
-        public void TestNestedSorting()
-        {
-            Directory dir = NewDirectory();
-            RandomIndexWriter w = new RandomIndexWriter(Random(), dir, NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random())).SetMergePolicy(NoMergePolicy.COMPOUND_FILES));
-
-            IList<Document> docs = new List<Document>();
-            Document document = new Document();
-            document.Add(new StringField("field2", "a", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "b", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "c", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "a", Field.Store.NO));
-            docs.Add(document);
-            w.AddDocuments(docs);
-            w.Commit();
-
-            docs.Clear();
-            document = new Document();
-            document.Add(new StringField("field2", "c", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "d", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "e", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "b", Field.Store.NO));
-            docs.Add(document);
-            w.AddDocuments(docs);
-
-            docs.Clear();
-            document = new Document();
-            document.Add(new StringField("field2", "e", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "f", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "g", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "c", Field.Store.NO));
-            docs.Add(document);
-            w.AddDocuments(docs);
-
-            docs.Clear();
-            document = new Document();
-            document.Add(new StringField("field2", "g", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "h", Field.Store.NO));
-            document.Add(new StringField("filter_1", "F", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "i", Field.Store.NO));
-            document.Add(new StringField("filter_1", "F", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "d", Field.Store.NO));
-            docs.Add(document);
-            w.AddDocuments(docs);
-            w.Commit();
-
-            docs.Clear();
-            document = new Document();
-            document.Add(new StringField("field2", "i", Field.Store.NO));
-            document.Add(new StringField("filter_1", "F", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "j", Field.Store.NO));
-            document.Add(new StringField("filter_1", "F", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "k", Field.Store.NO));
-            document.Add(new StringField("filter_1", "F", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "f", Field.Store.NO));
-            docs.Add(document);
-            w.AddDocuments(docs);
-
-            docs.Clear();
-            document = new Document();
-            document.Add(new StringField("field2", "k", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "l", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "m", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "g", Field.Store.NO));
-            docs.Add(document);
-            w.AddDocuments(docs);
-
-            // This doc will not be included, because it doesn't have nested docs
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "h", Field.Store.NO));
-            w.AddDocument(document);
-
-            docs.Clear();
-            document = new Document();
-            document.Add(new StringField("field2", "m", Field.Store.NO));
-            document.Add(new StringField("filter_1", "T", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "n", Field.Store.NO));
-            document.Add(new StringField("filter_1", "F", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("field2", "o", Field.Store.NO));
-            document.Add(new StringField("filter_1", "F", Field.Store.NO));
-            docs.Add(document);
-            document = new Document();
-            document.Add(new StringField("__type", "parent", Field.Store.NO));
-            document.Add(new StringField("field1", "i", Field.Store.NO));
-            docs.Add(document);
-            w.AddDocuments(docs);
-            w.Commit();
-
-            // Some garbage docs, just to check if the NestedFieldComparator can deal with this.
-            document = new Document();
-            document.Add(new StringField("fieldXXX", "x", Field.Store.NO));
-            w.AddDocument(document);
-            document = new Document();
-            document.Add(new StringField("fieldXXX", "x", Field.Store.NO));
-            w.AddDocument(document);
-            document = new Document();
-            document.Add(new StringField("fieldXXX", "x", Field.Store.NO));
-            w.AddDocument(document);
-
-            IndexSearcher searcher = new IndexSearcher(DirectoryReader.Open(w.w, false));
-            w.Dispose();
-            Filter parentFilter = new QueryWrapperFilter(new TermQuery(new Term("__type", "parent")));
-            Filter childFilter = new QueryWrapperFilter(new PrefixQuery(new Term("field2")));
-            ToParentBlockJoinQuery query = new ToParentBlockJoinQuery(new FilteredQuery(new MatchAllDocsQuery(), childFilter), new FixedBitSetCachingWrapperFilter(parentFilter), ScoreMode.None);
-
-            // Sort by field ascending, order first
-            ToParentBlockJoinSortField sortField = new ToParentBlockJoinSortField("field2", SortField.Type_e.STRING, false, Wrap(parentFilter), Wrap(childFilter));
-            Sort sort = new Sort(sortField);
-            TopFieldDocs topDocs = searcher.Search(query, 5, sort);
-            assertEquals(7, topDocs.TotalHits);
-            assertEquals(5, topDocs.ScoreDocs.Length);
-            assertEquals(3, topDocs.ScoreDocs[0].Doc);
-            assertEquals("a", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[0]).Fields[0]).Utf8ToString());
-            assertEquals(7, topDocs.ScoreDocs[1].Doc);
-            assertEquals("c", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[1]).Fields[0]).Utf8ToString());
-            assertEquals(11, topDocs.ScoreDocs[2].Doc);
-            assertEquals("e", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[2]).Fields[0]).Utf8ToString());
-            assertEquals(15, topDocs.ScoreDocs[3].Doc);
-            assertEquals("g", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[3]).Fields[0]).Utf8ToString());
-            assertEquals(19, topDocs.ScoreDocs[4].Doc);
-            assertEquals("i", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[4]).Fields[0]).Utf8ToString());
-
-            // Sort by field ascending, order last
-            sortField = new ToParentBlockJoinSortField("field2", SortField.Type_e.STRING, false, true, Wrap(parentFilter), Wrap(childFilter));
-            sort = new Sort(sortField);
-            topDocs = searcher.Search(query, 5, sort);
-            assertEquals(7, topDocs.TotalHits);
-            assertEquals(5, topDocs.ScoreDocs.Length);
-            assertEquals(3, topDocs.ScoreDocs[0].Doc);
-            assertEquals("c", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[0]).Fields[0]).Utf8ToString());
-            assertEquals(7, topDocs.ScoreDocs[1].Doc);
-            assertEquals("e", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[1]).Fields[0]).Utf8ToString());
-            assertEquals(11, topDocs.ScoreDocs[2].Doc);
-            assertEquals("g", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[2]).Fields[0]).Utf8ToString());
-            assertEquals(15, topDocs.ScoreDocs[3].Doc);
-            assertEquals("i", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[3]).Fields[0]).Utf8ToString());
-            assertEquals(19, topDocs.ScoreDocs[4].Doc);
-            assertEquals("k", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[4]).Fields[0]).Utf8ToString());
-
-            // Sort by field descending, order last
-            sortField = new ToParentBlockJoinSortField("field2", SortField.Type_e.STRING, true, Wrap(parentFilter), Wrap(childFilter));
-            sort = new Sort(sortField);
-            topDocs = searcher.Search(query, 5, sort);
-            assertEquals(topDocs.TotalHits, 7);
-            assertEquals(5, topDocs.ScoreDocs.Length);
-            assertEquals(28, topDocs.ScoreDocs[0].Doc);
-            assertEquals("o", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[0]).Fields[0]).Utf8ToString());
-            assertEquals(23, topDocs.ScoreDocs[1].Doc);
-            assertEquals("m", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[1]).Fields[0]).Utf8ToString());
-            assertEquals(19, topDocs.ScoreDocs[2].Doc);
-            assertEquals("k", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[2]).Fields[0]).Utf8ToString());
-            assertEquals(15, topDocs.ScoreDocs[3].Doc);
-            assertEquals("i", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[3]).Fields[0]).Utf8ToString());
-            assertEquals(11, topDocs.ScoreDocs[4].Doc);
-            assertEquals("g", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[4]).Fields[0]).Utf8ToString());
-
-            // Sort by field descending, order last, sort filter (filter_1:T)
-            childFilter = new QueryWrapperFilter(new TermQuery((new Term("filter_1", "T"))));
-            query = new ToParentBlockJoinQuery(new FilteredQuery(new MatchAllDocsQuery(), childFilter), new FixedBitSetCachingWrapperFilter(parentFilter), ScoreMode.None);
-            sortField = new ToParentBlockJoinSortField("field2", SortField.Type_e.STRING, true, Wrap(parentFilter), Wrap(childFilter));
-            sort = new Sort(sortField);
-            topDocs = searcher.Search(query, 5, sort);
-            assertEquals(6, topDocs.TotalHits);
-            assertEquals(5, topDocs.ScoreDocs.Length);
-            assertEquals(23, topDocs.ScoreDocs[0].Doc);
-            assertEquals("m", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[0]).Fields[0]).Utf8ToString());
-            assertEquals(28, topDocs.ScoreDocs[1].Doc);
-            assertEquals("m", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[1]).Fields[0]).Utf8ToString());
-            assertEquals(11, topDocs.ScoreDocs[2].Doc);
-            assertEquals("g", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[2]).Fields[0]).Utf8ToString());
-            assertEquals(15, topDocs.ScoreDocs[3].Doc);
-            assertEquals("g", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[3]).Fields[0]).Utf8ToString());
-            assertEquals(7, topDocs.ScoreDocs[4].Doc);
-            assertEquals("e", ((BytesRef)((FieldDoc)topDocs.ScoreDocs[4]).Fields[0]).Utf8ToString());
-
-            searcher.IndexReader.Dispose();
-            dir.Dispose();
-        }
-
-        private Filter Wrap(Filter filter)
-        {
-            return Random().NextBoolean() ? new FixedBitSetCachingWrapperFilter(filter) : filter;
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4820f236/Lucene.Net.Tests.Join/TestBlockJoinValidation.cs
----------------------------------------------------------------------
diff --git a/Lucene.Net.Tests.Join/TestBlockJoinValidation.cs b/Lucene.Net.Tests.Join/TestBlockJoinValidation.cs
deleted file mode 100644
index 5fdd35f..0000000
--- a/Lucene.Net.Tests.Join/TestBlockJoinValidation.cs
+++ /dev/null
@@ -1,227 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using Apache.NMS;
-using Lucene.Net.Analysis;
-using Lucene.Net.Documents;
-using Lucene.Net.Index;
-using Lucene.Net.Join;
-using Lucene.Net.Randomized.Generators;
-using Lucene.Net.Search;
-using Lucene.Net.Store;
-using Lucene.Net.Support;
-using Lucene.Net.Util;
-using NUnit.Framework;
-
-namespace Lucene.Net.Tests.Join
-{
-    /*
-	 * 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.
-	 */
-
-    public class TestBlockJoinValidation : LuceneTestCase
-    {
-
-        public const int AMOUNT_OF_SEGMENTS = 5;
-        public const int AMOUNT_OF_PARENT_DOCS = 10;
-        public const int AMOUNT_OF_CHILD_DOCS = 5;
-        public static readonly int AMOUNT_OF_DOCS_IN_SEGMENT = AMOUNT_OF_PARENT_DOCS + AMOUNT_OF_PARENT_DOCS * AMOUNT_OF_CHILD_DOCS;
-
-        private Directory Directory;
-        private IndexReader IndexReader;
-        private IndexSearcher IndexSearcher;
-        private Filter ParentsFilter;
-        
-        [SetUp]
-        public override void SetUp()
-        {
-            Directory = NewDirectory();
-            IndexWriterConfig config = new IndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()));
-            IndexWriter indexWriter = new IndexWriter(Directory, config);
-            for (int i = 0; i < AMOUNT_OF_SEGMENTS; i++)
-            {
-                IList<Document> segmentDocs = CreateDocsForSegment(i);
-                indexWriter.AddDocuments(segmentDocs);
-                indexWriter.Commit();
-            }
-            IndexReader = DirectoryReader.Open(indexWriter, Random().NextBoolean());
-            indexWriter.Dispose();
-            IndexSearcher = new IndexSearcher(IndexReader);
-            ParentsFilter = new FixedBitSetCachingWrapperFilter(new QueryWrapperFilter(new WildcardQuery(new Term("parent", "*"))));
-        }
-
-        [TearDown]
-        public override void TearDown()
-        {
-            IndexReader.Dispose();
-            Directory.Dispose();
-        }
-
-        [Test]
-        public void TestNextDocValidationForToParentBjq()
-        {
-            Query parentQueryWithRandomChild = CreateChildrenQueryWithOneParent(GetRandomChildNumber(0));
-            var blockJoinQuery = new ToParentBlockJoinQuery(parentQueryWithRandomChild, ParentsFilter, ScoreMode.None);
-
-            var ex = Throws<InvalidOperationException>(() => IndexSearcher.Search(blockJoinQuery, 1));
-            StringAssert.Contains("child query must only match non-parent docs", ex.Message);
-
-        }
-
-        [Test]
-        public void TestAdvanceValidationForToParentBjq()
-        {
-            int randomChildNumber = GetRandomChildNumber(0);
-            // we need to make advance method meet wrong document, so random child number
-            // in BJQ must be greater than child number in Boolean clause
-            int nextRandomChildNumber = GetRandomChildNumber(randomChildNumber);
-            Query parentQueryWithRandomChild = CreateChildrenQueryWithOneParent(nextRandomChildNumber);
-            ToParentBlockJoinQuery blockJoinQuery = new ToParentBlockJoinQuery(parentQueryWithRandomChild, ParentsFilter, ScoreMode.None);
-            // advance() method is used by ConjunctionScorer, so we need to create Boolean conjunction query
-            BooleanQuery conjunctionQuery = new BooleanQuery();
-            WildcardQuery childQuery = new WildcardQuery(new Term("child", CreateFieldValue(randomChildNumber)));
-            conjunctionQuery.Add(new BooleanClause(childQuery, BooleanClause.Occur.MUST));
-            conjunctionQuery.Add(new BooleanClause(blockJoinQuery, BooleanClause.Occur.MUST));
-
-            var ex = Throws<InvalidOperationException>(() => IndexSearcher.Search(conjunctionQuery, 1));
-            StringAssert.Contains("child query must only match non-parent docs", ex.Message);
-        }
-
-        [Test]
-        public void TestNextDocValidationForToChildBjq()
-        {
-            Query parentQueryWithRandomChild = CreateParentsQueryWithOneChild(GetRandomChildNumber(0));
-            var blockJoinQuery = new ToChildBlockJoinQuery(parentQueryWithRandomChild, ParentsFilter, false);
-
-            var ex = Throws<InvalidOperationException>(() => IndexSearcher.Search(blockJoinQuery, 1));
-            StringAssert.Contains(ToChildBlockJoinQuery.InvalidQueryMessage, ex.Message);
-        }
-        
-        [Test]
-        public void TestAdvanceValidationForToChildBjq()
-        {
-            int randomChildNumber = GetRandomChildNumber(0);
-            // we need to make advance method meet wrong document, so random child number
-            // in BJQ must be greater than child number in Boolean clause
-            int nextRandomChildNumber = GetRandomChildNumber(randomChildNumber);
-            Query parentQueryWithRandomChild = CreateParentsQueryWithOneChild(nextRandomChildNumber);
-            var blockJoinQuery = new ToChildBlockJoinQuery(parentQueryWithRandomChild, ParentsFilter, false);
-            // advance() method is used by ConjunctionScorer, so we need to create Boolean conjunction query
-            var conjunctionQuery = new BooleanQuery();
-            var childQuery = new WildcardQuery(new Term("child", CreateFieldValue(randomChildNumber)));
-            conjunctionQuery.Add(new BooleanClause(childQuery, BooleanClause.Occur.MUST));
-            conjunctionQuery.Add(new BooleanClause(blockJoinQuery, BooleanClause.Occur.MUST));
-            
-            var ex = Throws<InvalidOperationException>(() => IndexSearcher.Search(conjunctionQuery, 1));
-            StringAssert.Contains(ToChildBlockJoinQuery.InvalidQueryMessage, ex.Message);
-        }
-
-        private static IList<Document> CreateDocsForSegment(int segmentNumber)
-        {
-            IList<IList<Document>> blocks = new List<IList<Document>>(AMOUNT_OF_PARENT_DOCS);
-            for (int i = 0; i < AMOUNT_OF_PARENT_DOCS; i++)
-            {
-                blocks.Add(CreateParentDocWithChildren(segmentNumber, i));
-            }
-            IList<Document> result = new List<Document>(AMOUNT_OF_DOCS_IN_SEGMENT);
-            foreach (IList<Document> block in blocks)
-            {
-                result.AddRange(block);
-            }
-            return result;
-        }
-
-        private static IList<Document> CreateParentDocWithChildren(int segmentNumber, int parentNumber)
-        {
-            IList<Document> result = new List<Document>(AMOUNT_OF_CHILD_DOCS + 1);
-            for (int i = 0; i < AMOUNT_OF_CHILD_DOCS; i++)
-            {
-                result.Add(CreateChildDoc(segmentNumber, parentNumber, i));
-            }
-            result.Add(CreateParentDoc(segmentNumber, parentNumber));
-            return result;
-        }
-
-        private static Document CreateParentDoc(int segmentNumber, int parentNumber)
-        {
-            Document result = new Document();
-            result.Add(NewStringField("id", CreateFieldValue(segmentNumber * AMOUNT_OF_PARENT_DOCS + parentNumber), Field.Store.YES));
-            result.Add(NewStringField("parent", CreateFieldValue(parentNumber), Field.Store.NO));
-            return result;
-        }
-
-        private static Document CreateChildDoc(int segmentNumber, int parentNumber, int childNumber)
-        {
-            Document result = new Document();
-            result.Add(NewStringField("id", CreateFieldValue(segmentNumber * AMOUNT_OF_PARENT_DOCS + parentNumber, childNumber), Field.Store.YES));
-            result.Add(NewStringField("child", CreateFieldValue(childNumber), Field.Store.NO));
-            return result;
-        }
-
-        private static string CreateFieldValue(params int[] documentNumbers)
-        {
-            StringBuilder stringBuilder = new StringBuilder();
-            foreach (int documentNumber in documentNumbers)
-            {
-                if (stringBuilder.Length > 0)
-                {
-                    stringBuilder.Append("_");
-                }
-                stringBuilder.Append(documentNumber);
-            }
-            return stringBuilder.ToString();
-        }
-
-        private static Query CreateChildrenQueryWithOneParent(int childNumber)
-        {
-            TermQuery childQuery = new TermQuery(new Term("child", CreateFieldValue(childNumber)));
-            Query randomParentQuery = new TermQuery(new Term("id", CreateFieldValue(RandomParentId)));
-            BooleanQuery childrenQueryWithRandomParent = new BooleanQuery();
-            childrenQueryWithRandomParent.Add(new BooleanClause(childQuery, BooleanClause.Occur.SHOULD));
-            childrenQueryWithRandomParent.Add(new BooleanClause(randomParentQuery, BooleanClause.Occur.SHOULD));
-            return childrenQueryWithRandomParent;
-        }
-
-        private static Query CreateParentsQueryWithOneChild(int randomChildNumber)
-        {
-            BooleanQuery childQueryWithRandomParent = new BooleanQuery();
-            Query parentsQuery = new TermQuery(new Term("parent", CreateFieldValue(RandomParentNumber)));
-            childQueryWithRandomParent.Add(new BooleanClause(parentsQuery, BooleanClause.Occur.SHOULD));
-            childQueryWithRandomParent.Add(new BooleanClause(RandomChildQuery(randomChildNumber), BooleanClause.Occur.SHOULD));
-            return childQueryWithRandomParent;
-        }
-
-        private static int RandomParentId
-        {
-            get { return Random().Next(AMOUNT_OF_PARENT_DOCS*AMOUNT_OF_SEGMENTS); }
-        }
-
-        private static int RandomParentNumber
-        {
-            get { return Random().Next(AMOUNT_OF_PARENT_DOCS); }
-        }
-
-        private static Query RandomChildQuery(int randomChildNumber)
-        {
-            return new TermQuery(new Term("id", CreateFieldValue(RandomParentId, randomChildNumber)));
-        }
-
-        private static int GetRandomChildNumber(int notLessThan)
-        {
-            return notLessThan + Random().Next(AMOUNT_OF_CHILD_DOCS - notLessThan);
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4820f236/Lucene.Net.Tests.Join/TestJoinUtil.cs
----------------------------------------------------------------------
diff --git a/Lucene.Net.Tests.Join/TestJoinUtil.cs b/Lucene.Net.Tests.Join/TestJoinUtil.cs
deleted file mode 100644
index 81513c7..0000000
--- a/Lucene.Net.Tests.Join/TestJoinUtil.cs
+++ /dev/null
@@ -1,1165 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using Lucene.Net.Analysis;
-using Lucene.Net.Documents;
-using Lucene.Net.Index;
-using Lucene.Net.Join;
-using Lucene.Net.Randomized.Generators;
-using Lucene.Net.Search;
-using Lucene.Net.Store;
-using Lucene.Net.Support;
-using Lucene.Net.Util;
-using NUnit.Framework;
-
-namespace Lucene.Net.Tests.Join
-{
-    /*
-	 * 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.
-	 */
-     
-    public class TestJoinUtil : LuceneTestCase
-    {
-        [Test]
-        public void TestSimple()
-        {
-            const string idField = "id";
-            const string toField = "productId";
-
-            Directory dir = NewDirectory();
-            RandomIndexWriter w = new RandomIndexWriter(Random(), dir,
-                NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()))
-                    .SetMergePolicy(NewLogMergePolicy()));
-
-            // 0
-            Document doc = new Document();
-            doc.Add(new TextField("description", "random text", Field.Store.NO));
-            doc.Add(new TextField("name", "name1", Field.Store.NO));
-            doc.Add(new TextField(idField, "1", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 1
-            doc = new Document();
-            doc.Add(new TextField("price", "10.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "2", Field.Store.NO));
-            doc.Add(new TextField(toField, "1", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 2
-            doc = new Document();
-            doc.Add(new TextField("price", "20.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "3", Field.Store.NO));
-            doc.Add(new TextField(toField, "1", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 3
-            doc = new Document();
-            doc.Add(new TextField("description", "more random text", Field.Store.NO));
-            doc.Add(new TextField("name", "name2", Field.Store.NO));
-            doc.Add(new TextField(idField, "4", Field.Store.NO));
-            w.AddDocument(doc);
-            w.Commit();
-
-            // 4
-            doc = new Document();
-            doc.Add(new TextField("price", "10.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "5", Field.Store.NO));
-            doc.Add(new TextField(toField, "4", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 5
-            doc = new Document();
-            doc.Add(new TextField("price", "20.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "6", Field.Store.NO));
-            doc.Add(new TextField(toField, "4", Field.Store.NO));
-            w.AddDocument(doc);
-
-            IndexSearcher indexSearcher = new IndexSearcher(w.Reader);
-            w.Dispose();
-
-            // Search for product
-            Query joinQuery = JoinUtil.CreateJoinQuery(idField, false, toField, new TermQuery(new Term("name", "name2")),
-                indexSearcher, ScoreMode.None);
-
-            TopDocs result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(2, result.TotalHits);
-            assertEquals(4, result.ScoreDocs[0].Doc);
-            assertEquals(5, result.ScoreDocs[1].Doc);
-
-            joinQuery = JoinUtil.CreateJoinQuery(idField, false, toField, new TermQuery(new Term("name", "name1")),
-                indexSearcher, ScoreMode.None);
-            result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(2, result.TotalHits);
-            assertEquals(1, result.ScoreDocs[0].Doc);
-            assertEquals(2, result.ScoreDocs[1].Doc);
-
-            // Search for offer
-            joinQuery = JoinUtil.CreateJoinQuery(toField, false, idField, new TermQuery(new Term("id", "5")),
-                indexSearcher, ScoreMode.None);
-            result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(1, result.TotalHits);
-            assertEquals(3, result.ScoreDocs[0].Doc);
-
-            indexSearcher.IndexReader.Dispose();
-            dir.Dispose();
-        }
-
-        // TermsWithScoreCollector.MV.Avg forgets to grow beyond TermsWithScoreCollector.INITIAL_ARRAY_SIZE
-        [Test]
-        public void TestOverflowTermsWithScoreCollector()
-        {
-            Test300spartans(true, ScoreMode.Avg);
-        }
-
-        [Test]
-        public void TestOverflowTermsWithScoreCollectorRandom()
-        {
-            var scoreModeLength = Enum.GetNames(typeof(ScoreMode)).Length;
-            Test300spartans(Random().NextBoolean(), (ScoreMode) Random().Next(scoreModeLength));
-        }
-
-        protected virtual void Test300spartans(bool multipleValues, ScoreMode scoreMode)
-        {
-            const string idField = "id";
-            const string toField = "productId";
-
-            Directory dir = NewDirectory();
-            RandomIndexWriter w = new RandomIndexWriter(Random(), dir,
-                NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()))
-                    .SetMergePolicy(NewLogMergePolicy()));
-
-            // 0
-            Document doc = new Document();
-            doc.Add(new TextField("description", "random text", Field.Store.NO));
-            doc.Add(new TextField("name", "name1", Field.Store.NO));
-            doc.Add(new TextField(idField, "0", Field.Store.NO));
-            w.AddDocument(doc);
-
-            doc = new Document();
-            doc.Add(new TextField("price", "10.0", Field.Store.NO));
-            for (int i = 0; i < 300; i++)
-            {
-                doc.Add(new TextField(toField, "" + i, Field.Store.NO));
-                if (!multipleValues)
-                {
-                    w.AddDocument(doc);
-                    doc.RemoveFields(toField);
-                }
-            }
-            w.AddDocument(doc);
-
-            IndexSearcher indexSearcher = new IndexSearcher(w.Reader);
-            w.Dispose();
-
-            // Search for product
-            Query joinQuery = JoinUtil.CreateJoinQuery(toField, multipleValues, idField,
-                new TermQuery(new Term("price", "10.0")), indexSearcher, scoreMode);
-
-            TopDocs result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(1, result.TotalHits);
-            assertEquals(0, result.ScoreDocs[0].Doc);
-
-
-            indexSearcher.IndexReader.Dispose();
-            dir.Dispose();
-        }
-
-        /// <summary>
-        /// LUCENE-5487: verify a join query inside a SHOULD BQ
-        ///  will still use the join query's optimized BulkScorers 
-        /// </summary>
-        [Test]
-        public void TestInsideBooleanQuery()
-        {
-            const string idField = "id";
-            const string toField = "productId";
-
-            Directory dir = NewDirectory();
-            RandomIndexWriter w = new RandomIndexWriter(Random(), dir,
-                NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()))
-                    .SetMergePolicy(NewLogMergePolicy()));
-
-            // 0
-            Document doc = new Document();
-            doc.Add(new TextField("description", "random text", Field.Store.NO));
-            doc.Add(new TextField("name", "name1", Field.Store.NO));
-            doc.Add(new TextField(idField, "7", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 1
-            doc = new Document();
-            doc.Add(new TextField("price", "10.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "2", Field.Store.NO));
-            doc.Add(new TextField(toField, "7", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 2
-            doc = new Document();
-            doc.Add(new TextField("price", "20.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "3", Field.Store.NO));
-            doc.Add(new TextField(toField, "7", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 3
-            doc = new Document();
-            doc.Add(new TextField("description", "more random text", Field.Store.NO));
-            doc.Add(new TextField("name", "name2", Field.Store.NO));
-            doc.Add(new TextField(idField, "0", Field.Store.NO));
-            w.AddDocument(doc);
-            w.Commit();
-
-            // 4
-            doc = new Document();
-            doc.Add(new TextField("price", "10.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "5", Field.Store.NO));
-            doc.Add(new TextField(toField, "0", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 5
-            doc = new Document();
-            doc.Add(new TextField("price", "20.0", Field.Store.NO));
-            doc.Add(new TextField(idField, "6", Field.Store.NO));
-            doc.Add(new TextField(toField, "0", Field.Store.NO));
-            w.AddDocument(doc);
-
-            w.ForceMerge(1);
-
-            IndexSearcher indexSearcher = new IndexSearcher(w.Reader);
-            w.Dispose();
-
-            // Search for product
-            Query joinQuery = JoinUtil.CreateJoinQuery(idField, false, toField,
-                new TermQuery(new Term("description", "random")), indexSearcher, ScoreMode.Avg);
-
-            BooleanQuery bq = new BooleanQuery();
-            bq.Add(joinQuery, BooleanClause.Occur.SHOULD);
-            bq.Add(new TermQuery(new Term("id", "3")), BooleanClause.Occur.SHOULD);
-
-            indexSearcher.Search(bq, new CollectorAnonymousInnerClassHelper(this));
-
-            indexSearcher.IndexReader.Dispose();
-            dir.Dispose();
-        }
-
-        private class CollectorAnonymousInnerClassHelper : Collector
-        {
-            private readonly TestJoinUtil OuterInstance;
-
-            public CollectorAnonymousInnerClassHelper(TestJoinUtil outerInstance)
-            {
-                OuterInstance = outerInstance;
-            }
-
-            internal bool sawFive;
-
-            public override AtomicReaderContext NextReader
-            {
-                set { }
-            }
-
-            public override void Collect(int docID)
-            {
-                // Hairy / evil (depends on how BooleanScorer
-                // stores temporarily collected docIDs by
-                // appending to head of linked list):
-                if (docID == 5)
-                {
-                    sawFive = true;
-                }
-                else if (docID == 1)
-                {
-                    assertFalse("optimized bulkScorer was not used for join query embedded in boolean query!", sawFive);
-                }
-            }
-
-            public override Scorer Scorer
-            {
-                set { }
-            }
-
-            public override bool AcceptsDocsOutOfOrder()
-            {
-                return true;
-            }
-        }
-
-        [Test]
-        public void TestSimpleWithScoring()
-        {
-            const string idField = "id";
-            const string toField = "movieId";
-
-            Directory dir = NewDirectory();
-            RandomIndexWriter w = new RandomIndexWriter(Random(), dir,
-                NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random()))
-                    .SetMergePolicy(NewLogMergePolicy()));
-
-            // 0
-            Document doc = new Document();
-            doc.Add(new TextField("description", "A random movie", Field.Store.NO));
-            doc.Add(new TextField("name", "Movie 1", Field.Store.NO));
-            doc.Add(new TextField(idField, "1", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 1
-            doc = new Document();
-            doc.Add(new TextField("subtitle", "The first subtitle of this movie", Field.Store.NO));
-            doc.Add(new TextField(idField, "2", Field.Store.NO));
-            doc.Add(new TextField(toField, "1", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 2
-            doc = new Document();
-            doc.Add(new TextField("subtitle", "random subtitle; random event movie", Field.Store.NO));
-            doc.Add(new TextField(idField, "3", Field.Store.NO));
-            doc.Add(new TextField(toField, "1", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 3
-            doc = new Document();
-            doc.Add(new TextField("description", "A second random movie", Field.Store.NO));
-            doc.Add(new TextField("name", "Movie 2", Field.Store.NO));
-            doc.Add(new TextField(idField, "4", Field.Store.NO));
-            w.AddDocument(doc);
-            w.Commit();
-
-            // 4
-            doc = new Document();
-            doc.Add(new TextField("subtitle", "a very random event happened during christmas night", Field.Store.NO));
-            doc.Add(new TextField(idField, "5", Field.Store.NO));
-            doc.Add(new TextField(toField, "4", Field.Store.NO));
-            w.AddDocument(doc);
-
-            // 5
-            doc = new Document();
-            doc.Add(new TextField("subtitle", "movie end movie test 123 test 123 random", Field.Store.NO));
-            doc.Add(new TextField(idField, "6", Field.Store.NO));
-            doc.Add(new TextField(toField, "4", Field.Store.NO));
-            w.AddDocument(doc);
-
-            IndexSearcher indexSearcher = new IndexSearcher(w.Reader);
-            w.Dispose();
-
-            // Search for movie via subtitle
-            Query joinQuery = JoinUtil.CreateJoinQuery(toField, false, idField,
-                new TermQuery(new Term("subtitle", "random")), indexSearcher, ScoreMode.Max);
-            TopDocs result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(2, result.TotalHits);
-            assertEquals(0, result.ScoreDocs[0].Doc);
-            assertEquals(3, result.ScoreDocs[1].Doc);
-
-            // Score mode max.
-            joinQuery = JoinUtil.CreateJoinQuery(toField, false, idField, new TermQuery(new Term("subtitle", "movie")),
-                indexSearcher, ScoreMode.Max);
-            result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(2, result.TotalHits);
-            assertEquals(3, result.ScoreDocs[0].Doc);
-            assertEquals(0, result.ScoreDocs[1].Doc);
-
-            // Score mode total
-            joinQuery = JoinUtil.CreateJoinQuery(toField, false, idField, new TermQuery(new Term("subtitle", "movie")),
-                indexSearcher, ScoreMode.Total);
-            result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(2, result.TotalHits);
-            assertEquals(0, result.ScoreDocs[0].Doc);
-            assertEquals(3, result.ScoreDocs[1].Doc);
-
-            //Score mode avg
-            joinQuery = JoinUtil.CreateJoinQuery(toField, false, idField, new TermQuery(new Term("subtitle", "movie")),
-                indexSearcher, ScoreMode.Avg);
-            result = indexSearcher.Search(joinQuery, 10);
-            assertEquals(2, result.TotalHits);
-            assertEquals(3, result.ScoreDocs[0].Doc);
-            assertEquals(0, result.ScoreDocs[1].Doc);
-
-            indexSearcher.IndexReader.Dispose();
-            dir.Dispose();
-        }
-
-        [Test]
-        public void TestSingleValueRandomJoin()
-        {
-            int maxIndexIter = TestUtil.NextInt(Random(), 6, 12);
-            int maxSearchIter = TestUtil.NextInt(Random(), 13, 26);
-            ExecuteRandomJoin(false, maxIndexIter, maxSearchIter, TestUtil.NextInt(Random(), 87, 764));
-        }
-
-        [Test]
-        public void TestMultiValueRandomJoin()
-            // this test really takes more time, that is why the number of iterations are smaller.
-        {
-            int maxIndexIter = TestUtil.NextInt(Random(), 3, 6);
-            int maxSearchIter = TestUtil.NextInt(Random(), 6, 12);
-            ExecuteRandomJoin(true, maxIndexIter, maxSearchIter, TestUtil.NextInt(Random(), 11, 57));
-        }
-        
-        private void ExecuteRandomJoin(bool multipleValuesPerDocument, int maxIndexIter, int maxSearchIter,
-            int numberOfDocumentsToIndex)
-        {
-            for (int indexIter = 1; indexIter <= maxIndexIter; indexIter++)
-            {
-                if (VERBOSE)
-                {
-                    Console.WriteLine("indexIter=" + indexIter);
-                }
-                Directory dir = NewDirectory();
-                RandomIndexWriter w = new RandomIndexWriter(Random(), dir,
-                    NewIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(Random(), MockTokenizer.KEYWORD, false))
-                        .SetMergePolicy(NewLogMergePolicy()));
-                bool scoreDocsInOrder = TestJoinUtil.Random().NextBoolean();
-                IndexIterationContext context = CreateContext(numberOfDocumentsToIndex, w, multipleValuesPerDocument,
-                    scoreDocsInOrder);
-
-                IndexReader topLevelReader = w.Reader;
-                w.Dispose();
-                for (int searchIter = 1; searchIter <= maxSearchIter; searchIter++)
-                {
-                    if (VERBOSE)
-                    {
-                        Console.WriteLine("searchIter=" + searchIter);
-                    }
-                    IndexSearcher indexSearcher = NewSearcher(topLevelReader);
-
-                    int r = Random().Next(context.RandomUniqueValues.Length);
-                    bool from = context.RandomFrom[r];
-                    string randomValue = context.RandomUniqueValues[r];
-                    FixedBitSet expectedResult = CreateExpectedResult(randomValue, from, indexSearcher.IndexReader,
-                        context);
-
-                    Query actualQuery = new TermQuery(new Term("value", randomValue));
-                    if (VERBOSE)
-                    {
-                        Console.WriteLine("actualQuery=" + actualQuery);
-                    }
-                    
-                    var scoreModeLength = Enum.GetNames(typeof(ScoreMode)).Length;
-                    ScoreMode scoreMode = (ScoreMode) Random().Next(scoreModeLength);
-                    if (VERBOSE)
-                    {
-                        Console.WriteLine("scoreMode=" + scoreMode);
-                    }
-
-                    Query joinQuery;
-                    if (from)
-                    {
-                        joinQuery = JoinUtil.CreateJoinQuery("from", multipleValuesPerDocument, "to", actualQuery,
-                            indexSearcher, scoreMode);
-                    }
-                    else
-                    {
-                        joinQuery = JoinUtil.CreateJoinQuery("to", multipleValuesPerDocument, "from", actualQuery,
-                            indexSearcher, scoreMode);
-                    }
-                    if (VERBOSE)
-                    {
-                        Console.WriteLine("joinQuery=" + joinQuery);
-                    }
-
-                    // Need to know all documents that have matches. TopDocs doesn't give me that and then I'd be also testing TopDocsCollector...
-                    FixedBitSet actualResult = new FixedBitSet(indexSearcher.IndexReader.MaxDoc);
-                    TopScoreDocCollector topScoreDocCollector = TopScoreDocCollector.Create(10, false);
-                    indexSearcher.Search(joinQuery,
-                        new CollectorAnonymousInnerClassHelper2(this, scoreDocsInOrder, context, actualResult,
-                            topScoreDocCollector));
-                    // Asserting bit set...
-                    if (VERBOSE)
-                    {
-                        Console.WriteLine("expected cardinality:" + expectedResult.Cardinality());
-                        DocIdSetIterator iterator = expectedResult.GetIterator();
-                        for (int doc = iterator.NextDoc();
-                            doc != DocIdSetIterator.NO_MORE_DOCS;
-                            doc = iterator.NextDoc())
-                        {
-                            Console.WriteLine(string.Format("Expected doc[{0}] with id value {1}", doc, indexSearcher.Doc(doc).Get("id")));
-                        }
-                        Console.WriteLine("actual cardinality:" + actualResult.Cardinality());
-                        iterator = actualResult.GetIterator();
-                        for (int doc = iterator.NextDoc();
-                            doc != DocIdSetIterator.NO_MORE_DOCS;
-                            doc = iterator.NextDoc())
-                        {
-                            Console.WriteLine(string.Format("Actual doc[{0}] with id value {1}", doc, indexSearcher.Doc(doc).Get("id")));
-                        }
-                    }
-                    assertEquals(expectedResult, actualResult);
-
-                    // Asserting TopDocs...
-                    TopDocs expectedTopDocs = CreateExpectedTopDocs(randomValue, from, scoreMode, context);
-                    TopDocs actualTopDocs = topScoreDocCollector.TopDocs();
-                    assertEquals(expectedTopDocs.TotalHits, actualTopDocs.TotalHits);
-                    assertEquals(expectedTopDocs.ScoreDocs.Length, actualTopDocs.ScoreDocs.Length);
-                    if (scoreMode == ScoreMode.None)
-                    {
-                        continue;
-                    }
-
-                    assertEquals(expectedTopDocs.MaxScore, actualTopDocs.MaxScore, 0.0f);
-                    for (int i = 0; i < expectedTopDocs.ScoreDocs.Length; i++)
-                    {
-                        if (VERBOSE)
-                        {
-                            string.Format("Expected doc: {0} | Actual doc: {1}\n", expectedTopDocs.ScoreDocs[i].Doc, actualTopDocs.ScoreDocs[i].Doc);
-                            string.Format("Expected score: {0} | Actual score: {1}\n", expectedTopDocs.ScoreDocs[i].Score, actualTopDocs.ScoreDocs[i].Score);
-                        }
-                        assertEquals(expectedTopDocs.ScoreDocs[i].Doc, actualTopDocs.ScoreDocs[i].Doc);
-                        assertEquals(expectedTopDocs.ScoreDocs[i].Score, actualTopDocs.ScoreDocs[i].Score, 0.0f);
-                        Explanation explanation = indexSearcher.Explain(joinQuery, expectedTopDocs.ScoreDocs[i].Doc);
-                        assertEquals(expectedTopDocs.ScoreDocs[i].Score, explanation.Value, 0.0f);
-                    }
-                }
-                topLevelReader.Dispose();
-                dir.Dispose();
-            }
-        }
-
-        private class CollectorAnonymousInnerClassHelper2 : Collector
-        {
-            private readonly TestJoinUtil OuterInstance;
-
-            private bool ScoreDocsInOrder;
-            private IndexIterationContext Context;
-            private FixedBitSet ActualResult;
-            private TopScoreDocCollector TopScoreDocCollector;
-
-            public CollectorAnonymousInnerClassHelper2(TestJoinUtil outerInstance, bool scoreDocsInOrder,
-                IndexIterationContext context, FixedBitSet actualResult,
-                TopScoreDocCollector topScoreDocCollector)
-            {
-                OuterInstance = outerInstance;
-                ScoreDocsInOrder = scoreDocsInOrder;
-                Context = context;
-                ActualResult = actualResult;
-                TopScoreDocCollector = topScoreDocCollector;
-            }
-
-
-            private int _docBase;
-            
-            public override void Collect(int doc)
-            {
-                ActualResult.Set(doc + _docBase);
-                TopScoreDocCollector.Collect(doc);
-            }
-
-            public override AtomicReaderContext NextReader
-            {
-                set
-                {
-                    _docBase = value.DocBase;
-                    TopScoreDocCollector.NextReader = value;
-                }
-            }
-            
-            public override Scorer Scorer
-            {
-                set { TopScoreDocCollector.Scorer = value; }
-            }
-
-            public override bool AcceptsDocsOutOfOrder()
-            {
-                return ScoreDocsInOrder;
-            }
-        }
-        
-        private IndexIterationContext CreateContext(int nDocs, RandomIndexWriter writer, bool multipleValuesPerDocument,
-            bool scoreDocsInOrder)
-        {
-            return CreateContext(nDocs, writer, writer, multipleValuesPerDocument, scoreDocsInOrder);
-        }
-        
-        private IndexIterationContext CreateContext(int nDocs, RandomIndexWriter fromWriter, RandomIndexWriter toWriter,
-            bool multipleValuesPerDocument, bool scoreDocsInOrder)
-        {
-            IndexIterationContext context = new IndexIterationContext();
-            int numRandomValues = nDocs/2;
-            context.RandomUniqueValues = new string[numRandomValues];
-            ISet<string> trackSet = new HashSet<string>();
-            context.RandomFrom = new bool[numRandomValues];
-            for (int i = 0; i < numRandomValues; i++)
-            {
-                string uniqueRandomValue;
-                do
-                {
-                    uniqueRandomValue = TestUtil.RandomRealisticUnicodeString(Random());
-                    //        uniqueRandomValue = TestUtil.randomSimpleString(random);
-                } while ("".Equals(uniqueRandomValue) || trackSet.Contains(uniqueRandomValue));
-                // Generate unique values and empty strings aren't allowed.
-                trackSet.Add(uniqueRandomValue);
-                context.RandomFrom[i] = Random().NextBoolean();
-                context.RandomUniqueValues[i] = uniqueRandomValue;
-            }
-
-            RandomDoc[] docs = new RandomDoc[nDocs];
-            for (int i = 0; i < nDocs; i++)
-            {
-                string id = Convert.ToString(i);
-                int randomI = Random().Next(context.RandomUniqueValues.Length);
-                string value = context.RandomUniqueValues[randomI];
-                Document document = new Document();
-                document.Add(NewTextField(Random(), "id", id, Field.Store.NO));
-                document.Add(NewTextField(Random(), "value", value, Field.Store.NO));
-
-                bool from = context.RandomFrom[randomI];
-                int numberOfLinkValues = multipleValuesPerDocument ? 2 + Random().Next(10) : 1;
-                docs[i] = new RandomDoc(id, numberOfLinkValues, value, from);
-                for (int j = 0; j < numberOfLinkValues; j++)
-                {
-                    string linkValue = context.RandomUniqueValues[Random().Next(context.RandomUniqueValues.Length)];
-                    docs[i].LinkValues.Add(linkValue);
-                    if (from)
-                    {
-                        if (!context.FromDocuments.ContainsKey(linkValue))
-                        {
-                            context.FromDocuments[linkValue] = new List<RandomDoc>();
-                        }
-                        if (!context.RandomValueFromDocs.ContainsKey(value))
-                        {
-                            context.RandomValueFromDocs[value] = new List<RandomDoc>();
-                        }
-
-                        context.FromDocuments[linkValue].Add(docs[i]);
-                        context.RandomValueFromDocs[value].Add(docs[i]);
-                        document.Add(NewTextField(Random(), "from", linkValue, Field.Store.NO));
-                    }
-                    else
-                    {
-                        if (!context.ToDocuments.ContainsKey(linkValue))
-                        {
-                            context.ToDocuments[linkValue] = new List<RandomDoc>();
-                        }
-                        if (!context.RandomValueToDocs.ContainsKey(value))
-                        {
-                            context.RandomValueToDocs[value] = new List<RandomDoc>();
-                        }
-
-                        context.ToDocuments[linkValue].Add(docs[i]);
-                        context.RandomValueToDocs[value].Add(docs[i]);
-                        document.Add(NewTextField(Random(), "to", linkValue, Field.Store.NO));
-                    }
-                }
-
-                RandomIndexWriter w;
-                if (from)
-                {
-                    w = fromWriter;
-                }
-                else
-                {
-                    w = toWriter;
-                }
-
-                w.AddDocument(document);
-                if (Random().Next(10) == 4)
-                {
-                    w.Commit();
-                }
-                if (VERBOSE)
-                {
-                    Console.WriteLine("Added document[" + docs[i].Id + "]: " + document);
-                }
-            }
-
-            // Pre-compute all possible hits for all unique random values. On top of this also compute all possible score for
-            // any ScoreMode.
-            IndexSearcher fromSearcher = NewSearcher(fromWriter.Reader);
-            IndexSearcher toSearcher = NewSearcher(toWriter.Reader);
-            for (int i = 0; i < context.RandomUniqueValues.Length; i++)
-            {
-                string uniqueRandomValue = context.RandomUniqueValues[i];
-                string fromField;
-                string toField;
-                IDictionary<string, IDictionary<int, JoinScore>> queryVals;
-                if (context.RandomFrom[i])
-                {
-                    fromField = "from";
-                    toField = "to";
-                    queryVals = context.FromHitsToJoinScore;
-                }
-                else
-                {
-                    fromField = "to";
-                    toField = "from";
-                    queryVals = context.ToHitsToJoinScore;
-                }
-                IDictionary<BytesRef, JoinScore> joinValueToJoinScores = new Dictionary<BytesRef, JoinScore>();
-                if (multipleValuesPerDocument)
-                {
-                    fromSearcher.Search(new TermQuery(new Term("value", uniqueRandomValue)),
-                        new CollectorAnonymousInnerClassHelper3(this, context, fromField, joinValueToJoinScores));
-                }
-                else
-                {
-                    fromSearcher.Search(new TermQuery(new Term("value", uniqueRandomValue)),
-                        new CollectorAnonymousInnerClassHelper4(this, context, fromField, joinValueToJoinScores));
-                }
-
-                IDictionary<int, JoinScore> docToJoinScore = new Dictionary<int, JoinScore>();
-                if (multipleValuesPerDocument)
-                {
-                    if (scoreDocsInOrder)
-                    {
-                        AtomicReader slowCompositeReader = SlowCompositeReaderWrapper.Wrap(toSearcher.IndexReader);
-                        Terms terms = slowCompositeReader.Terms(toField);
-                        if (terms != null)
-                        {
-                            DocsEnum docsEnum = null;
-                            TermsEnum termsEnum = null;
-                            SortedSet<BytesRef> joinValues =
-                                new SortedSet<BytesRef>(BytesRef.UTF8SortedAsUnicodeComparer);
-                            joinValues.AddAll(joinValueToJoinScores.Keys);
-                            foreach (BytesRef joinValue in joinValues)
-                            {
-                                termsEnum = terms.Iterator(termsEnum);
-                                if (termsEnum.SeekExact(joinValue))
-                                {
-                                    docsEnum = termsEnum.Docs(slowCompositeReader.LiveDocs, docsEnum, DocsEnum.FLAG_NONE);
-                                    JoinScore joinScore = joinValueToJoinScores[joinValue];
-
-                                    for (int doc = docsEnum.NextDoc();
-                                        doc != DocIdSetIterator.NO_MORE_DOCS;
-                                        doc = docsEnum.NextDoc())
-                                    {
-                                        // First encountered join value determines the score.
-                                        // Something to keep in mind for many-to-many relations.
-                                        if (!docToJoinScore.ContainsKey(doc))
-                                        {
-                                            docToJoinScore[doc] = joinScore;
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    else
-                    {
-                        toSearcher.Search(new MatchAllDocsQuery(),
-                            new CollectorAnonymousInnerClassHelper5(this, context, toField, joinValueToJoinScores,
-                                docToJoinScore));
-                    }
-                }
-                else
-                {
-                    toSearcher.Search(new MatchAllDocsQuery(),
-                        new CollectorAnonymousInnerClassHelper6(this, context, toField, joinValueToJoinScores,
-                            docToJoinScore));
-                }
-                queryVals[uniqueRandomValue] = docToJoinScore;
-            }
-
-            fromSearcher.IndexReader.Dispose();
-            toSearcher.IndexReader.Dispose();
-
-            return context;
-        }
-
-        private class CollectorAnonymousInnerClassHelper3 : Collector
-        {
-            private readonly TestJoinUtil OuterInstance;
-
-            private IndexIterationContext Context;
-            private string FromField;
-            private IDictionary<BytesRef, JoinScore> JoinValueToJoinScores;
-
-            public CollectorAnonymousInnerClassHelper3(TestJoinUtil outerInstance,
-                IndexIterationContext context, string fromField,
-                IDictionary<BytesRef, JoinScore> joinValueToJoinScores)
-            {
-                OuterInstance = outerInstance;
-                Context = context;
-                FromField = fromField;
-                JoinValueToJoinScores = joinValueToJoinScores;
-                joinValue = new BytesRef();
-            }
-
-
-            private Scorer scorer;
-            private SortedSetDocValues docTermOrds;
-            internal readonly BytesRef joinValue;
-            
-            public override void Collect(int doc)
-            {
-                docTermOrds.Document = doc;
-                long ord;
-                while ((ord = docTermOrds.NextOrd()) != SortedSetDocValues.NO_MORE_ORDS)
-                {
-                    docTermOrds.LookupOrd(ord, joinValue);
-                    var joinScore = JoinValueToJoinScores[joinValue];
-                    if (joinScore == null)
-                    {
-                        JoinValueToJoinScores[BytesRef.DeepCopyOf(joinValue)] = joinScore = new JoinScore();
-                    }
-                    joinScore.AddScore(scorer.Score());
-                }
-            }
-            
-            public override AtomicReaderContext NextReader
-            {
-                set { docTermOrds = FieldCache.DEFAULT.GetDocTermOrds(value.AtomicReader, FromField); }
-            }
-
-            public override Scorer Scorer
-            {
-                set { scorer = value; }
-            }
-
-            public override bool AcceptsDocsOutOfOrder()
-            {
-                return false;
-            }
-        }
-
-        private class CollectorAnonymousInnerClassHelper4 : Collector
-        {
-            private readonly TestJoinUtil OuterInstance;
-
-            private IndexIterationContext Context;
-            private string FromField;
-            private IDictionary<BytesRef, JoinScore> JoinValueToJoinScores;
-
-            public CollectorAnonymousInnerClassHelper4(TestJoinUtil outerInstance,
-                IndexIterationContext context, string fromField,
-                IDictionary<BytesRef, JoinScore> joinValueToJoinScores)
-            {
-                OuterInstance = outerInstance;
-                Context = context;
-                FromField = fromField;
-                JoinValueToJoinScores = joinValueToJoinScores;
-                spare = new BytesRef();
-            }
-
-
-            private Scorer scorer;
-            private BinaryDocValues terms;
-            private Bits docsWithField;
-            private readonly BytesRef spare;
-            
-            public override void Collect(int doc)
-            {
-                terms.Get(doc, spare);
-                BytesRef joinValue = spare;
-                if (joinValue.Length == 0 && !docsWithField.Get(doc))
-                {
-                    return;
-                }
-
-                var joinScore = JoinValueToJoinScores[joinValue];
-                if (joinScore == null)
-                {
-                    JoinValueToJoinScores[BytesRef.DeepCopyOf(joinValue)] = joinScore = new JoinScore();
-                }
-                joinScore.AddScore(scorer.Score());
-            }
-            
-            public override AtomicReaderContext NextReader
-            {
-                set
-                {
-                    terms = FieldCache.DEFAULT.GetTerms(value.AtomicReader, FromField, true);
-                    docsWithField = FieldCache.DEFAULT.GetDocsWithField(value.AtomicReader, FromField);
-                }
-            }
-
-            public override Scorer Scorer
-            {
-                set { scorer = value; }
-            }
-
-            public override bool AcceptsDocsOutOfOrder()
-            {
-                return false;
-            }
-        }
-
-        private class CollectorAnonymousInnerClassHelper5 : Collector
-        {
-            private readonly TestJoinUtil OuterInstance;
-
-            private string _toField;
-            private readonly IDictionary<BytesRef, JoinScore> _joinValueToJoinScores;
-            private readonly IDictionary<int, JoinScore> _docToJoinScore;
-
-            private SortedSetDocValues docTermOrds;
-            private readonly BytesRef scratch;
-            private int docBase;
-
-            public CollectorAnonymousInnerClassHelper5(TestJoinUtil testJoinUtil, IndexIterationContext context, 
-                string toField, IDictionary<BytesRef, JoinScore> joinValueToJoinScores, 
-                IDictionary<int, JoinScore> docToJoinScore)
-            {
-                OuterInstance = testJoinUtil;
-                _toField = toField;
-                _joinValueToJoinScores = joinValueToJoinScores;
-                _docToJoinScore = docToJoinScore;
-            }
-
-            public override void Collect(int doc)
-            {
-                docTermOrds.Document = doc;
-                long ord;
-                while ((ord = docTermOrds.NextOrd()) != SortedSetDocValues.NO_MORE_ORDS)
-                {
-                    docTermOrds.LookupOrd(ord, scratch);
-                    JoinScore joinScore = _joinValueToJoinScores[scratch];
-                    if (joinScore == null)
-                    {
-                        continue;
-                    }
-                    int basedDoc = docBase + doc;
-                    // First encountered join value determines the score.
-                    // Something to keep in mind for many-to-many relations.
-                    if (!_docToJoinScore.ContainsKey(basedDoc))
-                    {
-                        _docToJoinScore[basedDoc] = joinScore;
-                    }
-                }
-            }
-            
-            public override AtomicReaderContext NextReader
-            {
-                set
-                {
-                    docBase = value.DocBase;
-                    docTermOrds = FieldCache.DEFAULT.GetDocTermOrds(value.AtomicReader, _toField);
-                }
-            }
-
-            public override bool AcceptsDocsOutOfOrder()
-            {
-                return false;
-            }
-
-            public override Scorer Scorer
-            {
-                set { }
-            }
-        }
-
-        private class CollectorAnonymousInnerClassHelper6 : Collector
-        {
-            private readonly TestJoinUtil OuterInstance;
-
-            private IndexIterationContext Context;
-            private string ToField;
-            private IDictionary<BytesRef, JoinScore> JoinValueToJoinScores;
-            private IDictionary<int, JoinScore> DocToJoinScore;
-
-            private BinaryDocValues terms;
-            private int docBase;
-            private readonly BytesRef spare;
-
-            public CollectorAnonymousInnerClassHelper6(TestJoinUtil testJoinUtil, 
-                IndexIterationContext context, string toField, 
-                IDictionary<BytesRef, JoinScore> joinValueToJoinScores, 
-                IDictionary<int, JoinScore> docToJoinScore)
-            {
-                OuterInstance = testJoinUtil;
-                ToField = toField;
-                JoinValueToJoinScores = joinValueToJoinScores;
-                DocToJoinScore = docToJoinScore;
-            }
-
-            public override void Collect(int doc)
-            {
-                terms.Get(doc, spare);
-                JoinScore joinScore = JoinValueToJoinScores[spare];
-                if (joinScore == null)
-                {
-                    return;
-                }
-                DocToJoinScore[docBase + doc] = joinScore;
-            }
-            
-            public override AtomicReaderContext NextReader
-            {
-                set
-                {
-                    terms = FieldCache.DEFAULT.GetTerms(value.AtomicReader, ToField, false);
-                    docBase = value.DocBase;
-                }
-            }
-
-            public override bool AcceptsDocsOutOfOrder()
-            {
-                return false;
-            }
-
-            public override Scorer Scorer
-            {
-                set { }
-            }
-        }
-
-        private TopDocs CreateExpectedTopDocs(string queryValue, bool from, ScoreMode scoreMode,
-            IndexIterationContext context)
-        {
-            var hitsToJoinScores = @from
-                ? context.FromHitsToJoinScore[queryValue]
-                : context.ToHitsToJoinScore[queryValue];
-
-            var hits = new List<KeyValuePair<int, JoinScore>>(hitsToJoinScores.EntrySet());
-            hits.Sort(new ComparatorAnonymousInnerClassHelper(this, scoreMode));
-            ScoreDoc[] scoreDocs = new ScoreDoc[Math.Min(10, hits.Count)];
-            for (int i = 0; i < scoreDocs.Length; i++)
-            {
-                KeyValuePair<int, JoinScore> hit = hits[i];
-                scoreDocs[i] = new ScoreDoc(hit.Key, hit.Value.Score(scoreMode));
-            }
-            return new TopDocs(hits.Count, scoreDocs, hits.Count == 0 ? float.NaN : hits[0].Value.Score(scoreMode));
-        }
-
-        private class ComparatorAnonymousInnerClassHelper : IComparer<KeyValuePair<int, JoinScore>>
-        {
-            private readonly TestJoinUtil OuterInstance;
-
-            private ScoreMode ScoreMode;
-
-            public ComparatorAnonymousInnerClassHelper(TestJoinUtil outerInstance, ScoreMode scoreMode)
-            {
-                OuterInstance = outerInstance;
-                ScoreMode = scoreMode;
-            }
-
-            public virtual int Compare(KeyValuePair<int, JoinScore> hit1, KeyValuePair<int, JoinScore> hit2)
-            {
-                float score1 = hit1.Value.Score(ScoreMode);
-                float score2 = hit2.Value.Score(ScoreMode);
-
-                int cmp = score2.CompareTo(score1);
-                if (cmp != 0)
-                {
-                    return cmp;
-                }
-                return hit1.Key - hit2.Key;
-            }
-        }
-
-        private FixedBitSet CreateExpectedResult(string queryValue, bool from, IndexReader topLevelReader,
-            IndexIterationContext context)
-        {
-            IDictionary<string, IList<RandomDoc>> randomValueDocs;
-            IDictionary<string, IList<RandomDoc>> linkValueDocuments;
-            if (from)
-            {
-                randomValueDocs = context.RandomValueFromDocs;
-                linkValueDocuments = context.ToDocuments;
-            }
-            else
-            {
-                randomValueDocs = context.RandomValueToDocs;
-                linkValueDocuments = context.FromDocuments;
-            }
-
-            FixedBitSet expectedResult = new FixedBitSet(topLevelReader.MaxDoc);
-            IList<RandomDoc> matchingDocs = randomValueDocs[queryValue];
-            if (matchingDocs == null)
-            {
-                return new FixedBitSet(topLevelReader.MaxDoc);
-            }
-
-            foreach (RandomDoc matchingDoc in matchingDocs)
-            {
-                foreach (string linkValue in matchingDoc.LinkValues)
-                {
-                    IList<RandomDoc> otherMatchingDocs = linkValueDocuments[linkValue];
-                    if (otherMatchingDocs == null)
-                    {
-                        continue;
-                    }
-
-                    foreach (RandomDoc otherSideDoc in otherMatchingDocs)
-                    {
-                        DocsEnum docsEnum = MultiFields.GetTermDocsEnum(topLevelReader,
-                            MultiFields.GetLiveDocs(topLevelReader), "id", new BytesRef(otherSideDoc.Id), 0);
-                        Debug.Assert(docsEnum != null);
-                        int doc = docsEnum.NextDoc();
-                        expectedResult.Set(doc);
-                    }
-                }
-            }
-            return expectedResult;
-        }
-
-        private class IndexIterationContext
-        {
-
-            internal string[] RandomUniqueValues;
-            internal bool[] RandomFrom;
-            internal IDictionary<string, IList<RandomDoc>> FromDocuments = new Dictionary<string, IList<RandomDoc>>();
-            internal IDictionary<string, IList<RandomDoc>> ToDocuments = new Dictionary<string, IList<RandomDoc>>();
-
-            internal IDictionary<string, IList<RandomDoc>> RandomValueFromDocs =
-                new Dictionary<string, IList<RandomDoc>>();
-
-            internal IDictionary<string, IList<RandomDoc>> RandomValueToDocs =
-                new Dictionary<string, IList<RandomDoc>>();
-
-            internal IDictionary<string, IDictionary<int, JoinScore>> FromHitsToJoinScore =
-                new Dictionary<string, IDictionary<int, JoinScore>>();
-
-            internal IDictionary<string, IDictionary<int, JoinScore>> ToHitsToJoinScore =
-                new Dictionary<string, IDictionary<int, JoinScore>>();
-        }
-
-        private class RandomDoc
-        {
-            internal readonly string Id;
-            internal readonly IList<string> LinkValues;
-            internal readonly string Value;
-            internal readonly bool From;
-
-            internal RandomDoc(string id, int numberOfLinkValues, string value, bool from)
-            {
-                Id = id;
-                From = from;
-                LinkValues = new List<string>(numberOfLinkValues);
-                Value = value;
-            }
-        }
-
-        private class JoinScore
-        {
-            internal float MaxScore;
-            internal float Total;
-            internal int Count;
-
-            internal virtual void AddScore(float score)
-            {
-                Total += score;
-                if (score > MaxScore)
-                {
-                    MaxScore = score;
-                }
-                Count++;
-            }
-
-            internal virtual float Score(ScoreMode mode)
-            {
-                switch (mode)
-                {
-                    case ScoreMode.None:
-                        return 1.0f;
-                    case ScoreMode.Total:
-                        return Total;
-                    case ScoreMode.Avg:
-                        return Total/Count;
-                    case ScoreMode.Max:
-                        return MaxScore;
-                }
-                throw new ArgumentException("Unsupported ScoreMode: " + mode);
-            }
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4820f236/Lucene.Net.Tests.Join/packages.config
----------------------------------------------------------------------
diff --git a/Lucene.Net.Tests.Join/packages.config b/Lucene.Net.Tests.Join/packages.config
deleted file mode 100644
index f0ed309..0000000
--- a/Lucene.Net.Tests.Join/packages.config
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Apache.NMS" version="1.6.0.3083" targetFramework="net451" />
-  <package id="NUnit" version="2.6.3" targetFramework="net451" />
-</packages>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4820f236/Lucene.Net.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.sln b/Lucene.Net.sln
index 2051e77..debbc08 100644
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@ -38,11 +38,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Codecs", "src\Lu
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Codecs.Tests", "src\Lucene.Net.Tests.Codecs\Lucene.Net.Codecs.Tests.csproj", "{351B75B1-BBD5-4E32-8036-7BED4E0135A6}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Join", "Lucene.Net.Join\Lucene.Net.Join.csproj", "{E8A339C7-FCF6-4A72-8586-56D8961D7B99}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Join", "src\Lucene.Net.Join\Lucene.Net.Join.csproj", "{E8A339C7-FCF6-4A72-8586-56D8961D7B99}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Grouping", "Lucene.Net.Grouping\Lucene.Net.Grouping.csproj", "{02BAB603-067D-48B1-AEDD-316849652568}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Grouping", "src\Lucene.Net.Grouping\Lucene.Net.Grouping.csproj", "{02BAB603-067D-48B1-AEDD-316849652568}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Join", "Lucene.Net.Tests.Join\Lucene.Net.Tests.Join.csproj", "{4C1B794F-8158-45E6-85B3-2C46569BEBC2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Join", "src\Lucene.Net.Tests.Join\Lucene.Net.Tests.Join.csproj", "{4C1B794F-8158-45E6-85B3-2C46569BEBC2}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4820f236/src/Lucene.Net.Grouping/GroupDocs.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Grouping/GroupDocs.cs b/src/Lucene.Net.Grouping/GroupDocs.cs
new file mode 100644
index 0000000..00cdf83
--- /dev/null
+++ b/src/Lucene.Net.Grouping/GroupDocs.cs
@@ -0,0 +1,71 @@
+using Lucene.Net.Search;
+
+namespace Lucene.Net.Grouping
+{
+    /*
+	 * 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>
+    /// Represents one group in the results.
+    /// 
+    /// @lucene.experimental 
+    /// </summary>
+    public class GroupDocs<TGroupValueType>
+    {
+        /// <summary>
+        /// The groupField value for all docs in this group; this
+        /// may be null if hits did not have the groupField. 
+        /// </summary>
+        public readonly TGroupValueType GroupValue;
+
+        /// <summary>
+        /// Max score in this group
+        /// </summary>
+        public readonly float MaxScore;
+
+        /// <summary>
+        /// Overall aggregated score of this group (currently only set by join queries). 
+        /// </summary>
+        public readonly float Score;
+
+        /// <summary>
+        /// Hits; this may be {@link org.apache.lucene.search.FieldDoc} instances if the
+        /// withinGroupSort sorted by fields. 
+        /// </summary>
+        public readonly ScoreDoc[] ScoreDocs;
+
+        /// <summary>
+        /// Total hits within this group
+        /// </summary>
+        public readonly int TotalHits;
+
+        /// <summary>
+        /// Matches the groupSort passed to {@link AbstractFirstPassGroupingCollector}. 
+        /// </summary>
+        public readonly object[] GroupSortValues;
+
+        public GroupDocs(float score, float maxScore, int totalHits, ScoreDoc[] scoreDocs, TGroupValueType groupValue, object[] groupSortValues)
+        {
+            Score = score;
+            MaxScore = maxScore;
+            TotalHits = totalHits;
+            ScoreDocs = scoreDocs;
+            GroupValue = groupValue;
+            GroupSortValues = groupSortValues;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4820f236/src/Lucene.Net.Grouping/Lucene.Net.Grouping.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Grouping/Lucene.Net.Grouping.csproj b/src/Lucene.Net.Grouping/Lucene.Net.Grouping.csproj
new file mode 100644
index 0000000..5d4fbe2
--- /dev/null
+++ b/src/Lucene.Net.Grouping/Lucene.Net.Grouping.csproj
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.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>{02BAB603-067D-48B1-AEDD-316849652568}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Grouping</RootNamespace>
+    <AssemblyName>Lucene.Net.Grouping</AssemblyName>
+    <TargetFrameworkVersion>v4.5.1</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.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="GroupDocs.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TopGroups.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/4820f236/src/Lucene.Net.Grouping/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Grouping/Properties/AssemblyInfo.cs b/src/Lucene.Net.Grouping/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..9e6c1ce
--- /dev/null
+++ b/src/Lucene.Net.Grouping/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+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.Grouping")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Lucene.Net.Grouping")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[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("02bab603-067d-48b1-aedd-316849652568")]
+
+// 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")]