From 08972b8cbbc3cc31c48e1fd4ca42dbd8c87dad35 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Tue, 5 Mar 2013 11:13:33 -0800 Subject: [PATCH] Incremental work on multiple indexes --HG-- branch : 1.x extra : rebase_source : 39da1f112307ff02bf7a01ecabc95a43271d476c --- .../Indexing/IndexingTaskExecutorTests.cs | 4 +- src/Orchard.Web/Modules/Lucene/Module.txt | 1 + .../Commands/IndexingCommands.cs | 71 +++++++++++++---- .../Modules/Orchard.Indexing/Migrations.cs | 3 + .../Orchard.Indexing/Services/IndexService.cs | 2 +- .../Services/IndexingTaskExecutor.cs | 26 +++++-- .../Orchard.Indexing/Settings/EditorEvents.cs | 3 +- .../Orchard.Indexing/Settings/TypeIndexing.cs | 11 ++- .../Orchard.Indexing/Views/Admin/Index.cshtml | 2 +- .../DefinitionTemplates/TypeIndexing.cshtml | 26 +++++-- .../Orchard.Search/Commands/SearchCommands.cs | 28 +++++++ .../Controllers/AdminController.cs | 9 ++- .../Controllers/ContentPickerController.cs | 3 +- .../Controllers/SearchController.cs | 10 ++- .../Drivers/SearchSettingsPartDriver.cs | 22 ++++-- .../Modules/Orchard.Search/Migrations.cs | 11 ++- .../Models/SearchSettingsPart.cs | 5 ++ .../Models/SearchSettingsPartRecord.cs | 7 +- .../Orchard.Search/Orchard.Search.csproj | 5 ++ .../Orchard.Search/Recipes/Search.recipe.xml | 30 +++++++ .../Orchard.Search/Services/ISearchService.cs | 2 +- .../Orchard.Search/Services/SearchService.cs | 8 +- .../ContentPickerFieldEditorEvents.cs | 1 + .../Settings/ContentPickerFieldSettings.cs | 1 + .../ViewModels/SearchSettingsViewModel.cs | 8 +- .../ContentPickerSearchFieldSettings.cshtml | 17 +++- .../Parts/Search.SiteSettings.cshtml | 78 +++++++++++++++---- .../Orchard.Setup/Recipes/blog.recipe.xml | 4 +- .../Orchard.Setup/Recipes/default.recipe.xml | 4 +- src/Orchard/Indexing/DefaultIndexManager.cs | 4 +- src/Orchard/Indexing/MetaDataExtensions.cs | 4 +- 31 files changed, 324 insertions(+), 86 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Commands/SearchCommands.cs create mode 100644 src/Orchard.Web/Modules/Orchard.Search/Recipes/Search.recipe.xml diff --git a/src/Orchard.Tests.Modules/Indexing/IndexingTaskExecutorTests.cs b/src/Orchard.Tests.Modules/Indexing/IndexingTaskExecutorTests.cs index b57053c27..56cba118f 100644 --- a/src/Orchard.Tests.Modules/Indexing/IndexingTaskExecutorTests.cs +++ b/src/Orchard.Tests.Modules/Indexing/IndexingTaskExecutorTests.cs @@ -111,7 +111,7 @@ namespace Orchard.Tests.Modules.Indexing { var thingType = new ContentTypeDefinitionBuilder() .Named(ThingDriver.ContentTypeName) - .WithSetting("TypeIndexing.Included", "true") + .WithSetting("TypeIndexing.Indexes", "Search") .Build(); _contentDefinitionManager @@ -145,7 +145,7 @@ namespace Orchard.Tests.Modules.Indexing { public void ShouldNotIndexContentIfIndexDocumentIsEmpty() { var alphaType = new ContentTypeDefinitionBuilder() .Named("alpha") - .WithSetting("TypeIndexing.Included", "true") // the content types should be indexed, but there is no content at all + .WithSetting("TypeIndexing.Indexes", "Search") // the content types should be indexed, but there is no content at all .Build(); _contentDefinitionManager diff --git a/src/Orchard.Web/Modules/Lucene/Module.txt b/src/Orchard.Web/Modules/Lucene/Module.txt index 7eb63a4ce..9a96020d4 100644 --- a/src/Orchard.Web/Modules/Lucene/Module.txt +++ b/src/Orchard.Web/Modules/Lucene/Module.txt @@ -6,4 +6,5 @@ Version: 1.6 OrchardVersion: 1.4.1 Description: The Lucene module enables the site to be indexed using Lucene.NET. The index generated by this module can then be used by the search module to provide an integrated full-text search experience to a web site. FeatureDescription: Lucene indexing services. +Dependencies: Orchard.Indexing Category: Search diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Commands/IndexingCommands.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Commands/IndexingCommands.cs index 74252036b..a5cefdda9 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Commands/IndexingCommands.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Commands/IndexingCommands.cs @@ -2,9 +2,9 @@ using System.Linq; using Orchard.Commands; using Orchard.ContentManagement; -using Orchard.ContentManagement.Aspects; using Orchard.Indexing.Services; using Orchard.Tasks.Indexing; +using Orchard.Utility.Extensions; namespace Orchard.Indexing.Commands { public class IndexingCommands : DefaultOrchardCommandHandler { @@ -12,7 +12,6 @@ namespace Orchard.Indexing.Commands { private readonly IIndexingService _indexingService; private readonly IIndexingTaskManager _indexingTaskManager; private readonly IContentManager _contentManager; - private const string SearchIndexName = "Search"; public IndexingCommands( IIndexManager indexManager, @@ -31,29 +30,66 @@ namespace Orchard.Indexing.Commands { [OrchardSwitch] public string ContentItem { get; set; } + [CommandName("index create")] + [CommandHelp("index create \r\n\t" + "Creates a new index with the specified name")] + public void Create(string index) { + if (!_indexManager.HasIndexProvider()) { + Context.Output.WriteLine(T("No index service available")); + return; + } + + if (string.IsNullOrWhiteSpace(index)) { + Context.Output.WriteLine(T("Invalid index name.")); + return; + } + + if (index.ToSafeName() != index) { + Context.Output.WriteLine(T("Invalid index name.")); + } + else { + _indexManager.GetSearchIndexProvider().CreateIndex(index); + Context.Output.WriteLine(T("New index has been created succeffully.")); + } + } + [CommandName("index update")] - [CommandHelp("index update\r\n\t" + "Updates the search index")] - public void Update() { - _indexingService.UpdateIndex(SearchIndexName); + [CommandHelp("index update \r\n\t" + "Updates the specified index")] + public void Update(string index) { + if (string.IsNullOrWhiteSpace(index)) { + Context.Output.WriteLine(T("Invalid index name.")); + return; + } + + _indexingService.UpdateIndex(index); Context.Output.WriteLine(T("Index is now being updated...")); } [CommandName("index rebuild")] - [CommandHelp("index rebuild \r\n\t" + "Rebuilds the search index")] - public void Rebuild() { - _indexingService.RebuildIndex(SearchIndexName); + [CommandHelp("index rebuild \r\n\t" + "Rebuilds the specified index")] + public void Rebuild(string index) { + if (string.IsNullOrWhiteSpace(index)) { + Context.Output.WriteLine(T("Invalid index name.")); + return; + } + + _indexingService.RebuildIndex(index); Context.Output.WriteLine(T("Index is now being rebuilt...")); } - [CommandName("index search")] - [CommandHelp("index search /Query:\r\n\t" + "Searches the specified terms in the search index")] + [CommandName("index query")] + [CommandHelp("index query /Query:\r\n\t" + "Searches the specified terms in the specified index")] [OrchardSwitches("Query")] - public void Search() { + public void Search(string index) { + if (string.IsNullOrWhiteSpace(index)) { + Context.Output.WriteLine(T("Invalid index name.")); + return; + } + if ( !_indexManager.HasIndexProvider() ) { Context.Output.WriteLine(T("No index available")); return; } - var searchBuilder = _indexManager.GetSearchIndexProvider().CreateSearchBuilder(SearchIndexName); + var searchBuilder = _indexManager.GetSearchIndexProvider().CreateSearchBuilder(index); var results = searchBuilder.Parse( new [] {"body", "title"}, Query).Search(); Context.Output.WriteLine("{0} result{1}\r\n-----------------\r\n", results.Count(), results.Count() > 0 ? "s" : ""); @@ -76,15 +112,20 @@ namespace Orchard.Indexing.Commands { } [CommandName("index stats")] - [CommandHelp("index stats\r\n\t" + "Displays some statistics about the search index")] + [CommandHelp("index stats \r\n\t" + "Displays some statistics about the search index")] [OrchardSwitches("IndexName")] - public void Stats() { + public void Stats(string index) { + if (string.IsNullOrWhiteSpace(index)) { + Context.Output.WriteLine(T("Invalid index name.")); + return; + } + if ( !_indexManager.HasIndexProvider() ) { Context.Output.WriteLine(T("No index available")); return; } - Context.Output.WriteLine(T("Number of indexed documents: {0}", _indexManager.GetSearchIndexProvider().NumDocs(SearchIndexName))); + Context.Output.WriteLine(T("Number of indexed documents: {0}", _indexManager.GetSearchIndexProvider().NumDocs(index))); } [CommandName("index refresh")] diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Migrations.cs index 596cf9959..7621b2898 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Migrations.cs @@ -15,5 +15,8 @@ namespace Orchard.Indexing { return 1; } + + // todo: When upgrading from 1, change TypeIndexing.Included to TypeIndexing.Indexes = "Search" + // todo: When upgrading from 1, define SearchSettingsPart.SelectedIndex to "Search" } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexService.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexService.cs index 4e68f2de9..732d0ba50 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexService.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexService.cs @@ -68,7 +68,7 @@ namespace Orchard.Indexing.Services handler.UpdateIndex(indexName); } - Services.Notifier.Information(T("The search index has been updated.")); + Services.Notifier.Information(T("The index {0} has been updated.", indexName)); } IndexEntry IIndexingService.GetIndexEntry(string indexName) { diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs index cdae2aade..d233370d0 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Services/IndexingTaskExecutor.cs @@ -166,6 +166,13 @@ namespace Orchard.Indexing.Services { foreach (var item in contentItems) { try { + + // skip items from types which are not indexed + var settings = GetTypeIndexingSettings(item); + if (!settings.Indexes.Contains(indexName)) { + continue; + } + IDocumentIndex documentIndex = ExtractDocumentIndex(item); if (documentIndex != null && documentIndex.IsDirty) { @@ -195,8 +202,17 @@ namespace Orchard.Indexing.Services { foreach (var item in indexingTasks) { try { + + IDocumentIndex documentIndex = null; + // item.ContentItem can be null if the content item has been deleted - IDocumentIndex documentIndex = ExtractDocumentIndex(item.ContentItem); + if (item.ContentItem != null) { + // skip items from types which are not indexed + var settings = GetTypeIndexingSettings(item.ContentItem); + if (!settings.Indexes.Contains(indexName)) { + documentIndex = ExtractDocumentIndex(item.ContentItem); + } + } if (documentIndex == null || item.Delete) { deleteFromIndex.Add(item.Id); @@ -284,12 +300,6 @@ namespace Orchard.Indexing.Services { return null; } - // skip items from types which are not indexed - var settings = GetTypeIndexingSettings(contentItem); - if (!settings.Included) { - return null; - } - var documentIndex = _indexProvider.New(contentItem.Id); // call all handlers to add content to index @@ -301,7 +311,7 @@ namespace Orchard.Indexing.Services { if (contentItem == null || contentItem.TypeDefinition == null || contentItem.TypeDefinition.Settings == null) { - return new TypeIndexing {Included = false}; + return new TypeIndexing {Indexes = ""}; } return contentItem.TypeDefinition.Settings.GetModel(); } diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs index 69f37315a..5542970db 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/EditorEvents.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using Orchard.ContentManagement; using Orchard.ContentManagement.MetaData; using Orchard.ContentManagement.MetaData.Builders; @@ -28,7 +29,7 @@ namespace Orchard.Indexing.Settings { public override IEnumerable TypeEditorUpdate(ContentTypeDefinitionBuilder builder, IUpdateModel updateModel) { var model = new TypeIndexing(); updateModel.TryUpdateModel(model, "TypeIndexing", null, null); - builder.WithSetting("TypeIndexing.Included", model.Included ? true.ToString() : null); + builder.WithSetting("TypeIndexing.Indexes", model.Indexes); CreateIndexingTasks(); diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/TypeIndexing.cs b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/TypeIndexing.cs index 45e90a4e7..3cba107f7 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Settings/TypeIndexing.cs +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Settings/TypeIndexing.cs @@ -1,5 +1,12 @@ -namespace Orchard.Indexing.Settings { +using System; + +namespace Orchard.Indexing.Settings { public class TypeIndexing { - public bool Included { get; set; } + public string Indexes { get; set; } + + public string[] List { + get { return String.IsNullOrEmpty(Indexes) ? new string[0] : Indexes.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); } + set { Indexes = String.Join(",", value); } + } } } diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.Indexing/Views/Admin/Index.cshtml index 29314bd33..afdcf66b6 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Views/Admin/Index.cshtml @@ -61,7 +61,7 @@ } } else { -
@T("There are no indexes.")
+
@T("There is currently no index.")
} @if (Model.IndexProvider != null) { diff --git a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml index 8d39be8b5..54df88943 100644 --- a/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Indexing/Views/DefinitionTemplates/TypeIndexing.cshtml @@ -1,7 +1,21 @@ -@model Orchard.Indexing.Settings.TypeIndexing +@using Orchard.Indexing +@using Orchard.Utility.Extensions +@model Orchard.Indexing.Settings.TypeIndexing +@{ + var indexProvider = WorkContext.Resolve().GetSearchIndexProvider(); + +} -
- @Html.EditorFor(m=>m.Included) - - @Html.ValidationMessageFor(m=>m.Included) -
\ No newline at end of file +@if (indexProvider != null) { +
+ @T("Index this content type in:") + @{ var i = 0;} + @foreach (var index in indexProvider.List()) { +
+ + +
+ i++; + } +
+} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Commands/SearchCommands.cs b/src/Orchard.Web/Modules/Orchard.Search/Commands/SearchCommands.cs new file mode 100644 index 000000000..b16a8fb56 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Commands/SearchCommands.cs @@ -0,0 +1,28 @@ +using Orchard.Commands; +using Orchard.ContentManagement; +using Orchard.Search.Models; + +namespace Orchard.Search.Commands { + public class SearchCommands : DefaultOrchardCommandHandler { + private readonly IOrchardServices _orchardServices; + + public SearchCommands(IOrchardServices orchardServices) { + _orchardServices = orchardServices; + } + + [CommandName("search use")] + [CommandHelp("search use \r\n\t" + "Defines the default index to use for search")] + public void Index(string index) { + var settings = _orchardServices.WorkContext.CurrentSite.As(); + + if (string.IsNullOrWhiteSpace(index)) { + Context.Output.WriteLine(T("Invalid index name.")); + return; + } + + if (settings != null) { + settings.SearchIndex = index; + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs index d8efc8da9..641baefd4 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Controllers/AdminController.cs @@ -36,15 +36,16 @@ namespace Orchard.Search.Controllers { public Localizer T { get; set; } public ActionResult Index(PagerParameters pagerParameters, string searchText = "") { - Pager pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); - var searchFields = Services.WorkContext.CurrentSite.As().SearchedFields; - + var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); + var searchSettingsPart = Services.WorkContext.CurrentSite.As(); + IPageOfItems searchHits = new PageOfItems(new ISearchHit[] { }); try { searchHits = _searchService.Query(searchText, pager.Page, pager.PageSize, Services.WorkContext.CurrentSite.As().Record.FilterCulture, - searchFields, + searchSettingsPart.SearchIndex, + searchSettingsPart.SearchedFields, searchHit => searchHit); } catch (Exception exception) { diff --git a/src/Orchard.Web/Modules/Orchard.Search/Controllers/ContentPickerController.cs b/src/Orchard.Web/Modules/Orchard.Search/Controllers/ContentPickerController.cs index ccaf3a580..1eeb767fa 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Controllers/ContentPickerController.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Controllers/ContentPickerController.cs @@ -64,7 +64,8 @@ namespace Orchard.Search.Controllers { return View("NoIndex"); } - var builder = _indexManager.GetSearchIndexProvider().CreateSearchBuilder("Search"); + var builder = _indexManager.GetSearchIndexProvider().CreateSearchBuilder(settings.SearchIndex); + try { builder.Parse(searchFields, searchText); diff --git a/src/Orchard.Web/Modules/Orchard.Search/Controllers/SearchController.cs b/src/Orchard.Web/Modules/Orchard.Search/Controllers/SearchController.cs index 0f184cb87..50da369b6 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Controllers/SearchController.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Controllers/SearchController.cs @@ -46,14 +46,20 @@ namespace Orchard.Search.Controllers { public ActionResult Index(PagerParameters pagerParameters, string q = "") { var pager = new Pager(_siteService.GetSiteSettings(), pagerParameters); - var searchFields = Services.WorkContext.CurrentSite.As().SearchedFields; + var searchSettingPart = Services.WorkContext.CurrentSite.As(); + + if (String.IsNullOrEmpty(searchSettingPart.SearchIndex)) { + Services.Notifier.Error(T("Please define a default search index")); + return HttpNotFound(); + } IPageOfItems searchHits = new PageOfItems(new ISearchHit[] { }); try { searchHits = _searchService.Query(q, pager.Page, pager.PageSize, Services.WorkContext.CurrentSite.As().Record.FilterCulture, - searchFields, + searchSettingPart.SearchIndex, + searchSettingPart.SearchedFields, searchHit => searchHit); } catch(Exception exception) { Logger.Error(T("Invalid search query: {0}", exception.Message).Text); diff --git a/src/Orchard.Web/Modules/Orchard.Search/Drivers/SearchSettingsPartDriver.cs b/src/Orchard.Web/Modules/Orchard.Search/Drivers/SearchSettingsPartDriver.cs index 073d16d00..20e2512c7 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Drivers/SearchSettingsPartDriver.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Drivers/SearchSettingsPartDriver.cs @@ -11,7 +11,6 @@ using Orchard.Search.ViewModels; namespace Orchard.Search.Drivers { public class SearchSettingsPartDriver : ContentPartDriver { - private const string SearchIndexName = "Search"; private readonly IIndexManager _indexManager; public SearchSettingsPartDriver(IIndexManager indexManager) { @@ -30,24 +29,33 @@ namespace Orchard.Search.Drivers { protected override DriverResult Editor(SearchSettingsPart part, IUpdateModel updater, dynamic shapeHelper) { return ContentShape("Parts_Search_SiteSettings", () => { - SearchSettingsViewModel model = new SearchSettingsViewModel(); + var model = new SearchSettingsViewModel(); String[] searchedFields = part.SearchedFields; if (updater != null) { // submitting: rebuild model from form data if (updater.TryUpdateModel(model, Prefix, null, null)) { // update part if successful - part.SearchedFields = model.Entries.Where(e => e.Selected).Select(e => e.Field).ToArray(); + part.SearchIndex = model.SelectedIndex; + part.SearchedFields = model.Entries.First(e => e.Index == model.SelectedIndex).Fields.Where(e => e.Selected).Select(e => e.Field).ToArray(); part.FilterCulture = model.FilterCulture; } } else if (_indexManager.HasIndexProvider()) { // viewing editor: build model from part model.FilterCulture = part.FilterCulture; - model.Entries = new List(); - foreach (var field in _indexManager.GetSearchIndexProvider().GetFields(SearchIndexName)) { - model.Entries.Add(new SearchSettingsEntry { Field = field, Selected = searchedFields.Contains(field) }); - } + model.SelectedIndex = part.SearchIndex; + model.Entries = _indexManager.GetSearchIndexProvider().List().Select(x => { + var indexSettings = new IndexSettingsEntry { + Index = x, + Fields = new List() + }; + foreach (var field in _indexManager.GetSearchIndexProvider().GetFields(x)) { + indexSettings.Fields.Add(new SearchSettingsEntry {Field = field, Selected = (x == part.SearchIndex && searchedFields.Contains(field))}); + } + + return indexSettings; + }).ToList(); } return shapeHelper.EditorTemplate(TemplateName: "Parts/Search.SiteSettings", Model: model, Prefix: Prefix); diff --git a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs index 42aa6f327..8b45b8266 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Migrations.cs @@ -10,6 +10,7 @@ namespace Orchard.Search { .ContentPartRecord() .Column("FilterCulture") .Column("SearchedFields", c => c.Unlimited()) + .Column("SearchIndex") ); ContentDefinitionManager.AlterTypeDefinition("SearchForm", @@ -20,7 +21,15 @@ namespace Orchard.Search { .WithSetting("Stereotype", "Widget") ); - return 1; + return 2; + } + + public int UpdateFrom1() { + SchemaBuilder.AlterTable("SearchSettingsPartRecord", table => table + .AddColumn("SearchIndex") + ); + + return 2; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPart.cs b/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPart.cs index 30f64edc0..fd07b9085 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPart.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPart.cs @@ -12,5 +12,10 @@ namespace Orchard.Search.Models { get { return Record.FilterCulture; } set { Record.FilterCulture = value; } } + + public string SearchIndex { + get { return Record.SearchIndex; } + set { Record.SearchIndex = value; } + } } } diff --git a/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPartRecord.cs b/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPartRecord.cs index c85efd9f0..03a8beaaa 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPartRecord.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Models/SearchSettingsPartRecord.cs @@ -2,12 +2,13 @@ using Orchard.ContentManagement.Records; namespace Orchard.Search.Models { public class SearchSettingsPartRecord : ContentPartRecord { - public virtual bool FilterCulture { get; set; } - public virtual string SearchedFields { get; set; } - public SearchSettingsPartRecord() { FilterCulture = false; SearchedFields = "body, title"; } + + public virtual bool FilterCulture { get; set; } + public virtual string SearchedFields { get; set; } + public virtual string SearchIndex { get; set; } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj index d49cdf83e..36300156d 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj +++ b/src/Orchard.Web/Modules/Orchard.Search/Orchard.Search.csproj @@ -47,6 +47,7 @@ + 3.5 @@ -56,6 +57,7 @@ + @@ -87,6 +89,9 @@ + + Designer + diff --git a/src/Orchard.Web/Modules/Orchard.Search/Recipes/Search.recipe.xml b/src/Orchard.Web/Modules/Orchard.Search/Recipes/Search.recipe.xml new file mode 100644 index 000000000..0ac0f23a9 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.Search/Recipes/Search.recipe.xml @@ -0,0 +1,30 @@ + + + + Search + Configures a default search index and search settings using the Lucene engine. + The Orchard Team + http://orchardproject.net + developer + 1.0 + + + + + + + + + + + + + + + + + index create Search + index update Search + search use Search + + diff --git a/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs b/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs index 3414e839d..a20035d57 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Services/ISearchService.cs @@ -4,6 +4,6 @@ using Orchard.Indexing; namespace Orchard.Search.Services { public interface ISearchService : IDependency { - IPageOfItems Query(string query, int skip, int? take, bool filterCulture, string[] searchFields, Func shapeResult); + IPageOfItems Query(string query, int skip, int? take, bool filterCulture, string index, string[] searchFields, Func shapeResult); } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs b/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs index 88eec9439..a89228844 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Services/SearchService.cs @@ -21,18 +21,18 @@ namespace Orchard.Search.Services { public IOrchardServices Services { get; set; } public Localizer T { get; set; } - ISearchBuilder Search() { + ISearchBuilder Search(string index) { return _indexManager.HasIndexProvider() - ? _indexManager.GetSearchIndexProvider().CreateSearchBuilder("Search") + ? _indexManager.GetSearchIndexProvider().CreateSearchBuilder(index) : new NullSearchBuilder(); } - IPageOfItems ISearchService.Query(string query, int page, int? pageSize, bool filterCulture, string[] searchFields, Func shapeResult) { + IPageOfItems ISearchService.Query(string query, int page, int? pageSize, bool filterCulture, string index, string[] searchFields, Func shapeResult) { if (string.IsNullOrWhiteSpace(query)) return new PageOfItems(Enumerable.Empty()); - var searchBuilder = Search().Parse(searchFields, query); + var searchBuilder = Search(index).Parse(searchFields, query); if (filterCulture) { var culture = _cultureManager.GetSiteCulture(); diff --git a/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldEditorEvents.cs b/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldEditorEvents.cs index a4409b69d..dd94e15af 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldEditorEvents.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldEditorEvents.cs @@ -26,6 +26,7 @@ namespace Orchard.Search.Settings { var model = new ContentPickerSearchFieldSettings(); if (updateModel.TryUpdateModel(model, "ContentPickerSearchFieldSettings", null, null)) { builder.WithSetting("ContentPickerSearchFieldSettings.ShowSearchTab", model.ShowSearchTab.ToString(CultureInfo.InvariantCulture)); + builder.WithSetting("ContentPickerSearchFieldSettings.SearchIndex", model.SearchIndex); builder.WithSetting("ContentPickerSearchFieldSettings.DisplayedContentTypes", model.DisplayedContentTypes); } diff --git a/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldSettings.cs b/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldSettings.cs index 5a8c8a41a..c16b88a64 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldSettings.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/Settings/ContentPickerFieldSettings.cs @@ -5,6 +5,7 @@ } public bool ShowSearchTab { get; set; } + public string SearchIndex { get; set; } public string DisplayedContentTypes { get; set; } } } diff --git a/src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchSettingsViewModel.cs b/src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchSettingsViewModel.cs index a4da7cd4c..f8aba67c5 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchSettingsViewModel.cs +++ b/src/Orchard.Web/Modules/Orchard.Search/ViewModels/SearchSettingsViewModel.cs @@ -2,10 +2,16 @@ namespace Orchard.Search.ViewModels { public class SearchSettingsViewModel { - public IList Entries { get; set; } + public string SelectedIndex { get; set; } + public IList Entries { get; set; } public bool FilterCulture { get; set; } } + public class IndexSettingsEntry { + public string Index { get; set; } + public IList Fields { get; set; } + } + public class SearchSettingsEntry { public string Field { get; set; } public bool Selected { get; set; } diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/DefinitionTemplates/ContentPickerSearchFieldSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Search/Views/DefinitionTemplates/ContentPickerSearchFieldSettings.cshtml index 46e3d7fe5..3e03bd512 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Views/DefinitionTemplates/ContentPickerSearchFieldSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/DefinitionTemplates/ContentPickerSearchFieldSettings.cshtml @@ -1,4 +1,9 @@ -@model Orchard.Search.Settings.ContentPickerSearchFieldSettings +@using Orchard.Indexing +@model Orchard.Search.Settings.ContentPickerSearchFieldSettings +@{ + var indexManager = WorkContext.Resolve(); + var indexProvider = indexManager.GetSearchIndexProvider(); +}
@@ -7,6 +12,16 @@
+
+ + + @T("The index to use when displaying this tab.") +
+
@Html.TextBoxFor(m => m.DisplayedContentTypes) diff --git a/src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/Search.SiteSettings.cshtml b/src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/Search.SiteSettings.cshtml index ebda47b6d..e8024181d 100644 --- a/src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/Search.SiteSettings.cshtml +++ b/src/Orchard.Web/Modules/Orchard.Search/Views/EditorTemplates/Parts/Search.SiteSettings.cshtml @@ -1,28 +1,55 @@ -@model Orchard.Search.ViewModels.SearchSettingsViewModel -@using Orchard.Search.ViewModels; - +@using Orchard.Search.ViewModels +@model Orchard.Search.ViewModels.SearchSettingsViewModel +@{ + Script.Require("jQuery"); + +}
@T("Search")
- - @T("Check any property which should be used for search queries.") - @{var entryIndex = 0;} - + + @if (Model.Entries != null && Model.Entries.Any()) { -
    - @foreach(var modelEntry in Model.Entries) { -
  • - @Html.EditorFor(m => m.Entries[entryIndex].Selected) - @Html.HiddenFor(m => m.Entries[entryIndex].Field) - -
  • - entryIndex = entryIndex + 1; + if (String.IsNullOrWhiteSpace(Model.SelectedIndex)) { + Model.Entries.Insert(0, new IndexSettingsEntry { Index = "" }); } -
+ + + @T("Select which index to use in search queries.") + + +
    + @{var entryIndex = 0;} + @foreach(var modelEntry in Model.Entries) { + @Html.HiddenFor(m => m.Entries[entryIndex].Index) +
  • + @if (modelEntry.Fields != null && modelEntry.Fields.Any()) { +
      + @{ var fieldIndex = 0;} + @foreach (var fieldEntry in Model.Entries[entryIndex].Fields) { +
    • + @Html.EditorFor(m => m.Entries[entryIndex].Fields[fieldIndex].Selected) + @Html.HiddenFor(m => m.Entries[entryIndex].Fields[fieldIndex].Field) + +
    • + fieldIndex++; + } +
    + } +
  • + entryIndex++; + } +
+ @T("Check any property which should be used for search queries.") + } else { - @T("There are currently no fields to search from. Please update you index, and check some indexable content exists.") + @T("There is currently no index to search from. Please update you index, and check some indexable content exists.") }
@@ -33,3 +60,20 @@
+ +@using (Script.Foot()) { + +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml b/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml index 7b0588011..bfd5e1f48 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml +++ b/src/Orchard.Web/Modules/Orchard.Setup/Recipes/blog.recipe.xml @@ -19,12 +19,12 @@ - + - + diff --git a/src/Orchard.Web/Modules/Orchard.Setup/Recipes/default.recipe.xml b/src/Orchard.Web/Modules/Orchard.Setup/Recipes/default.recipe.xml index 211337586..11d5cc317 100644 --- a/src/Orchard.Web/Modules/Orchard.Setup/Recipes/default.recipe.xml +++ b/src/Orchard.Web/Modules/Orchard.Setup/Recipes/default.recipe.xml @@ -18,13 +18,13 @@ - + - + diff --git a/src/Orchard/Indexing/DefaultIndexManager.cs b/src/Orchard/Indexing/DefaultIndexManager.cs index b5aa3047f..0be2b9b28 100644 --- a/src/Orchard/Indexing/DefaultIndexManager.cs +++ b/src/Orchard/Indexing/DefaultIndexManager.cs @@ -13,11 +13,11 @@ namespace Orchard.Indexing { #region IIndexManager Members public bool HasIndexProvider() { - return _indexProviders.AsQueryable().Count() > 0; + return _indexProviders.Any(); } public IIndexProvider GetSearchIndexProvider() { - return _indexProviders.AsQueryable().FirstOrDefault(); + return _indexProviders.FirstOrDefault(); } #endregion diff --git a/src/Orchard/Indexing/MetaDataExtensions.cs b/src/Orchard/Indexing/MetaDataExtensions.cs index e7a6490b1..e69f96e09 100644 --- a/src/Orchard/Indexing/MetaDataExtensions.cs +++ b/src/Orchard/Indexing/MetaDataExtensions.cs @@ -2,8 +2,8 @@ namespace Orchard.Indexing { public static class MetaDataExtensions { - public static ContentTypeDefinitionBuilder Indexed(this ContentTypeDefinitionBuilder builder) { - return builder.WithSetting("TypeIndexing.Included", "true"); + public static ContentTypeDefinitionBuilder Indexed(this ContentTypeDefinitionBuilder builder, params string[] indexes) { + return builder.WithSetting("TypeIndexing.Indexes", string.Join(",", indexes ?? new string[0])); } } }