Skip to content

Commit ae2c59b

Browse files
authored
Make the indexing batch size configurable (#20543)
* Introduce configurable batch size for indexing * Stop using Examine indexing events for reporting index rebuild operation completeness (it is volatile)
1 parent b142dcc commit ae2c59b

File tree

7 files changed

+113
-42
lines changed

7 files changed

+113
-42
lines changed

src/Umbraco.Core/Configuration/Models/IndexingSettings.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,16 @@ namespace Umbraco.Cms.Core.Configuration.Models;
99
public class IndexingSettings
1010
{
1111
private const bool StaticExplicitlyIndexEachNestedProperty = false;
12+
private const int StaticBatchSize = 10000;
1213

1314
/// <summary>
1415
/// Gets or sets a value for whether each nested property should have it's own indexed value. Requires a rebuild of indexes when changed.
1516
/// </summary>
1617
[DefaultValue(StaticExplicitlyIndexEachNestedProperty)]
1718
public bool ExplicitlyIndexEachNestedProperty { get; set; } = StaticExplicitlyIndexEachNestedProperty;
19+
20+
/// <summary>
21+
/// Gets or sets a value for how many items to index at a time.
22+
/// </summary>
23+
public int BatchSize { get; set; } = StaticBatchSize;
1824
}

src/Umbraco.Infrastructure/Examine/ContentIndexPopulator.cs

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
using Examine;
2+
using Microsoft.Extensions.DependencyInjection;
23
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Options;
5+
using Umbraco.Cms.Core.Configuration.Models;
6+
using Umbraco.Cms.Core.DependencyInjection;
37
using Umbraco.Cms.Core.Models;
48
using Umbraco.Cms.Core.Persistence.Querying;
59
using Umbraco.Cms.Core.Services;
@@ -20,20 +24,45 @@ public class ContentIndexPopulator : IndexPopulator<IUmbracoContentIndex>
2024
private readonly bool _publishedValuesOnly;
2125
private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory;
2226

27+
private IndexingSettings _indexingSettings;
28+
2329
/// <summary>
2430
/// This is a static query, it's parameters don't change so store statically
2531
/// </summary>
2632
private IQuery<IContent>? _publishedQuery;
2733

34+
[Obsolete("Please use the non-obsolete constructor. Scheduled for removal in V19.")]
35+
public ContentIndexPopulator(
36+
ILogger<ContentIndexPopulator> logger,
37+
IContentService contentService,
38+
IUmbracoDatabaseFactory umbracoDatabaseFactory,
39+
IContentValueSetBuilder contentValueSetBuilder)
40+
: this(logger, false, null, contentService, umbracoDatabaseFactory, contentValueSetBuilder, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())
41+
{
42+
}
43+
2844
/// <summary>
2945
/// Default constructor to lookup all content data
3046
/// </summary>
3147
public ContentIndexPopulator(
3248
ILogger<ContentIndexPopulator> logger,
3349
IContentService contentService,
3450
IUmbracoDatabaseFactory umbracoDatabaseFactory,
35-
IContentValueSetBuilder contentValueSetBuilder)
36-
: this(logger, false, null, contentService, umbracoDatabaseFactory, contentValueSetBuilder)
51+
IContentValueSetBuilder contentValueSetBuilder,
52+
IOptionsMonitor<IndexingSettings> indexingSettings)
53+
: this(logger, false, null, contentService, umbracoDatabaseFactory, contentValueSetBuilder, indexingSettings)
54+
{
55+
}
56+
57+
[Obsolete("Please use the non-obsolete constructor. Scheduled for removal in V19.")]
58+
public ContentIndexPopulator(
59+
ILogger<ContentIndexPopulator> logger,
60+
bool publishedValuesOnly,
61+
int? parentId,
62+
IContentService contentService,
63+
IUmbracoDatabaseFactory umbracoDatabaseFactory,
64+
IValueSetBuilder<IContent> contentValueSetBuilder)
65+
: this(logger, publishedValuesOnly, parentId, contentService, umbracoDatabaseFactory, contentValueSetBuilder, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())
3766
{
3867
}
3968

@@ -46,14 +75,21 @@ public ContentIndexPopulator(
4675
int? parentId,
4776
IContentService contentService,
4877
IUmbracoDatabaseFactory umbracoDatabaseFactory,
49-
IValueSetBuilder<IContent> contentValueSetBuilder)
78+
IValueSetBuilder<IContent> contentValueSetBuilder,
79+
IOptionsMonitor<IndexingSettings> indexingSettings)
5080
{
5181
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
5282
_umbracoDatabaseFactory = umbracoDatabaseFactory ?? throw new ArgumentNullException(nameof(umbracoDatabaseFactory));
5383
_contentValueSetBuilder = contentValueSetBuilder ?? throw new ArgumentNullException(nameof(contentValueSetBuilder));
5484
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
5585
_publishedValuesOnly = publishedValuesOnly;
5686
_parentId = parentId;
87+
_indexingSettings = indexingSettings.CurrentValue;
88+
89+
indexingSettings.OnChange(change =>
90+
{
91+
_indexingSettings = change;
92+
});
5793
}
5894

