Skip to content

Commit 9bc7470

Browse files
authored
Add per-field metadata (#4376)
Relates: #4341 This commit adds the ability to define per-field metadata in mappings, which will be returned via the Get Mapping API and Field Capabilities API.
1 parent fc2d172 commit 9bc7470

File tree

9 files changed

+96
-31
lines changed

9 files changed

+96
-31
lines changed

src/Nest/Mapping/AttributeBased/ElasticsearchPropertyAttributeBase.cs

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public abstract class ElasticsearchPropertyAttributeBase : Attribute, IProperty,
2323

2424
IDictionary<string, object> IProperty.LocalMetadata { get; set; }
2525

26+
IDictionary<string, string> IProperty.Meta { get; set; }
27+
2628
PropertyName IProperty.Name { get; set; }
2729
private IProperty Self => this;
2830
string IProperty.Type { get; set; }

src/Nest/Mapping/Types/PropertyBase.cs

+16-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ public interface IProperty : IFieldMapping
2020
[IgnoreDataMember]
2121
IDictionary<string, object> LocalMetadata { get; set; }
2222

23+
/// <summary>
24+
/// Metadata attached to the field. This metadata is stored in but opaque to Elasticsearch. It is
25+
/// only useful for multiple applications that work on the same indices to share
26+
/// meta information about fields such as units.
27+
///<para></para>
28+
/// Field metadata enforces at most 5 entries, that keys have a length that
29+
/// is less than or equal to 20, and that values are strings whose length is less
30+
/// than or equal to 50.
31+
/// </summary>
32+
[DataMember(Name = "meta")]
33+
IDictionary<string, string> Meta { get; set; }
34+
2335
/// <summary>
2436
/// The name of the property
2537
/// </summary>
@@ -53,11 +65,14 @@ public abstract class PropertyBase : IProperty, IPropertyWithClrOrigin
5365
/// <inheritdoc />
5466
public IDictionary<string, object> LocalMetadata { get; set; }
5567

68+
/// <inheritdoc />
69+
public IDictionary<string, string> Meta { get; set; }
70+
5671
/// <inheritdoc />
5772
public PropertyName Name { get; set; }
5873

5974
protected string DebugDisplay => $"Type: {((IProperty)this).Type ?? "<empty>"}, Name: {Name.DebugDisplay} ";
60-
75+
6176
public override string ToString() => DebugDisplay;
6277

6378
/// <summary>

src/Nest/Mapping/Types/PropertyDescriptorBase.cs

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ protected string TypeOverride
2525

2626
IDictionary<string, object> IProperty.LocalMetadata { get; set; }
2727
PropertyName IProperty.Name { get; set; }
28+
IDictionary<string, string> IProperty.Meta { get; set; }
2829

2930
string IProperty.Type
3031
{
@@ -41,5 +42,9 @@ string IProperty.Type
4142
/// <inheritdoc cref="IProperty.LocalMetadata" />
4243
public TDescriptor LocalMetadata(Func<FluentDictionary<string, object>, FluentDictionary<string, object>> selector) =>
4344
Assign(selector, (a, v) => a.LocalMetadata = v?.Invoke(new FluentDictionary<string, object>()));
45+
46+
/// <inheritdoc cref="IProperty.Meta" />
47+
public TDescriptor Meta(Func<FluentDictionary<string, string>, FluentDictionary<string, string>> selector) =>
48+
Assign(selector, (a, v) => a.Meta = v?.Invoke(new FluentDictionary<string, string>()));
4449
}
4550
}

src/Nest/Mapping/Types/PropertyFormatter.cs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Collections.Generic;
23
using Elasticsearch.Net.Utf8Json;
34
using Elasticsearch.Net.Utf8Json.Internal;
45
using Elasticsearch.Net.Utf8Json.Resolvers;

src/Nest/Search/FieldCapabilities/FieldCapabilitiesResponse.cs

+3
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,8 @@ public class FieldCapabilities
8888

8989
[DataMember(Name = "searchable")]
9090
public bool Searchable { get; internal set; }
91+
92+
[DataMember(Name = "meta")]
93+
public IReadOnlyDictionary<string, string[]> Meta { get; internal set; } = EmptyReadOnly<string, string[]>.Dictionary;
9194
}
9295
}

