Skip to content

Commit b8c4e89

Browse files
Add support for wildcard property (#4890) (#4899)
Relates: elastic/elasticsearch#49993 Co-authored-by: Russ Cam <[email protected]>
1 parent b08a638 commit b8c4e89

File tree

8 files changed

+188
-1
lines changed

8 files changed

+188
-1
lines changed

src/Nest/Mapping/DynamicTemplate/SingleMapping.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ public IProperty SearchAsYouType(Func<SearchAsYouTypePropertyDescriptor<T>, ISea
141141
public IProperty ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector) =>
142142
selector?.Invoke(new ConstantKeywordPropertyDescriptor<T>());
143143

144+
/// <inheritdoc />
145+
public IProperty Wildcard(Func<WildcardPropertyDescriptor<T>, IWildcardProperty> selector) =>
146+
selector?.Invoke(new WildcardPropertyDescriptor<T>());
147+
144148
#pragma warning disable CS3001 // Argument type is not CLS-compliant
145149
public IProperty Scalar(Expression<Func<T, int>> field, Func<NumberPropertyDescriptor<T>, INumberProperty> selector = null) =>
146150
selector.InvokeOrDefault(new NumberPropertyDescriptor<T>().Name(field).Type(NumberType.Integer));

src/Nest/Mapping/Types/FieldType.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,9 @@ public enum FieldType
148148
Histogram,
149149

150150
[EnumMember(Value = "constant_keyword")]
151-
ConstantKeyword
151+
ConstantKeyword,
152+
153+
[EnumMember(Value = "wildcard")]
154+
Wildcard,
152155
}
153156
}

src/Nest/Mapping/Types/Properties.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ TReturnType Nested<TChild>(Func<NestedPropertyDescriptor<T, TChild>, INestedProp
145145

146146
/// <inheritdoc cref="IConstantKeywordProperty"/>
147147
TReturnType ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector);
148+
149+
/// <inheritdoc cref="IWildcardProperty"/>
150+
TReturnType Wildcard(Func<WildcardPropertyDescriptor<T>, IWildcardProperty> selector);
148151
}
149152