5995
private IQuery<IContent> PublishedQuery => _publishedQuery ??=
@@ -75,7 +111,6 @@ protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
75111
return;
76112
}
77113

78-
const int pageSize = 10000;
79114
var pageIndex = 0;
80115

81116
var contentParentId = -1;
@@ -86,11 +121,11 @@ protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
86121

87122
if (_publishedValuesOnly)
88123
{
89-
IndexPublishedContent(contentParentId, pageIndex, pageSize, indexes);
124+
IndexPublishedContent(contentParentId, pageIndex, _indexingSettings.BatchSize, indexes);
90125
}
91126
else
92127
{
93-
IndexAllContent(contentParentId, pageIndex, pageSize, indexes);
128+
IndexAllContent(contentParentId, pageIndex, _indexingSettings.BatchSize, indexes);
94129
}
95130
}
96131

src/Umbraco.Infrastructure/Examine/DeliveryApiContentIndexHelper.cs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
using Microsoft.Extensions.DependencyInjection;
12
using Microsoft.Extensions.Options;
23
using Umbraco.Cms.Core.Configuration.Models;
4+
using Umbraco.Cms.Core.DependencyInjection;
35
using Umbraco.Cms.Core.Models;
46
using Umbraco.Cms.Core.Persistence.Querying;
57
using Umbraco.Cms.Core.Services;
@@ -14,22 +16,33 @@ internal sealed class DeliveryApiContentIndexHelper : IDeliveryApiContentIndexHe
1416
private readonly IUmbracoDatabaseFactory _umbracoDatabaseFactory;
1517
private DeliveryApiSettings _deliveryApiSettings;
1618

19+
private IndexingSettings _indexingSettings;
20+
21+
[Obsolete("Please use the non-obsolete constructor. Scheduled for removal in V19.")]
1722
public DeliveryApiContentIndexHelper(
1823
IContentService contentService,
1924
IUmbracoDatabaseFactory umbracoDatabaseFactory,
2025
IOptionsMonitor<DeliveryApiSettings> deliveryApiSettings)
26+
: this(contentService, umbracoDatabaseFactory, deliveryApiSettings, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())
27+
{
28+
}
29+
30+
public DeliveryApiContentIndexHelper(
31+
IContentService contentService,
32+
IUmbracoDatabaseFactory umbracoDatabaseFactory,
33+
IOptionsMonitor<DeliveryApiSettings> deliveryApiSettings,
34+
IOptionsMonitor<IndexingSettings> indexingSettings)
2135
{
2236
_contentService = contentService;
2337
_umbracoDatabaseFactory = umbracoDatabaseFactory;
2438
_deliveryApiSettings = deliveryApiSettings.CurrentValue;
39+
_indexingSettings = indexingSettings.CurrentValue;
2540
deliveryApiSettings.OnChange(settings => _deliveryApiSettings = settings);
41+
indexingSettings.OnChange(settings => _indexingSettings = settings);
2642
}
2743

2844
public void EnumerateApplicableDescendantsForContentIndex(int rootContentId, Action<IContent[]> actionToPerform)
29-
{
30-
const int pageSize = 10000;
31-
EnumerateApplicableDescendantsForContentIndex(rootContentId, actionToPerform, pageSize);
32-
}
45+
=> EnumerateApplicableDescendantsForContentIndex(rootContentId, actionToPerform, _indexingSettings.BatchSize);
3346

