diff --git a/NuGet.Config b/NuGet.Config
index 7d786702f4..64425091dc 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -7,6 +7,6 @@
-->
-
+
diff --git a/build/NuSpecs/tools/serilog.config.install.xdt b/build/NuSpecs/tools/serilog.config.install.xdt
index e0df2985c7..b4a10b7bc2 100644
--- a/build/NuSpecs/tools/serilog.config.install.xdt
+++ b/build/NuSpecs/tools/serilog.config.install.xdt
@@ -2,7 +2,7 @@
>
-
+
diff --git a/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs
new file mode 100644
index 0000000000..cfa9de5fa6
--- /dev/null
+++ b/src/Umbraco.Examine.Lucene/BackOfficeExamineSearcher.cs
@@ -0,0 +1,338 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using Examine;
+using Umbraco.Core;
+using Umbraco.Core.Models;
+using Umbraco.Core.Models.Identity;
+using Umbraco.Core.Persistence;
+using Umbraco.Core.Services;
+using Umbraco.Web.Models.ContentEditing;
+
+namespace Umbraco.Examine
+{
+ public class BackOfficeExamineSearcher : IBackOfficeExamineSearcher
+ {
+ private readonly IExamineManager _examineManager;
+ private readonly ILocalizationService _languageService;
+ private readonly ICurrentUserAccessor _currentUserAccessor;
+ private readonly IEntityService _entityService;
+ private readonly IUmbracoTreeSearcherFields _treeSearcherFields;
+
+ public BackOfficeExamineSearcher(IExamineManager examineManager,
+ ILocalizationService languageService,
+ ICurrentUserAccessor currentUserAccessor,
+ IEntityService entityService,
+ IUmbracoTreeSearcherFields treeSearcherFields)
+ {
+ _examineManager = examineManager;
+ _languageService = languageService;
+ _currentUserAccessor = currentUserAccessor;
+ _entityService = entityService;
+ _treeSearcherFields = treeSearcherFields;
+ }
+
+ public IEnumerable Search(string query, UmbracoEntityTypes entityType, int pageSize, long pageIndex, out long totalFound, string searchFrom = null, bool ignoreUserStartNodes = false)
+ {
+ var sb = new StringBuilder();
+
+ string type;
+ var indexName = Constants.UmbracoIndexes.InternalIndexName;
+ var fields = _treeSearcherFields.GetBackOfficeFields().ToList();
+
+ //special GUID check since if a user searches on one specifically we need to escape it
+ if (Guid.TryParse(query, out var g))
+ {
+ query = "\"" + g.ToString() + "\"";
+ }
+
+ var currentUser = _currentUserAccessor.TryGetCurrentUser();
+
+ switch (entityType)
+ {
+ case UmbracoEntityTypes.Member:
+ indexName = Constants.UmbracoIndexes.MembersIndexName;
+ type = "member";
+ fields.AddRange(_treeSearcherFields.GetBackOfficeMembersFields());
+ if (searchFrom != null && searchFrom != Constants.Conventions.MemberTypes.AllMembersListId && searchFrom.Trim() != "-1")
+ {
+ sb.Append("+__NodeTypeAlias:");
+ sb.Append(searchFrom);
+ sb.Append(" ");
+ }
+ break;
+ case UmbracoEntityTypes.Media:
+ type = "media";
+ fields.AddRange(_treeSearcherFields.GetBackOfficeMediaFields());
+ var allMediaStartNodes = currentUser != null
+ ? currentUser.CalculateMediaStartNodeIds(_entityService)
+ : Array.Empty();
+ AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, ignoreUserStartNodes, _entityService);
+ break;
+ case UmbracoEntityTypes.Document:
+ type = "content";
+ fields.AddRange(_treeSearcherFields.GetBackOfficeDocumentFields());
+ var allContentStartNodes = currentUser != null
+ ? currentUser.CalculateContentStartNodeIds(_entityService)
+ : Array.Empty();
+ AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, ignoreUserStartNodes, _entityService);
+ break;
+ default:
+ throw new NotSupportedException("The " + typeof(BackOfficeExamineSearcher) + " currently does not support searching against object type " + entityType);
+ }
+
+ if (!_examineManager.TryGetIndex(indexName, out var index))
+ throw new InvalidOperationException("No index found by name " + indexName);
+
+ var internalSearcher = index.GetSearcher();
+
+ if (!BuildQuery(sb, query, searchFrom, fields, type))
+ {
+ totalFound = 0;
+ return Enumerable.Empty();
+ }
+
+ var result = internalSearcher.CreateQuery().NativeQuery(sb.ToString())
+ //only return the number of items specified to read up to the amount of records to fill from 0 -> the number of items on the page requested
+ .Execute(Convert.ToInt32(pageSize * (pageIndex + 1)));
+
+ totalFound = result.TotalItemCount;
+
+ var pagedResult = result.Skip(Convert.ToInt32(pageIndex));
+
+ return pagedResult;
+ }
+
+ private bool BuildQuery(StringBuilder sb, string query, string searchFrom, List fields, string type)
+ {
+ //build a lucene query:
+ // the nodeName will be boosted 10x without wildcards
+ // then nodeName will be matched normally with wildcards
+ // the rest will be normal without wildcards
+
+ var allLangs = _languageService.GetAllLanguages().Select(x => x.IsoCode.ToLowerInvariant()).ToList();
+
+ //check if text is surrounded by single or double quotes, if so, then exact match
+ var surroundedByQuotes = Regex.IsMatch(query, "^\".*?\"$")
+ || Regex.IsMatch(query, "^\'.*?\'$");
+
+ if (surroundedByQuotes)
+ {
+ //strip quotes, escape string, the replace again
+ query = query.Trim('\"', '\'');
+
+ query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
+
+ //nothing to search
+ if (searchFrom.IsNullOrWhiteSpace() && query.IsNullOrWhiteSpace())
+ {
+ return false;
+ }
+
+ //update the query with the query term
+ if (query.IsNullOrWhiteSpace() == false)
+ {
+ //add back the surrounding quotes
+ query = string.Format("{0}{1}{0}", "\"", query);
+
+ sb.Append("+(");
+
+ AppendNodeNamePhraseWithBoost(sb, query, allLangs);
+
+ foreach (var f in fields)
+ {
+ //additional fields normally
+ sb.Append(f);
+ sb.Append(": (");
+ sb.Append(query);
+ sb.Append(") ");
+ }
+
+ sb.Append(") ");
+ }
+ }
+ else
+ {
+ var trimmed = query.Trim(new[] { '\"', '\'' });
+
+ //nothing to search
+ if (searchFrom.IsNullOrWhiteSpace() && trimmed.IsNullOrWhiteSpace())
+ {
+ return false;
+ }
+
+ //update the query with the query term
+ if (trimmed.IsNullOrWhiteSpace() == false)
+ {
+ query = Lucene.Net.QueryParsers.QueryParser.Escape(query);
+
+ var querywords = query.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+
+ sb.Append("+(");
+
+ AppendNodeNameExactWithBoost(sb, query, allLangs);
+
+ AppendNodeNameWithWildcards(sb, querywords, allLangs);
+
+ foreach (var f in fields)
+ {
+ var queryWordsReplaced = new string[querywords.Length];
+
+ // when searching file names containing hyphens we need to replace the hyphens with spaces
+ if (f.Equals(UmbracoExamineFieldNames.UmbracoFileFieldName))
+ {
+ for (var index = 0; index < querywords.Length; index++)
+ {
+ queryWordsReplaced[index] = querywords[index].Replace("\\-", " ").Replace("_", " ").Trim(" ");
+ }
+ }
+ else
+ {
+ queryWordsReplaced = querywords;
+ }
+
+ //additional fields normally
+ sb.Append(f);
+ sb.Append(":");
+ sb.Append("(");
+ foreach (var w in queryWordsReplaced)
+ {
+ sb.Append(w.ToLower());
+ sb.Append("* ");
+ }
+ sb.Append(")");
+ sb.Append(" ");
+ }
+
+ sb.Append(") ");
+ }
+ }
+
+ //must match index type
+ sb.Append("+__IndexType:");
+ sb.Append(type);
+
+ return true;
+ }
+
+ private void AppendNodeNamePhraseWithBoost(StringBuilder sb, string query, IEnumerable allLangs)
+ {
+ //node name exactly boost x 10
+ sb.Append("nodeName: (");
+ sb.Append(query.ToLower());
+ sb.Append(")^10.0 ");
+
+ //also search on all variant node names
+ foreach (var lang in allLangs)
+ {
+ //node name exactly boost x 10
+ sb.Append($"nodeName_{lang}: (");
+ sb.Append(query.ToLower());
+ sb.Append(")^10.0 ");
+ }
+ }
+
+ private void AppendNodeNameExactWithBoost(StringBuilder sb, string query, IEnumerable allLangs)
+ {
+ //node name exactly boost x 10
+ sb.Append("nodeName:");
+ sb.Append("\"");
+ sb.Append(query.ToLower());
+ sb.Append("\"");
+ sb.Append("^10.0 ");
+ //also search on all variant node names
+ foreach (var lang in allLangs)
+ {
+ //node name exactly boost x 10
+ sb.Append($"nodeName_{lang}:");
+ sb.Append("\"");
+ sb.Append(query.ToLower());
+ sb.Append("\"");
+ sb.Append("^10.0 ");
+ }
+ }
+
+ private void AppendNodeNameWithWildcards(StringBuilder sb, string[] querywords, IEnumerable allLangs)
+ {
+ //node name normally with wildcards
+ sb.Append("nodeName:");
+ sb.Append("(");
+ foreach (var w in querywords)
+ {
+ sb.Append(w.ToLower());
+ sb.Append("* ");
+ }
+ sb.Append(") ");
+ //also search on all variant node names
+ foreach (var lang in allLangs)
+ {
+ //node name normally with wildcards
+ sb.Append($"nodeName_{lang}:");
+ sb.Append("(");
+ foreach (var w in querywords)
+ {
+ sb.Append(w.ToLower());
+ sb.Append("* ");
+ }
+ sb.Append(") ");
+ }
+ }
+
+ private void AppendPath(StringBuilder sb, UmbracoObjectTypes objectType, int[] startNodeIds, string searchFrom, bool ignoreUserStartNodes, IEntityService entityService)
+ {
+ if (sb == null) throw new ArgumentNullException(nameof(sb));
+ if (entityService == null) throw new ArgumentNullException(nameof(entityService));
+
+ UdiParser.TryParse(searchFrom, true, out var udi);
+ searchFrom = udi == null ? searchFrom : entityService.GetId(udi).Result.ToString();
+
+ var entityPath = int.TryParse(searchFrom, out var searchFromId) && searchFromId > 0
+ ? entityService.GetAllPaths(objectType, searchFromId).FirstOrDefault()
+ : null;
+ if (entityPath != null)
+ {
+ // find... only what's underneath
+ sb.Append("+__Path:");
+ AppendPath(sb, entityPath.Path, false);
+ sb.Append(" ");
+ }
+ else if (startNodeIds.Length == 0)
+ {
+ // make sure we don't find anything
+ sb.Append("+__Path:none ");
+ }
+ else if (startNodeIds.Contains(-1) == false && ignoreUserStartNodes == false) // -1 = no restriction
+ {
+ var entityPaths = entityService.GetAllPaths(objectType, startNodeIds);
+
+ // for each start node, find the start node, and what's underneath
+ // +__Path:(-1*,1234 -1*,1234,* -1*,5678 -1*,5678,* ...)
+ sb.Append("+__Path:(");
+ var first = true;
+ foreach (var ep in entityPaths)
+ {
+ if (first)
+ first = false;
+ else
+ sb.Append(" ");
+ AppendPath(sb, ep.Path, true);
+ }
+ sb.Append(") ");
+ }
+ }
+
+ private void AppendPath(StringBuilder sb, string path, bool includeThisNode)
+ {
+ path = path.Replace("-", "\\-").Replace(",", "\\,");
+ if (includeThisNode)
+ {
+ sb.Append(path);
+ sb.Append(" ");
+ }
+ sb.Append(path);
+ sb.Append("\\,*");
+ }
+ }
+}
diff --git a/src/Umbraco.Examine/ExamineExtensions.cs b/src/Umbraco.Examine.Lucene/ExamineExtensions.cs
similarity index 68%
rename from src/Umbraco.Examine/ExamineExtensions.cs
rename to src/Umbraco.Examine.Lucene/ExamineExtensions.cs
index d231a86f69..d697bf6f0d 100644
--- a/src/Umbraco.Examine/ExamineExtensions.cs
+++ b/src/Umbraco.Examine.Lucene/ExamineExtensions.cs
@@ -1,14 +1,11 @@
using System;
-using System.Collections.Generic;
using System.Linq;
-using System.Text.RegularExpressions;
using Examine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Analysis;
using Lucene.Net.Index;
using Lucene.Net.QueryParsers;
using Lucene.Net.Search;
-using Lucene.Net.Store;
using Umbraco.Core;
using Version = Lucene.Net.Util.Version;
using Umbraco.Core.Logging;
@@ -16,19 +13,12 @@ using System.Threading;
namespace Umbraco.Examine
{
+
///
/// Extension methods for the LuceneIndex
///
public static class ExamineExtensions
{
- ///
- /// Matches a culture iso name suffix
- ///
- ///
- /// myFieldName_en-us will match the "en-us"
- ///
- internal static readonly Regex CultureIsoCodeFieldNameMatchExpression = new Regex("^([_\\w]+)_([a-z]{2}-[a-z0-9]{2,4})$", RegexOptions.Compiled);
-
private static bool _isConfigured = false;
private static object _configuredInit = null;
private static object _isConfiguredLocker = new object();
@@ -52,51 +42,6 @@ namespace Umbraco.Examine
});
}
- //TODO: We need a public method here to just match a field name against CultureIsoCodeFieldNameMatchExpression
-
- ///
- /// Returns all index fields that are culture specific (suffixed)
- ///
- ///
- ///
- ///
- public static IEnumerable GetCultureFields(this IUmbracoIndex index, string culture)
- {
- var allFields = index.GetFields();
- // ReSharper disable once LoopCanBeConvertedToQuery
- foreach (var field in allFields)
- {
- var match = CultureIsoCodeFieldNameMatchExpression.Match(field);
- if (match.Success && match.Groups.Count == 3 && culture.InvariantEquals(match.Groups[2].Value))
- yield return field;
- }
- }
-
- ///
- /// Returns all index fields that are culture specific (suffixed) or invariant
- ///
- ///
- ///
- ///
- public static IEnumerable GetCultureAndInvariantFields(this IUmbracoIndex index, string culture)
- {
- var allFields = index.GetFields();
- // ReSharper disable once LoopCanBeConvertedToQuery
- foreach (var field in allFields)
- {
- var match = CultureIsoCodeFieldNameMatchExpression.Match(field);
- if (match.Success && match.Groups.Count == 3 && culture.InvariantEquals(match.Groups[2].Value))
- {
- yield return field; //matches this culture field
- }
- else if (!match.Success)
- {
- yield return field; //matches no culture field (invariant)
- }
-
- }
- }
-
internal static bool TryParseLuceneQuery(string query)
{
// TODO: I'd assume there would be a more strict way to parse the query but not that i can find yet, for now we'll
@@ -107,7 +52,7 @@ namespace Umbraco.Examine
try
{
//This will pass with a plain old string without any fields, need to figure out a way to have it properly parse
- var parsed = new QueryParser(Version.LUCENE_30, "nodeName", new KeywordAnalyzer()).Parse(query);
+ var parsed = new QueryParser(Version.LUCENE_30, UmbracoExamineFieldNames.NodeNameFieldName, new KeywordAnalyzer()).Parse(query);
return true;
}
catch (ParseException)
@@ -126,7 +71,7 @@ namespace Umbraco.Examine
///
/// This is not thread safe, use with care
///
- internal static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing)
+ private static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing)
{
foreach (var luceneIndexer in examineManager.Indexes.OfType())
{
diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs
new file mode 100644
index 0000000000..0d701d388d
--- /dev/null
+++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComponent.cs
@@ -0,0 +1,50 @@
+using Examine;
+using Examine.LuceneEngine.Directories;
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Examine
+{
+
+ public sealed class ExamineLuceneComponent : IComponent
+ {
+ private readonly IndexRebuilder _indexRebuilder;
+ private readonly IExamineManager _examineManager;
+ private readonly IMainDom _mainDom;
+ private readonly ILogger _logger;
+
+ public ExamineLuceneComponent(IndexRebuilder indexRebuilder, IExamineManager examineManager, IMainDom mainDom, ILogger logger)
+ {
+ _indexRebuilder = indexRebuilder;
+ _examineManager = examineManager;
+ _mainDom = mainDom;
+ _logger = logger;
+ }
+
+ public void Initialize()
+ {
+ //we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the AppDomain
+ //terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock
+ //which simply checks the existence of the lock file
+ DirectoryFactory.DefaultLockFactory = d =>
+ {
+ var simpleFsLockFactory = new NoPrefixSimpleFsLockFactory(d);
+ return simpleFsLockFactory;
+ };
+
+ _indexRebuilder.RebuildingIndexes += IndexRebuilder_RebuildingIndexes;
+ }
+
+ ///
+ /// Handles event to ensure that all lucene based indexes are properly configured before rebuilding
+ ///
+ ///
+ ///
+ private void IndexRebuilder_RebuildingIndexes(object sender, IndexRebuildingEventArgs e) => _examineManager.ConfigureIndexes(_mainDom, _logger);
+
+ public void Terminate()
+ {
+ }
+ }
+}
diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs
new file mode 100644
index 0000000000..724149a01d
--- /dev/null
+++ b/src/Umbraco.Examine.Lucene/ExamineLuceneComposer.cs
@@ -0,0 +1,20 @@
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+
+namespace Umbraco.Examine
+{
+ // We want to run after core composers since we are replacing some items
+ [ComposeAfter(typeof(ICoreComposer))]
+ [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
+ public sealed class ExamineLuceneComposer : ComponentComposer
+ {
+ public override void Compose(Composition composition)
+ {
+ base.Compose(composition);
+
+ composition.RegisterUnique();
+ composition.RegisterUnique();
+ composition.RegisterUnique();
+ }
+ }
+}
diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs
new file mode 100644
index 0000000000..e1e80ead2f
--- /dev/null
+++ b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComponent.cs
@@ -0,0 +1,33 @@
+using Examine;
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Examine
+{
+ public class ExamineLuceneFinalComponent : IComponent
+ {
+ private readonly IProfilingLogger _logger;
+ private readonly IExamineManager _examineManager;
+ private readonly IMainDom _mainDom;
+
+ public ExamineLuceneFinalComponent(IProfilingLogger logger, IExamineManager examineManager, IMainDom mainDom)
+ {
+ _logger = logger;
+ _examineManager = examineManager;
+ _mainDom = mainDom;
+ }
+
+ public void Initialize()
+ {
+ if (!_mainDom.IsMainDom) return;
+
+ // Ensures all lucene based indexes are unlocked and ready to go
+ _examineManager.ConfigureIndexes(_mainDom, _logger);
+ }
+
+ public void Terminate()
+ {
+ }
+ }
+}
diff --git a/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs
new file mode 100644
index 0000000000..1a73426568
--- /dev/null
+++ b/src/Umbraco.Examine.Lucene/ExamineLuceneFinalComposer.cs
@@ -0,0 +1,13 @@
+using Umbraco.Core;
+using Umbraco.Core.Composing;
+
+namespace Umbraco.Examine
+{
+ // examine's Lucene final composer composes after all user composers
+ // and *also* after ICoreComposer (in case IUserComposer is disabled)
+ [ComposeAfter(typeof(IUserComposer))]
+ [ComposeAfter(typeof(ICoreComposer))]
+ [RuntimeLevel(MinLevel = RuntimeLevel.Run)]
+ public class ExamineLuceneFinalComposer : ComponentComposer
+ { }
+}
diff --git a/src/Umbraco.Examine/LuceneIndexCreator.cs b/src/Umbraco.Examine.Lucene/LuceneIndexCreator.cs
similarity index 100%
rename from src/Umbraco.Examine/LuceneIndexCreator.cs
rename to src/Umbraco.Examine.Lucene/LuceneIndexCreator.cs
diff --git a/src/Umbraco.Examine/LuceneIndexDiagnostics.cs b/src/Umbraco.Examine.Lucene/LuceneIndexDiagnostics.cs
similarity index 100%
rename from src/Umbraco.Examine/LuceneIndexDiagnostics.cs
rename to src/Umbraco.Examine.Lucene/LuceneIndexDiagnostics.cs
diff --git a/src/Umbraco.Examine.Lucene/LuceneIndexDiagnosticsFactory.cs b/src/Umbraco.Examine.Lucene/LuceneIndexDiagnosticsFactory.cs
new file mode 100644
index 0000000000..cc1fc115ca
--- /dev/null
+++ b/src/Umbraco.Examine.Lucene/LuceneIndexDiagnosticsFactory.cs
@@ -0,0 +1,35 @@
+using Examine;
+using Examine.LuceneEngine.Providers;
+using Umbraco.Core.Logging;
+using Umbraco.Core.IO;
+
+namespace Umbraco.Examine
+{
+ ///
+ /// Implementation of which returns
+ /// for lucene based indexes that don't have an implementation else fallsback to the default implementation.
+ ///
+ public class LuceneIndexDiagnosticsFactory : IndexDiagnosticsFactory
+ {
+ private readonly ILogger _logger;
+ private readonly IIOHelper _ioHelper;
+
+ public LuceneIndexDiagnosticsFactory(ILogger logger, IIOHelper ioHelper)
+ {
+ _logger = logger;
+ _ioHelper = ioHelper;
+ }
+
+ public override IIndexDiagnostics Create(IIndex index)
+ {
+ if (!(index is IIndexDiagnostics indexDiag))
+ {
+ if (index is LuceneIndex luceneIndex)
+ indexDiag = new LuceneIndexDiagnostics(luceneIndex, _logger, _ioHelper);
+ else
+ indexDiag = base.Create(index);
+ }
+ return indexDiag;
+ }
+ }
+}
diff --git a/src/Umbraco.Examine/NoPrefixSimpleFsLockFactory.cs b/src/Umbraco.Examine.Lucene/NoPrefixSimpleFsLockFactory.cs
similarity index 100%
rename from src/Umbraco.Examine/NoPrefixSimpleFsLockFactory.cs
rename to src/Umbraco.Examine.Lucene/NoPrefixSimpleFsLockFactory.cs
diff --git a/src/Umbraco.Examine/Properties/AssemblyInfo.cs b/src/Umbraco.Examine.Lucene/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/Umbraco.Examine/Properties/AssemblyInfo.cs
rename to src/Umbraco.Examine.Lucene/Properties/AssemblyInfo.cs
diff --git a/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj
new file mode 100644
index 0000000000..f91cc02a71
--- /dev/null
+++ b/src/Umbraco.Examine.Lucene/Umbraco.Examine.Lucene.csproj
@@ -0,0 +1,104 @@
+
+
+
+
+ v4.7.2
+ false
+ {07FBC26B-2927-4A22-8D96-D644C667FECC}
+ Library
+ Umbraco.Examine.Lucene
+ Umbraco.Examine
+ ..\
+
+ $(AdditionalFileItemNames);Content
+
+
+ true
+ portable
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+ latest
+
+
+ portable
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ bin\Release\Umbraco.Examine.Lucene.xml
+ false
+ latest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.0.0-alpha.20200128.15
+
+
+ 1.0.0-beta2-19554-01
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+ 3.3.0
+ runtime; build; native; contentfiles; analyzers
+ all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Properties\SolutionInfo.cs
+
+
+
+
+ {29aa69d9-b597-4395-8d42-43b1263c240a}
+ Umbraco.Abstractions
+
+
+ {f9b7fe05-0f93-4d0d-9c10-690b33ecbbd8}
+ Umbraco.Examine
+
+
+ {3ae7bf57-966b-45a5-910a-954d7c554441}
+ Umbraco.Infrastructure
+
+
+
+
\ No newline at end of file
diff --git a/src/Umbraco.Examine/UmbracoContentIndex.cs b/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs
similarity index 97%
rename from src/Umbraco.Examine/UmbracoContentIndex.cs
rename to src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs
index 33fd2d0ee7..1c8cd4b074 100644
--- a/src/Umbraco.Examine/UmbracoContentIndex.cs
+++ b/src/Umbraco.Examine.Lucene/UmbracoContentIndex.cs
@@ -20,7 +20,7 @@ namespace Umbraco.Examine
///
public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex
{
- public const string VariesByCultureFieldName = SpecialFieldPrefix + "VariesByCulture";
+
protected ILocalizationService LanguageService { get; }
#region Constructors
@@ -132,7 +132,7 @@ namespace Umbraco.Examine
{
//find all descendants based on path
var descendantPath = $@"\-1\,*{nodeId}\,*";
- var rawQuery = $"{IndexPathFieldName}:{descendantPath}";
+ var rawQuery = $"{UmbracoExamineFieldNames.IndexPathFieldName}:{descendantPath}";
var searcher = GetSearcher();
var c = searcher.CreateQuery();
var filtered = c.NativeQuery(rawQuery);
diff --git a/src/Umbraco.Examine/UmbracoExamineIndex.cs b/src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs
similarity index 88%
rename from src/Umbraco.Examine/UmbracoExamineIndex.cs
rename to src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs
index f7dfcf6375..880440f4f9 100644
--- a/src/Umbraco.Examine/UmbracoExamineIndex.cs
+++ b/src/Umbraco.Examine.Lucene/UmbracoExamineIndex.cs
@@ -28,19 +28,7 @@ namespace Umbraco.Examine
// call context (and the database it can contain)! ideally we should be able to override
// SafelyProcessQueueItems but that's not possible in the current version of Examine.
- ///
- /// Used to store the path of a content object
- ///
- public const string IndexPathFieldName = SpecialFieldPrefix + "Path";
- public const string NodeKeyFieldName = SpecialFieldPrefix + "Key";
- public const string UmbracoFileFieldName = "umbracoFileSrc";
- public const string IconFieldName = SpecialFieldPrefix + "Icon";
- public const string PublishedFieldName = SpecialFieldPrefix + "Published";
-
- ///
- /// The prefix added to a field when it is duplicated in order to store the original raw value.
- ///
- public const string RawFieldPrefix = SpecialFieldPrefix + "Raw_";
+
///
/// Create a new
@@ -141,7 +129,7 @@ namespace Umbraco.Examine
{
var d = docArgs.Document;
- foreach (var f in docArgs.ValueSet.Values.Where(x => x.Key.StartsWith(RawFieldPrefix)).ToList())
+ foreach (var f in docArgs.ValueSet.Values.Where(x => x.Key.StartsWith(UmbracoExamineFieldNames.RawFieldPrefix)).ToList())
{
if (f.Value.Count > 0)
{
@@ -182,13 +170,13 @@ namespace Umbraco.Examine
var path = e.ValueSet.GetValue("path");
if (path != null)
{
- e.ValueSet.Set(IndexPathFieldName, path);
+ e.ValueSet.Set(UmbracoExamineFieldNames.IndexPathFieldName, path);
}
//icon
- if (e.ValueSet.Values.TryGetValue("icon", out var icon) && e.ValueSet.Values.ContainsKey(IconFieldName) == false)
+ if (e.ValueSet.Values.TryGetValue("icon", out var icon) && e.ValueSet.Values.ContainsKey(UmbracoExamineFieldNames.IconFieldName) == false)
{
- e.ValueSet.Values[IconFieldName] = icon;
+ e.ValueSet.Values[UmbracoExamineFieldNames.IconFieldName] = icon;
}
}
diff --git a/src/Umbraco.Examine/UmbracoExamineIndexDiagnostics.cs b/src/Umbraco.Examine.Lucene/UmbracoExamineIndexDiagnostics.cs
similarity index 100%
rename from src/Umbraco.Examine/UmbracoExamineIndexDiagnostics.cs
rename to src/Umbraco.Examine.Lucene/UmbracoExamineIndexDiagnostics.cs
diff --git a/src/Umbraco.Web/Search/UmbracoIndexesCreator.cs b/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs
similarity index 96%
rename from src/Umbraco.Web/Search/UmbracoIndexesCreator.cs
rename to src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs
index 71b5bee108..173300a472 100644
--- a/src/Umbraco.Web/Search/UmbracoIndexesCreator.cs
+++ b/src/Umbraco.Examine.Lucene/UmbracoIndexesCreator.cs
@@ -1,17 +1,14 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
-using Umbraco.Examine;
using Lucene.Net.Analysis.Standard;
using Examine.LuceneEngine;
using Examine;
using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
-using Umbraco.Web.PublishedCache.NuCache;
-namespace Umbraco.Web.Search
+namespace Umbraco.Examine
{
///
/// Creates the indexes used by Umbraco
@@ -53,7 +50,7 @@ namespace Umbraco.Web.Search
///
public override IEnumerable Create()
{
- return new []
+ return new[]
{
CreateInternalIndex(),
CreateExternalIndex(),
diff --git a/src/Umbraco.Examine/UmbracoMemberIndex.cs b/src/Umbraco.Examine.Lucene/UmbracoMemberIndex.cs
similarity index 94%
rename from src/Umbraco.Examine/UmbracoMemberIndex.cs
rename to src/Umbraco.Examine.Lucene/UmbracoMemberIndex.cs
index 494c661062..0e9128d31a 100644
--- a/src/Umbraco.Examine/UmbracoMemberIndex.cs
+++ b/src/Umbraco.Examine.Lucene/UmbracoMemberIndex.cs
@@ -1,6 +1,4 @@
-using System.Collections.Generic;
-using Examine;
-using Examine.LuceneEngine;
+using Examine;
using Lucene.Net.Analysis;
using Umbraco.Core;
using Umbraco.Core.IO;
diff --git a/src/Umbraco.Examine/BaseValueSetBuilder.cs b/src/Umbraco.Examine/BaseValueSetBuilder.cs
index 4a306aa5ff..2350d3cb84 100644
--- a/src/Umbraco.Examine/BaseValueSetBuilder.cs
+++ b/src/Umbraco.Examine/BaseValueSetBuilder.cs
@@ -1,5 +1,4 @@
using System.Collections.Generic;
-using System.Linq;
using Examine;
using Umbraco.Core;
using Umbraco.Core.Models;
diff --git a/src/Umbraco.Examine/ContentIndexPopulator.cs b/src/Umbraco.Examine/ContentIndexPopulator.cs
index 99ff4d7f87..8b34c3315a 100644
--- a/src/Umbraco.Examine/ContentIndexPopulator.cs
+++ b/src/Umbraco.Examine/ContentIndexPopulator.cs
@@ -6,7 +6,6 @@ using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Services;
using Umbraco.Core.Persistence;
-using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
namespace Umbraco.Examine
diff --git a/src/Umbraco.Examine/ContentValueSetBuilder.cs b/src/Umbraco.Examine/ContentValueSetBuilder.cs
index b2f8ae720b..c115939b7d 100644
--- a/src/Umbraco.Examine/ContentValueSetBuilder.cs
+++ b/src/Umbraco.Examine/ContentValueSetBuilder.cs
@@ -46,16 +46,16 @@ namespace Umbraco.Examine
var values = new Dictionary>
{
{"icon", c.ContentType.Icon?.Yield() ?? Enumerable.Empty()},
- {UmbracoExamineIndex.PublishedFieldName, new object[] {c.Published ? "y" : "n"}}, //Always add invariant published value
+ {UmbracoExamineFieldNames.PublishedFieldName, new object[] {c.Published ? "y" : "n"}}, //Always add invariant published value
{"id", new object[] {c.Id}},
- {UmbracoExamineIndex.NodeKeyFieldName, new object[] {c.Key}},
+ {UmbracoExamineFieldNames.NodeKeyFieldName, new object[] {c.Key}},
{"parentID", new object[] {c.Level > 1 ? c.ParentId : -1}},
{"level", new object[] {c.Level}},
{"creatorID", new object[] {c.CreatorId}},
{"sortOrder", new object[] {c.SortOrder}},
{"createDate", new object[] {c.CreateDate}}, //Always add invariant createDate
{"updateDate", new object[] {c.UpdateDate}}, //Always add invariant updateDate
- {"nodeName", (PublishedValuesOnly //Always add invariant nodeName
+ {UmbracoExamineFieldNames.NodeNameFieldName, (PublishedValuesOnly //Always add invariant nodeName
? c.PublishName?.Yield()
: c.Name?.Yield()) ?? Enumerable.Empty()},
{"urlName", urlValue?.Yield() ?? Enumerable.Empty()}, //Always add invariant urlName
@@ -65,12 +65,12 @@ namespace Umbraco.Examine
{"writerName",(c.GetWriterProfile(_userService)?.Name ?? "??").Yield() },
{"writerID", new object[] {c.WriterId}},
{"templateID", new object[] {c.TemplateId ?? 0}},
- {UmbracoContentIndex.VariesByCultureFieldName, new object[] {"n"}},
+ {UmbracoExamineFieldNames.VariesByCultureFieldName, new object[] {"n"}},
};
if (isVariant)
{
- values[UmbracoContentIndex.VariesByCultureFieldName] = new object[] { "y" };
+ values[UmbracoExamineFieldNames.VariesByCultureFieldName] = new object[] { "y" };
foreach (var culture in c.AvailableCultures)
{
@@ -80,7 +80,7 @@ namespace Umbraco.Examine
values[$"nodeName_{lowerCulture}"] = (PublishedValuesOnly
? c.GetPublishName(culture)?.Yield()
: c.GetCultureName(culture)?.Yield()) ?? Enumerable.Empty();
- values[$"{UmbracoExamineIndex.PublishedFieldName}_{lowerCulture}"] = (c.IsCulturePublished(culture) ? "y" : "n").Yield