Adding Lucene analyzer extensibility point

This commit is contained in:
Sebastien Ros
2014-08-06 16:56:11 -07:00
parent bd7e71d721
commit fdd6c0aba7
11 changed files with 123 additions and 20 deletions

View File

@@ -59,7 +59,9 @@ namespace Orchard.Tests.Modules.Indexing {
Directory.CreateDirectory(_basePath);
_contentDefinitionManager = new Mock<IContentDefinitionManager>();
_appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath);
builder.RegisterType<DefaultLuceneAnalyzerProvider>().As<ILuceneAnalyzerProvider>();
builder.RegisterType<DefaultLuceneAnalyzerSelector>().As<ILuceneAnalyzerSelector>();
builder.RegisterType<LuceneIndexProvider>().As<IIndexProvider>();
builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>();
builder.RegisterType<IndexingTaskExecutor>().As<IIndexingTaskExecutor>();

View File

@@ -35,6 +35,8 @@ namespace Orchard.Tests.Modules.Indexing {
_appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath);
var builder = new ContainerBuilder();
builder.RegisterType<DefaultLuceneAnalyzerProvider>().As<ILuceneAnalyzerProvider>();
builder.RegisterType<DefaultLuceneAnalyzerSelector>().As<ILuceneAnalyzerSelector>();
builder.RegisterType<LuceneIndexProvider>().As<IIndexProvider>();
builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>();

View File

@@ -34,6 +34,8 @@ namespace Orchard.Tests.Modules.Indexing {
_appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath);
var builder = new ContainerBuilder();
builder.RegisterType<DefaultLuceneAnalyzerProvider>().As<ILuceneAnalyzerProvider>();
builder.RegisterType<DefaultLuceneAnalyzerSelector>().As<ILuceneAnalyzerSelector>();
builder.RegisterType<LuceneIndexProvider>().As<IIndexProvider>();
builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>();

View File

@@ -71,6 +71,11 @@
<Compile Include="Models\LuceneDocumentIndex.cs" />
<Compile Include="Models\LuceneSearchHit.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Services\DefaultLuceneAnalyzerSelector.cs" />
<Compile Include="Services\DefaultLuceneAnalyzerProvider.cs" />
<Compile Include="Services\ILuceneAnalyzerProvider.cs" />
<Compile Include="Services\ILuceneAnalyzerSelector.cs" />
<Compile Include="Services\LuceneAnalyzerSelectorResult.cs" />
<Compile Include="Services\LuceneIndexProvider.cs" />
<Compile Include="Services\LuceneSearchBuilder.cs" />
<Compile Include="Services\SearchBits.cs" />

