Implemented RebuildIndex plus UpdateIndex signal to backgroung tasks. Adapted UI.

--HG--
branch : dev
This commit is contained in:
Sebastien Ros
2010-06-04 17:42:20 -07:00
parent d93c9274c8
commit 9eebb483ae
12 changed files with 193 additions and 74 deletions

View File

@@ -58,7 +58,11 @@ namespace Orchard.Tests.Indexing {
[Test]
public void IndexProviderShouldOverwriteAlreadyExistingIndex() {
_provider.CreateIndex("default");
_provider.Store("default", _provider.New(1).Add("body", null));
Assert.That(_provider.IsEmpty("default"), Is.False);
_provider.CreateIndex("default");
Assert.That(_provider.IsEmpty("default"), Is.True);
}
[Test]
@@ -193,5 +197,24 @@ namespace Orchard.Tests.Indexing {
_provider.SetLastIndexUtc("default", new DateTime(1901, 1, 1, 1, 1, 1, 1));
Assert.That(_provider.GetLastIndexUtc("default"), Is.EqualTo(DefaultIndexProvider.DefaultMinDateTime));
}
[Test]
public void IsEmptyShouldBeTrueForNoneExistingIndexes() {
_provider.IsEmpty("dummy");
Assert.That(_provider.IsEmpty("default"), Is.True);
}
[Test]
public void IsEmptyShouldBeTrueForJustNewIndexes() {
_provider.CreateIndex("default");
Assert.That(_provider.IsEmpty("default"), Is.True);
}
[Test]
public void IsEmptyShouldBeFalseWhenThereIsADocument() {
_provider.CreateIndex("default");
_provider.Store("default", _provider.New(1).Add("body", null));
Assert.That(_provider.IsEmpty("default"), Is.False);
}
}
}

View File

