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); Directory.CreateDirectory(_basePath);
_contentDefinitionManager = new Mock<IContentDefinitionManager>(); _contentDefinitionManager = new Mock<IContentDefinitionManager>();
_appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath); _appDataFolder = AppDataFolderTests.CreateAppDataFolder(_basePath);
builder.RegisterType<DefaultLuceneAnalyzerProvider>().As<ILuceneAnalyzerProvider>();
builder.RegisterType<DefaultLuceneAnalyzerSelector>().As<ILuceneAnalyzerSelector>();
builder.RegisterType<LuceneIndexProvider>().As<IIndexProvider>(); builder.RegisterType<LuceneIndexProvider>().As<IIndexProvider>();
builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>(); builder.RegisterInstance(_appDataFolder).As<IAppDataFolder>();
builder.RegisterType<IndexingTaskExecutor>().As<IIndexingTaskExecutor>(); builder.RegisterType<IndexingTaskExecutor>().As<IIndexingTaskExecutor>();

View File

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

View File

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

View File

@@ -71,6 +71,11 @@
<Compile Include="Models\LuceneDocumentIndex.cs" /> <Compile Include="Models\LuceneDocumentIndex.cs" />
<Compile Include="Models\LuceneSearchHit.cs" /> <Compile Include="Models\LuceneSearchHit.cs" />
<Compile Include="Properties\AssemblyInfo.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\LuceneIndexProvider.cs" />
<Compile Include="Services\LuceneSearchBuilder.cs" /> <Compile Include="Services\LuceneSearchBuilder.cs" />
<Compile Include="Services\SearchBits.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> /// </summary>
public class LuceneIndexProvider : IIndexProvider { public class LuceneIndexProvider : IIndexProvider {
private readonly IAppDataFolder _appDataFolder; private readonly IAppDataFolder _appDataFolder;
public static readonly Version LuceneVersion = Version.LUCENE_29;
private readonly Analyzer _analyzer ;
private readonly string _basePath; 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; _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 // 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"); _basePath = _appDataFolder.Combine("Sites", shellSettings.Name, "Indexes");
@@ -48,18 +52,13 @@ namespace Lucene.Services {
public Localizer T { get; set; } public Localizer T { get; set; }
public ILogger Logger { 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() { private void EnsureDirectoryExists() {
var directory = new DirectoryInfo(_appDataFolder.MapPath(_basePath)); var directory = new DirectoryInfo(_appDataFolder.MapPath(_basePath));
if(!directory.Exists) { if(!directory.Exists) {
directory.Create(); directory.Create();
} }
} }
protected virtual Directory GetDirectory(string indexName) { protected virtual Directory GetDirectory(string indexName) {
var directoryInfo = new DirectoryInfo(_appDataFolder.MapPath(_appDataFolder.Combine(_basePath, indexName))); var directoryInfo = new DirectoryInfo(_appDataFolder.MapPath(_appDataFolder.Combine(_basePath, indexName)));
return FSDirectory.Open(directoryInfo); return FSDirectory.Open(directoryInfo);
@@ -104,7 +103,7 @@ namespace Lucene.Services {
} }
public void CreateIndex(string indexName) { 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 // Remove any previous document for these content items
Delete(indexName, indexDocuments.Select(i => i.ContentItemId)); 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) { foreach (var indexDocument in indexDocuments) {
var doc = CreateDocument(indexDocument); var doc = CreateDocument(indexDocument);
@@ -151,8 +150,8 @@ namespace Lucene.Services {
if (!documentIds.Any()) { if (!documentIds.Any()) {
return; 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(); var query = new BooleanQuery();
try { try {
@@ -173,7 +172,7 @@ namespace Lucene.Services {
} }
public ISearchBuilder CreateSearchBuilder(string indexName) { 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) { public IEnumerable<string> GetFields(string indexName) {

View File

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