View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Orchard;
namespace Lucene.Services {
public class DefaultLuceneAnalyzerProvider : ILuceneAnalyzerProvider {
private IEnumerable<ILuceneAnalyzerSelector> _analyzerSelectors;
public DefaultLuceneAnalyzerProvider(IEnumerable<ILuceneAnalyzerSelector> analyzerSelectors) {
_analyzerSelectors = analyzerSelectors;
}
public Analyzer GetAnalyzer(string indexName) {
var analyzer = _analyzerSelectors
.Select(x => x.GetLuceneAnalyzer(indexName))
.Where(x => x != null)
.OrderByDescending(x => x.Priority)
.Select(x => x.Analyzer)
.FirstOrDefault();
if (analyzer != null) {
return analyzer;
}
return new StandardAnalyzer(LuceneIndexProvider.LuceneVersion);
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Lucene.Net.Analysis.Standard;
namespace Lucene.Services {
public class DefaultLuceneAnalyzerSelector : ILuceneAnalyzerSelector {
public LuceneAnalyzerSelectorResult GetLuceneAnalyzer(string indexName) {
return new LuceneAnalyzerSelectorResult {
Priority = -5,
Analyzer = new StandardAnalyzer(LuceneIndexProvider.LuceneVersion)
};
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Lucene.Net.Analysis;
using Orchard;
namespace Lucene.Services {
public interface ILuceneAnalyzerProvider : IDependency {
Analyzer GetAnalyzer(string indexName);
}
}

View File

@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard;
namespace Lucene.Services {
public interface ILuceneAnalyzerSelector : IDependency {
LuceneAnalyzerSelectorResult GetLuceneAnalyzer(string indexName);
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Lucene.Net.Analysis;
namespace Lucene.Services {
public class LuceneAnalyzerSelectorResult {
public int Priority { get; set; }
public Analyzer Analyzer { get; set; }
}
}

View File

@@ -24,14 +24,18 @@ namespace Lucene.Services {
/// </summary>
public class LuceneIndexProvider : IIndexProvider {
private readonly IAppDataFolder _appDataFolder;
public static readonly Version LuceneVersion = Version.LUCENE_29;
private readonly Analyzer _analyzer ;
private readonly string _basePath;
public static readonly DateTime DefaultMinDateTime = new DateTime(1980, 1, 1);
private ILuceneAnalyzerProvider _analyzerProvider;
public LuceneIndexProvider(IAppDataFolder appDataFolder, ShellSettings shellSettings) {
public static readonly Version LuceneVersion = Version.LUCENE_29;
public static readonly DateTime DefaultMinDateTime = new DateTime(1980, 1, 1);
public LuceneIndexProvider(
IAppDataFolder appDataFolder,
ShellSettings shellSettings,
ILuceneAnalyzerProvider analyzerProvider) {
_appDataFolder = appDataFolder;
_analyzer = CreateAnalyzer();
_analyzerProvider = analyzerProvider;
// TODO: (sebros) Find a common way to get where tenant's specific files should go. "Sites/Tenant" is hard coded in multiple places
_basePath = _appDataFolder.Combine("Sites", shellSettings.Name, "Indexes");
@@ -48,18 +52,13 @@ namespace Lucene.Services {
public Localizer T { get; set; }
public ILogger Logger { get; set; }
public static Analyzer CreateAnalyzer() {
// StandardAnalyzer does lower-case and stop-word filtering. It also removes punctuation
return new StandardAnalyzer(LuceneVersion);
}
private void EnsureDirectoryExists() {
var directory = new DirectoryInfo(_appDataFolder.MapPath(_basePath));
if(!directory.Exists) {
directory.Create();
}
}
protected virtual Directory GetDirectory(string indexName) {
var directoryInfo = new DirectoryInfo(_appDataFolder.MapPath(_appDataFolder.Combine(_basePath, indexName)));
return FSDirectory.Open(directoryInfo);
@@ -104,7 +103,7 @@ namespace Lucene.Services {
}
public void CreateIndex(string indexName) {
using (new IndexWriter(GetDirectory(indexName), _analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED)) {
using (new IndexWriter(GetDirectory(indexName), _analyzerProvider.GetAnalyzer(indexName), true, IndexWriter.MaxFieldLength.UNLIMITED)) {
}
}
@@ -131,7 +130,7 @@ namespace Lucene.Services {
// Remove any previous document for these content items
Delete(indexName, indexDocuments.Select(i => i.ContentItemId));
using(var writer = new IndexWriter(GetDirectory(indexName), _analyzer, false, IndexWriter.MaxFieldLength.UNLIMITED)) {
using (var writer = new IndexWriter(GetDirectory(indexName), _analyzerProvider.GetAnalyzer(indexName), false, IndexWriter.MaxFieldLength.UNLIMITED)) {
foreach (var indexDocument in indexDocuments) {
var doc = CreateDocument(indexDocument);
@@ -151,8 +150,8 @@ namespace Lucene.Services {
if (!documentIds.Any()) {
return;
}
using(var writer = new IndexWriter(GetDirectory(indexName), _analyzer, false, IndexWriter.MaxFieldLength.UNLIMITED)) {
using (var writer = new IndexWriter(GetDirectory(indexName), _analyzerProvider.GetAnalyzer(indexName), false, IndexWriter.MaxFieldLength.UNLIMITED)) {
var query = new BooleanQuery();
try {
@@ -173,7 +172,7 @@ namespace Lucene.Services {
}
public ISearchBuilder CreateSearchBuilder(string indexName) {
return new LuceneSearchBuilder(GetDirectory(indexName)) { Logger = Logger };
return new LuceneSearchBuilder(GetDirectory(indexName), _analyzerProvider, indexName) { Logger = Logger };
}
public IEnumerable<string> GetFields(string indexName) {

View File

@@ -19,6 +19,8 @@ namespace Lucene.Services {
private const int MaxResults = Int16.MaxValue;
private readonly Directory _directory;
private ILuceneAnalyzerProvider _analyzerProvider;
private string _indexName;
private readonly List<BooleanClause> _clauses;
private readonly List<BooleanClause> _filters;
@@ -34,12 +36,17 @@ namespace Lucene.Services {
private bool _exactMatch;
private float _boost;
private Query _query;
private readonly Analyzer _analyzer = LuceneIndexProvider.CreateAnalyzer();
public ILogger Logger { get; set; }
public LuceneSearchBuilder(Directory directory) {
public LuceneSearchBuilder(
Directory directory,
ILuceneAnalyzerProvider analyzerProvider,
string indexName) {
_directory = directory;
_indexName = indexName;
_analyzerProvider = analyzerProvider;
Logger = NullLogger.Instance;
_count = MaxResults;
@@ -72,7 +79,7 @@ namespace Lucene.Services {
foreach (var defaultField in defaultFields) {
CreatePendingClause();
_query = new QueryParser(LuceneIndexProvider.LuceneVersion, defaultField, _analyzer).Parse(query);
_query = new QueryParser(LuceneIndexProvider.LuceneVersion, defaultField, _analyzerProvider.GetAnalyzer(_indexName)).Parse(query);
}
return this;