150153
public partial class PropertiesDescriptor<T> where T : class
@@ -229,6 +232,10 @@ public PropertiesDescriptor<T> Object<TChild>(Func<ObjectTypeDescriptor<T, TChil
229232
public PropertiesDescriptor<T> ConstantKeyword(Func<ConstantKeywordPropertyDescriptor<T>, IConstantKeywordProperty> selector) =>
230233
SetProperty(selector);
231234

235+
/// <inheritdoc cref="IWildcardProperty"/>
236+
public PropertiesDescriptor<T> Wildcard(Func<WildcardPropertyDescriptor<T>, IWildcardProperty> selector) =>
237+
SetProperty(selector);
238+
232239
public PropertiesDescriptor<T> Custom(IProperty customType) => SetProperty(customType);
233240

234241
private PropertiesDescriptor<T> SetProperty<TDescriptor, TInterface>(Func<TDescriptor, TInterface> selector)

src/Nest/Mapping/Types/PropertyFormatter.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ public IProperty Deserialize(ref JsonReader reader, IJsonFormatterResolver forma
9898
case FieldType.Flattened: return Deserialize<FlattenedProperty>(ref segmentReader, formatterResolver);
9999
case FieldType.Histogram: return Deserialize<HistogramProperty>(ref segmentReader, formatterResolver);
100100
case FieldType.ConstantKeyword: return Deserialize<ConstantKeywordProperty>(ref segmentReader, formatterResolver);
101+
case FieldType.Wildcard: return Deserialize<WildcardProperty>(ref segmentReader, formatterResolver);
101102
case FieldType.None:
102103
// no "type" field in the property mapping, or FieldType enum could not be parsed from typeString
103104
return Deserialize<ObjectProperty>(ref segmentReader, formatterResolver);
@@ -209,6 +210,9 @@ public void Serialize(ref JsonWriter writer, IProperty value, IJsonFormatterReso
209210
case IConstantKeywordProperty constantKeywordProperty:
210211
Serialize(ref writer, constantKeywordProperty, formatterResolver);
211212
break;
213+
case IWildcardProperty wildcardProperty:
214+
Serialize(ref writer, wildcardProperty, formatterResolver);
215+
break;
212216
case IGenericProperty genericProperty:
213217
Serialize(ref writer, genericProperty, formatterResolver);
214218
break;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
namespace Nest
6+
{
7+
/// <inheritdoc cref="IWildcardProperty"/>
8+
public class WildcardAttribute : ElasticsearchPropertyAttributeBase, IWildcardProperty
9+
{
10+
public WildcardAttribute() : base(FieldType.Wildcard) { }
11+
12+
int? IWildcardProperty.IgnoreAbove { get; set; }
13+
14+
private IWildcardProperty Self => this;
15+
16+
/// <inheritdoc cref="IWildcardProperty.IgnoreAbove" />
17+
public int IgnoreAbove
18+
{
19+
get => Self.IgnoreAbove.GetValueOrDefault(2147483647);
20+
set => Self.IgnoreAbove = value;
21+
}
22+
23+
/// <inheritdoc cref="IWildcardProperty.NullValue" />
24+
public string NullValue { get; set; }
25+
}
26+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System.Diagnostics;
6+
using System.Runtime.Serialization;
7+
using Elasticsearch.Net.Utf8Json;
8+
9+
namespace Nest
10+
{
11+
/// <summary>
12+
/// A wildcard field stores values optimised for wildcard grep-like queries.
13+
/// <para />
14+
/// Available in Elasticsearch 7.9.0+ with at least a basic license level
15+
/// </summary>
16+
[InterfaceDataContract]
17+
public interface IWildcardProperty : IProperty
18+
{
19+
/// <summary>
20+
/// Do not index any string longer than this value. Defaults to 2147483647 so that all values would be accepted.
21+
/// </summary>
22+
[DataMember(Name = "ignore_above")]
23+
int? IgnoreAbove { get; set; }
24+
25+
/// <summary>
26+
/// Accepts a string value which is substituted for any explicit null values. Defaults to null, which means the field is treated as missing.
27+
/// </summary>
28+
[DataMember(Name ="null_value")]
29+
string NullValue { get; set; }
30+
}
31+
32+
/// <inheritdoc cref="IWildcardProperty" />
33+
[DebuggerDisplay("{DebugDisplay}")]
34+
public class WildcardProperty : PropertyBase, IWildcardProperty
35+
{
36+
public WildcardProperty() : base(FieldType.Wildcard) { }
37+
38+
/// <inheritdoc cref="IWildcardProperty.IgnoreAbove" />
39+
public int? IgnoreAbove { get; set; }
40+
41+
/// <inheritdoc cref="IWildcardProperty.NullValue" />
42+
public string NullValue { get; set; }
43+
}
44+
45+
/// <inheritdoc cref="IWildcardProperty" />
46+
[DebuggerDisplay("{DebugDisplay}")]
47+
public class WildcardPropertyDescriptor<T>
48+
: PropertyDescriptorBase<WildcardPropertyDescriptor<T>, IWildcardProperty, T>, IWildcardProperty
49+
where T : class
50+
{
51+
public WildcardPropertyDescriptor() : base(FieldType.Wildcard) { }
52+
53+
int? IWildcardProperty.IgnoreAbove { get; set; }
54+
string IWildcardProperty.NullValue { get; set; }
55+
56+
/// <inheritdoc cref="IWildcardProperty.IgnoreAbove" />
57+
public WildcardPropertyDescriptor<T> IgnoreAbove(int? ignoreAbove) => Assign(ignoreAbove, (a, v) => a.IgnoreAbove = v);
58+
59+
/// <inheritdoc cref="IWildcardProperty.NullValue" />
60+
public WildcardPropertyDescriptor<T> NullValue(string nullValue) => Assign(nullValue, (a, v) => a.NullValue = v);
61+
}
62+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
6+
using Nest;
7+
8+
namespace Tests.Mapping.Types.Specialized.Wildcard
9+
{
10+
public class WildcardTest
11+
{
12+
[Wildcard(IgnoreAbove = 512, NullValue = "foo")]
13+
public string Full { get; set; }
14+
15+
[Wildcard]
16+
public string Simple { get; set; }
17+
}
18+
19+
[SkipVersion("<7.9.0", "introduced in 7.9.0")]
20+
public class WildcardAttributeTests : AttributeTestsBase<WildcardTest>
21+
{
22+
protected override object ExpectJson => new
23+
{
24+
properties = new
25+
{
26+
full = new
27+
{
28+
type = "wildcard",
29+
ignore_above = 512,
30+
null_value = "foo"
31+
},
32+
simple = new
33+
{
34+
type = "wildcard"
35+
}
36+
}
37+
};
38+
}
39+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using System;
6+
using Elastic.Elasticsearch.Xunit.XunitPlumbing;
7+
using Nest;
8+
using Tests.Core.ManagedElasticsearch.Clusters;
9+
using Tests.Domain;
10+
using Tests.Framework.EndpointTests.TestState;
11+
12+
namespace Tests.Mapping.Types.Specialized.Wildcard
13+
{
14+
[SkipVersion("<7.9.0", "introduced in 7.9.0")]
15+
public class WildcardPropertyTests : PropertyTestsBase
16+
{
17+
public WildcardPropertyTests(WritableCluster cluster, EndpointUsage usage) : base(cluster, usage) { }
18+
19+
protected override object ExpectJson => new
20+
{
21+
properties = new
22+
{
23+
description = new
24+
{
25+
type = "wildcard"
26+
}
27+
}
28+
};
29+
30+
protected override Func<PropertiesDescriptor<Project>, IPromise<IProperties>> FluentProperties => f => f
31+
.Wildcard(s => s
32+
.Name(n => n.Description)
33+
);
34+
35+
protected override IProperties InitializerProperties => new Properties
36+
{
37+
{
38+
"description", new WildcardProperty()
39+
}
40+
};
41+
}
42+
}

0 commit comments

Comments
 (0)