Skip to content

Commit a34d1e5

Browse files
committed
Support slice in delete by query (#3014)
Closes #2859
1 parent e0a42a5 commit a34d1e5

File tree

3 files changed

+130
-1
lines changed

3 files changed

+130
-1
lines changed

src/Nest/Document/Multiple/DeleteByQuery/DeleteByQueryRequest.cs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,75 @@
33

44
namespace Nest
55
{
6+
/// <summary>
7+
/// Delete documents that match a given query
8+
/// </summary>
69
public partial interface IDeleteByQueryRequest
710
{
11+
/// <summary>
12+
/// The query to use to select documents for deletion
13+
/// </summary>
814
[JsonProperty("query")]
915
QueryContainer Query { get; set; }
16+
17+
/// <summary>
18+
/// Parallelize the deleting process. This parallelization can improve efficiency and
19+
/// provide a convenient way to break the request down into smaller parts.
20+
/// </summary>
21+
[JsonProperty("slice")]
22+
ISlicedScroll Slice { get; set; }
1023
}
1124

25+
/// <inheritdoc />
1226
public interface IDeleteByQueryRequest<T> : IDeleteByQueryRequest where T : class { }
1327

28+
/// <inheritdoc cref="IDeleteByQueryRequest"/>
1429
public partial class DeleteByQueryRequest
1530
{
31+
/// <inheritdoc />
1632
public QueryContainer Query { get; set; }
1733

34+
/// <inheritdoc />
35+
public ISlicedScroll Slice { get; set; }
1836
}
1937

38+
/// <inheritdoc cref="IDeleteByQueryRequest"/>
2039
public partial class DeleteByQueryRequest<T> : IDeleteByQueryRequest<T>
2140
where T : class
2241
{
2342
public DeleteByQueryRequest() : this(typeof(T), typeof(T)){ }
2443

44+
/// <inheritdoc />
2545
public QueryContainer Query { get; set; }
46+
47+
/// <inheritdoc />
48+
public ISlicedScroll Slice { get; set; }
2649
}
2750

51+
/// <inheritdoc cref="IDeleteByQueryRequest"/>
2852
public partial class DeleteByQueryDescriptor<T> : IDeleteByQueryRequest<T>
2953
where T : class
3054
{
3155
QueryContainer IDeleteByQueryRequest.Query { get; set; }
56+
ISlicedScroll IDeleteByQueryRequest.Slice { get; set; }
3257

58+
/// <summary>
59+
/// A match_all query to select all documents. Convenient shorthand for specifying
60+
/// a match_all query using <see cref="Query"/>
61+
/// </summary>
3362
public DeleteByQueryDescriptor<T> MatchAll() => Assign(a => a.Query = new QueryContainerDescriptor<T>().MatchAll());
3463

64+
/// <summary>
65+
/// The query to use to select documents for deletion
66+
/// </summary>
3567
public DeleteByQueryDescriptor<T> Query(Func<QueryContainerDescriptor<T>, QueryContainer> querySelector) =>
3668
Assign(a => a.Query = querySelector?.Invoke(new QueryContainerDescriptor<T>()));
69+
70+
/// <summary>
71+
/// Parallelize the deleting process. This parallelization can improve efficiency and
72+
/// provide a convenient way to break the request down into smaller parts.
73+
/// </summary>
74+
public DeleteByQueryDescriptor<T> Slice(Func<SlicedScrollDescriptor<T>, ISlicedScroll> selector) =>
75+
Assign(a => a.Slice = selector?.Invoke(new SlicedScrollDescriptor<T>()));
3776
}
3877
}

src/Nest/Document/Multiple/DeleteByQuery/DeleteByQueryResponse.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ public interface IDeleteByQueryResponse : IResponse
1717
[JsonProperty("timed_out")]
1818
bool TimedOut { get; }
1919

20+
[JsonProperty("slice_id")]
21+
int? SliceId { get; }
22+
2023
[JsonProperty("deleted")]
2124
long Deleted { get; }
2225

@@ -58,6 +61,8 @@ public class DeleteByQueryResponse : ResponseBase, IDeleteByQueryResponse
5861

5962
public bool TimedOut { get; internal set; }
6063

64+
public int? SliceId { get; internal set; }
65+
6166
public long Deleted { get; internal set; }
6267

6368
public long Batches { get; internal set; }

src/Tests/Document/Multiple/DeleteByQuery/DeleteByQueryApiTests.cs

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using Tests.Framework;
88
using Tests.Framework.Integration;
99
using Tests.Framework.ManagedElasticsearch.Clusters;
10+
using Tests.Framework.ManagedElasticsearch.NodeSeeders;
1011
using Tests.Framework.MockData;
1112
using Xunit;
1213
using static Nest.Infer;
@@ -21,10 +22,23 @@ protected override void IntegrationSetup(IElasticClient client, CallUniqueValues
2122
{
2223
foreach (var index in values.Values)
2324
{
25+
this.Client.CreateIndex(index, c => c
26+
.Settings(s => s
27+
.NumberOfShards(2)
28+
.NumberOfReplicas(0)
29+
.Analysis(DefaultSeeder.ProjectAnalysisSettings)
30+
)
31+
.Mappings(m => m
32+
.Map<Project>(p => p
33+
.AutoMap()
34+
.Properties(DefaultSeeder.ProjectProperties)
35+
)
36+
)
37+
);
38+
2439
this.Client.IndexMany(Project.Projects, index);
2540
var cloneIndex = index + "-clone";
2641
this.Client.CreateIndex(cloneIndex);
27-
2842
this.Client.Refresh(Index(index).And(cloneIndex));
2943
}
3044
}
@@ -200,4 +214,75 @@ protected override void ExpectResponse(IDeleteByQueryResponse response)
200214
failure.Cause.Type.Should().NotBeNullOrWhiteSpace();
201215
}
202216
}
217+
218+
public class DeleteByQueryWithSlicesApiTests : DeleteByQueryApiTests
219+
{
220+
private static List<string> FirstTenProjectNames => Project.Projects.Take(10).Select(p => p.Name).ToList();
221+
222+
public DeleteByQueryWithSlicesApiTests(IntrusiveOperationCluster cluster, EndpointUsage usage) : base(cluster, usage) { }
223+
224+
protected override bool ExpectIsValid => true;
225+
protected override int ExpectStatusCode => 200;
226+
227+
protected override string UrlPath => $"/{CallIsolatedValue}/project/_delete_by_query";
228+
229+
protected override object ExpectJson =>
230+
new
231+
{
232+
slice = new { id = 0, max = 2 },
233+
query = new { terms = new { name = new { terms = FirstTenProjectNames } } }
234+
};
235+
236+
protected override DeleteByQueryDescriptor<Project> NewDescriptor() => new DeleteByQueryDescriptor<Project>(this.CallIsolatedValue);
237+
238+
protected override Func<DeleteByQueryDescriptor<Project>, IDeleteByQueryRequest> Fluent => d => d
239+
.Index(this.CallIsolatedValue)
240+
.Slice(s => s
241+
.Id(0)
242+
.Max(2)
243+
)
244+
.Query(q => q
245+
.Terms(m => m
246+
.Field(p => p.Name)
247+
.Terms(FirstTenProjectNames)
248+
)
249+
)
250+
;
251+
252+
protected override DeleteByQueryRequest Initializer => new DeleteByQueryRequest(this.CallIsolatedValue, Type<Project>())
253+
{
254+
Slice = new SlicedScroll
255+
{
256+
Id = 0,
257+
Max = 2
258+
},
259+
Query = new TermsQuery
260+
{
261+
Field = Field<Project>(p => p.Name),
262+
Terms = FirstTenProjectNames
263+
},
264+
};
265+
266+
protected override void ExpectResponse(IDeleteByQueryResponse response)
267+
{
268+
response.ShouldBeValid();
269+
response.SliceId.Should().Be(0);
270+
271+
// Since we only executed one slice of the two, some of the documents that
272+
// match the query will still exist.
273+
Client.Refresh(CallIsolatedValue);
274+
275+
var countResponse = Client.Count<Project>(c => c
276+
.Index(CallIsolatedValue)
277+
.Query(q => q
278+
.Terms(m => m
279+
.Field(p => p.Name)
280+
.Terms(FirstTenProjectNames)
281+
)
282+
)
283+
);
284+
285+
countResponse.Count.Should().BeGreaterThan(0);
286+
}
287+
}
203288
}

0 commit comments

Comments
 (0)