tests/Tests/ClientConcepts/HighLevel/Serialization/ExtendingNestTypes.doc.cs

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class ExtendingNestTypes
3535
public class MyPluginProperty : IProperty
3636
{
3737
IDictionary<string, object> IProperty.LocalMetadata { get; set; }
38+
IDictionary<string, string> IProperty.Meta { get; set; }
3839
public string Type { get; set; } = "my_plugin_property";
3940
public PropertyName Name { get; set; }
4041

tests/Tests/Mapping/LocalMetadata/LocalMetadataVisitorTests.cs

+6-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
using Nest;
55
using Tests.Mapping.Types.Core.Text;
66

7-
namespace Tests.Mapping.LocalMetadata {
7+
namespace Tests.Mapping.LocalMetadata
8+
{
89
public class LocalMetadataVisitorTests
910
{
1011
[U]
@@ -17,7 +18,7 @@ public void CanAssignAndAccessLocalMetadataInitializer()
1718
.AddTestLocalMetadata()
1819
)) as ITypeMapping;
1920

20-
var visitor = new LocalMatadataVisitor();
21+
var visitor = new LocalMetadataVisitor();
2122
var walker = new MappingWalker(visitor);
2223
walker.Accept(descriptor.Properties);
2324

@@ -36,7 +37,7 @@ public void CanAssignAndAccessLocalMetadataFluent()
3637
)
3738
)) as ITypeMapping;
3839

39-
var visitor = new LocalMatadataVisitor();
40+
var visitor = new LocalMetadataVisitor();
4041
var walker = new MappingWalker(visitor);
4142
walker.Accept(descriptor.Properties);
4243

@@ -63,7 +64,7 @@ public static TDescriptor AddTestLocalMetadata<TDescriptor>(this TDescriptor des
6364
}
6465
}
6566

66-
public class LocalMatadataVisitor : NoopMappingVisitor
67+
public class LocalMetadataVisitor : NoopMappingVisitor
6768
{
6869
public int MetadataCount { get; set; }
6970

@@ -77,4 +78,4 @@ public override void Visit(ITextProperty property)
7778
property.LocalMetadata.Should().Contain("Test", "TestValue");
7879
}
7980
}
80-
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using Elastic.Xunit.XunitPlumbing;
4+
using FluentAssertions;
5+
using Nest;
6+
using Tests.ClientConcepts.HighLevel.CovariantHits;
7+
using Tests.Core.Extensions;
8+
using Tests.Core.ManagedElasticsearch.Clusters;
9+
using Tests.Domain;
10+
using Tests.Framework.EndpointTests.TestState;
11+
using Tests.Mapping.Types;
12+
13+
namespace Tests.Mapping.Meta
14+
{
15+
[SkipVersion("<7.6.0", "Meta added in Elasticsearch 7.6.0")]
16+
public class MetaMappingApiTests
17+
: PropertyTestsBase
18+
{
19+
public MetaMappingApiTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }
20+
21+
protected override Func<PropertiesDescriptor<Project>, IPromise<IProperties>> FluentProperties => p => p
22+
.Number(n => n
23+
.Name(nn => nn.Rank)
24+
.Type(NumberType.Integer)
25+
.Meta(m => m
26+
.Add("unit", "popularity")
27+
)
28+
);
29+
protected override IProperties InitializerProperties => new Properties<Project>
30+
{
31+
{ n => n.Rank, new NumberProperty(NumberType.Integer)
32+
{
33+
Meta = new Dictionary<string, string>
34+
{
35+
{ "unit", "popularity" }
36+
}
37+
}
38+
}
39+
};
40+
41+
protected override void ExpectResponse(PutMappingResponse response)
42+
{
43+
base.ExpectResponse(response);
44+
45+
// check the meta shows up in get mapping API
46+
var getMappingResponse = Client.Indices.GetMapping<Project>(m => m.Index(CallIsolatedValue));
47+
getMappingResponse.IsValid.Should().BeTrue();
48+
var mappingMeta = getMappingResponse.Indices[CallIsolatedValue].Mappings.Properties["rank"].Meta;
49+
mappingMeta.Should().NotBeNull().And.ContainKey("unit");
50+
mappingMeta["unit"].Should().Be("popularity");
51+
52+
// check the meta shows up in field capabilities API
53+
var fieldCapsResponse = Client.FieldCapabilities(CallIsolatedValue, f => f
54+
.Fields<Project>(ff => ff.Rank)
55+
);
56+
fieldCapsResponse.IsValid.Should().BeTrue();
57+
var meta = fieldCapsResponse.Fields["rank"].Integer.Meta;
58+
meta.Should().NotBeNull().And.ContainKey("unit");
59+
meta["unit"].Should().BeEquivalentTo("popularity");
60+
}
61+
}
62+
}

tests/Tests/Mapping/Metafields/MetafieldsMappingApiTestsBase.cs

-25
This file was deleted.

0 commit comments

Comments
 (0)