Skip to content

Commit

Permalink
[Backport master] Support mapping runtime fields (#5234)
Browse files Browse the repository at this point in the history
* Support mapping runtime fields
* Add missing XML comment for PIT
* Fixes for master namespaces

Co-authored-by: Steve Gordon <sgordon@hotmail.co.uk>
  • Loading branch information
github-actions[bot] and stevejgordon authored Jan 7, 2021
1 parent 6894e47 commit f0b2e5d
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ public partial class PutMappingRequest
/// <inheritdoc />
public IRoutingField RoutingField { get; set; }

/// <inheritdoc />
public IRuntimeFields RuntimeFields { get; set; }

/// <inheritdoc />
public ISizeField SizeField { get; set; }

Expand All @@ -82,6 +85,7 @@ public partial class PutMappingDescriptor<TDocument> where TDocument : class
bool? ITypeMapping.NumericDetection { get; set; }
IProperties ITypeMapping.Properties { get; set; }
IRoutingField ITypeMapping.RoutingField { get; set; }
IRuntimeFields ITypeMapping.RuntimeFields { get; set; }
ISizeField ITypeMapping.SizeField { get; set; }
ISourceField ITypeMapping.SourceField { get; set; }

Expand Down Expand Up @@ -150,6 +154,10 @@ public PutMappingDescriptor<TDocument> SourceField(Func<SourceFieldDescriptor, I
public PutMappingDescriptor<TDocument> RoutingField(Func<RoutingFieldDescriptor<TDocument>, IRoutingField> routingFieldSelector) =>
Assign(routingFieldSelector, (a, v) => a.RoutingField = v?.Invoke(new RoutingFieldDescriptor<TDocument>()));

/// <inheritdoc cref="ITypeMapping.RuntimeFields" />
public PutMappingDescriptor<TDocument> RuntimeFields(Func<RuntimeFieldsDescriptor, IPromise<IRuntimeFields>> runtimeFieldsSelector) =>
Assign(runtimeFieldsSelector, (a, v) => a.RuntimeFields = v?.Invoke(new RuntimeFieldsDescriptor())?.Value);

/// <inheritdoc cref="ITypeMapping.FieldNamesField" />
public PutMappingDescriptor<TDocument> FieldNamesField(Func<FieldNamesFieldDescriptor<TDocument>, IFieldNamesField> fieldNamesFieldSelector) =>
Assign(fieldNamesFieldSelector, (a, v) => a.FieldNamesField = v.Invoke(new FieldNamesFieldDescriptor<TDocument>()));
Expand Down
2 changes: 2 additions & 0 deletions src/Nest/Mapping/Mappings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ public abstract class ObsoleteMappingsBase : ITypeMapping
IProperties ITypeMapping.Properties { get => Wrapped.Properties; set => Wrapped.Properties = value; }
[DataMember(Name = "_routing")]
IRoutingField ITypeMapping.RoutingField { get => Wrapped.RoutingField; set => Wrapped.RoutingField = value; }
[DataMember(Name = "runtime")]
IRuntimeFields ITypeMapping.RuntimeFields { get => Wrapped.RuntimeFields; set => Wrapped.RuntimeFields = value; }
[DataMember(Name = "_size")]
ISizeField ITypeMapping.SizeField { get => Wrapped.SizeField; set => Wrapped.SizeField = value; }
[DataMember(Name = "_source")]
Expand Down
59 changes: 59 additions & 0 deletions src/Nest/Mapping/RuntimeFields/RuntimeField.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System.Runtime.Serialization;
using Nest.Utf8Json;

namespace Nest
{
[InterfaceDataContract]
[ReadAs(typeof(RuntimeField))]
public interface IRuntimeField
{
/// <summary>
/// Runtime fields with a type of date can accept the format parameter exactly as the date field type.
/// <see cref="DateFormat" />
/// </summary>
[DataMember(Name = "format")]
string Format { get; set; }

/// <summary>
/// The script to be evaluated for field calculation at search time.
/// </summary>
[DataMember(Name = "script")]
IStoredScript Script { get; set; }

/// <summary>
/// The datatype of the runtime field.
/// </summary>
[DataMember(Name = "type")]
FieldType Type { get; set; }
}

public class RuntimeField : IRuntimeField
{
/// <inheritdoc />
public string Format { get; set; }
/// <inheritdoc />
public IStoredScript Script { get; set; }
/// <inheritdoc />
public FieldType Type { get; set; }
}

public class RuntimeFieldDescriptor
: DescriptorBase<RuntimeFieldDescriptor, IRuntimeField>, IRuntimeField
{
public RuntimeFieldDescriptor(FieldType fieldType) => Self.Type = fieldType;

string IRuntimeField.Format { get; set; }
IStoredScript IRuntimeField.Script { get; set; }
FieldType IRuntimeField.Type { get; set; }

public RuntimeFieldDescriptor Format(string format) => Assign(format, (a, v) => a.Format = v);

public RuntimeFieldDescriptor Script(IStoredScript script) => Assign(script, (a, v) => a.Script = v);

public RuntimeFieldDescriptor Script(string source) => Assign(source, (a, v) => a.Script = new PainlessScript(source));
}
}
36 changes: 36 additions & 0 deletions src/Nest/Mapping/RuntimeFields/RuntimeFields.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information

using System;
using System.Collections.Generic;
using Nest.Utf8Json;

namespace Nest
{
[JsonFormatter(typeof(VerbatimDictionaryKeysFormatter<RuntimeFields, IRuntimeFields, string, IRuntimeField>))]
public interface IRuntimeFields : IIsADictionary<string, IRuntimeField> { }

public class RuntimeFields : IsADictionaryBase<string, IRuntimeField>, IRuntimeFields
{
public RuntimeFields() { }

public RuntimeFields(IDictionary<string, IRuntimeField> container) : base(container) { }

public RuntimeFields(Dictionary<string, IRuntimeField> container) : base(container) { }

public void Add(string name, IRuntimeField runtimeField) => BackingDictionary.Add(name, runtimeField);
}

public class RuntimeFieldsDescriptor
: IsADictionaryDescriptorBase<RuntimeFieldsDescriptor, RuntimeFields, string, IRuntimeField>
{
public RuntimeFieldsDescriptor() : base(new RuntimeFields()) { }

public RuntimeFieldsDescriptor RuntimeField(string name, FieldType type, Func<RuntimeFieldDescriptor, IRuntimeField> selector) =>
Assign(name, selector?.Invoke(new RuntimeFieldDescriptor(type)));

public RuntimeFieldsDescriptor RuntimeField(string name, FieldType type) =>
Assign(name, new RuntimeFieldDescriptor(type));
}
}
14 changes: 14 additions & 0 deletions src/Nest/Mapping/TypeMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ public interface ITypeMapping
[DataMember(Name = "_routing")]
IRoutingField RoutingField { get; set; }

/// <summary>
/// Specifies runtime fields for the mapping.
/// </summary>
[DataMember(Name = "runtime")]
IRuntimeFields RuntimeFields { get; set; }

/// <summary>
/// If enabled, indexes the size in bytes of the original _source field.
/// Requires mapper-size plugin be installed
Expand Down Expand Up @@ -147,6 +153,9 @@ public class TypeMapping : ITypeMapping
/// <inheritdoc />
public IRoutingField RoutingField { get; set; }

/// <inheritdoc />
public IRuntimeFields RuntimeFields { get; set; }

/// <inheritdoc />
public ISizeField SizeField { get; set; }

Expand All @@ -171,6 +180,7 @@ public class TypeMappingDescriptor<T> : DescriptorBase<TypeMappingDescriptor<T>,
bool? ITypeMapping.NumericDetection { get; set; }
IProperties ITypeMapping.Properties { get; set; }
IRoutingField ITypeMapping.RoutingField { get; set; }
IRuntimeFields ITypeMapping.RuntimeFields { get; set; }
ISizeField ITypeMapping.SizeField { get; set; }
ISourceField ITypeMapping.SourceField { get; set; }

Expand Down Expand Up @@ -259,6 +269,10 @@ public TypeMappingDescriptor<T> DisableIndexField(bool? disabled = true) =>
public TypeMappingDescriptor<T> RoutingField(Func<RoutingFieldDescriptor<T>, IRoutingField> routingFieldSelector) =>
Assign(routingFieldSelector, (a, v) => a.RoutingField = v?.Invoke(new RoutingFieldDescriptor<T>()));

/// <inheritdoc cref="ITypeMapping.RuntimeFields" />
public TypeMappingDescriptor<T> RuntimeFields(Func<RuntimeFieldsDescriptor, IPromise<IRuntimeFields>> runtimeFieldsSelector) =>
Assign(runtimeFieldsSelector, (a, v) => a.RuntimeFields = v?.Invoke(new RuntimeFieldsDescriptor())?.Value);

/// <inheritdoc cref="ITypeMapping.FieldNamesField" />
public TypeMappingDescriptor<T> FieldNamesField(Func<FieldNamesFieldDescriptor<T>, IFieldNamesField> fieldNamesFieldSelector) =>
Assign(fieldNamesFieldSelector.Invoke(new FieldNamesFieldDescriptor<T>()), (a, v) => a.FieldNamesField = v);
Expand Down
3 changes: 3 additions & 0 deletions src/Nest/Search/Search/SearchRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ public partial interface ISearchRequest : ITypedSearchRequest
[DataMember(Name = "version")]
bool? Version { get; set; }

/// <summary>
/// The <see cref="PointInTime"/> to search over.
/// </summary>
[DataMember(Name = "pit")]
IPointInTime PointInTime { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,4 +338,61 @@ protected override LazyResponses ClientUsage() => Calls(
(client, r) => client.MapAsync(r)
);
}

[SkipVersion("<7.11.0", "Runtime fields introduced in 7.11.0")]
public class PutMappingWithRuntimeFieldsTests : ApiTestBase<ReadOnlyCluster, PutMappingResponse, IPutMappingRequest, PutMappingDescriptor<Project>, PutMappingRequest>
{
// These test serialisation only. Integration tests take place in RuntimeFieldsTests.cs

private const string ScriptValue = "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))";

public PutMappingWithRuntimeFieldsTests(ReadOnlyCluster cluster, EndpointUsage usage) : base(cluster, usage) { }

protected override HttpMethod HttpMethod => HttpMethod.PUT;

protected override string UrlPath => $"/{CallIsolatedValue}/_mapping";

protected override PutMappingRequest Initializer => new(CallIsolatedValue)
{
RuntimeFields = new RuntimeFields
{
{ "runtime_date", new RuntimeField { Type = FieldType.Date, Format = "yyyy-MM-dd" } },
{ "runtime_scripted", new RuntimeField { Type = FieldType.Keyword, Script = new PainlessScript(ScriptValue) } }
}
};

protected override Func<PutMappingDescriptor<Project>, IPutMappingRequest> Fluent => d => d
.Index(CallIsolatedValue)
.RuntimeFields(rtf => rtf
.RuntimeField("runtime_date", FieldType.Date, rf => rf.Format("yyyy-MM-dd"))
.RuntimeField("runtime_scripted", FieldType.Keyword, rf=> rf.Script(new PainlessScript(ScriptValue))));

protected override LazyResponses ClientUsage() => Calls(
(client, f) => client.Indices.PutMapping(f),
(client, f) => client.Indices.PutMappingAsync(f),
(client, r) => client.Indices.PutMapping(r),
(client, r) => client.Indices.PutMappingAsync(r)
);

protected override object ExpectJson => new
{
runtime = new
{
runtime_date = new
{
type = "date",
format = "yyyy-MM-dd"
},
runtime_scripted = new
{
type = "keyword",
script = new
{
lang = "painless",
source = ScriptValue
}
}
}
};
}
}
Loading

0 comments on commit f0b2e5d

Please sign in to comment.