├── .gitattributes
├── .gitignore
├── LICENSE.md
├── README.md
└── src
├── .nuget
├── NuGet.Config
├── NuGet.exe
└── NuGet.targets
├── SimpleLucene.Tests
├── Data
│ └── Repository.cs
├── Definitions
│ ├── ProductIndexDefinition.cs
│ └── ProductResultDefinition.cs
├── Entities
│ └── Product.cs
├── IndexOptionsTestFixture.cs
├── IndexQueueTestFixture.cs
├── IndexServiceTestFixture.cs
├── MemoryIndexSearcher.cs
├── MemoryIndexWriter.cs
├── Properties
│ └── AssemblyInfo.cs
├── Queries
│ └── ProductQuery.cs
├── SearchServiceTestFixture.cs
├── SimpleLucene.Tests.csproj
├── Tasks
│ ├── ProductUpdateTask.cs
│ └── TaskEqualityTestFixture.cs
├── TestIndexLocation.cs
└── packages.config
├── SimpleLucene.sln
└── SimpleLucene
├── BaseIndexLocation.cs
├── DelegateSearchResultDefinition.cs
├── DirectoryIndexSearcher.cs
├── DirectoryIndexWriter.cs
├── DocumentExtensions.cs
├── DocumentResultDefinition.cs
├── FileSystemIndexLocation.cs
├── IIndexDefinition.cs
├── IIndexLocation.cs
├── IIndexSearcher.cs
├── IIndexService.cs
├── IIndexWriter.cs
├── IResultDefinition.cs
├── ISearchService.cs
├── IndexManagement
├── IIndexTask.cs
├── Impl
│ ├── EntityDeleteTask.cs
│ └── EntityUpdateTask.cs
└── IndexQueue.cs
├── IndexOptions.cs
├── IndexResult.cs
├── IndexService.cs
├── Properties
└── AssemblyInfo.cs
├── QueryBase.cs
├── SearchResult.cs
├── SearchService.cs
├── SimpleLucene.csproj
├── SimpleLuceneExtensions.cs
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [Oo]bj
2 | [Bb]in
3 | *.user
4 | *.suo
5 | *.[Cc]ache
6 | *.bak
7 | *.ncb
8 | *.log
9 | *.DS_Store
10 | [Tt]humbs.db
11 | _ReSharper.*
12 | *.resharper
13 | Ankh.NoLoad
14 | tools
15 | build
16 | packages
17 | artifacts
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2014 Ben Foster, United Kingdom
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | SimpleLucene
2 | ============
3 |
4 | SimpleLucene is a wrapper for the popular Lucene.NET search engine.
--------------------------------------------------------------------------------
/src/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benfoster/SimpleLucene/a0fdd8fc86a723d06d148e8ed4b1cc33bbdad107/src/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/src/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 |
32 |
33 |
34 |
35 | $(SolutionDir).nuget
36 |
37 |
38 |
39 | packages.$(MSBuildProjectName.Replace(' ', '_')).config
40 |
41 |
42 |
43 |
44 |
45 | $(PackagesProjectConfig)
46 |
47 |
48 |
49 |
50 | packages.config
51 |
52 |
53 |
54 |
55 |
56 |
57 | $(NuGetToolsPath)\NuGet.exe
58 | @(PackageSource)
59 |
60 | "$(NuGetExePath)"
61 | mono --runtime=v4.0.30319 $(NuGetExePath)
62 |
63 | $(TargetDir.Trim('\\'))
64 |
65 | -RequireConsent
66 | -NonInteractive
67 |
68 | "$(SolutionDir) "
69 | "$(SolutionDir)"
70 |
71 |
72 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
73 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
74 |
75 |
76 |
77 | RestorePackages;
78 | $(BuildDependsOn);
79 |
80 |
81 |
82 |
83 | $(BuildDependsOn);
84 | BuildPackage;
85 |
86 |
87 |
88 |
89 |
90 |
91 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
113 |
115 |
116 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Data/Repository.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using SimpleLucene.Tests.Entities;
6 |
7 | namespace SimpleLucene.Tests.Data
8 | {
9 | public class Repository
10 | {
11 | public IList Products {
12 | get {
13 | return new List {
14 | new Product { Id = 1, Name = "Football" },
15 | new Product { Id = 2, Name = "Coffee Cup"},
16 | new Product { Id = 3, Name = "Nike Trainers"},
17 | new Product { Id = 4, Name = "Apple iPod Nano"},
18 | new Product { Id = 5, Name = "Asus eeePC"},
19 | new Product { Id = 6, Name = "Pack of cards"},
20 | new Product { Id = 7, Name = "Funky TShirt"},
21 | new Product { Id = 8, Name = "Blackberry 9800"},
22 | new Product { Id = 9, Name = "Guitar Hero"},
23 | new Product { Id = 10, Name = "House Plant"},
24 | };
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Definitions/ProductIndexDefinition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using SimpleLucene.Tests.Entities;
6 | using Lucene.Net.Documents;
7 | using Lucene.Net.Index;
8 |
9 | namespace SimpleLucene.Tests.Definitions
10 | {
11 | public class ProductIndexDefinition : IIndexDefinition
12 | {
13 | public Document Convert(Product p) {
14 | var document = new Document();
15 | document.Add(new Field("type", "product", Field.Store.NO, Field.Index.NOT_ANALYZED));
16 | document.Add(new Field("id", p.Id.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
17 | document.Add(new Field("name", p.Name, Field.Store.YES, Field.Index.ANALYZED));
18 | return document;
19 | }
20 |
21 | public Term GetIndex(Product p) {
22 | return new Term("id", p.Id.ToString());
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Definitions/ProductResultDefinition.cs:
--------------------------------------------------------------------------------
1 | using SimpleLucene.Tests.Entities;
2 |
3 | namespace SimpleLucene.Tests.Definitions
4 | {
5 | public class ProductResultDefinition : IResultDefinition
6 | {
7 | public Product Convert(Lucene.Net.Documents.Document document)
8 | {
9 | return new Product
10 | {
11 | Id = document.GetValue("id"),
12 | Name = document.GetValue("name")
13 | };
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Entities/Product.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace SimpleLucene.Tests.Entities
7 | {
8 | public class Product
9 | {
10 | public int Id { get; set; }
11 | public string Name { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/IndexOptionsTestFixture.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using NUnit.Framework;
6 | using Lucene.Net.Analysis.Standard;
7 | using Lucene.Net.Analysis;
8 |
9 | namespace SimpleLucene.Tests
10 | {
11 | [TestFixture]
12 | public class IndexOptionsTestFixture
13 | {
14 | [Test]
15 | public void Two_default_instances_are_equal()
16 | {
17 | var io1 = new IndexOptions();
18 | var io2 = new IndexOptions();
19 |
20 | Assert.AreEqual(io1, io2);
21 | }
22 |
23 | [Test]
24 | public void Two_references_to_the_same_object_are_equal()
25 | {
26 | var io1 = new IndexOptions { IndexLocation = new TestIndexLocation("products") };
27 | var io2 = io1;
28 | Assert.AreEqual(io1, io2);
29 | }
30 |
31 | [Test]
32 | public void Two_index_options_with_same_locations_are_equal()
33 | {
34 | var io1 = new IndexOptions { IndexLocation = new TestIndexLocation("products") };
35 | var io2 = new IndexOptions { IndexLocation = new TestIndexLocation("products") };
36 | Assert.AreEqual(io1, io2);
37 | }
38 |
39 | [Test]
40 | public void Two_index_options_with_different_locations_are_not_equal() {
41 | var io1 = new IndexOptions { IndexLocation = new TestIndexLocation("products") };
42 | var io2 = new IndexOptions { IndexLocation = new TestIndexLocation("products2") };
43 | Assert.AreNotEqual(io1, io2);
44 | }
45 |
46 | [Test]
47 | public void Two_index_options_with_different_recreate_index_are_not_equal()
48 | {
49 | var io1 = new IndexOptions { IndexLocation = new TestIndexLocation("products"), RecreateIndex = true };
50 | var io2 = new IndexOptions { IndexLocation = new TestIndexLocation("products"), RecreateIndex = false };
51 | Assert.AreNotEqual(io1, io2);
52 | }
53 |
54 | [Test]
55 | public void Two_index_options_with_different_optimize_index_are_not_equal()
56 | {
57 | var io1 = new IndexOptions { IndexLocation = new TestIndexLocation("products"), OptimizeIndex = true };
58 | var io2 = new IndexOptions { IndexLocation = new TestIndexLocation("products"), OptimizeIndex = false };
59 | Assert.AreNotEqual(io1, io2);
60 | }
61 |
62 | [Test]
63 | public void Two_index_options_with_different_analyzers_are_not_equal()
64 | {
65 | var io1 = new IndexOptions { IndexLocation = new TestIndexLocation("products") }; // default Standard Analyzer
66 | var io2 = new IndexOptions { IndexLocation = new TestIndexLocation("products"), Analyzer = new SimpleAnalyzer() };
67 | Assert.AreNotEqual(io1, io2);
68 | }
69 |
70 | [Test]
71 | public void Two_index_options_with_same_attributes_are_equal()
72 | {
73 | var io1 = new IndexOptions();
74 | io1.Attributes.Add("somekey", "somevalue");
75 | io1.Attributes.Add("somecount", 100);
76 | var io2 = new IndexOptions();
77 | io2.Attributes.Add("somekey", "somevalue");
78 | io2.Attributes.Add("somecount", 100);
79 | Assert.AreEqual(io1, io2);
80 | }
81 |
82 | [Test]
83 | public void Two_index_options_with_different_attributes_are_not_equal()
84 | {
85 | var io1 = new IndexOptions();
86 | io1.Attributes.Add("somekey", "somevalue");
87 | var io2 = new IndexOptions();
88 | io2.Attributes.Add("someotherkey", "someothervalue");
89 | Assert.AreNotEqual(io1, io2);
90 | }
91 |
92 | [Test]
93 | public void Two_index_options_with_same_attributes_but_diff_values_are_not_equal()
94 | {
95 | var io1 = new IndexOptions();
96 | io1.Attributes.Add("somekey", "somevalue");
97 | io1.Attributes.Add("somecount", 100);
98 | var io2 = new IndexOptions();
99 | io2.Attributes.Add("somekey", "somevalue2");
100 | io2.Attributes.Add("somecount", 150);
101 | Assert.AreNotEqual(io1, io2);
102 | }
103 | }
104 | }
105 |
106 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/IndexQueueTestFixture.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using NUnit.Framework;
4 | using SimpleLucene.IndexManagement;
5 | using SimpleLucene.Tests.Definitions;
6 | using SimpleLucene.Tests.Entities;
7 |
8 | namespace SimpleLucene.Tests
9 | {
10 | [TestFixture]
11 | public class IndexQueueTestFixture
12 | {
13 | [Test]
14 | public void Can_add_index_task_to_queue()
15 | {
16 | var task = new EntityUpdateTask(new Product(),
17 | new ProductIndexDefinition(), new TestIndexLocation());
18 |
19 | IndexQueue.Instance.Queue(task);
20 |
21 | Assert.IsTrue(IndexQueue.Instance.Contains(task));
22 |
23 | IIndexTask fromQueue;
24 | IndexQueue.Instance.TryDequeue(out fromQueue);
25 |
26 | Assert.AreEqual(task, fromQueue);
27 | }
28 |
29 |
30 | [Test]
31 | public void Can_resolve_index_services_when_processing_index_queue()
32 | {
33 | var t1 = new EntityUpdateTask(new Product(), new ProductIndexDefinition(), new TestIndexLocation("products"));
34 | var t2 = new EntityUpdateTask(new Product(), new ProductIndexDefinition(), new TestIndexLocation("products"));
35 | var t3 = new EntityUpdateTask(new Product(), new ProductIndexDefinition(), new TestIndexLocation("products2"));
36 |
37 | Action queue = t => IndexQueue.Instance.Queue(t);
38 |
39 | queue(t1);
40 | queue(t2);
41 | queue(t3);
42 |
43 | var services = new HashSet();
44 |
45 | IIndexTask task;
46 | while (IndexQueue.Instance.TryDequeue(out task))
47 | {
48 | var service = services.FindWithOptions(task.IndexOptions);
49 |
50 | if (service == null) {
51 | service = new IndexService(new DirectoryIndexWriter(task.IndexOptions.IndexLocation.GetDirectory(), task.IndexOptions.RecreateIndex));
52 | services.Add(service);
53 | }
54 |
55 | // process the task
56 | }
57 |
58 | Assert.IsTrue(services.Count == 2);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/IndexServiceTestFixture.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Index;
2 | using Lucene.Net.Search;
3 | using NUnit.Framework;
4 | using SimpleLucene.Tests.Data;
5 | using SimpleLucene.Tests.Definitions;
6 | using System.Linq;
7 |
8 | namespace SimpleLucene.Tests
9 | {
10 | [TestFixture]
11 | public class IndexServiceTestFixture
12 | {
13 | [Test]
14 | public void Can_index_a_single_entity()
15 | {
16 | var repo = new Repository();
17 | var product = repo.Products.First();
18 |
19 | var writer = new MemoryIndexWriter(true);
20 |
21 | using (var indexService = new IndexService(writer))
22 | {
23 | var result = indexService.IndexEntity(product, new ProductIndexDefinition());
24 | Assert.AreEqual(1, result.Count);
25 | Assert.AreEqual(0, result.Errors.Count);
26 | }
27 | }
28 |
29 | [Test]
30 | public void Can_index_a_collection_of_entities()
31 | {
32 | var repo = new Repository();
33 |
34 | var writer = new MemoryIndexWriter(true);
35 | using (var indexService = new IndexService(writer))
36 | {
37 | var result = indexService.IndexEntities(repo.Products, new ProductIndexDefinition());
38 | Assert.AreEqual(10, result.Count);
39 | Assert.AreEqual(0, result.Errors.Count);
40 | }
41 | }
42 |
43 | [Test]
44 | public void Can_use_the_same_index_writer_for_multiple_index_operations()
45 | {
46 | var repo = new Repository();
47 |
48 | var writer = new MemoryIndexWriter(true);
49 | var indexService = new IndexService(writer);
50 |
51 | var p1p5 = repo.Products.Skip(0).Take(5);
52 | var result = indexService.IndexEntities(p1p5, new ProductIndexDefinition());
53 | Assert.AreEqual(5, result.Count);
54 |
55 | var p6p10 = repo.Products.Skip(5).Take(5);
56 | var result2 = indexService.IndexEntities(p6p10, new ProductIndexDefinition());
57 | Assert.AreEqual(5,result2.Count);
58 |
59 | var searcher = new MemoryIndexSearcher(writer.Directory, true);
60 |
61 | var searchResult = new SearchService(searcher).SearchIndex(new TermQuery(new Term("type", "product")));
62 |
63 | Assert.AreEqual(0, searchResult.Documents.Count(), "Index writer has not yet been committed so should return 0");
64 | // commits writer
65 | indexService.Dispose();
66 |
67 | searchResult = new SearchService(searcher).SearchIndex(new TermQuery(new Term("type", "product")));
68 | Assert.AreEqual(10, searchResult.Documents.Count());
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/MemoryIndexSearcher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 | using Lucene.Net.Search;
7 | using Lucene.Net.Store;
8 |
9 | namespace SimpleLucene.Tests
10 | {
11 | public class MemoryIndexSearcher : IIndexSearcher
12 | {
13 | private readonly bool readOnly;
14 | private readonly RAMDirectory directory;
15 |
16 | public MemoryIndexSearcher(RAMDirectory directory, bool readOnly) {
17 | this.readOnly = readOnly;
18 | this.directory = directory;
19 | }
20 |
21 | public Searcher Create() {
22 | return new IndexSearcher(directory, readOnly);
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/MemoryIndexWriter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Lucene.Net.Index;
6 | using System.IO;
7 | using Lucene.Net.Store;
8 | using Lucene.Net.Analysis.Standard;
9 |
10 | namespace SimpleLucene.Tests
11 | {
12 | public class MemoryIndexWriter : IIndexWriter
13 | {
14 | public bool CreateIndex {get; private set;}
15 |
16 | public RAMDirectory Directory { get; set; }
17 |
18 | public MemoryIndexWriter(bool createIndex)
19 | {
20 | this.Directory = new RAMDirectory();
21 | this.CreateIndex = createIndex;
22 | this.IndexOptions = new IndexOptions();
23 | }
24 |
25 | public IndexOptions IndexOptions { get; set; }
26 |
27 | public IndexWriter Create()
28 | {
29 | var ramDirectory = new RAMDirectory();
30 | this.Directory = ramDirectory;
31 | return new IndexWriter(ramDirectory,
32 | new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30),
33 | CreateIndex,
34 | IndexWriter.MaxFieldLength.UNLIMITED);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SimpleLucene.Tests")]
9 | [assembly: AssemblyDescription("Test project for SimpleLucene")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Ben Foster")]
12 | [assembly: AssemblyProduct("SimpleLucene.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © Ben Foster 2011")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("2ed8faad-e36a-437b-a217-5b0c59ae0132")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Queries/ProductQuery.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using Lucene.Net.Search;
6 | using Lucene.Net.Index;
7 |
8 | namespace SimpleLucene.Tests.Queries
9 | {
10 | public class ProductQuery : QueryBase
11 | {
12 | public ProductQuery(Query query) : base(query) { }
13 | public ProductQuery() { }
14 |
15 | public ProductQuery WithId(int id)
16 | {
17 | if (id > 0)
18 | {
19 | var query = new TermQuery(new Term("id", id.ToString()));
20 | this.AddQuery(query);
21 | }
22 | return this;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/SearchServiceTestFixture.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using Lucene.Net.Index;
3 | using Lucene.Net.Search;
4 | using Lucene.Net.Store;
5 | using NUnit.Framework;
6 | using SimpleLucene.Tests.Data;
7 | using SimpleLucene.Tests.Definitions;
8 | using SimpleLucene.Tests.Queries;
9 | using SimpleLucene.Tests.Entities;
10 |
11 | namespace SimpleLucene.Tests
12 | {
13 | [TestFixture]
14 | public class SearchServiceTestFixture
15 | {
16 | RAMDirectory directory;
17 |
18 | [TestFixtureSetUp]
19 | public void SetUp()
20 | {
21 | var repo = new Repository();
22 |
23 | var writer = new MemoryIndexWriter(true);
24 | using (var indexService = new IndexService(writer))
25 | {
26 | indexService.IndexEntities(repo.Products, new ProductIndexDefinition());
27 | }
28 | directory = writer.Directory;
29 | }
30 |
31 | [TestFixtureTearDown]
32 | public void TearDown()
33 | {
34 | directory.Close();
35 | }
36 |
37 | [Test]
38 | public void Can_search_index()
39 | {
40 | var indexSearcher = new MemoryIndexSearcher(directory, true);
41 | var searchService = new SearchService(indexSearcher);
42 |
43 | var result = searchService.SearchIndex(new ProductQuery().WithId(5).Query);
44 | Assert.IsNotNull(result);
45 | Assert.AreEqual(1, result.Documents.Count());
46 | }
47 |
48 | [Test]
49 | public void Can_transform_results_with_result_definition()
50 | {
51 | var indexSearcher = new MemoryIndexSearcher(directory, true);
52 | var searchService = new SearchService(indexSearcher);
53 |
54 | var result = searchService.SearchIndex(
55 | new TermQuery(new Term("type", "product")),
56 | new ProductResultDefinition()
57 | );
58 |
59 | Assert.IsNotNull(result);
60 | Assert.AreEqual(10, result.Results.Count());
61 | }
62 |
63 | [Test]
64 | public void Can_transform_results_with_delegate_definition()
65 | {
66 | var indexSearcher = new MemoryIndexSearcher(directory, true);
67 | var searchService = new SearchService(indexSearcher);
68 |
69 | var result = searchService.SearchIndex(
70 | new TermQuery(new Term("id", "1")),
71 | doc => {
72 | return new Product { Name = doc.Get("name") };
73 | });
74 |
75 | Assert.AreEqual(result.Results.Count(), 1);
76 | Assert.AreEqual(result.Results.First().Name, "Football");
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/SimpleLucene.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {C9FF8CA5-7D30-44A6-9D26-20F2C5213251}
9 | Library
10 | Properties
11 | SimpleLucene.Tests
12 | SimpleLucene.Tests
13 | v4.0
14 | 512
15 | ..\
16 | true
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | False
38 | ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll
39 |
40 |
41 | False
42 | ..\packages\Lucene.Net.3.0.3\lib\NET40\Lucene.Net.dll
43 |
44 |
45 | False
46 | ..\packages\NUnit.2.5.9.10348\lib\nunit.framework.dll
47 |
48 |
49 | False
50 | ..\packages\NUnit.2.5.9.10348\lib\nunit.mocks.dll
51 |
52 |
53 | False
54 | ..\packages\NUnit.2.5.9.10348\lib\pnunit.framework.dll
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | {72761871-5706-4ADD-A464-8935CC45FC57}
84 | SimpleLucene
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
95 |
96 |
97 |
98 |
105 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Tasks/ProductUpdateTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using SimpleLucene.Tests.Entities;
6 | using SimpleLucene.IndexManagement;
7 | using System.IO;
8 |
9 | namespace SimpleLucene.Tests.Tasks
10 | {
11 | public class ProductUpdateTask : IIndexTask
12 | {
13 | protected readonly Product entity;
14 |
15 | public ProductUpdateTask(Product entity)
16 | {
17 | this.entity = entity;
18 | }
19 |
20 | public override bool Equals(object obj)
21 | {
22 | return (Equals(obj as ProductUpdateTask));
23 | }
24 |
25 | public override int GetHashCode() {
26 | if (Equals(entity.Id, default(int)))
27 | return base.GetHashCode();
28 | return entity.Id.GetHashCode();
29 | }
30 |
31 | private static bool IsTransient(Product p)
32 | {
33 | return p != null &&
34 | Equals(p.Id, default(int));
35 | }
36 |
37 | public virtual bool Equals(ProductUpdateTask other)
38 | {
39 | if (other == null)
40 | return false;
41 |
42 | if (ReferenceEquals(this, other))
43 | return true;
44 |
45 | if (!IsTransient(this.entity) && !IsTransient(other.entity))
46 | return Equals(entity.Id, other.entity.Id);
47 |
48 |
49 | return false;
50 | }
51 |
52 | #region IIndexTask Members
53 |
54 | public void Execute(IIndexService indexService)
55 | {
56 | throw new NotImplementedException();
57 | }
58 |
59 | public IndexOptions IndexOptions { get; set; }
60 |
61 | #endregion
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/Tasks/TaskEqualityTestFixture.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using NUnit.Framework;
6 | using SimpleLucene.Tests.Entities;
7 | using SimpleLucene.IndexManagement;
8 | using SimpleLucene.Tests.Definitions;
9 | using System.IO;
10 |
11 | namespace SimpleLucene.Tests.Tasks
12 | {
13 | [TestFixture]
14 | public class TaskEqualityTestFixture
15 | {
16 | [Test]
17 | public void Two_of_same_task_type_with_different_entities_should_not_be_equal()
18 | {
19 | var p1 = new Product { Id = 1 };
20 | var p2 = new Product { Id = 2 };
21 |
22 | var task1 = new ProductUpdateTask(p1);
23 | var task2 = new ProductUpdateTask(p2);
24 |
25 | Assert.AreNotEqual(task1, task2);
26 | }
27 |
28 | [Test]
29 | public void Two_tasks_with_same_entity_should_be_equal()
30 | {
31 | var p1 = new Product { Id = 1 };
32 |
33 | var task1 = new ProductUpdateTask(p1);
34 | var task2 = new ProductUpdateTask(p1);
35 |
36 | Assert.AreEqual(task1, task2);
37 | }
38 |
39 | [Test]
40 | public void Two_different_task_types_with_same_entity_should_not_be_equal()
41 | {
42 | var p1 = new Product { Id = 1 };
43 |
44 | var task1 = new ProductUpdateTask(p1);
45 | var task2 = new EntityUpdateTask(p1, new ProductIndexDefinition(), new TestIndexLocation());
46 |
47 | Assert.AreNotEqual(task1, task2);
48 | }
49 |
50 | [Test]
51 | public void Index_queue_resolves_equality()
52 | {
53 | var p1 = new Product { Id = 1 };
54 |
55 | var task1 = new ProductUpdateTask(p1);
56 |
57 | IndexQueue.Instance.Queue(task1);
58 |
59 | var task2 = new ProductUpdateTask(p1);
60 |
61 | Assert.IsTrue(IndexQueue.Instance.Contains(task2));
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/TestIndexLocation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace SimpleLucene.Tests
8 | {
9 | public class TestIndexLocation : BaseIndexLocation {
10 |
11 | private string indexLocation;
12 |
13 | public TestIndexLocation(string indexDirectory = "")
14 | {
15 | indexLocation = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "indexes");
16 |
17 | if (!string.IsNullOrEmpty(indexDirectory))
18 | indexLocation = Path.Combine(indexLocation, indexDirectory);
19 | }
20 |
21 | public override string GetPath() {
22 | return indexLocation;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/SimpleLucene.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/SimpleLucene.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2013
4 | VisualStudioVersion = 12.0.30110.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{1CDA62F0-38CE-477E-A2F4-047ABBAA79C8}"
7 | ProjectSection(SolutionItems) = preProject
8 | .nuget\NuGet.Config = .nuget\NuGet.Config
9 | .nuget\NuGet.exe = .nuget\NuGet.exe
10 | .nuget\NuGet.targets = .nuget\NuGet.targets
11 | EndProjectSection
12 | EndProject
13 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLucene", "SimpleLucene\SimpleLucene.csproj", "{72761871-5706-4ADD-A464-8935CC45FC57}"
14 | EndProject
15 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLucene.Tests", "SimpleLucene.Tests\SimpleLucene.Tests.csproj", "{C9FF8CA5-7D30-44A6-9D26-20F2C5213251}"
16 | EndProject
17 | Global
18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
19 | Debug|Any CPU = Debug|Any CPU
20 | Release|Any CPU = Release|Any CPU
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {72761871-5706-4ADD-A464-8935CC45FC57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
24 | {72761871-5706-4ADD-A464-8935CC45FC57}.Debug|Any CPU.Build.0 = Debug|Any CPU
25 | {72761871-5706-4ADD-A464-8935CC45FC57}.Release|Any CPU.ActiveCfg = Release|Any CPU
26 | {72761871-5706-4ADD-A464-8935CC45FC57}.Release|Any CPU.Build.0 = Release|Any CPU
27 | {C9FF8CA5-7D30-44A6-9D26-20F2C5213251}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
28 | {C9FF8CA5-7D30-44A6-9D26-20F2C5213251}.Debug|Any CPU.Build.0 = Debug|Any CPU
29 | {C9FF8CA5-7D30-44A6-9D26-20F2C5213251}.Release|Any CPU.ActiveCfg = Release|Any CPU
30 | {C9FF8CA5-7D30-44A6-9D26-20F2C5213251}.Release|Any CPU.Build.0 = Release|Any CPU
31 | EndGlobalSection
32 | GlobalSection(SolutionProperties) = preSolution
33 | HideSolutionNode = FALSE
34 | EndGlobalSection
35 | EndGlobal
36 |
--------------------------------------------------------------------------------
/src/SimpleLucene/BaseIndexLocation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SimpleLucene
4 | {
5 | ///
6 | /// A base class for index locations.
7 | ///
8 | public abstract class BaseIndexLocation : IIndexLocation
9 | {
10 | ///
11 | /// Compares the index location based on it's path
12 | ///
13 | public virtual bool Equals(IIndexLocation other)
14 | {
15 | if (other == null)
16 | {
17 | return false;
18 | }
19 | return other.GetPath().Equals(this.GetPath(), StringComparison.InvariantCultureIgnoreCase);
20 | }
21 |
22 | public override bool Equals(object obj)
23 | {
24 | return Equals(obj as IIndexLocation);
25 | }
26 |
27 | public override int GetHashCode()
28 | {
29 | return base.GetHashCode();
30 | }
31 |
32 | public abstract string GetPath();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/SimpleLucene/DelegateSearchResultDefinition.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Lucene.Net.Documents;
3 |
4 | namespace SimpleLucene
5 | {
6 | public class DelegateSearchResultDefinition : IResultDefinition
7 | {
8 | private readonly Func converter;
9 | public DelegateSearchResultDefinition(Func converter)
10 | {
11 | if (converter == null)
12 | {
13 | throw new ArgumentNullException("converter");
14 | }
15 |
16 | this.converter = converter;
17 | }
18 |
19 | public T Convert(Document document)
20 | {
21 | if (document == null)
22 | {
23 | throw new ArgumentNullException("document");
24 | }
25 |
26 | return converter(document);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/SimpleLucene/DirectoryIndexSearcher.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Search;
2 | using Lucene.Net.Store;
3 | using System;
4 | using System.IO;
5 |
6 | namespace SimpleLucene
7 | {
8 | ///
9 | /// A searcher for directory based indexes
10 | ///
11 | public class DirectoryIndexSearcher : IIndexSearcher
12 | {
13 | private readonly DirectoryInfo indexLocation;
14 | private readonly bool readOnly;
15 |
16 | public DirectoryIndexSearcher(DirectoryInfo indexLocation, bool readOnly = true)
17 | {
18 | if (indexLocation == null)
19 | {
20 | throw new ArgumentNullException("indexLocation");
21 | }
22 |
23 | this.indexLocation = indexLocation;
24 | this.readOnly = readOnly;
25 | }
26 |
27 | ///
28 | /// Creates the underlying Lucene searcher.
29 | ///
30 | /// A Lucene Searcher
31 | public Searcher Create()
32 | {
33 | var fsDirectory = FSDirectory.Open(indexLocation);
34 | return new IndexSearcher(fsDirectory, true);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/SimpleLucene/DirectoryIndexWriter.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Analysis;
2 | using Lucene.Net.Analysis.Standard;
3 | using Lucene.Net.Index;
4 | using Lucene.Net.Store;
5 | using System;
6 | using System.IO;
7 |
8 | namespace SimpleLucene
9 | {
10 | ///
11 | /// A writer for directory based indexes
12 | ///
13 | public class DirectoryIndexWriter : IIndexWriter
14 | {
15 | public IndexOptions IndexOptions { get; set; }
16 |
17 | public DirectoryIndexWriter(DirectoryInfo indexLocation, bool recreateIndex = false)
18 | : this(indexLocation, new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30), recreateIndex)
19 | { }
20 |
21 | public DirectoryIndexWriter(DirectoryInfo indexLocation, Analyzer analyzer, bool recreateIndex = false)
22 | {
23 | if (indexLocation == null)
24 | {
25 | throw new ArgumentNullException("indexLocation");
26 | }
27 |
28 | if (analyzer == null)
29 | {
30 | throw new ArgumentNullException("analyzer");
31 | }
32 |
33 | IndexOptions = new IndexOptions
34 | {
35 | IndexLocation = new FileSystemIndexLocation(indexLocation),
36 | RecreateIndex = recreateIndex,
37 | Analyzer = analyzer
38 | };
39 | }
40 |
41 | ///
42 | /// Creates the underlying Lucene index writer.
43 | ///
44 | /// A Lucene Index Writer
45 | public IndexWriter Create()
46 | {
47 | var fsDirectory = FSDirectory.Open(IndexOptions.IndexLocation.GetDirectory());
48 |
49 | var recreateIndex = this.IndexOptions.RecreateIndex;
50 |
51 | if (!recreateIndex) // then we should create anyway
52 | recreateIndex = !(IndexReader.IndexExists(fsDirectory));
53 |
54 | return new IndexWriter(fsDirectory,
55 | IndexOptions.Analyzer,
56 | recreateIndex,
57 | IndexWriter.MaxFieldLength.UNLIMITED);
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/SimpleLucene/DocumentExtensions.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Documents;
2 | using System;
3 |
4 | namespace SimpleLucene
5 | {
6 | ///
7 | /// Extension methods for .
8 | ///
9 | public static class DocumentExtensions
10 | {
11 | public static T GetValue(this Document document, string field)
12 | {
13 | if (document == null)
14 | {
15 | throw new ArgumentNullException("document");
16 | }
17 |
18 | if (string.IsNullOrEmpty("field"))
19 | {
20 | throw new ArgumentNullException("field");
21 | }
22 |
23 | var value = document.Get(field);
24 |
25 | if (value != null)
26 | {
27 | return (T)Convert.ChangeType(value, typeof(T));
28 | }
29 |
30 | return default(T);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/SimpleLucene/DocumentResultDefinition.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Documents;
2 |
3 | namespace SimpleLucene
4 | {
5 | ///
6 | /// A simple result definition for untyped searches (just returns the Lucene document)
7 | ///
8 | public class DocumentResultDefinition : IResultDefinition
9 | {
10 | public Document Convert(Document document)
11 | {
12 | return document;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/SimpleLucene/FileSystemIndexLocation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace SimpleLucene
5 | {
6 | ///
7 | /// Represents a file sytem based index location
8 | ///
9 | public class FileSystemIndexLocation : BaseIndexLocation
10 | {
11 | private readonly DirectoryInfo directoryInfo;
12 |
13 | public FileSystemIndexLocation(DirectoryInfo directoryInfo)
14 | {
15 | if (directoryInfo == null)
16 | {
17 | throw new ArgumentNullException("directoryInfo");
18 | }
19 |
20 | this.directoryInfo = directoryInfo;
21 | }
22 |
23 | public override string GetPath()
24 | {
25 | return directoryInfo.FullName;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IIndexDefinition.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Documents;
2 | using Lucene.Net.Index;
3 |
4 | namespace SimpleLucene
5 | {
6 | public interface IIndexDefinition where T : class
7 | {
8 | Document Convert(T entity);
9 | Term GetIndex(T entity);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IIndexLocation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SimpleLucene
4 | {
5 | public interface IIndexLocation : IEquatable
6 | {
7 | string GetPath();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IIndexSearcher.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Search;
2 |
3 | namespace SimpleLucene
4 | {
5 | public interface IIndexSearcher
6 | {
7 | Searcher Create();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IIndexService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Lucene.Net.Documents;
4 | using Lucene.Net.Index;
5 |
6 | namespace SimpleLucene
7 | {
8 | public interface IIndexService : IDisposable
9 | {
10 | IIndexWriter IndexWriter { get; }
11 | IndexResult IndexEntities(IEnumerable entities, IIndexDefinition definition) where TEntity : class;
12 | IndexResult IndexEntities(IEnumerable entities, Func converter);
13 | IndexResult IndexEntity(TEntity entity, IIndexDefinition definition) where TEntity : class;
14 | void Remove(Term searchTerm);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IIndexWriter.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Index;
2 |
3 | namespace SimpleLucene
4 | {
5 | public interface IIndexWriter
6 | {
7 | IndexWriter Create();
8 | IndexOptions IndexOptions { get; set; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IResultDefinition.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Documents;
2 |
3 | namespace SimpleLucene
4 | {
5 | public interface IResultDefinition
6 | {
7 | T Convert(Document document);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/SimpleLucene/ISearchService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Lucene.Net.Documents;
3 | using Lucene.Net.Search;
4 | namespace SimpleLucene
5 | {
6 | public interface ISearchService : IDisposable
7 | {
8 | SearchResult SearchIndex(Query query);
9 | SearchResult SearchIndex(Query query, IResultDefinition definition);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IndexManagement/IIndexTask.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SimpleLucene.IndexManagement
3 | {
4 | ///
5 | /// Interface for index tasks
6 | ///
7 | public interface IIndexTask
8 | {
9 | void Execute(IIndexService indexService);
10 | IndexOptions IndexOptions { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IndexManagement/Impl/EntityDeleteTask.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Index;
2 | using System;
3 |
4 | namespace SimpleLucene.IndexManagement
5 | {
6 | ///
7 | /// A task for removing an entity from an index
8 | ///
9 | /// The type of entity to remove
10 | public class EntityDeleteTask : IIndexTask where TEntity : class
11 | {
12 | protected readonly Term term;
13 |
14 | public IndexOptions IndexOptions { get; set; }
15 |
16 | public EntityDeleteTask(IIndexLocation indexLocation, string fieldName, string value)
17 | {
18 | if (indexLocation == null)
19 | {
20 | throw new ArgumentNullException("indexLocation");
21 | }
22 |
23 | if (string.IsNullOrEmpty("fieldName"))
24 | {
25 | throw new ArgumentNullException("fieldName");
26 | }
27 |
28 | if (string.IsNullOrEmpty("value"))
29 | {
30 | throw new ArgumentNullException("value");
31 | }
32 |
33 | term = new Term(fieldName, value);
34 | IndexOptions = new IndexOptions { IndexLocation = indexLocation };
35 | }
36 |
37 | public void Execute(IIndexService indexService)
38 | {
39 | if (indexService == null)
40 | {
41 | throw new ArgumentNullException("indexService");
42 | }
43 |
44 | indexService.Remove(term);
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IndexManagement/Impl/EntityUpdateTask.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SimpleLucene.IndexManagement
4 | {
5 | ///
6 | /// An task for reindexing an entity
7 | ///
8 | /// The type of entity to index
9 | public class EntityUpdateTask : IIndexTask where TEntity : class
10 | {
11 | protected readonly TEntity entity;
12 | protected readonly IIndexDefinition definition;
13 |
14 | public IndexOptions IndexOptions { get; set; }
15 |
16 | public EntityUpdateTask(TEntity entity, IIndexDefinition definition, IIndexLocation indexLocation)
17 | {
18 | if (entity == null)
19 | {
20 | throw new ArgumentNullException("entity");
21 | }
22 |
23 | if (definition == null)
24 | {
25 | throw new ArgumentNullException("definition");
26 | }
27 |
28 | if (indexLocation == null)
29 | {
30 | throw new ArgumentNullException("indexLocation");
31 | }
32 |
33 | this.entity = entity;
34 | this.definition = definition;
35 | this.IndexOptions = new IndexOptions { IndexLocation = indexLocation };
36 | }
37 |
38 | public void Execute(IIndexService indexService)
39 | {
40 | if (indexService == null)
41 | {
42 | throw new ArgumentNullException("indexService");
43 | }
44 |
45 | var result = indexService.IndexEntity(entity, definition);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IndexManagement/IndexQueue.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Concurrent;
2 | using System.Linq;
3 |
4 | namespace SimpleLucene.IndexManagement
5 | {
6 | ///
7 | /// Provides a simple queue for index tasks
8 | ///
9 | public class IndexQueue
10 | {
11 | static readonly IndexQueue instance = new IndexQueue();
12 | static readonly object padlock = new object();
13 |
14 | private ConcurrentQueue cq = new ConcurrentQueue();
15 |
16 | private IndexQueue() { }
17 |
18 | public static IndexQueue Instance
19 | {
20 | get { return instance; }
21 | }
22 |
23 | public void Queue(IIndexTask task)
24 | {
25 | cq.Enqueue(task);
26 | }
27 |
28 | public bool TryDequeue(out IIndexTask task)
29 | {
30 | return cq.TryDequeue(out task);
31 | }
32 |
33 | public bool Contains(IIndexTask instance)
34 | {
35 | lock (padlock)
36 | {
37 | return cq.Contains(instance);
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IndexOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Lucene.Net.Analysis;
4 | using Lucene.Net.Analysis.Standard;
5 |
6 | namespace SimpleLucene
7 | {
8 | ///
9 | /// Used as a definition for resolving indexwriters
10 | ///
11 | public class IndexOptions : IEquatable
12 | {
13 | public IndexOptions()
14 | {
15 | this.Analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
16 | this.Attributes = new Dictionary();
17 | }
18 |
19 | public bool OptimizeIndex { get; set; }
20 | public bool RecreateIndex { get; set; }
21 | public IIndexLocation IndexLocation { get; set; }
22 | public Analyzer Analyzer { get; set; }
23 | public IDictionary Attributes { get; set; }
24 |
25 | public bool Equals(IndexOptions other)
26 | {
27 | if (other == null)
28 | return false;
29 |
30 | return (AreEqual(other.OptimizeIndex, this.OptimizeIndex))
31 | && (AreEqual(other.RecreateIndex, this.RecreateIndex))
32 | && (AreEqual(other.IndexLocation, this.IndexLocation))
33 | && (AreEqual(other.Analyzer.GetType(), this.Analyzer.GetType()))
34 | && (CompareAttributes(other.Attributes));
35 | }
36 |
37 | public override bool Equals(object obj)
38 | {
39 | return Equals(obj as IndexOptions);
40 | }
41 |
42 | public override int GetHashCode()
43 | {
44 | return base.GetHashCode();
45 | }
46 |
47 | protected bool AreEqual(object obj1, object obj2)
48 | {
49 | if (obj1 == null && obj2 == null)
50 | return true;
51 |
52 | return (obj1.Equals(obj2));
53 | }
54 |
55 | protected bool CompareAttributes(IDictionary other)
56 | {
57 | foreach (var item in this.Attributes)
58 | {
59 | object obj;
60 | if (other.TryGetValue(item.Key, out obj))
61 | {
62 | if (!AreEqual(obj, item.Value))
63 | return false;
64 | }
65 | else
66 | {
67 | return false;
68 | }
69 | }
70 | return true;
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IndexResult.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Collections.ObjectModel;
3 |
4 | namespace SimpleLucene
5 | {
6 | public class IndexResult
7 | {
8 | private List errors;
9 |
10 | public IndexResult()
11 | {
12 | errors = new List();
13 | }
14 |
15 | public bool Success { get; set; }
16 | public int Count { get; set; }
17 | public long ExecutionTime { get; set; }
18 |
19 | public void AddError(string error)
20 | {
21 | errors.Add(error);
22 | }
23 |
24 | public ReadOnlyCollection Errors { get { return errors.AsReadOnly(); } }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/SimpleLucene/IndexService.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Lucene.Net.Documents;
4 | using Lucene.Net.Index;
5 | using System.Diagnostics;
6 |
7 | namespace SimpleLucene
8 | {
9 | ///
10 | /// Default index service implementation
11 | ///
12 | public class IndexService : IIndexService
13 | {
14 | private bool isDisposed;
15 | private readonly IIndexWriter indexWriter;
16 | private IndexWriter luceneWriter;
17 |
18 | public IndexService(IIndexWriter indexWriter)
19 | {
20 | if (indexWriter == null)
21 | {
22 | throw new ArgumentNullException("indexWriter");
23 | }
24 |
25 | this.indexWriter = indexWriter;
26 | }
27 |
28 | public IIndexWriter IndexWriter
29 | {
30 | get
31 | {
32 | return indexWriter;
33 | }
34 | }
35 |
36 | ///
37 | /// Indexes a collection of entities using the provided index definition
38 | ///
39 | /// The type of entity to index
40 | /// A list of entities
41 | /// The index definition
42 | /// An index result with the outcome of the indexing operation
43 | public IndexResult IndexEntities(IEnumerable entities, IIndexDefinition definition) where TEntity : class
44 | {
45 | return IndexEntities(entities, definition.Convert);
46 | }
47 |
48 | ///
49 | /// Indexes a collection of entities using a delegate index definition
50 | ///
51 | /// The type of entity to index
52 | /// A list of entities
53 | /// The delegate converter
54 | /// An index result with the outcome of the indexing operation
55 | public IndexResult IndexEntities(IEnumerable entities, Func converter)
56 | {
57 | var result = new IndexResult();
58 | result.ExecutionTime = Time(() =>
59 | {
60 | foreach (TEntity entity in entities)
61 | {
62 | this.GetWriter().AddDocument(converter(entity));
63 | result.Count++;
64 | }
65 | result.Success = true;
66 | });
67 |
68 | return result;
69 | }
70 |
71 | ///
72 | /// Indexes a single entity with the provided definition
73 | ///
74 | /// The type of entity to index
75 | /// The entity to index
76 | /// The index definition
77 | /// An index result with the outcome of the indexing operation
78 | public IndexResult IndexEntity(TEntity entity, IIndexDefinition definition) where TEntity : class
79 | {
80 | var result = new IndexResult();
81 | result.ExecutionTime = Time(() =>
82 | {
83 | this.GetWriter().UpdateDocument(definition.GetIndex(entity), definition.Convert(entity));
84 | result.Count++;
85 | result.Success = true;
86 | });
87 |
88 | return result;
89 | }
90 |
91 | ///
92 | /// Removes all documents that match the given term in the index
93 | ///
94 | /// A search term to match
95 | public void Remove(Term searchTerm)
96 | {
97 | this.GetWriter().DeleteDocuments(searchTerm);
98 | }
99 |
100 | public void Dispose()
101 | {
102 | if (!isDisposed && luceneWriter != null)
103 | {
104 | if (indexWriter.IndexOptions.OptimizeIndex)
105 | luceneWriter.Optimize();
106 |
107 | luceneWriter.Commit();
108 | luceneWriter.Dispose();
109 | isDisposed = true;
110 | }
111 | luceneWriter = null;
112 | }
113 |
114 | protected IndexWriter GetWriter()
115 | {
116 | if (isDisposed)
117 | isDisposed = false;
118 |
119 | if (luceneWriter == null)
120 | luceneWriter = indexWriter.Create();
121 |
122 | return luceneWriter;
123 | }
124 |
125 | private static long Time(Action action)
126 | {
127 | var sw = Stopwatch.StartNew();
128 | action.Invoke();
129 | return sw.ElapsedMilliseconds;
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/SimpleLucene/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("SimpleLucene")]
9 | [assembly: AssemblyDescription("SimpleLucene is a wrapper for the popular Lucene.NET search engine.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Ben Foster")]
12 | [assembly: AssemblyProduct("SimpleLucene")]
13 | [assembly: AssemblyCopyright("Copyright © Ben Foster 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("8ebb4eca-8479-4e58-bc67-64557a3c3013")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.2")]
36 | [assembly: AssemblyFileVersion("1.0.0.2")]
37 | [assembly: AssemblyInformationalVersion("1.0.0.2")]
38 |
--------------------------------------------------------------------------------
/src/SimpleLucene/QueryBase.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Index;
2 | using Lucene.Net.Search;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | namespace SimpleLucene
7 | {
8 | ///
9 | /// A base class for deriving custom query objects
10 | ///
11 | public abstract class QueryBase
12 | {
13 | private readonly BooleanQuery baseQuery = new BooleanQuery();
14 |
15 | protected QueryBase() { }
16 |
17 | protected QueryBase(Query query)
18 | {
19 | AddQuery(query);
20 | }
21 |
22 | public Query Query
23 | {
24 | get { return baseQuery; }
25 | }
26 |
27 | protected void AddQuery(Query query)
28 | {
29 | AddQuery(query, Occur.MUST);
30 | }
31 |
32 | protected void AddQuery(Query query, Occur occur)
33 | {
34 | if (query != null)
35 | {
36 | baseQuery.Add(query, occur);
37 | }
38 | }
39 |
40 | protected Query GetQueryFromList(IList list, string key)
41 | {
42 | return GetQueryFromList(list, (i) => key, i => i.ToString());
43 | }
44 |
45 | protected Query GetQueryFromList(IList list, Func key, Func value)
46 | {
47 | if (list.Count > 1)
48 | {
49 | var query = new BooleanQuery();
50 | foreach (var id in list)
51 | {
52 | query.Add(TermQuery(key(id), value(id)), Occur.MUST);
53 | }
54 | return query;
55 | }
56 | if (list.Count == 1)
57 | {
58 | return TermQuery(key(list[0]), value(list[0]));
59 | }
60 | return null;
61 | }
62 |
63 | protected Query TermQuery(string key, string value)
64 | {
65 | return new TermQuery(new Term(key, value));
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/SimpleLucene/SearchResult.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using Lucene.Net.Documents;
4 |
5 | namespace SimpleLucene
6 | {
7 | public class SearchResult
8 | {
9 | private readonly IEnumerable documents;
10 | private readonly IResultDefinition definition;
11 |
12 | private IEnumerable entities;
13 |
14 | public SearchResult(IEnumerable documents, IResultDefinition definition)
15 | {
16 | this.documents = documents;
17 | this.definition = definition;
18 | }
19 |
20 | public IEnumerable Documents
21 | {
22 | get { return documents; }
23 | }
24 |
25 | public IEnumerable Results
26 | {
27 | get
28 | {
29 | if (entities == null && definition != null)
30 | {
31 | entities = documents.Select(doc => definition.Convert(doc)).ToList();
32 | }
33 | return entities;
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/SimpleLucene/SearchService.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Documents;
2 | using Lucene.Net.Search;
3 | using System;
4 | using System.Linq;
5 |
6 | namespace SimpleLucene
7 | {
8 | ///
9 | /// Default search service implementation
10 | ///
11 | public class SearchService : ISearchService
12 | {
13 | private readonly IIndexSearcher indexSearcher;
14 | private Searcher luceneSearcher;
15 | private bool isDisposed;
16 |
17 | public SearchService(IIndexSearcher indexSearcher)
18 | {
19 | if (indexSearcher == null)
20 | {
21 | throw new ArgumentNullException("indexSearcher");
22 | }
23 |
24 | this.indexSearcher = indexSearcher;
25 | }
26 |
27 | ///
28 | /// Searches an index using the provided query
29 | ///
30 | /// A Lucene query to use for the search
31 | /// A search result containing Lucene documents
32 | public SearchResult SearchIndex(Query query)
33 | {
34 | return SearchIndex(query, new DocumentResultDefinition());
35 | }
36 |
37 | ///
38 | /// Searches an index using the provided query and returns a strongly typed result object
39 | ///
40 | /// The type of result object to return
41 | /// A Lucene query to use for the search
42 | /// A search definition used to transform the returned Lucene documents
43 | /// A search result object containing both Lucene documents and typed objects based on the definition
44 | public SearchResult SearchIndex(Query query, IResultDefinition definition)
45 | {
46 | var searcher = this.GetSearcher();
47 | TopDocs hits = null;
48 | hits = searcher.Search(query, 25000);
49 | var results = hits.ScoreDocs.Select(h => searcher.Doc(h.Doc));
50 | return new SearchResult(results, definition);
51 | }
52 |
53 | public void Dispose()
54 | {
55 | if (!isDisposed && luceneSearcher != null)
56 | {
57 | luceneSearcher.Dispose();
58 | }
59 | luceneSearcher = null;
60 | }
61 |
62 | protected Searcher GetSearcher()
63 | {
64 | if (isDisposed)
65 | {
66 | isDisposed = false;
67 | }
68 |
69 | if (luceneSearcher == null)
70 | {
71 | luceneSearcher = indexSearcher.Create();
72 | }
73 |
74 | return luceneSearcher;
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/SimpleLucene/SimpleLucene.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {72761871-5706-4ADD-A464-8935CC45FC57}
9 | Library
10 | Properties
11 | SimpleLucene
12 | SimpleLucene
13 | v4.0
14 | 512
15 | ..\
16 | true
17 |
18 |
19 | true
20 | full
21 | false
22 | bin\Debug\
23 | DEBUG;TRACE
24 | prompt
25 | 4
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | False
38 | ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll
39 |
40 |
41 | False
42 | ..\packages\Lucene.Net.3.0.3\lib\NET40\Lucene.Net.dll
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
88 |
89 |
90 |
91 |
98 |
--------------------------------------------------------------------------------
/src/SimpleLucene/SimpleLuceneExtensions.cs:
--------------------------------------------------------------------------------
1 | using Lucene.Net.Documents;
2 | using Lucene.Net.Search;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 |
8 | namespace SimpleLucene
9 | {
10 | ///
11 | /// Extension methods for SimpleLucene components
12 | ///
13 | public static class SimpleLuceneExtensions
14 | {
15 | ///
16 | /// Finds a valid index service that has a writer with matching index options
17 | ///
18 | /// The services collection to search
19 | /// The index options to match
20 | /// Index Service
21 | public static IIndexService FindWithOptions(this IEnumerable services, IndexOptions options)
22 | {
23 | if (services == null)
24 | {
25 | throw new ArgumentNullException("services");
26 | }
27 |
28 | return services.SingleOrDefault(s => s.IndexWriter.IndexOptions.Equals(options));
29 | }
30 |
31 | ///
32 | /// Creates a DirectoryInfo object from the index location's path
33 | ///
34 | /// The index location
35 | /// DirectoryInfo
36 | public static DirectoryInfo GetDirectory(this IIndexLocation location)
37 | {
38 | if (location == null)
39 | {
40 | throw new ArgumentNullException("location");
41 | }
42 |
43 | return new DirectoryInfo(location.GetPath());
44 | }
45 |
46 | ///
47 | /// Searches an index using the provided query and returns a strongly typed result object
48 | ///
49 | /// The type of result object to return
50 | /// A Lucene query to use for the search
51 | /// A delegate definition to transform the returned Lucene documents
52 | /// A search result object containing both Lucene documents and typed objects based on the delegate definition
53 | public static SearchResult SearchIndex(this ISearchService searchService,
54 | Query query, Func definition)
55 | {
56 | if (searchService == null)
57 | {
58 | throw new ArgumentNullException("searchService");
59 | }
60 |
61 | return searchService.SearchIndex(query, new DelegateSearchResultDefinition(definition));
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/SimpleLucene/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------