You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2017/07/06 13:07:08 UTC

[11/14] lucenenet git commit: Ported Lucene.Net.Demo + tests (minus the FormBasedXmlQueryDemo QueryParser.Xml demo)

Ported Lucene.Net.Demo + tests (minus the FormBasedXmlQueryDemo QueryParser.Xml demo)


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

Branch: refs/heads/master
Commit: 775df65469e68271dc0610f91f13c4819034aa4b
Parents: bfccac0
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Jul 6 18:41:46 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Jul 6 18:41:46 2017 +0700

----------------------------------------------------------------------
 Lucene.Net.Portable.sln                         |  20 +
 Lucene.Net.sln                                  |  52 ++
 .../Facet/AssociationsFacetsExample.cs          | 178 +++++
 .../Facet/DistanceFacetsExample.cs              | 275 ++++++++
 .../Facet/ExpressionAggregationFacetsExample.cs | 129 ++++
 .../Facet/MultiCategoryListsFacetsExample.cs    | 148 ++++
 src/Lucene.Net.Demo/Facet/RangeFacetsExample.cs | 151 +++++
 .../Facet/SimpleFacetsExample.cs                | 274 ++++++++
 .../Facet/SimpleSortedSetFacetsExample.cs       | 171 +++++
 src/Lucene.Net.Demo/IndexFiles.cs               | 223 ++++++
 src/Lucene.Net.Demo/Lucene.Net.Demo.csproj      | 119 ++++
 .../Lucene.Net.Demo.project.json                |   8 +
 src/Lucene.Net.Demo/Lucene.Net.Demo.xproj       |  21 +
 src/Lucene.Net.Demo/Properties/AssemblyInfo.cs  |  51 ++
 src/Lucene.Net.Demo/SearchFiles.cs              | 313 +++++++++
 src/Lucene.Net.Demo/project.json                |  45 ++
 src/Lucene.Net.Facet/DrillSideways.cs           |   2 +-
 src/Lucene.Net.Facet/FacetResult.cs             |   1 +
 .../Facet/TestAssociationsFacetsExample.cs      |  44 ++
 .../Facet/TestDistanceFacetsExample.cs          |  50 ++
 .../TestExpressionAggregationFacetsExample.cs   |  36 +
 .../TestMultiCategoryListsFacetsExample.cs      |  37 +
 .../Facet/TestRangeFacetsExample.cs             |  50 ++
 .../Facet/TestSimpleFacetsExample.cs            |  61 ++
 .../Facet/TestSimpleSortedSetFacetsExample.cs   |  45 ++
 .../Lucene.Net.Tests.Demo.csproj                | 125 ++++
 .../Lucene.Net.Tests.Demo.project.json          |  11 +
 .../Lucene.Net.Tests.Demo.xproj                 |  22 +
 .../Properties/AssemblyInfo.cs                  |  42 ++
 .../Test-Files/Docs/apache1.0.txt               |  56 ++
 .../Test-Files/Docs/apache1.1.txt               |  58 ++
 .../Test-Files/Docs/apache2.0.txt               | 201 ++++++
 .../Test-Files/Docs/cpl1.0.txt                  |  74 ++
 .../Test-Files/Docs/epl1.0.txt                  |  88 +++
 .../Test-Files/Docs/freebsd.txt                 |  10 +
 .../Test-Files/Docs/gpl1.0.txt                  | 250 +++++++
 .../Test-Files/Docs/gpl2.0.txt                  | 339 ++++++++++
 .../Test-Files/Docs/gpl3.0.txt                  | 674 +++++++++++++++++++
 .../Test-Files/Docs/lgpl2.1.txt                 | 504 ++++++++++++++
 .../Test-Files/Docs/lgpl3.txt                   | 165 +++++
 .../Test-Files/Docs/lpgl2.0.txt                 | 481 +++++++++++++
 .../Test-Files/Docs/mit.txt                     |  22 +
 .../Test-Files/Docs/mozilla1.1.txt              | 470 +++++++++++++
 .../Test-Files/Docs/mozilla_eula_firefox3.txt   |  29 +
 .../Docs/mozilla_eula_thunderbird2.txt          |  27 +
 src/Lucene.Net.Tests.Demo/TestDemo.cs           | 101 +++
 src/Lucene.Net.Tests.Demo/project.json          |  47 ++
 47 files changed, 6299 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/Lucene.Net.Portable.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.Portable.sln b/Lucene.Net.Portable.sln