@@ -70,6 +70,21 @@ namespace Orchard.Core.Indexing.Lucene {
return new DirectoryInfo(_appDataFolder.MapPath(Path.Combine(_basePath, indexName))).Exists;
}
public bool IsEmpty(string indexName) {
if(!Exists(indexName)) {
return true;
}
var reader = IndexReader.Open(GetDirectory(indexName), true);
try {
return reader.NumDocs() == 0;
}
finally {
reader.Close();
}
}
public void CreateIndex(string indexName) {
var writer = new IndexWriter(GetDirectory(indexName), _analyzer, true, IndexWriter.MaxFieldLength.UNLIMITED);
writer.Close();
@@ -118,7 +133,6 @@ namespace Orchard.Core.Indexing.Lucene {
writer.Optimize();
writer.Close();
}
}
public void Delete(string indexName, int documentId) {

View File

@@ -10,47 +10,104 @@ using Orchard.Logging;
using Orchard.Services;
using Orchard.Tasks;
using Orchard.Core.Indexing.Models;
using Orchard.Tasks.Indexing;
using Orchard.Indexing;
namespace Orchard.Core.Indexing.Services {
/// <summary>
/// Contains the logic which is regularly executed to retrieve index information from multiple content handlers.
/// </summary>
[UsedImplicitly]
public class IndexingTaskExecutor : IBackgroundTask {
public class IndexingTaskExecutor : IBackgroundTask, IIndexNotifierHandler {
private readonly IClock _clock;
private readonly IRepository<IndexingTaskRecord> _repository;
private readonly IEnumerable<IContentHandler> _handlers;
private IIndexProvider _indexProvider;
private readonly IIndexManager _indexManager;
private readonly IIndexingTaskManager _indexingTaskManager;
private readonly IContentManager _contentManager;
private const string SearchIndexName = "Search";
private readonly object _synLock = new object();
public IndexingTaskExecutor(
IClock clock,
IRepository<IndexingTaskRecord> repository,
IEnumerable<IContentHandler> handlers,
IIndexManager indexManager,
IIndexingTaskManager indexingTaskManager,
IContentManager contentManager) {
_clock = clock;
_repository = repository;
_indexManager = indexManager;
_handlers = handlers;
_indexingTaskManager = indexingTaskManager;
_contentManager = contentManager;
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void UpdateIndex(string indexName) {
if (indexName == SearchIndexName) {
Sweep();
}
}
public void Sweep() {
if ( !System.Threading.Monitor.TryEnter(_synLock) ) {
Logger.Information("Index was requested but was already running");
return;
}
try {
if (!_indexManager.HasIndexProvider()) {
return;
}
_indexProvider = _indexManager.GetSearchIndexProvider();
var updateIndexDocuments = new List<IIndexDocument>();
var lastIndexing = DateTime.UtcNow;
// Do we need to rebuild the full index (first time module is used, or rebuild index requested) ?
if (_indexProvider.IsEmpty(SearchIndexName)) {
Logger.Information("Rebuild index started");
// mark current last task, as we should process older ones (in case of rebuild index only)
lastIndexing = _indexingTaskManager.GetLastTaskDateTime();
// get every existing content item to index it
foreach (var contentItem in _contentManager.Query(VersionOptions.Published).List()) {
try {
var context = new IndexContentContext {
ContentItem = contentItem,
IndexDocument = _indexProvider.New(contentItem.Id)
};
// dispatch to handlers to retrieve index information
foreach (var handler in _handlers) {
handler.Indexing(context);
}
updateIndexDocuments.Add(context.IndexDocument);
foreach (var handler in _handlers) {
handler.Indexed(context);
}
}
catch (Exception ex) {
Logger.Warning(ex, "Unable to index content item #{0} during rebuild", contentItem.Id);
}
}
}
else {
// retrieve last processed index time
var lastIndexing = _indexProvider.GetLastIndexUtc(SearchIndexName);
lastIndexing = _indexProvider.GetLastIndexUtc(SearchIndexName);
}
_indexProvider.SetLastIndexUtc(SearchIndexName, _clock.UtcNow);
// retrieve not yet processed tasks
@@ -66,8 +123,6 @@ namespace Orchard.Core.Indexing.Services {
_indexProvider.CreateIndex(SearchIndexName);
}
var updateIndexDocuments = new List<IIndexDocument>();
// process Delete tasks
try {
_indexProvider.Delete(SearchIndexName, taskRecords.Where(t => t.Action == IndexingTaskRecord.Delete).Select(t => t.Id));
@@ -111,5 +166,9 @@ namespace Orchard.Core.Indexing.Services {
}
}
}
finally {
System.Threading.Monitor.Exit(_synLock);
}
}
}
}

View File

@@ -59,12 +59,8 @@ namespace Orchard.Core.Indexing.Services {
Logger.Information("Deleting index task created for [{0}:{1}]", contentItem.ContentType, contentItem.Id);
}
public IEnumerable<IIndexingTask> GetTasks(DateTime? createdAfter) {
return _repository
.Fetch(x => x.CreatedUtc > createdAfter)
.Select(x => new IndexingTask(_contentManager, x))
.Cast<IIndexingTask>()
.ToReadOnlyCollection();
public DateTime GetLastTaskDateTime() {
return _repository.Table.Max(t => t.CreatedUtc) ?? DateTime.MinValue;
}
/// <summary>

View File

@@ -1,4 +1,5 @@
using System.Web.Mvc;
using System;
using System.Web.Mvc;
using Orchard.Localization;
using Orchard.Search.Services;
using Orchard.Search.ViewModels;
@@ -18,7 +19,7 @@ namespace Orchard.Search.Controllers {
public Localizer T { get; set; }
public ActionResult Index() {
var viewModel = new SearchIndexViewModel {HasIndexToManage = _searchService.HasIndexToManage};
var viewModel = new SearchIndexViewModel {HasIndexToManage = _searchService.HasIndexToManage, IndexUpdatedUtc = _searchService.GetIndexUpdatedUtc()};
if (!viewModel.HasIndexToManage)
Services.Notifier.Information(T("There is not search index to manage for this site."));

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Orchard.Indexing;
namespace Orchard.Search.Services {
@@ -7,5 +8,6 @@ namespace Orchard.Search.Services {
IEnumerable<ISearchHit> Query(string term);
void RebuildIndex();
void UpdateIndex();
DateTime GetIndexUpdatedUtc();
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.Indexing;
using Orchard.Localization;
@@ -8,12 +9,14 @@ namespace Orchard.Search.Services
{
public class SearchService : ISearchService
{
private const string SearchIndexName = "search";
private const string SearchIndexName = "Search";
private readonly IIndexManager _indexManager;
private readonly IEnumerable<IIndexNotifierHandler> _indexNotifierHandlers;
public SearchService(IOrchardServices services, IIndexManager indexManager) {
public SearchService(IOrchardServices services, IIndexManager indexManager, IEnumerable<IIndexNotifierHandler> indexNotifierHandlers) {
Services = services;
_indexManager = indexManager;
_indexNotifierHandlers = indexNotifierHandlers;
T = NullLocalizer.Instance;
}
@@ -49,10 +52,20 @@ namespace Orchard.Search.Services
}
public void UpdateIndex() {
//todo: this
//if (_indexManager.HasIndexProvider())
// _indexManager.GetSearchIndexProvider().UpdateIndex(SearchIndexName);
foreach(var handler in _indexNotifierHandlers) {
handler.UpdateIndex(SearchIndexName);
}
Services.Notifier.Information(T("The search index has been updated."));
}
public DateTime GetIndexUpdatedUtc() {
if(!HasIndexToManage) {
return DateTime.MinValue;
}
return _indexManager.GetSearchIndexProvider().GetLastIndexUtc(SearchIndexName);
}
}
}

View File

@@ -10,7 +10,7 @@ using (Html.BeginForm("update", "admin", FormMethod.Post, new {area = "Orchard.S
}
using (Html.BeginForm("rebuild", "admin", FormMethod.Post, new {area = "Orchard.Search"})) { %>
<fieldset>
<p><%=T("Rebuild the search index for a fresh start. <button type=\"submit\" title=\"Rebuild the search index.\">Rebuld</button>") %></p>
<p><%=T("Rebuild the search index for a fresh start. <button type=\"submit\" title=\"Rebuild the search index.\">Rebuild</button>") %></p>
<%=Html.AntiForgeryTokenOrchard() %>
</fieldset><%
} %>

View File

@@ -0,0 +1,5 @@
namespace Orchard.Indexing {
public interface IIndexNotifierHandler : IEvents {
void UpdateIndex(string indexName);
}
}

View File

@@ -18,6 +18,11 @@ namespace Orchard.Indexing {
/// </summary>
void DeleteIndex(string name);
/// <summary>
/// Whether an index is empty or not
/// </summary>
bool IsEmpty(string indexName);
/// <summary>
/// Creates an empty document
/// </summary>

View File

@@ -349,6 +349,7 @@
<Compile Include="Environment\State\IShellStateManager.cs" />
<Compile Include="Environment\State\ShellStateCoordinator.cs" />
<Compile Include="IDependency.cs" />
<Compile Include="Indexing\IIndexNotifierHandler.cs" />
<Compile Include="Localization\Services\DefaultCultureManager.cs" />
<Compile Include="Localization\Services\DefaultResourceManager.cs" />
<Compile Include="Indexing\DefaultIndexManager.cs" />

View File

@@ -15,9 +15,9 @@ namespace Orchard.Tasks.Indexing {
void CreateDeleteIndexTask(ContentItem contentItem);
/// <summary>
/// Loads all indexing tasks created after to a specific date and time
/// Returns the Date Time of the last task created
/// </summary>
IEnumerable<IIndexingTask> GetTasks(DateTime? createdAfter);
DateTime GetLastTaskDateTime();
/// <summary>
/// Deletes all indexing tasks assigned to a specific content item