3447
internal void EnumerateApplicableDescendantsForContentIndex(int rootContentId, Action<IContent[]> actionToPerform, int pageSize)
3548
{

src/Umbraco.Infrastructure/Examine/MediaIndexPopulator.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
using Examine;
2+
using Microsoft.Extensions.DependencyInjection;
23
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Options;
5+
using Umbraco.Cms.Core.Configuration.Models;
6+
using Umbraco.Cms.Core.DependencyInjection;
37
using Umbraco.Cms.Core.Models;
48
using Umbraco.Cms.Core.Services;
59

@@ -15,23 +19,43 @@ public class MediaIndexPopulator : IndexPopulator<IUmbracoContentIndex>
1519
private readonly IValueSetBuilder<IMedia> _mediaValueSetBuilder;
1620
private readonly int? _parentId;
1721

22+
private IndexingSettings _indexingSettings;
23+
24+
[Obsolete("Please use the non-obsolete constructor. Scheduled for removal in V19.")]
25+
public MediaIndexPopulator(ILogger<MediaIndexPopulator> logger, IMediaService mediaService, IValueSetBuilder<IMedia> mediaValueSetBuilder)
26+
: this(logger, null, mediaService, mediaValueSetBuilder, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())
27+
{
28+
}
29+
1830
/// <summary>
1931
/// Default constructor to lookup all content data
2032
/// </summary>
21-
public MediaIndexPopulator(ILogger<MediaIndexPopulator> logger, IMediaService mediaService, IValueSetBuilder<IMedia> mediaValueSetBuilder)
22-
: this(logger, null, mediaService, mediaValueSetBuilder)
33+
public MediaIndexPopulator(ILogger<MediaIndexPopulator> logger, IMediaService mediaService, IValueSetBuilder<IMedia> mediaValueSetBuilder, IOptionsMonitor<IndexingSettings> indexingSettings)
34+
: this(logger, null, mediaService, mediaValueSetBuilder, indexingSettings)
35+
{
36+
}
37+
38+
[Obsolete("Please use the non-obsolete constructor. Scheduled for removal in V19.")]
39+
public MediaIndexPopulator(ILogger<MediaIndexPopulator> logger, int? parentId, IMediaService mediaService, IValueSetBuilder<IMedia> mediaValueSetBuilder)
40+
: this(logger, parentId, mediaService, mediaValueSetBuilder, StaticServiceProvider.Instance.GetRequiredService<IOptionsMonitor<IndexingSettings>>())
2341
{
2442
}
2543

2644
/// <summary>
2745
/// Optional constructor allowing specifying custom query parameters
2846
/// </summary>
29-
public MediaIndexPopulator(ILogger<MediaIndexPopulator> logger, int? parentId, IMediaService mediaService, IValueSetBuilder<IMedia> mediaValueSetBuilder)
47+
public MediaIndexPopulator(ILogger<MediaIndexPopulator> logger, int? parentId, IMediaService mediaService, IValueSetBuilder<IMedia> mediaValueSetBuilder, IOptionsMonitor<IndexingSettings> indexingSettings)
3048
{
3149
_logger = logger;
3250
_parentId = parentId;
3351
_mediaService = mediaService;
3452
_mediaValueSetBuilder = mediaValueSetBuilder;
53+
_indexingSettings = indexingSettings.CurrentValue;
54+
55+
indexingSettings.OnChange(change =>
56+
{
57+
_indexingSettings = change;
58+
});
3559
}
3660

3761
protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
@@ -46,7 +70,6 @@ protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
4670
return;
4771
}
4872

49-
const int pageSize = 10000;
5073
var pageIndex = 0;
5174

5275
var mediaParentId = -1;
@@ -60,7 +83,7 @@ protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
6083

6184
do
6285
{
63-
media = _mediaService.GetPagedDescendants(mediaParentId, pageIndex, pageSize, out _).ToArray();
86+
media = _mediaService.GetPagedDescendants(mediaParentId, pageIndex, _indexingSettings.BatchSize, out _).ToArray();
6487

6588
// ReSharper disable once PossibleMultipleEnumeration
6689
foreach (IIndex index in indexes)
@@ -70,6 +93,6 @@ protected override void PopulateIndexes(IReadOnlyList<IIndex> indexes)
7093

7194
pageIndex++;
7295
}
73-
while (media.Length == pageSize);
96+
while (media.Length == _indexingSettings.BatchSize);
7497
}
7598
}

src/Umbraco.Infrastructure/Examine/PublishedContentIndexPopulator.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using Microsoft.Extensions.Logging;
2+
using Microsoft.Extensions.Options;
3+
using Umbraco.Cms.Core.Configuration.Models;
24
using Umbraco.Cms.Core.Services;
35
using Umbraco.Cms.Infrastructure.Persistence;
46