index 0b7f53e..9e3b91d 100644
--- a/Lucene.Net.Portable.sln
+++ b/Lucene.Net.Portable.sln
@@ -93,6 +93,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Analysis.Phoneti
 EndProject
 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Analysis.Phonetic", "src\Lucene.Net.Tests.Analysis.Phonetic\Lucene.Net.Tests.Analysis.Phonetic.xproj", "{1FE12EF7-4C89-4D49-BDD1-E49DC285F21B}"
 EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Demo", "src\Lucene.Net.Demo\Lucene.Net.Demo.xproj", "{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Demo", "src\Lucene.Net.Tests.Demo\Lucene.Net.Tests.Demo.xproj", "{93DF8BAA-9CAA-4142-8E96-55481188C012}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -429,6 +433,22 @@ Global
 		{1FE12EF7-4C89-4D49-BDD1-E49DC285F21B}.Release|Any CPU.Build.0 = Release|Any CPU
 		{1FE12EF7-4C89-4D49-BDD1-E49DC285F21B}.Release|x86.ActiveCfg = Release|Any CPU
 		{1FE12EF7-4C89-4D49-BDD1-E49DC285F21B}.Release|x86.Build.0 = Release|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Debug|x86.Build.0 = Debug|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Release|x86.ActiveCfg = Release|Any CPU
+		{4BCD7980-0CF4-4DA0-B069-F555A41CB44D}.Release|x86.Build.0 = Release|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Debug|x86.Build.0 = Debug|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Release|Any CPU.Build.0 = Release|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Release|x86.ActiveCfg = Release|Any CPU
+		{93DF8BAA-9CAA-4142-8E96-55481188C012}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/Lucene.Net.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.sln b/Lucene.Net.sln
index 74a64a3..a187ccc 100644
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@ -102,6 +102,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Analysis.Phoneti
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Analysis.Phonetic", "src\Lucene.Net.Tests.Analysis.Phonetic\Lucene.Net.Tests.Analysis.Phonetic.csproj", "{A2867797-0A5D-4878-8F59-58C399C9A4E4}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Demo", "src\Lucene.Net.Demo\Lucene.Net.Demo.csproj", "{D1661154-8F5B-499A-8B2D-04B8A67F4232}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Demo", "src\Lucene.Net.Tests.Demo\Lucene.Net.Tests.Demo.csproj", "{571B361E-B0D4-445E-A0BC-1A24AA184258}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -1007,6 +1011,54 @@ Global
 		{A2867797-0A5D-4878-8F59-58C399C9A4E4}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
 		{A2867797-0A5D-4878-8F59-58C399C9A4E4}.Release35|x86.ActiveCfg = Release|Any CPU
 		{A2867797-0A5D-4878-8F59-58C399C9A4E4}.Release35|x86.Build.0 = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug|x86.Build.0 = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug35|x86.ActiveCfg = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Debug35|x86.Build.0 = Debug|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release|x86.ActiveCfg = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release|x86.Build.0 = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release35|Any CPU.Build.0 = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release35|x86.ActiveCfg = Release|Any CPU
+		{D1661154-8F5B-499A-8B2D-04B8A67F4232}.Release35|x86.Build.0 = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug|x86.Build.0 = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug35|x86.ActiveCfg = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Debug35|x86.Build.0 = Debug|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release|Any CPU.Build.0 = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release|x86.ActiveCfg = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release|x86.Build.0 = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|Any CPU.Build.0 = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|x86.ActiveCfg = Release|Any CPU
+		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Facet/AssociationsFacetsExample.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Facet/AssociationsFacetsExample.cs b/src/Lucene.Net.Demo/Facet/AssociationsFacetsExample.cs
new file mode 100644
index 0000000..f3649d0
--- /dev/null
+++ b/src/Lucene.Net.Demo/Facet/AssociationsFacetsExample.cs
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+// Lucene.Net.Facet
+
+using Lucene.Net.Analysis.Core;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Demo.Facet
+{
+    /// <summary>
+    /// Shows example usage of category associations.
+    /// </summary>
+    public class AssociationsFacetsExample
+    {
+        /// <summary>
+        /// Using a constant for all functionality related to a specific index
+        /// is the best strategy. This allows you to upgrade Lucene.Net first
+        /// and plan the upgrade of the index binary format for a later time. 
+        /// Once the index is upgraded, you simply need to update the constant 
+        /// version and redeploy your application.
+        /// </summary>
+        private const LuceneVersion EXAMPLE_VERSION = LuceneVersion.LUCENE_48;
+
+        private readonly Directory indexDir = new RAMDirectory();
+        private readonly Directory taxoDir = new RAMDirectory();
+        private readonly FacetsConfig config;
+
+        /// <summary>Empty constructor</summary>
+        public AssociationsFacetsExample()
+        {
+            config = new FacetsConfig();
+            config.SetMultiValued("tags", true);
+            config.SetIndexFieldName("tags", "$tags");
+            config.SetMultiValued("genre", true);
+            config.SetIndexFieldName("genre", "$genre");
+        }
+
+        /// <summary>Build the example index.</summary>
+        private void Index()
+        {
+            IndexWriterConfig iwc = new IndexWriterConfig(EXAMPLE_VERSION,
+                                                  new WhitespaceAnalyzer(EXAMPLE_VERSION));
+            using (IndexWriter indexWriter = new IndexWriter(indexDir, iwc))
+
+            // Writes facet ords to a separate directory from the main index
+            using (DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir))
+            {
+
+                Document doc = new Document();
+                // 3 occurrences for tag 'lucene'
+
+                // LUCENENET TODO: Create extension methods for built-in field types ( .AddFacetField("", ""), .AddInt32AssociationsFacetField(), etc ).
+                doc.Add(new Int32AssociationFacetField(3, "tags", "lucene"));
+                // 87% confidence level of genre 'computing'
+                doc.Add(new SingleAssociationFacetField(0.87f, "genre", "computing"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                // 1 occurrence for tag 'lucene'
+                doc.Add(new Int32AssociationFacetField(1, "tags", "lucene"));
+                // 2 occurrence for tag 'solr'
+                doc.Add(new Int32AssociationFacetField(2, "tags", "solr"));
+                // 75% confidence level of genre 'computing'
+                doc.Add(new SingleAssociationFacetField(0.75f, "genre", "computing"));
+                // 34% confidence level of genre 'software'
+                doc.Add(new SingleAssociationFacetField(0.34f, "genre", "software"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+            } // Disposes indexWriter and taxoWriter
+        }
+
+        /// <summary>User runs a query and aggregates facets by summing their association values.</summary>
+        private IList<FacetResult> SumAssociations()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+
+                FacetsCollector fc = new FacetsCollector();
+
+                // MatchAllDocsQuery is for "browsing" (counts facets
+                // for all non-deleted docs in the index); normally
+                // you'd use a "normal" query:
+                FacetsCollector.Search(searcher, new MatchAllDocsQuery(), 10, fc);
+
+                Facets tags = new TaxonomyFacetSumInt32Associations("$tags", taxoReader, config, fc);
+                Facets genre = new TaxonomyFacetSumSingleAssociations("$genre", taxoReader, config, fc);
+
+                // Retrieve results
+                IList<FacetResult> results = new List<FacetResult>();
+
+                results.Add(tags.GetTopChildren(10, "tags"));
+                results.Add(genre.GetTopChildren(10, "genre"));
+
+                return results;
+
+            } // Disposes indexReader and taxoReader
+        }
+
+        /// <summary>User drills down on 'tags/solr'.</summary>
+        private FacetResult DrillDown()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+
+                // Passing no baseQuery means we drill down on all
+                // documents ("browse only"):
+                DrillDownQuery q = new DrillDownQuery(config);
+
+                // Now user drills down on Publish Date/2010:
+                q.Add("tags", "solr");
+                FacetsCollector fc = new FacetsCollector();
+                FacetsCollector.Search(searcher, q, 10, fc);
+
+                // Retrieve results
+                Facets facets = new TaxonomyFacetSumSingleAssociations("$genre", taxoReader, config, fc);
+                FacetResult result = facets.GetTopChildren(10, "genre");
+
+                return result;
+
+            } // Disposes indexReader and taxoReader
+        }
+
+        /// <summary>Runs summing association example.</summary>
+        public IList<FacetResult> RunSumAssociations()
+        {
+            Index();
+            return SumAssociations();
+        }
+
+        /// <summary>Runs the drill-down example.</summary>
+        public FacetResult RunDrillDown()
+        {
+            Index();
+            return DrillDown();
+        }
+
+        /// <summary>Runs the sum int/float associations examples and prints the results.</summary>
+        public static void Main(string[] args)
+        {
+            Console.WriteLine("Sum associations example:");
+            Console.WriteLine("-------------------------");
+            IList<FacetResult> results = new AssociationsFacetsExample().RunSumAssociations();
+            Console.WriteLine("tags: " + results[0]);
+            Console.WriteLine("genre: " + results[1]);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Facet/DistanceFacetsExample.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Facet/DistanceFacetsExample.cs b/src/Lucene.Net.Demo/Facet/DistanceFacetsExample.cs
new file mode 100644
index 0000000..5c5c7d8
--- /dev/null
+++ b/src/Lucene.Net.Demo/Facet/DistanceFacetsExample.cs
@@ -0,0 +1,275 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+// Lucene.Net.Expressions
+// Lucene.Net.Facet
+
+using Lucene.Net.Analysis.Core;
+using Lucene.Net.Documents;
+using Lucene.Net.Expressions;
+using Lucene.Net.Expressions.JS;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Range;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Index;
+using Lucene.Net.Queries;
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using System;
+using System.Diagnostics;
+using System.Globalization;
+
+namespace Lucene.Net.Demo.Facet
+{
+    /// <summary>
+    /// Shows simple usage of dynamic range faceting, using the
+    /// expressions module to calculate distance.
+    /// </summary>
+    public class DistanceFacetsExample : IDisposable
+    {
+        /// <summary>
+        /// Using a constant for all functionality related to a specific index
+        /// is the best strategy. This allows you to upgrade Lucene.Net first
+        /// and plan the upgrade of the index binary format for a later time. 
+        /// Once the index is upgraded, you simply need to update the constant 
+        /// version and redeploy your application.
+        /// </summary>
+        private const LuceneVersion EXAMPLE_VERSION = LuceneVersion.LUCENE_48;
+
+        internal static readonly DoubleRange ONE_KM = new DoubleRange("< 1 km", 0.0, true, 1.0, false);
+        internal static readonly DoubleRange TWO_KM = new DoubleRange("< 2 km", 0.0, true, 2.0, false);
+        internal static readonly DoubleRange FIVE_KM = new DoubleRange("< 5 km", 0.0, true, 5.0, false);
+        internal static readonly DoubleRange TEN_KM = new DoubleRange("< 10 km", 0.0, true, 10.0, false);
+
+        private readonly Directory indexDir = new RAMDirectory();
+        private IndexSearcher searcher;
+        private readonly FacetsConfig config = new FacetsConfig();
+
+        /// <summary>The "home" latitude.</summary>
+        public readonly static double ORIGIN_LATITUDE = 40.7143528;
+
+        /// <summary>The "home" longitude.</summary>
+        public readonly static double ORIGIN_LONGITUDE = -74.0059731;
+
+        /// <summary>
+        /// Radius of the Earth in KM
+        /// <para/>
+        /// NOTE: this is approximate, because the earth is a bit
+        /// wider at the equator than the poles.  See
+        /// http://en.wikipedia.org/wiki/Earth_radius
+        /// </summary>
+        public readonly static double EARTH_RADIUS_KM = 6371.01;
+
+        /// <summary>Build the example index.</summary>
+        public void Index()
+        {
+            using (IndexWriter writer = new IndexWriter(indexDir, new IndexWriterConfig(EXAMPLE_VERSION,
+                new WhitespaceAnalyzer(EXAMPLE_VERSION))))
+            {
+                // TODO: we could index in radians instead ... saves all the conversions in GetBoundingBoxFilter
+
+                // Add documents with latitude/longitude location:
+                Document doc = new Document();
+                doc.Add(new DoubleField("latitude", 40.759011, Field.Store.NO));
+                doc.Add(new DoubleField("longitude", -73.9844722, Field.Store.NO));
+                writer.AddDocument(doc);
+
+                doc = new Document();
+                doc.Add(new DoubleField("latitude", 40.718266, Field.Store.NO));
+                doc.Add(new DoubleField("longitude", -74.007819, Field.Store.NO));
+                writer.AddDocument(doc);
+
+                doc = new Document();
+                doc.Add(new DoubleField("latitude", 40.7051157, Field.Store.NO));
+                doc.Add(new DoubleField("longitude", -74.0088305, Field.Store.NO));
+                writer.AddDocument(doc);
+
+                // Open near-real-time searcher
+                searcher = new IndexSearcher(DirectoryReader.Open(writer, true));
+
+            } // Disposes writer
+        }
+
+        private ValueSource GetDistanceValueSource()
+        {
+            Expression distance = JavascriptCompiler.Compile(
+                string.Format(CultureInfo.InvariantCulture, "haversin({0:R},{1:R},latitude,longitude)", ORIGIN_LATITUDE, ORIGIN_LONGITUDE));
+
+            SimpleBindings bindings = new SimpleBindings();
+            bindings.Add(new SortField("latitude", SortFieldType.DOUBLE));
+            bindings.Add(new SortField("longitude", SortFieldType.DOUBLE));
+
+            return distance.GetValueSource(bindings);
+        }
+
+        /// <summary>
+        /// Given a latitude and longitude (in degrees) and the
+        /// maximum great circle (surface of the earth) distance,
+        /// returns a simple Filter bounding box to "fast match"
+        /// candidates.
+        /// </summary>
+        public static Filter GetBoundingBoxFilter(double originLat, double originLng, double maxDistanceKM)
+        {
+            // Basic bounding box geo math from
+            // http://JanMatuschek.de/LatitudeLongitudeBoundingCoordinates,
+            // licensed under creative commons 3.0:
+            // http://creativecommons.org/licenses/by/3.0
+
+            // TODO: maybe switch to recursive prefix tree instead
+            // (in lucene/spatial)?  It should be more efficient
+            // since it's a 2D trie...
+
+            // Degrees -> Radians:
+            double originLatRadians = originLat.ToRadians();
+            double originLngRadians = originLng.ToRadians();
+
+            double angle = maxDistanceKM / (SloppyMath.EarthDiameter(originLat) / 2.0);
+
+            double minLat = originLatRadians - angle;
+            double maxLat = originLatRadians + angle;
+
+            double minLng;
+            double maxLng;
+            if (minLat > -90.ToRadians() && maxLat < 90.ToRadians())
+            {
+                double delta = Math.Asin(Math.Sin(angle) / Math.Cos(originLatRadians));
+                minLng = originLngRadians - delta;
+                if (minLng < -180.ToRadians())
+                {
+                    minLng += 2 * Math.PI;
+                }
+                maxLng = originLngRadians + delta;
+                if (maxLng > 180.ToRadians())
+                {
+                    maxLng -= 2 * Math.PI;
+                }
+            }
+            else
+            {
+                // The query includes a pole!
+                minLat = Math.Max(minLat, -90.ToRadians());
+                maxLat = Math.Min(maxLat, 90.ToRadians());
+                minLng = -180.ToRadians();
+                maxLng = 180.ToRadians();
+            }
+
+            BooleanFilter f = new BooleanFilter();
+
+            // Add latitude range filter:
+            f.Add(NumericRangeFilter.NewDoubleRange("latitude", minLat.ToDegrees(), maxLat.ToDegrees(), true, true),
+                  Occur.MUST);
+
+            // Add longitude range filter:
+            if (minLng > maxLng)
+            {
+                // The bounding box crosses the international date
+                // line:
+                BooleanFilter lonF = new BooleanFilter();
+                lonF.Add(NumericRangeFilter.NewDoubleRange("longitude", minLng.ToDegrees(), null, true, true),
+                         Occur.SHOULD);
+                lonF.Add(NumericRangeFilter.NewDoubleRange("longitude", null, maxLng.ToDegrees(), true, true),
+                         Occur.SHOULD);
+                f.Add(lonF, Occur.MUST);
+            }
+            else
+            {
+                f.Add(NumericRangeFilter.NewDoubleRange("longitude", minLng.ToDegrees(), maxLng.ToDegrees(), true, true),
+                      Occur.MUST);
+            }
+
+            return f;
+        }
+
+        /// <summary>User runs a query and counts facets.</summary>
+        public FacetResult Search()
+        {
+            FacetsCollector fc = new FacetsCollector();
+
+            searcher.Search(new MatchAllDocsQuery(), fc);
+
+            Facets facets = new DoubleRangeFacetCounts("field", GetDistanceValueSource(), fc,
+                                                       GetBoundingBoxFilter(ORIGIN_LATITUDE, ORIGIN_LONGITUDE, 10.0),
+                                                       ONE_KM,
+                                                       TWO_KM,
+                                                       FIVE_KM,
+                                                       TEN_KM);
+
+            return facets.GetTopChildren(10, "field");
+        }
+
+        /// <summary>User drills down on the specified range.</summary>
+        public TopDocs DrillDown(DoubleRange range)
+        {
+            // Passing no baseQuery means we drill down on all
+            // documents ("browse only"):
+            DrillDownQuery q = new DrillDownQuery(null);
+            ValueSource vs = GetDistanceValueSource();
+            q.Add("field", range.GetFilter(GetBoundingBoxFilter(ORIGIN_LATITUDE, ORIGIN_LONGITUDE, range.Max), vs));
+            DrillSideways ds = new SearchDrillSideways(searcher, config, vs);
+            return ds.Search(q, 10).Hits;
+        }
+
+        private class SearchDrillSideways : DrillSideways
+        {
+            private readonly ValueSource vs;
+
+            public SearchDrillSideways(IndexSearcher indexSearcher, FacetsConfig facetsConfig, ValueSource valueSource)
+                : base(indexSearcher, facetsConfig, (TaxonomyReader)null)
+            {
+                this.vs = valueSource;
+            }
+
+            protected override Facets BuildFacetsResult(FacetsCollector drillDowns, FacetsCollector[] drillSideways, string[] drillSidewaysDims)
+            {
+                Debug.Assert(drillSideways.Length == 1);
+                return new DoubleRangeFacetCounts("field", vs, drillSideways[0], ONE_KM, TWO_KM, FIVE_KM, TEN_KM);
+            }
+        }
+
+        public void Dispose()
+        {
+            searcher?.IndexReader?.Dispose();
+            indexDir?.Dispose();
+        }
+
+        /// <summary>Runs the search and drill-down examples and prints the results.</summary>
+        public static void Main(string[] args)
+        {
+            using (DistanceFacetsExample example = new DistanceFacetsExample())
+            {
+                example.Index();
+
+                Console.WriteLine("Distance facet counting example:");
+                Console.WriteLine("-----------------------");
+                Console.WriteLine(example.Search());
+
+                Console.WriteLine("\n");
+                Console.WriteLine("Distance facet drill-down example (field/< 2 km):");
+                Console.WriteLine("---------------------------------------------");
+                TopDocs hits = example.DrillDown(TWO_KM);
+                Console.WriteLine(hits.TotalHits + " totalHits");
+
+            } // Disposes example
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Facet/ExpressionAggregationFacetsExample.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Facet/ExpressionAggregationFacetsExample.cs b/src/Lucene.Net.Demo/Facet/ExpressionAggregationFacetsExample.cs
new file mode 100644
index 0000000..c080b5a
--- /dev/null
+++ b/src/Lucene.Net.Demo/Facet/ExpressionAggregationFacetsExample.cs
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+// Lucene.Net.Expressions
+// Lucene.Net.Facet
+
+using Lucene.Net.Analysis.Core;
+using Lucene.Net.Documents;
+using Lucene.Net.Expressions;
+using Lucene.Net.Expressions.JS;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
+
+namespace Lucene.Net.Demo.Facet
+{
+    /// <summary>
+    /// Shows facets aggregation by an expression.
+    /// </summary>
+    public class ExpressionAggregationFacetsExample
+    {
+        /// <summary>
+        /// Using a constant for all functionality related to a specific index
+        /// is the best strategy. This allows you to upgrade Lucene.Net first
+        /// and plan the upgrade of the index binary format for a later time. 
+        /// Once the index is upgraded, you simply need to update the constant 
+        /// version and redeploy your application.
+        /// </summary>
+        private const LuceneVersion EXAMPLE_VERSION = LuceneVersion.LUCENE_48;
+
+        private readonly Directory indexDir = new RAMDirectory();
+        private readonly Directory taxoDir = new RAMDirectory();
+        private readonly FacetsConfig config = new FacetsConfig();
+
+        /// <summary>Build the example index.</summary>
+        private void Index()
+        {
+            using (IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(EXAMPLE_VERSION,
+                new WhitespaceAnalyzer(EXAMPLE_VERSION))))
+            // Writes facet ords to a separate directory from the main index
+            using (DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir))
+            {
+
+                Document doc = new Document();
+                doc.Add(new TextField("c", "foo bar", Field.Store.NO));
+                doc.Add(new NumericDocValuesField("popularity", 5L));
+                doc.Add(new FacetField("A", "B"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new TextField("c", "foo foo bar", Field.Store.NO));
+                doc.Add(new NumericDocValuesField("popularity", 3L));
+                doc.Add(new FacetField("A", "C"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+            } // Disposes indexWriter and taxoWriter
+        }
+
+        /// <summary>User runs a query and aggregates facets.</summary>
+        private FacetResult Search()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+
+                // Aggregate categories by an expression that combines the document's score
+                // and its popularity field
+                Expression expr = JavascriptCompiler.Compile("_score * sqrt(popularity)");
+                SimpleBindings bindings = new SimpleBindings();
+                bindings.Add(new SortField("_score", SortFieldType.SCORE)); // the score of the document
+                bindings.Add(new SortField("popularity", SortFieldType.INT64)); // the value of the 'popularity' field
+
+                // Aggregates the facet values
+                FacetsCollector fc = new FacetsCollector(true);
+
+                // MatchAllDocsQuery is for "browsing" (counts facets
+                // for all non-deleted docs in the index); normally
+                // you'd use a "normal" query:
+                FacetsCollector.Search(searcher, new MatchAllDocsQuery(), 10, fc);
+
+                // Retrieve results
+                Facets facets = new TaxonomyFacetSumValueSource(taxoReader, config, fc, expr.GetValueSource(bindings));
+                FacetResult result = facets.GetTopChildren(10, "A");
+
+                return result;
+
+            } // Disposes indexReader and taxoReader
+        }
+
+        /// <summary>Runs the search example.</summary>
+        public FacetResult RunSearch()
+        {
+            Index();
+            return Search();
+        }
+
+        /// <summary>Runs the search and drill-down examples and prints the results.</summary>
+        public static void Main(string[] args)
+        {
+            Console.WriteLine("Facet counting example:");
+            Console.WriteLine("-----------------------");
+            FacetResult result = new ExpressionAggregationFacetsExample().RunSearch();
+            Console.WriteLine(result);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Facet/MultiCategoryListsFacetsExample.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Facet/MultiCategoryListsFacetsExample.cs b/src/Lucene.Net.Demo/Facet/MultiCategoryListsFacetsExample.cs
new file mode 100644
index 0000000..a99fb4d
--- /dev/null
+++ b/src/Lucene.Net.Demo/Facet/MultiCategoryListsFacetsExample.cs
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+// Lucene.Net.Facet
+
+using Lucene.Net.Analysis.Core;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Demo.Facet
+{
+    /// <summary>
+    /// Demonstrates indexing categories into different indexed fields.
+    /// </summary>
+    public class MultiCategoryListsFacetsExample
+    {
+        /// <summary>
+        /// Using a constant for all functionality related to a specific index
+        /// is the best strategy. This allows you to upgrade Lucene.Net first
+        /// and plan the upgrade of the index binary format for a later time. 
+        /// Once the index is upgraded, you simply need to update the constant 
+        /// version and redeploy your application.
+        /// </summary>
+        private const LuceneVersion EXAMPLE_VERSION = LuceneVersion.LUCENE_48;
+
+        private readonly Directory indexDir = new RAMDirectory();
+        private readonly Directory taxoDir = new RAMDirectory();
+        private readonly FacetsConfig config = new FacetsConfig();
+
+        /// <summary>Creates a new instance and populates the catetory list params mapping.</summary>
+        public MultiCategoryListsFacetsExample()
+        {
+            config.SetIndexFieldName("Author", "author");
+            config.SetIndexFieldName("Publish Date", "pubdate");
+            config.SetHierarchical("Publish Date", true);
+        }
+
+        /// <summary>Build the example index.</summary>
+        private void Index()
+        {
+            using (IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(EXAMPLE_VERSION,
+                new WhitespaceAnalyzer(EXAMPLE_VERSION))))
+            // Writes facet ords to a separate directory from the main index
+            using (DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir))
+            {
+                Document doc = new Document();
+                
+                doc.Add(new FacetField("Author", "Bob"));
+                doc.Add(new FacetField("Publish Date", "2010", "10", "15"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Lisa"));
+                doc.Add(new FacetField("Publish Date", "2010", "10", "20"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Lisa"));
+                doc.Add(new FacetField("Publish Date", "2012", "1", "1"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Susan"));
+                doc.Add(new FacetField("Publish Date", "2012", "1", "7"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Frank"));
+                doc.Add(new FacetField("Publish Date", "1999", "5", "5"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+            } // Disposes indexWriter and taxoWriter
+        }
+
+        /// <summary>User runs a query and counts facets.</summary>
+        private IList<FacetResult> Search()
+        {
+            IList<FacetResult> results = new List<FacetResult>();
+
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+                FacetsCollector fc = new FacetsCollector();
+
+                // MatchAllDocsQuery is for "browsing" (counts facets
+                // for all non-deleted docs in the index); normally
+                // you'd use a "normal" query:
+                FacetsCollector.Search(searcher, new MatchAllDocsQuery(), 10, fc);
+
+                // Retrieve results
+
+                // Count both "Publish Date" and "Author" dimensions
+                Facets author = new FastTaxonomyFacetCounts("author", taxoReader, config, fc);
+                results.Add(author.GetTopChildren(10, "Author"));
+
+                Facets pubDate = new FastTaxonomyFacetCounts("pubdate", taxoReader, config, fc);
+                results.Add(pubDate.GetTopChildren(10, "Publish Date"));
+
+            } // Disposes indexReader and taxoReader
+
+            return results;
+        }
+
+        /// <summary>Runs the search example.</summary>
+        public IList<FacetResult> RunSearch()
+        {
+            Index();
+            return Search();
+        }
+
+        /// <summary>Runs the search example and prints the results.</summary>
+        public static void Main(string[] args)
+        {
+            Console.WriteLine("Facet counting over multiple category lists example:");
+            Console.WriteLine("-----------------------");
+            IList<FacetResult> results = new MultiCategoryListsFacetsExample().RunSearch();
+
+            Console.WriteLine("Author: " + results[0]);
+            Console.WriteLine("Publish Date: " + results[1]);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Facet/RangeFacetsExample.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Facet/RangeFacetsExample.cs b/src/Lucene.Net.Demo/Facet/RangeFacetsExample.cs
new file mode 100644
index 0000000..180c39b
--- /dev/null
+++ b/src/Lucene.Net.Demo/Facet/RangeFacetsExample.cs
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+// Lucene.Net.Facet
+
+using Lucene.Net.Analysis.Core;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Range;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
+
+namespace Lucene.Net.Demo.Facet
+{
+    /// <summary>
+    /// Shows simple usage of dynamic range faceting.
+    /// </summary>
+    public class RangeFacetsExample : IDisposable
+    {
+        /// <summary>
+        /// Using a constant for all functionality related to a specific index
+        /// is the best strategy. This allows you to upgrade Lucene.Net first
+        /// and plan the upgrade of the index binary format for a later time. 
+        /// Once the index is upgraded, you simply need to update the constant 
+        /// version and redeploy your application.
+        /// </summary>
+        private const LuceneVersion EXAMPLE_VERSION = LuceneVersion.LUCENE_48;
+
+        private readonly Directory indexDir = new RAMDirectory();
+        private IndexSearcher searcher;
+        private readonly long nowSec = DateTime.Now.Ticks;
+
+        internal readonly Int64Range PAST_HOUR;
+        internal readonly Int64Range PAST_SIX_HOURS;
+        internal readonly Int64Range PAST_DAY;
+
+        /// <summary>Constructor</summary>
+        public RangeFacetsExample()
+        {
+            PAST_HOUR = new Int64Range("Past hour", nowSec - 3600, true, nowSec, true);
+            PAST_SIX_HOURS = new Int64Range("Past six hours", nowSec - 6 * 3600, true, nowSec, true);
+            PAST_DAY = new Int64Range("Past day", nowSec - 24 * 3600, true, nowSec, true);
+        }
+
+        /// <summary>Build the example index.</summary>
+        public void Index()
+        {
+            using (IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(EXAMPLE_VERSION,
+                new WhitespaceAnalyzer(EXAMPLE_VERSION))))
+            {
+                // Add documents with a fake timestamp, 1000 sec before
+                // "now", 2000 sec before "now", ...:
+                for (int i = 0; i < 100; i++)
+                {
+                    Document doc = new Document();
+                    long then = nowSec - i * 1000;
+                    // Add as doc values field, so we can compute range facets:
+                    doc.Add(new NumericDocValuesField("timestamp", then));
+                    // Add as numeric field so we can drill-down:
+                    doc.Add(new Int64Field("timestamp", then, Field.Store.NO));
+                    indexWriter.AddDocument(doc);
+                }
+
+                // Open near-real-time searcher
+                searcher = new IndexSearcher(DirectoryReader.Open(indexWriter, true));
+
+            } // Disposes indexWriter
+        }
+
+        private FacetsConfig GetConfig()
+        {
+            return new FacetsConfig();
+        }
+
+        /// <summary>User runs a query and counts facets.</summary>
+        public FacetResult Search()
+        {
+            // Aggregates the facet counts
+            FacetsCollector fc = new FacetsCollector();
+
+            // MatchAllDocsQuery is for "browsing" (counts facets
+            // for all non-deleted docs in the index); normally
+            // you'd use a "normal" query:
+            FacetsCollector.Search(searcher, new MatchAllDocsQuery(), 10, fc);
+
+            Facets facets = new Int64RangeFacetCounts("timestamp", fc,
+                                                     PAST_HOUR,
+                                                     PAST_SIX_HOURS,
+                                                     PAST_DAY);
+            return facets.GetTopChildren(10, "timestamp");
+        }
+
+        /// <summary>User drills down on the specified range.</summary>
+        public TopDocs DrillDown(Int64Range range)
+        {
+            // Passing no baseQuery means we drill down on all
+            // documents ("browse only"):
+            DrillDownQuery q = new DrillDownQuery(GetConfig());
+
+            q.Add("timestamp", NumericRangeQuery.NewInt64Range("timestamp", range.Min, range.Max, range.MinInclusive, range.MaxInclusive));
+
+            return searcher.Search(q, 10);
+        }
+
+        public void Dispose()
+        {
+            searcher?.IndexReader?.Dispose();
+            indexDir?.Dispose();
+        }
+
+        /// <summary>Runs the search and drill-down examples and prints the results.</summary>
+        public static void Main(string[] args)
+        {
+            using (RangeFacetsExample example = new RangeFacetsExample())
+            {
+                example.Index();
+
+                Console.WriteLine("Facet counting example:");
+                Console.WriteLine("-----------------------");
+                Console.WriteLine(example.Search());
+
+                Console.WriteLine("\n");
+                Console.WriteLine("Facet drill-down example (timestamp/Past six hours):");
+                Console.WriteLine("---------------------------------------------");
+                TopDocs hits = example.DrillDown(example.PAST_SIX_HOURS);
+                Console.WriteLine(hits.TotalHits + " TotalHits");
+
+            } // Disposes example
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Facet/SimpleFacetsExample.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Facet/SimpleFacetsExample.cs b/src/Lucene.Net.Demo/Facet/SimpleFacetsExample.cs
new file mode 100644
index 0000000..1e5b49b
--- /dev/null
+++ b/src/Lucene.Net.Demo/Facet/SimpleFacetsExample.cs
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+// Lucene.Net.Facet
+
+using Lucene.Net.Analysis.Core;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Demo.Facet
+{
+    /// <summary>
+    /// Shows simple usage of faceted indexing and search.
+    /// </summary>
+    public class SimpleFacetsExample
+    {
+        /// <summary>
+        /// Using a constant for all functionality related to a specific index
+        /// is the best strategy. This allows you to upgrade Lucene.Net first
+        /// and plan the upgrade of the index binary format for a later time. 
+        /// Once the index is upgraded, you simply need to update the constant 
+        /// version and redeploy your application.
+        /// </summary>
+        private const LuceneVersion EXAMPLE_VERSION = LuceneVersion.LUCENE_48;
+
+        private readonly Directory indexDir = new RAMDirectory();
+        private readonly Directory taxoDir = new RAMDirectory();
+        private readonly FacetsConfig config = new FacetsConfig();
+
+        /// <summary>Constructor</summary>
+        public SimpleFacetsExample()
+        {
+            config.SetHierarchical("Publish Date", true);
+        }
+
+        /// <summary>Build the example index.</summary>
+        private void Index()
+        {
+            using (IndexWriter indexWriter = new IndexWriter(indexDir, new IndexWriterConfig(EXAMPLE_VERSION,
+                new WhitespaceAnalyzer(EXAMPLE_VERSION))))
+
+            // Writes facet ords to a separate directory from the main index
+            using (DirectoryTaxonomyWriter taxoWriter = new DirectoryTaxonomyWriter(taxoDir))
+            {
+
+                Document doc = new Document();
+                doc.Add(new FacetField("Author", "Bob"));
+                doc.Add(new FacetField("Publish Date", "2010", "10", "15"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Lisa"));
+                doc.Add(new FacetField("Publish Date", "2010", "10", "20"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Lisa"));
+                doc.Add(new FacetField("Publish Date", "2012", "1", "1"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Susan"));
+                doc.Add(new FacetField("Publish Date", "2012", "1", "7"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+                doc = new Document();
+                doc.Add(new FacetField("Author", "Frank"));
+                doc.Add(new FacetField("Publish Date", "1999", "5", "5"));
+                indexWriter.AddDocument(config.Build(taxoWriter, doc));
+
+            } // Disposes indexWriter and taxoWriter
+        }
+
+        /// <summary>User runs a query and counts facets.</summary>
+        private IList<FacetResult> FacetsWithSearch()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+
+                FacetsCollector fc = new FacetsCollector();
+
+                // MatchAllDocsQuery is for "browsing" (counts facets
+                // for all non-deleted docs in the index); normally
+                // you'd use a "normal" query:
+                FacetsCollector.Search(searcher, new MatchAllDocsQuery(), 10, fc);
+
+                // Retrieve results
+                IList<FacetResult> results = new List<FacetResult>();
+
+                // Count both "Publish Date" and "Author" dimensions
+                Facets facets = new FastTaxonomyFacetCounts(taxoReader, config, fc);
+                results.Add(facets.GetTopChildren(10, "Author"));
+                results.Add(facets.GetTopChildren(10, "Publish Date"));
+
+                return results;
+
+            } // Disposes indexReader and taxoReader
+        }
+
+        /// <summary>User runs a query and counts facets only without collecting the matching documents.</summary>
+        private IList<FacetResult> FacetsOnly()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+
+                FacetsCollector fc = new FacetsCollector();
+
+                // MatchAllDocsQuery is for "browsing" (counts facets
+                // for all non-deleted docs in the index); normally
+                // you'd use a "normal" query:
+                searcher.Search(new MatchAllDocsQuery(), null /*Filter */, fc);
+
+                // Retrieve results
+                IList<FacetResult> results = new List<FacetResult>();
+
+                // Count both "Publish Date" and "Author" dimensions
+                Facets facets = new FastTaxonomyFacetCounts(taxoReader, config, fc);
+
+                results.Add(facets.GetTopChildren(10, "Author"));
+                results.Add(facets.GetTopChildren(10, "Publish Date"));
+
+                return results;
+
+            } // Disposes indexReader and taxoReader
+        }
+
+        /// <summary>
+        /// User drills down on 'Publish Date/2010', and we
+        /// return facets for 'Author'
+        /// </summary>
+        private FacetResult DrillDown()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+
+                // Passing no baseQuery means we drill down on all
+                // documents ("browse only"):
+                DrillDownQuery q = new DrillDownQuery(config);
+
+                // Now user drills down on Publish Date/2010:
+                q.Add("Publish Date", "2010");
+                FacetsCollector fc = new FacetsCollector();
+                FacetsCollector.Search(searcher, q, 10, fc);
+
+                // Retrieve results
+                Facets facets = new FastTaxonomyFacetCounts(taxoReader, config, fc);
+                FacetResult result = facets.GetTopChildren(10, "Author");
+
+                return result;
+
+            } // Disposes indexReader and taxoReader
+        }
+
+        /// <summary>
+        /// User drills down on 'Publish Date/2010', and we
+        /// return facets for both 'Publish Date' and 'Author',
+        /// using DrillSideways.
+        /// </summary>
+        private IList<FacetResult> DrillSideways()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            using (TaxonomyReader taxoReader = new DirectoryTaxonomyReader(taxoDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+
+                // Passing no baseQuery means we drill down on all
+                // documents ("browse only"):
+                DrillDownQuery q = new DrillDownQuery(config);
+
+                // Now user drills down on Publish Date/2010:
+                q.Add("Publish Date", "2010");
+
+                DrillSideways ds = new DrillSideways(searcher, config, taxoReader);
+                DrillSideways.DrillSidewaysResult result = ds.Search(q, 10);
+
+                // Retrieve results
+                IList<FacetResult> facets = result.Facets.GetAllDims(10);
+
+                return facets;
+
+            } // Disposes indexReader and taxoReader
+        }
+
+        /// <summary>Runs the search example.</summary>
+        public IList<FacetResult> RunFacetOnly()
+        {
+            Index();
+            return FacetsOnly();
+        }
+
+        /// <summary>Runs the search example.</summary>
+        public IList<FacetResult> RunSearch()
+        {
+            Index();
+            return FacetsWithSearch();
+        }
+
+        /// <summary>Runs the drill-down example.</summary>
+        public FacetResult RunDrillDown()
+        {
+            Index();
+            return DrillDown();
+        }
+
+        /// <summary>Runs the drill-sideways example.</summary>
+        public IList<FacetResult> RunDrillSideways()
+        {
+            Index();
+            return DrillSideways();
+        }
+
+        /// <summary>Runs the search and drill-down examples and prints the results.</summary>
+        public static void Main(string[] args)
+        {
+            Console.WriteLine("Facet counting example:");
+            Console.WriteLine("-----------------------");
+            SimpleFacetsExample example1 = new SimpleFacetsExample();
+            IList<FacetResult> results1 = example1.RunFacetOnly();
+            Console.WriteLine("Author: " + results1[0]);
+            Console.WriteLine("Publish Date: " + results1[1]);
+
+            Console.WriteLine("Facet counting example (combined facets and search):");
+            Console.WriteLine("-----------------------");
+            SimpleFacetsExample example = new SimpleFacetsExample();
+            IList<FacetResult> results = example.RunSearch();
+            Console.WriteLine("Author: " + results[0]);
+            Console.WriteLine("Publish Date: " + results[1]);
+
+            Console.WriteLine();
+            Console.WriteLine("Facet drill-down example (Publish Date/2010):");
+            Console.WriteLine("---------------------------------------------");
+            Console.WriteLine("Author: " + example.RunDrillDown());
+
+            Console.WriteLine();
+            Console.WriteLine("Facet drill-sideways example (Publish Date/2010):");
+            Console.WriteLine("---------------------------------------------");
+            foreach (FacetResult result in example.RunDrillSideways())
+            {
+                Console.WriteLine(result);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Facet/SimpleSortedSetFacetsExample.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Facet/SimpleSortedSetFacetsExample.cs b/src/Lucene.Net.Demo/Facet/SimpleSortedSetFacetsExample.cs
new file mode 100644
index 0000000..b2d6da1
--- /dev/null
+++ b/src/Lucene.Net.Demo/Facet/SimpleSortedSetFacetsExample.cs
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+// Lucene.Net.Facet
+
+using Lucene.Net.Analysis.Core;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.SortedSet;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Demo.Facet
+{
+    /// <summary>
+    /// Shows simple usage of faceted indexing and search
+    /// using <see cref="SortedSetDocValuesFacetField"/> and 
+    /// <see cref="SortedSetDocValuesFacetCounts"/>.
+    /// </summary>
+    public class SimpleSortedSetFacetsExample
+    {
+        /// <summary>
+        /// Using a constant for all functionality related to a specific index
+        /// is the best strategy. This allows you to upgrade Lucene.Net first
+        /// and plan the upgrade of the index binary format for a later time. 
+        /// Once the index is upgraded, you simply need to update the constant 
+        /// version and redeploy your application.
+        /// </summary>
+        private const LuceneVersion EXAMPLE_VERSION = LuceneVersion.LUCENE_48;
+
+        private readonly Directory indexDir = new RAMDirectory();
+        private readonly FacetsConfig config = new FacetsConfig();
+
+        /// <summary>Build the example index.</summary>
+        private void Index()
+        {
+            using (IndexWriter indexWriter = new IndexWriter(indexDir, 
+                new IndexWriterConfig(EXAMPLE_VERSION,
+                new WhitespaceAnalyzer(EXAMPLE_VERSION))))
+            {
+                Document doc = new Document();
+                doc.Add(new SortedSetDocValuesFacetField("Author", "Bob"));
+                doc.Add(new SortedSetDocValuesFacetField("Publish Year", "2010"));
+                indexWriter.AddDocument(config.Build(doc));
+
+                doc = new Document();
+                doc.Add(new SortedSetDocValuesFacetField("Author", "Lisa"));
+                doc.Add(new SortedSetDocValuesFacetField("Publish Year", "2010"));
+                indexWriter.AddDocument(config.Build(doc));
+
+                doc = new Document();
+                doc.Add(new SortedSetDocValuesFacetField("Author", "Lisa"));
+                doc.Add(new SortedSetDocValuesFacetField("Publish Year", "2012"));
+                indexWriter.AddDocument(config.Build(doc));
+
+                doc = new Document();
+                doc.Add(new SortedSetDocValuesFacetField("Author", "Susan"));
+                doc.Add(new SortedSetDocValuesFacetField("Publish Year", "2012"));
+                indexWriter.AddDocument(config.Build(doc));
+
+                doc = new Document();
+                doc.Add(new SortedSetDocValuesFacetField("Author", "Frank"));
+                doc.Add(new SortedSetDocValuesFacetField("Publish Year", "1999"));
+                indexWriter.AddDocument(config.Build(doc));
+
+            } // Disposes indexWriter
+        }
+
+        /// <summary>User runs a query and counts facets.</summary>
+        private IList<FacetResult> Search()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+                SortedSetDocValuesReaderState state = new DefaultSortedSetDocValuesReaderState(indexReader);
+
+                // Aggregatses the facet counts
+                FacetsCollector fc = new FacetsCollector();
+
+                // MatchAllDocsQuery is for "browsing" (counts facets
+                // for all non-deleted docs in the index); normally
+                // you'd use a "normal" query:
+                FacetsCollector.Search(searcher, new MatchAllDocsQuery(), 10, fc);
+
+                // Retrieve results
+                Facets facets = new SortedSetDocValuesFacetCounts(state, fc);
+
+                IList<FacetResult> results = new List<FacetResult>();
+                results.Add(facets.GetTopChildren(10, "Author"));
+                results.Add(facets.GetTopChildren(10, "Publish Year"));
+
+                return results;
+
+            } // Disposes indexWriter
+        }
+
+        /// <summary>User drills down on 'Publish Year/2010'.</summary>
+        private FacetResult DrillDown()
+        {
+            using (DirectoryReader indexReader = DirectoryReader.Open(indexDir))
+            {
+                IndexSearcher searcher = new IndexSearcher(indexReader);
+                SortedSetDocValuesReaderState state = new DefaultSortedSetDocValuesReaderState(indexReader);
+
+                // Now user drills down on Publish Year/2010:
+                DrillDownQuery q = new DrillDownQuery(config);
+                q.Add("Publish Year", "2010");
+                FacetsCollector fc = new FacetsCollector();
+                FacetsCollector.Search(searcher, q, 10, fc);
+
+                // Retrieve results
+                Facets facets = new SortedSetDocValuesFacetCounts(state, fc);
+                FacetResult result = facets.GetTopChildren(10, "Author");
+
+                return result;
+
+            } // Disposes indexReader
+        }
+
+        /// <summary>Runs the search example.</summary>
+        public IList<FacetResult> RunSearch()
+        {
+            Index();
+            return Search();
+        }
+
+        /// <summary>Runs the drill-down example.</summary>
+        public FacetResult RunDrillDown()
+        {
+            Index();
+            return DrillDown();
+        }
+
+        /// <summary>Runs the search and drill-down examples and prints the results.</summary>
+        public static void Main(string[] args)
+        {
+            Console.WriteLine("Facet counting example:");
+            Console.WriteLine("-----------------------");
+            SimpleSortedSetFacetsExample example = new SimpleSortedSetFacetsExample();
+            IList<FacetResult> results = example.RunSearch();
+            Console.WriteLine("Author: " + results[0]);
+            Console.WriteLine("Publish Year: " + results[0]);
+
+            Console.WriteLine();
+            Console.WriteLine("Facet drill-down example (Publish Year/2010):");
+            Console.WriteLine("---------------------------------------------");
+            Console.WriteLine("Author: " + example.RunDrillDown());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/IndexFiles.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/IndexFiles.cs b/src/Lucene.Net.Demo/IndexFiles.cs
new file mode 100644
index 0000000..048821d
--- /dev/null
+++ b/src/Lucene.Net.Demo/IndexFiles.cs
@@ -0,0 +1,223 @@
+/*
+ * 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.
+ */
+
+// Add NuGet References:
+
+// Lucene.Net.Analysis.Common
+
+using Lucene.Net.Analysis;
+using Lucene.Net.Analysis.Standard;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
+using System.IO;
+using System.Text;
+
+namespace Lucene.Net.Demo
+{
+    /// <summary>
+    /// Index all text files under a directory.
+    /// <para/>
+    /// This is a command-line application demonstrating simple Lucene indexing.
+    /// Run it with no command-line arguments for usage information.
+    /// </summary>
+    public class IndexFiles
+    {
+        private IndexFiles() { }
+
+        /// <summary>Index all text files under a directory.</summary>
+        public static void Main(string[] args)
+        {
+            // The <CONSOLE_APP_NAME> should be the assembly name of the application
+            // this code is compiled into. In .NET Framework, it is the name of the EXE file.
+            // In .NET Core, you have the option of compiling this into either an EXE or a DLL 
+            // (see https://docs.microsoft.com/en-us/dotnet/core/deploying/index).
+            // In the latter case, the <CONSOLE_APP_NAME> will be "dotnet <DLL_NAME>.dll".
+            string usage = "Usage: <CONSOLE_APP_NAME> <INDEX_DIRECTORY> <SOURCE_DIRECTORY> "
+                        + "[-u|--update]\n\n"
+                        + "This indexes the documents in <SOURCE_DIRECTORY>, creating a Lucene index"
+                        + "in <INDEX_DIRECTORY> that can be searched with the search-files demo.";
+            
+            // Validate required arguments are present.
+            // If not, show usage information.
+            if (args.Length < 2)
+            {
+                Console.WriteLine(usage);
+                Environment.Exit(1);
+            }
+            string indexPath = args[0];
+            string sourcePath = args[1];
+            bool create = true;
+
+            for (int i = 0; i < args.Length; i++)
+            {
+                if ("-u".Equals(args[i]) || "--update".Equals(args[i]))
+                {
+                    create = false;
+                }
+            }
+
+            DirectoryInfo sourceDirectory = new DirectoryInfo(sourcePath);
+            if (!sourceDirectory.Exists)
+            {
+                Console.WriteLine("Source directory '" + sourcePath + "' does not exist, please check the path");
+                Environment.Exit(1);
+            }
+
+            DateTime start = DateTime.UtcNow;
+            try
+            {
+                Console.WriteLine("Indexing to directory '" + indexPath + "'...");
+
+                Store.Directory dir = FSDirectory.Open(indexPath);
+                // :Post-Release-Update-Version.LUCENE_XY:
+                Analyzer analyzer = new StandardAnalyzer(LuceneVersion.LUCENE_48);
+                IndexWriterConfig iwc = new IndexWriterConfig(LuceneVersion.LUCENE_48, analyzer);
+
+                if (create)
+                {
+                    // Create a new index in the directory, removing any
+                    // previously indexed documents:
+                    iwc.OpenMode = OpenMode.CREATE;
+                }
+                else
+                {
+                    // Add new documents to an existing index:
+                    iwc.OpenMode = OpenMode.CREATE_OR_APPEND;
+                }
+
+                // Optional: for better indexing performance, if you
+                // are indexing many documents, increase the RAM
+                // buffer.
+                //
+                // iwc.RAMBufferSizeMB = 256.0;
+
+                using (IndexWriter writer = new IndexWriter(dir, iwc))
+                {
+                    IndexDocs(writer, sourceDirectory);
+
+                    // NOTE: if you want to maximize search performance,
+                    // you can optionally call forceMerge here.  This can be
+                    // a terribly costly operation, so generally it's only
+                    // worth it when your index is relatively static (ie
+                    // you're done adding documents to it):
+                    //
+                    // writer.ForceMerge(1);
+                }
+
+                DateTime end = DateTime.UtcNow;
+                Console.WriteLine((end - start).TotalMilliseconds + " total milliseconds");
+            }
+            catch (IOException e)
+            {
+                Console.WriteLine(" caught a " + e.GetType() +
+                 "\n with message: " + e.Message);
+            }
+        }
+
+        /// <summary>
+        /// Recurses over files and directories found under the 
+        /// given directory and indexes each file.<para/>
+        /// 
+        /// NOTE: This method indexes one document per input file. 
+        /// This is slow. For good throughput, put multiple documents 
+        /// into your input file(s).
+        /// </summary>
+        /// <param name="writer">
+        ///     <see cref="IndexWriter"/> to the index where the given 
+        ///     file/dir info will be stored
+        /// </param>
+        /// <param name="directoryInfo">
+        ///     The directory to recurse into to find files to index.
+        /// </param>
+        /// <exception cref="IOException">
+        ///     If there is a low-level I/O error.
+        /// </exception>
+        internal static void IndexDocs(IndexWriter writer, DirectoryInfo directoryInfo)
+        {
+            foreach (var dirInfo in directoryInfo.GetDirectories())
+            {
+                IndexDocs(writer, dirInfo);
+            }
+            foreach (var fileInfo in directoryInfo.GetFiles())
+            {
+                IndexDocs(writer, fileInfo);
+            }
+        }
+
+        /// <summary>
+        /// Indexes the given file using the given writer.<para/>
+        /// </summary>
+        /// <param name="writer">
+        ///     <see cref="IndexWriter"/> to the index where the given 
+        ///     file info will be stored.
+        /// </param>
+        /// <param name="file">
+        ///     The file to index.
+        /// </param>
+        /// <exception cref="IOException">
+        ///     If there is a low-level I/O error.
+        /// </exception>
+        internal static void IndexDocs(IndexWriter writer, FileInfo file)
+        {
+            using (FileStream fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read))
+            {
+                // make a new, empty document
+                Document doc = new Document();
+
+                // Add the path of the file as a field named "path".  Use a
+                // field that is indexed (i.e. searchable), but don't tokenize 
+                // the field into separate words and don't index term frequency
+                // or positional information:
+                Field pathField = new StringField("path", file.FullName, Field.Store.YES);
+                doc.Add(pathField);
+
+                // Add the last modified date of the file a field named "modified".
+                // Use a LongField that is indexed (i.e. efficiently filterable with
+                // NumericRangeFilter).  This indexes to milli-second resolution, which
+                // is often too fine.  You could instead create a number based on
+                // year/month/day/hour/minutes/seconds, down the resolution you require.
+                // For example the long value 2011021714 would mean
+                // February 17, 2011, 2-3 PM.
+                doc.Add(new Int64Field("modified", file.LastWriteTimeUtc.Ticks, Field.Store.NO));
+
+                // Add the contents of the file to a field named "contents".  Specify a Reader,
+                // so that the text of the file is tokenized and indexed, but not stored.
+                // Note that FileReader expects the file to be in UTF-8 encoding.
+                // If that's not the case searching for special characters will fail.
+                doc.Add(new TextField("contents", new StreamReader(fs, Encoding.UTF8)));
+
+                if (writer.Config.OpenMode == OpenMode.CREATE)
+                {
+                    // New index, so we just add the document (no old document can be there):
+                    Console.WriteLine("adding " + file);
+                    writer.AddDocument(doc);
+                }
+                else
+                {
+                    // Existing index (an old copy of this document may have been indexed) so 
+                    // we use updateDocument instead to replace the old one matching the exact 
+                    // path, if present:
+                    Console.WriteLine("updating " + file);
+                    writer.UpdateDocument(new Term("path", file.FullName), doc);
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Lucene.Net.Demo.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Lucene.Net.Demo.csproj b/src/Lucene.Net.Demo/Lucene.Net.Demo.csproj
new file mode 100644
index 0000000..eb01c86
--- /dev/null
+++ b/src/Lucene.Net.Demo/Lucene.Net.Demo.csproj
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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.
+
+-->
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{D1661154-8F5B-499A-8B2D-04B8A67F4232}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Demo</RootNamespace>
+    <AssemblyName>Lucene.Net.Demo</AssemblyName>
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>TRACE;DEBUG</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </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>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup>
+    <DefineConstants>$(DefineConstants);FEATURE_SERIALIZABLE</DefineConstants>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Facet\AssociationsFacetsExample.cs" />
+    <Compile Include="Facet\DistanceFacetsExample.cs" />
+    <Compile Include="Facet\ExpressionAggregationFacetsExample.cs" />
+    <Compile Include="Facet\MultiCategoryListsFacetsExample.cs" />
+    <Compile Include="Facet\RangeFacetsExample.cs" />
+    <Compile Include="Facet\SimpleFacetsExample.cs" />
+    <Compile Include="Facet\SimpleSortedSetFacetsExample.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="..\CommonAssemblyInfo.cs">
+      <Link>Properties\CommonAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="IndexFiles.cs" />
+    <Compile Include="SearchFiles.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Lucene.Net.Analysis.Common\Lucene.Net.Analysis.Common.csproj">
+      <Project>{4add0bbc-b900-4715-9526-d871de8eea64}</Project>
+      <Name>Lucene.Net.Analysis.Common</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.Expressions\Lucene.Net.Expressions.csproj">
+      <Project>{dc83004c-183a-4e1a-abea-4fe95b4bc079}</Project>
+      <Name>Lucene.Net.Expressions</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
+      <Project>{48f7884a-9454-4e88-8413-9d35992cb440}</Project>
+      <Name>Lucene.Net.Facet</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.Queries\Lucene.Net.Queries.csproj">
+      <Project>{69d7956c-c2cc-4708-b399-a188fec384c4}</Project>
+      <Name>Lucene.Net.Queries</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.QueryParser\Lucene.Net.QueryParser.csproj">
+      <Project>{949ba34b-6ae6-4ce3-b578-61e13e4d76bf}</Project>
+      <Name>Lucene.Net.QueryParser</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net\Lucene.Net.csproj">
+      <Project>{5d4ad9be-1ffb-41ab-9943-25737971bf57}</Project>
+      <Name>Lucene.Net</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="Lucene.Net.Demo.project.json" />
+  </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/775df654/src/Lucene.Net.Demo/Lucene.Net.Demo.project.json
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Lucene.Net.Demo.project.json b/src/Lucene.Net.Demo/Lucene.Net.Demo.project.json
new file mode 100644
index 0000000..fb9054b
--- /dev/null
+++ b/src/Lucene.Net.Demo/Lucene.Net.Demo.project.json
@@ -0,0 +1,8 @@
+{
+  "runtimes": {
+    "win":{}
+  },  
+  "frameworks": {
+    "net451": {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/775df654/src/Lucene.Net.Demo/Lucene.Net.Demo.xproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Demo/Lucene.Net.Demo.xproj b/src/Lucene.Net.Demo/Lucene.Net.Demo.xproj
new file mode 100644
index 0000000..82e3ee2
--- /dev/null
+++ b/src/Lucene.Net.Demo/Lucene.Net.Demo.xproj
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>4bcd7980-0cf4-4da0-b069-f555a41cb44d</ProjectGuid>
+    <RootNamespace>Lucene.Net.Demo</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>