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 <[email protected]> Authored: Thu Jul 6 18:41:46 2017 +0700 Committer: Shad Storhaug <[email protected]> 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>