@@ -15,6 +17,7 @@ namespace Umbraco.Cms.Infrastructure.Examine;
1517
/// </remarks>
1618
public class PublishedContentIndexPopulator : ContentIndexPopulator
1719
{
20+
[Obsolete("Please use the non-obsolete constructor. Scheduled for removal in V19.")]
1821
public PublishedContentIndexPopulator(
1922
ILogger<PublishedContentIndexPopulator> logger,
2023
IContentService contentService,
@@ -23,4 +26,14 @@ public PublishedContentIndexPopulator(
2326
: base(logger, true, null, contentService, umbracoDatabaseFactory, contentValueSetBuilder)
2427
{
2528
}
29+
30+
public PublishedContentIndexPopulator(
31+
ILogger<PublishedContentIndexPopulator> logger,
32+
IContentService contentService,
33+
IUmbracoDatabaseFactory umbracoDatabaseFactory,
34+
IPublishedContentValueSetBuilder contentValueSetBuilder,
35+
IOptionsMonitor<IndexingSettings> indexingSettings)
36+
: base(logger, true, null, contentService, umbracoDatabaseFactory, contentValueSetBuilder, indexingSettings)
37+
{
38+
}
2639
}

src/Umbraco.Infrastructure/Services/IndexingRebuilderService.cs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,13 @@ public bool TryRebuild(IIndex index, string indexName)
4242
/// <inheritdoc />
4343
public async Task<bool> TryRebuildAsync(IIndex index, string indexName)
4444
{
45-
// Remove it in case there's a handler there already
46-
index.IndexOperationComplete -= Indexer_IndexOperationComplete;
47-
48-
// Now add a single handler
49-
index.IndexOperationComplete += Indexer_IndexOperationComplete;
50-
5145
try
5246
{
5347
Attempt<IndexRebuildResult> attempt = await _indexRebuilder.RebuildIndexAsync(indexName);
5448
return attempt.Success;
5549
}
5650
catch (Exception exception)
5751
{
58-
// Ensure it's not listening
59-
index.IndexOperationComplete -= Indexer_IndexOperationComplete;
6052
_logger.LogError(exception, "An error occurred rebuilding index");
6153
return false;
6254
}
@@ -70,19 +62,4 @@ public bool IsRebuilding(string indexName)
7062
/// <inheritdoc />
7163
public Task<bool> IsRebuildingAsync(string indexName)
7264
=> _indexRebuilder.IsRebuildingAsync(indexName);
73-
74-
private void Indexer_IndexOperationComplete(object? sender, EventArgs e)
75-
{
76-
var indexer = (IIndex?)sender;
77-
78-
_logger.LogDebug("Logging operation completed for index {IndexName}", indexer?.Name);
79-
80-
if (indexer is not null)
81-
{
82-
//ensure it's not listening anymore
83-
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
84-
}
85-
86-
_logger.LogInformation("Rebuilding index '{IndexerName}' done.", indexer?.Name);
87-
}
8865
}

tests/Umbraco.Tests.Integration/Umbraco.Examine.Lucene/UmbracoExamine/IndexInitializer.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class IndexInitializer
3939
private readonly IContentTypeService _contentTypeService;
4040
private readonly IDocumentUrlService _documentUrlService;
4141
private readonly ILanguageService _languageService;
42+
private readonly IOptionsMonitor<IndexingSettings> _indexSettings;
4243

4344
public IndexInitializer(
4445
IShortStringHelper shortStringHelper,
@@ -50,7 +51,8 @@ public IndexInitializer(
5051
ILocalizationService localizationService,
5152
IContentTypeService contentTypeService,
5253
IDocumentUrlService documentUrlService,
53-
ILanguageService languageService)
54+
ILanguageService languageService,
55+
IOptionsMonitor<IndexingSettings> indexSettings)
5456
{
5557
_shortStringHelper = shortStringHelper;
5658
_propertyEditors = propertyEditors;
@@ -62,6 +64,7 @@ public IndexInitializer(
6264
_contentTypeService = contentTypeService;
6365
_documentUrlService = documentUrlService;
6466
_languageService = languageService;
67+
_indexSettings = indexSettings;
6568
}
6669

6770
public ContentValueSetBuilder GetContentValueSetBuilder(bool publishedValuesOnly)
@@ -91,7 +94,8 @@ public ContentIndexPopulator GetContentIndexRebuilder(IContentService contentSer
9194
null,
9295
contentService,
9396
umbracoDatabaseFactory,
94-
contentValueSetBuilder);
97+
contentValueSetBuilder,
98+
_indexSettings);
9599
return contentIndexDataSource;
96100
}
97101

@@ -105,7 +109,7 @@ public MediaIndexPopulator GetMediaIndexRebuilder(IMediaService mediaService)
105109
_shortStringHelper,
106110
_contentSettings,
107111
StaticServiceProvider.Instance.GetRequiredService<IContentTypeService>());
108-
var mediaIndexDataSource = new MediaIndexPopulator(null, mediaService, mediaValueSetBuilder);
112+
var mediaIndexDataSource = new MediaIndexPopulator(null, mediaService, mediaValueSetBuilder, _indexSettings);
109113
return mediaIndexDataSource;
110114
}
111115

0 commit comments

Comments
 (0)