Skip to content

Commit

Permalink
Improvements for Search Azure AI (#16127)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek authored May 22, 2024
1 parent d2260a0 commit 58149c4
Show file tree
Hide file tree
Showing 26 changed files with 338 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ public async Task<IActionResult> Index(AzureAIIndexOptions options, PagerParamet

indexes = indexes
.Skip(pager.GetStartIndex())
.Take(pager.PageSize).ToList();
.Take(pager.PageSize)
.ToList();

// Maintain previous route data when generating page links.
var routeData = new RouteData();
Expand Down Expand Up @@ -246,7 +247,7 @@ public async Task<IActionResult> CreatePost(AzureAISettingsViewModel model)
settings.QueryAnalyzerName = settings.AnalyzerName;
}

settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings.IndexedContentTypes);
settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings);

if (await _indexManager.CreateAsync(settings))
{
Expand Down Expand Up @@ -366,7 +367,7 @@ public async Task<IActionResult> EditPost(AzureAISettingsViewModel model)
settings.QueryAnalyzerName = settings.AnalyzerName;
}

settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings.IndexedContentTypes);
settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings);

if (!await _indexManager.CreateAsync(settings))
{
Expand Down Expand Up @@ -452,12 +453,8 @@ public async Task<IActionResult> Rebuild(string indexName)
return NotFound();
}

if (!await _indexManager.ExistsAsync(indexName))
{
return NotFound();
}

settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings.IndexedContentTypes);
settings.SetLastTaskId(0);
settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings);
await _indexSettingsService.UpdateAsync(settings);
await _indexManager.RebuildAsync(settings);
await AsyncContentItemsAsync(settings.IndexName);
Expand Down Expand Up @@ -488,11 +485,13 @@ public async Task<IActionResult> Reset(string indexName)

if (!await _indexManager.ExistsAsync(indexName))
{
return NotFound();
await _notifier.ErrorAsync(H["Unable to reset the <em>{0}</em> index. Try rebuilding it instead.", indexName]);

return RedirectToAction(nameof(Index));
}

