Browse Source

Feature/elastic batch (#590)

* Batch update for elastic.

* Cleanup

* Fix bulk updates.
pull/593/head
Sebastian Stehle 5 years ago
committed by GitHub
parent
commit
8340f9ec70
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 73
      backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Elastic/ElasticSearchTextIndex.cs
  2. 29
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs
  3. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests_Elastic.cs
  4. 4
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests_Mongo.cs

73
backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Elastic/ElasticSearchTextIndex.cs

@ -50,31 +50,52 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Elastic
public async Task ExecuteAsync(params IndexCommand[] commands) public async Task ExecuteAsync(params IndexCommand[] commands)
{ {
var args = new List<object>();
foreach (var command in commands) foreach (var command in commands)
{ {
switch (command) switch (command)
{ {
case UpsertIndexEntry upsert: case UpsertIndexEntry upsert:
await UpsertAsync(upsert); Upsert(upsert, args);
break; break;
case UpdateIndexEntry update: case UpdateIndexEntry update:
await UpdateAsync(update); Update(update, args);
break; break;
case DeleteIndexEntry delete: case DeleteIndexEntry delete:
await DeleteAsync(delete); Delete(delete, args);
break; break;
} }
} }
if (args.Count > 0)
{
var result = await client.BulkAsync<StringResponse>(PostData.MultiJson(args));
if (!result.Success)
{
throw new InvalidOperationException($"Failed with ${result.Body}", result.OriginalException);
}
}
if (waitForTesting) if (waitForTesting)
{ {
await Task.Delay(1000); await Task.Delay(1000);
} }
} }
private async Task UpsertAsync(UpsertIndexEntry upsert) private void Upsert(UpsertIndexEntry upsert, List<object> args)
{ {
var data = new args.Add(new
{
index = new
{
_id = upsert.DocId,
_index = indexName,
}
});
args.Add(new
{ {
appId = upsert.AppId.Id.ToString(), appId = upsert.AppId.Id.ToString(),
appName = upsert.AppId.Name, appName = upsert.AppId.Name,
@ -84,38 +105,40 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text.Elastic
serveAll = upsert.ServeAll, serveAll = upsert.ServeAll,
servePublished = upsert.ServePublished, servePublished = upsert.ServePublished,
texts = upsert.Texts texts = upsert.Texts
}; });
var result = await client.IndexAsync<StringResponse>(indexName, upsert.DocId, CreatePost(data));
if (!result.Success)
{
throw new InvalidOperationException($"Failed with ${result.Body}", result.OriginalException);
}
} }
private async Task UpdateAsync(UpdateIndexEntry update) private void Update(UpdateIndexEntry update, List<object> args)
{ {
var data = new args.Add(new
{
update = new
{
_id = update.DocId,
_index = indexName,
}
});
args.Add(new
{ {
doc = new doc = new
{ {
serveAll = update.ServeAll, serveAll = update.ServeAll,
servePublished = update.ServePublished servePublished = update.ServePublished
} }
}; });
var result = await client.UpdateAsync<StringResponse>(indexName, update.DocId, CreatePost(data));
if (!result.Success)
{
throw new InvalidOperationException($"Failed with ${result.Body}", result.OriginalException);
}
} }
private Task DeleteAsync(DeleteIndexEntry delete) private void Delete(DeleteIndexEntry delete, List<object> args)
{ {
return client.DeleteAsync<StringResponse>(indexName, delete.DocId); args.Add(new
{
delete = new
{
_id = delete.DocId,
_index = indexName,
}
});
} }
public async Task<List<DomainId>?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope) public async Task<List<DomainId>?> SearchAsync(string? queryText, IAppEntity app, SearchFilter? filter, SearchScope scope)

29
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTestsBase.cs