settings.SetLastTaskId(0);
settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings.IndexedContentTypes);
settings.IndexMappings = await _azureAIIndexDocumentManager.GetMappingsAsync(settings);
await _indexSettingsService.UpdateAsync(settings);
await AsyncContentItemsAsync(settings.IndexName);
await _notifier.SuccessAsync(H["Index <em>{0}</em> reset successfully.", indexName]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,20 @@ namespace OrchardCore.Indexing
/// </summary>
public abstract class ContentFieldIndexHandler<TField> : IContentFieldIndexHandler where TField : ContentField
{
Task IContentFieldIndexHandler.BuildIndexAsync(ContentPart contentPart, ContentTypePartDefinition typePartDefinition, ContentPartFieldDefinition partFieldDefinition, BuildIndexContext context, IContentIndexSettings settings)
Task IContentFieldIndexHandler.BuildIndexAsync(
ContentPart contentPart,
ContentTypePartDefinition typePartDefinition,
ContentPartFieldDefinition partFieldDefinition,
BuildIndexContext context,
IContentIndexSettings settings)
{
if (contentPart == null)
{
return Task.CompletedTask;
}

ArgumentNullException.ThrowIfNull(partFieldDefinition);

if (!string.Equals(typeof(TField).Name, partFieldDefinition.FieldDefinition.Name, StringComparison.Ordinal) &&
!string.Equals(nameof(ContentField), partFieldDefinition.FieldDefinition.Name, StringComparison.Ordinal))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ namespace OrchardCore.Search.AzureAI;

public class AzureAISearchIndexPermissionHelper
{
public static readonly Permission ManageAzureAISearchIndexes = new("ManageAzureAISearchIndexes", "Manage Azure AI Search Indexes");
public static readonly Permission ManageAzureAISearchIndexes =
new("ManageAzureAISearchIndexes", "Manage Azure AI Search Indexes");

private static readonly Permission _indexPermissionTemplate = new("QueryAzureAISearchIndex_{0}", "Query Azure AI Search '{0}' Index", new[] { ManageAzureAISearchIndexes });
private static readonly Permission _indexPermissionTemplate =
new("QueryAzureAISearchIndex_{0}", "Query Azure AI Search '{0}' Index", [ManageAzureAISearchIndexes]);

private static readonly Dictionary<string, Permission> _permissions = [];

public static Permission GetPermission(string indexName)
{
ArgumentException.ThrowIfNullOrWhiteSpace(indexName, nameof(indexName));
ArgumentException.ThrowIfNullOrWhiteSpace(indexName);

if (!_permissions.TryGetValue(indexName, out var permission))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@

namespace OrchardCore.Search.AzureAI.Deployment;

public class AzureAISearchIndexDeploymentSource(AzureAISearchIndexSettingsService indexSettingsService) : IDeploymentSource
public class AzureAISearchIndexDeploymentSource : IDeploymentSource
{
private readonly AzureAISearchIndexSettingsService _indexSettingsService = indexSettingsService;
private readonly AzureAISearchIndexSettingsService _indexSettingsService;

public AzureAISearchIndexDeploymentSource(AzureAISearchIndexSettingsService indexSettingsService)
{
_indexSettingsService = indexSettingsService;
}

public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlanResult result)
{
Expand All @@ -22,6 +27,7 @@ public async Task ProcessDeploymentStepAsync(DeploymentStep step, DeploymentPlan
var indexSettings = await _indexSettingsService.GetSettingsAsync();

var data = new JsonArray();

var indicesToAdd = indexStep.IncludeAll
? indexSettings.Select(x => x.IndexName).ToArray()
: indexStep.IndexNames;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static IServiceCollection AddAzureAISearchServices(this IServiceCollectio
services.AddScoped<AzureAISearchIndexManager>();
services.AddScoped<AzureAIIndexDocumentManager>();
services.AddScoped<AzureAISearchIndexingService>();
services.AddScoped<IAzureAISearchFieldIndexEvents, DefaultAzureAISearchFieldIndexEvents>();
services.AddSingleton<AzureAISearchIndexSettingsService>();
services.AddSingleton<AzureAIClientFactory>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@

namespace OrchardCore.Search.AzureAI.Handlers;

public class AzureAISearchAuthorizationHandler(IServiceProvider serviceProvider) : AuthorizationHandler<PermissionRequirement>
public class AzureAISearchAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
private readonly IServiceProvider _serviceProvider = serviceProvider;
private readonly IServiceProvider _serviceProvider;

private IAuthorizationService _authorizationService;
private ISiteService _siteService;

public AzureAISearchAuthorizationHandler(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
if (context.HasSucceeded)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Threading.Tasks;
using OrchardCore.Search.AzureAI.Models;

namespace OrchardCore.Search.AzureAI.Handlers;

public class AzureAISearchFieldIndexEventsBase : IAzureAISearchFieldIndexEvents
{
public virtual Task MappingAsync(SearchIndexDefinition context)
=> Task.CompletedTask;

public virtual Task MappedAsync(SearchIndexDefinition context)
=> Task.CompletedTask;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,31 @@

namespace OrchardCore.Search.AzureAI.Handlers;

public class AzureAISearchIndexingContentHandler(IHttpContextAccessor httpContextAccessor) : ContentHandlerBase
public class AzureAISearchIndexingContentHandler : ContentHandlerBase
{
private readonly List<ContentContextBase> _contexts = [];
private readonly IHttpContextAccessor _httpContextAccessor = httpContextAccessor;

public override Task PublishedAsync(PublishContentContext context) => AddContextAsync(context);
public override Task CreatedAsync(CreateContentContext context) => AddContextAsync(context);
public override Task UpdatedAsync(UpdateContentContext context) => AddContextAsync(context);
public override Task RemovedAsync(RemoveContentContext context) => AddContextAsync(context);
public override Task UnpublishedAsync(PublishContentContext context) => AddContextAsync(context);
private readonly IHttpContextAccessor _httpContextAccessor;

public AzureAISearchIndexingContentHandler(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}

public override Task PublishedAsync(PublishContentContext context)
=> AddContextAsync(context);

public override Task CreatedAsync(CreateContentContext context)
=> AddContextAsync(context);

public override Task UpdatedAsync(UpdateContentContext context)
=> AddContextAsync(context);

public override Task RemovedAsync(RemoveContentContext context)
=> AddContextAsync(context);

public override Task UnpublishedAsync(PublishContentContext context)
=> AddContextAsync(context);

private Task AddContextAsync(ContentContextBase context)
{
Expand Down Expand Up @@ -101,7 +116,7 @@ private static async Task IndexingAsync(ShellScope scope, IEnumerable<ContentCon

if (contentItem == null)
{
await indexDocumentManager.DeleteDocumentsAsync(indexSettings.IndexName, new string[] { context.ContentItem.ContentItemId });
await indexDocumentManager.DeleteDocumentsAsync(indexSettings.IndexName, [context.ContentItem.ContentItemId]);
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System.Threading.Tasks;
using OrchardCore.Contents.Indexing;
using OrchardCore.Indexing;
using OrchardCore.Search.AzureAI.Models;
using OrchardCore.Search.AzureAI.Services;

namespace OrchardCore.Search.AzureAI.Handlers;

public sealed class DefaultAzureAISearchFieldIndexEvents : IAzureAISearchFieldIndexEvents
{
public Task MappingAsync(SearchIndexDefinition context)
{
if (context.IndexEntry.Type == DocumentIndex.Types.Text)
{
context.Map.IsCollection = !context.IndexEntry.Options.HasFlag(DocumentIndexOptions.Keyword);
context.Map.IsSearchable = true;
}
else
{
context.Map.IsFilterable = true;
context.Map.IsSortable = true;
}

return Task.CompletedTask;
}

public Task MappedAsync(SearchIndexDefinition context)
{
if (context.Map.AzureFieldKey == AzureAISearchIndexManager.FullTextKey)
{
context.Map.IsSearchable = true;
context.Map.IsCollection = false;
context.Map.IsSuggester = true;
}
else if (context.Map.AzureFieldKey == AzureAISearchIndexManager.DisplayTextAnalyzedKey)
{
context.Map.IsSearchable = true;
context.Map.IsCollection = false;
}
else if (context.Map.AzureFieldKey == IndexingConstants.ContentItemIdKey)
{
context.Map.IsKey = true;
context.Map.IsFilterable = true;
context.Map.IsSortable = true;
}
else if (context.Map.AzureFieldKey == IndexingConstants.ContentItemVersionIdKey ||
context.Map.AzureFieldKey == IndexingConstants.OwnerKey)
{
context.Map.IsFilterable = true;
context.Map.IsSortable = true;
}

return Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Threading.Tasks;
using OrchardCore.Search.AzureAI.Models;

namespace OrchardCore.Search.AzureAI;

public interface IAzureAISearchFieldIndexEvents
{
Task MappingAsync(SearchIndexDefinition context);

Task MappedAsync(SearchIndexDefinition context);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading.Tasks;
using OrchardCore.Search.AzureAI.Models;

namespace OrchardCore.Search.AzureAI;

Expand All @@ -7,28 +8,32 @@ public interface IAzureAISearchIndexEvents
/// <summary>
/// This event is invoked before removing an existing that already exists.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
Task RemovingAsync(AzureAISearchIndexRemoveContext context);

/// <summary>
/// This event is invoked after the index is removed.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
Task RemovedAsync(AzureAISearchIndexRemoveContext context);

/// <summary>
/// This event is invoked before the index is rebuilt.
/// If the rebuild deletes the index and create a new one, other events like Removing, Removed, Creating, or Created should not be invoked.
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
Task RebuildingAsync(AzureAISearchIndexRebuildContext context);

/// <summary>
/// This event is invoked after the index is rebuilt.
/// </summary>
Task RebuiltAsync(AzureAISearchIndexRebuildContext context);

/// <summary>
/// This event is invoked before the index is created.
/// </summary>
/// <param name="context"></param>
Task CreatingAsync(AzureAISearchIndexCreateContext context);

/// <summary>
/// This event is invoked after the index is created.
/// </summary>
Task CreatedAsync(AzureAISearchIndexCreateContext context);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using OrchardCore.Search.AzureAI.Models;

namespace OrchardCore.Search.AzureAI;
namespace OrchardCore.Search.AzureAI.Models;

public class AzureAISearchIndexCreateContext
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@ public class AzureAISearchIndexMap

public Types Type { get; set; }

public bool IsKey { get; set; }

public bool IsCollection { get; set; }

public bool IsSuggester { get; set; }

public bool IsFilterable { get; set; }

public bool IsSortable { get; set; }

public bool IsHidden { get; set; }

public bool IsFacetable { get; set; }

public bool IsSearchable { get; set; }

public DocumentIndexOptions Options { get; set; }

public AzureAISearchIndexMap()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using OrchardCore.Search.AzureAI.Models;

namespace OrchardCore.Search.AzureAI;
namespace OrchardCore.Search.AzureAI.Models;

public class AzureAISearchIndexRebuildContext
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace OrchardCore.Search.AzureAI;
namespace OrchardCore.Search.AzureAI.Models;

public class AzureAISearchIndexRemoveContext(string indexName, string indexFullName)
{
Expand Down
Loading

0 comments on commit 58149c4

Please sign in to comment.