@ -16,7 +16,6 @@ using Squidex.Domain.Apps.Entities.TestHelpers;
using Squidex.Domain.Apps.Events.Contents; using Squidex.Domain.Apps.Events.Contents;
using Squidex.Infrastructure; using Squidex.Infrastructure;
using Squidex.Infrastructure.EventSourcing; using Squidex.Infrastructure.EventSourcing;
using Squidex.Infrastructure.Validation;
using Xunit; using Xunit;
#pragma warning disable SA1401 // Fields should be private #pragma warning disable SA1401 // Fields should be private
@ -297,35 +296,31 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
protected IndexOperation Create(DomainId id, string language, string text) protected IndexOperation Create(DomainId id, string language, string text)
{ {
var data = var data = Data(language, text);
new NamedContentData()
.AddField("text",
new ContentFieldData()
.AddValue(language, text));
return Op(id, new ContentCreated { Data = data }); return Op(id, new ContentCreated { Data = data });
} }
protected IndexOperation Update(DomainId id, string language, string text) protected IndexOperation Update(DomainId id, string language, string text)
{ {
var data = var data = Data(language, text);
new NamedContentData()
.AddField("text",
new ContentFieldData()
.AddValue(language, text));
return Op(id, new ContentUpdated { Data = data }); return Op(id, new ContentUpdated { Data = data });
} }
protected IndexOperation CreateDraftWithData(DomainId id, string language, string text) protected IndexOperation CreateDraftWithData(DomainId id, string language, string text)
{ {
var data = var data = Data(language, text);
new NamedContentData()
return Op(id, new ContentDraftCreated { MigratedData = data });
}
private static NamedContentData Data(string language, string text)
{
return new NamedContentData()
.AddField("text", .AddField("text",
new ContentFieldData() new ContentFieldData()
.AddValue(language, text)); .AddValue(language, text));
return Op(id, new ContentDraftCreated { MigratedData = data });
} }
protected IndexOperation CreateDraft(DomainId id) protected IndexOperation CreateDraft(DomainId id)
@ -338,7 +333,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
return Op(id, new ContentStatusChanged { Status = Status.Published }); return Op(id, new ContentStatusChanged { Status = Status.Published });
} }
protected IndexOperation Unpublish( DomainId id) protected IndexOperation Unpublish(DomainId id)
{ {
return Op(id, new ContentStatusChanged { Status = Status.Draft }); return Op(id, new ContentStatusChanged { Status = Status.Draft });
} }
@ -376,7 +371,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
} }
else else
{ {
Assert.Empty(result); result.Should().BeEmpty();
} }
}; };
} }

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests_Elastic.cs

@ -17,7 +17,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
[Trait("Category", "Dependencies")] [Trait("Category", "Dependencies")]
public class TextIndexerTests_Elastic : TextIndexerTestsBase public class TextIndexerTests_Elastic : TextIndexerTestsBase
{ {
private sealed class TheFactory : IIndexerFactory private sealed class ElasticFactory : IIndexerFactory
{ {
public Task CleanupAsync() public Task CleanupAsync()
{ {
@ -34,7 +34,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
} }
} }
public override IIndexerFactory Factory { get; } = new TheFactory(); public override IIndexerFactory Factory { get; } = new ElasticFactory();
public TextIndexerTests_Elastic() public TextIndexerTests_Elastic()
{ {

4
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests_Mongo.cs

@ -19,7 +19,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
[Trait("Category", "Dependencies")] [Trait("Category", "Dependencies")]
public class TextIndexerTests_Mongo : TextIndexerTestsBase public class TextIndexerTests_Mongo : TextIndexerTestsBase
{ {
private sealed class TheFactory : IIndexerFactory private sealed class MongoFactory : IIndexerFactory
{ {
private readonly MongoClient mongoClient = new MongoClient("mongodb://localhost"); private readonly MongoClient mongoClient = new MongoClient("mongodb://localhost");
@ -40,7 +40,7 @@ namespace Squidex.Domain.Apps.Entities.Contents.Text
} }
} }
public override IIndexerFactory Factory { get; } = new TheFactory(); public override IIndexerFactory Factory { get; } = new MongoFactory();
public TextIndexerTests_Mongo() public TextIndexerTests_Mongo()
{ {

Loading…
Cancel
Save