Skip to content

Commit 031e811

Browse files
committed
Implement shape property type mapping.
1 parent 06517e3 commit 031e811

File tree

22 files changed

+359
-4
lines changed

22 files changed

+359
-4
lines changed

docs/client-concepts/high-level/mapping/auto-map.asciidoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ maps to `"geo_point"`
249249

250250
`Nest.IGeoShape`::
251251

252-
maps to `"geo_shape"`
252+
maps to `"geo_shape"` (if you want to map to a `"shape"` type use explicit mapping or the [Shape] attribute on the property)
253253

254254
`Nest.CompletionField`::
255255

src/CodeGeneration/ApiGenerator/Configuration/CodeConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace ApiGenerator.Configuration
88
{
99
public static class CodeConfiguration
1010
{
11-
/// <summary> These API"s are not implemented yet in the low and high level client</summary>
11+
/// <summary> These APIs are not implemented yet in the low and high level client</summary>
1212
public static string[] IgnoredApis { get; } =
1313
{
1414
// APIs is no longer useful and will be removed

src/Nest/CommonAbstractions/SerializationBehavior/JsonFormatters/NestFormatterResolver.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ internal sealed class InnerResolver : IJsonFormatterResolver
4646
new JsonNetCompatibleUriFormatter(),
4747
new GeoOrientationFormatter(),
4848
new NullableGeoOrientationFormatter(),
49+
new ShapeOrientationFormatter(),
50+
new NullableShapeOrientationFormatter(),
4951
}, new IJsonFormatterResolver[0]),
5052
BuiltinResolver.Instance, // Builtin primitives
5153
ElasticsearchNetEnumResolver.Instance, // Specialized Enum handling

src/Nest/Mapping/DynamicTemplate/SingleMapping.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ public IProperty GeoPoint(Func<GeoPointPropertyDescriptor<T>, IGeoPointProperty>
3636
public IProperty GeoShape(Func<GeoShapePropertyDescriptor<T>, IGeoShapeProperty> selector) =>
3737
selector?.Invoke(new GeoShapePropertyDescriptor<T>());
3838

39+
public IProperty Shape(Func<ShapePropertyDescriptor<T>, IShapeProperty> selector) =>
40+
selector?.Invoke(new ShapePropertyDescriptor<T>());
41+
3942
public IProperty IntegerRange(Func<IntegerRangePropertyDescriptor<T>, IIntegerRangeProperty> selector) =>
4043
selector?.Invoke(new IntegerRangePropertyDescriptor<T>());
4144

src/Nest/Mapping/Types/FieldType.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ public enum FieldType
135135
RankFeatures,
136136

137137
[EnumMember(Value = "flattened")]
138-
Flattened
138+
Flattened,
139+
140+
[EnumMember(Value = "shape")]
141+
Shape
139142
}
140143
}

src/Nest/Mapping/Types/Properties.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ TReturnType Nested<TChild>(Func<NestedPropertyDescriptor<T, TChild>, INestedProp
7676

7777
TReturnType GeoShape(Func<GeoShapePropertyDescriptor<T>, IGeoShapeProperty> selector);
7878

79+
TReturnType Shape(Func<ShapePropertyDescriptor<T>, IShapeProperty> selector);
80+
7981
TReturnType Completion(Func<CompletionPropertyDescriptor<T>, ICompletionProperty> selector);
8082

8183
TReturnType Murmur3Hash(Func<Murmur3HashPropertyDescriptor<T>, IMurmur3HashProperty> selector);
@@ -123,6 +125,8 @@ public PropertiesDescriptor() : base(new Properties<T>()) { }
123125

124126
public PropertiesDescriptor<T> GeoShape(Func<GeoShapePropertyDescriptor<T>, IGeoShapeProperty> selector) => SetProperty(selector);
125127

128+
public PropertiesDescriptor<T> Shape(Func<ShapePropertyDescriptor<T>, IShapeProperty> selector) => SetProperty(selector);
129+
126130
public PropertiesDescriptor<T> IntegerRange(Func<IntegerRangePropertyDescriptor<T>, IIntegerRangeProperty> selector) => SetProperty(selector);
127131

128132
public PropertiesDescriptor<T> Ip(Func<IpPropertyDescriptor<T>, IIpProperty> selector) => SetProperty(selector);

src/Nest/Mapping/Types/PropertyFormatter.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public IProperty Deserialize(ref JsonReader reader, IJsonFormatterResolver forma
7777
case FieldType.Ip: return Deserialize<IpProperty>(ref segmentReader, formatterResolver);
7878
case FieldType.GeoPoint: return Deserialize<GeoPointProperty>(ref segmentReader, formatterResolver);
7979
case FieldType.GeoShape: return Deserialize<GeoShapeProperty>(ref segmentReader, formatterResolver);
80+
case FieldType.Shape: return Deserialize<ShapeProperty>(ref segmentReader, formatterResolver);
8081
case FieldType.Completion: return Deserialize<CompletionProperty>(ref segmentReader, formatterResolver);
8182
case FieldType.TokenCount: return Deserialize<TokenCountProperty>(ref segmentReader, formatterResolver);
8283
case FieldType.Murmur3Hash: return Deserialize<Murmur3HashProperty>(ref segmentReader, formatterResolver);
@@ -156,6 +157,9 @@ public void Serialize(ref JsonWriter writer, IProperty value, IJsonFormatterReso
156157
case "geo_shape":
157158
Serialize<IGeoShapeProperty>(ref writer, value, formatterResolver);
158159
break;
160+
case "shape":
161+
Serialize<IShapeProperty>(ref writer, value, formatterResolver);
162+
break;
159163
case "completion":
160164
Serialize<ICompletionProperty>(ref writer, value, formatterResolver);
161165
break;
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
namespace Nest
2+
{
3+
/// <inheritdoc cref="IShapeProperty" />
4+
public class ShapeAttribute : ElasticsearchDocValuesPropertyAttributeBase, IShapeProperty
5+
{
6+
public ShapeAttribute() : base(FieldType.Shape) { }
7+
8+
bool? IShapeProperty.IgnoreMalformed { get; set; }
9+
bool? IShapeProperty.IgnoreZValue { get; set; }
10+
ShapeOrientation? IShapeProperty.Orientation { get; set; }
11+
private IShapeProperty Self => this;
12+
bool? IShapeProperty.Coerce { get; set; }
13+
14+
/// <inheritdoc cref="IShapeProperty.IgnoreMalformed" />
15+
public bool IgnoreMalformed
16+
{
17+
get => Self.IgnoreMalformed.GetValueOrDefault(false);
18+
set => Self.IgnoreMalformed = value;
19+
}
20+
21+
/// <inheritdoc cref="IShapeProperty.IgnoreZValue" />
22+
public bool IgnoreZValue
23+
{
24+
get => Self.IgnoreZValue.GetValueOrDefault(true);
25+
set => Self.IgnoreZValue = value;
26+
}
27+
28+
/// <inheritdoc cref="IShapeProperty.Orientation" />
29+
public ShapeOrientation Orientation
30+
{
31+
get => Self.Orientation.GetValueOrDefault(ShapeOrientation.CounterClockWise);
32+
set => Self.Orientation = value;
33+
}
34+
35+
/// <inheritdoc cref="IShapeProperty.Coerce" />
36+
public bool Coerce
37+
{
38+
get => Self.Coerce.GetValueOrDefault(true);
39+
set => Self.Coerce = value;
40+
}
41+
}
42+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
using Elasticsearch.Net.Utf8Json;
2+
3+
namespace Nest
4+
{
5+
public enum ShapeOrientation
6+
{
7+
ClockWise,
8+
CounterClockWise
9+
}
10+
11+
internal class ShapeOrientationFormatter : IJsonFormatter<ShapeOrientation>
12+
{
13+
public void Serialize(ref JsonWriter writer, ShapeOrientation value, IJsonFormatterResolver formatterResolver)
14+
{
15+
switch (value)
16+
{
17+
case ShapeOrientation.CounterClockWise:
18+
writer.WriteString("counterclockwise");
19+
break;
20+
case ShapeOrientation.ClockWise:
21+
writer.WriteString("clockwise");
22+
break;
23+
}
24+
}
25+
26+
public ShapeOrientation Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
27+
{
28+
if (reader.ReadIsNull())
29+
{
30+
// Default
31+
return ShapeOrientation.CounterClockWise;
32+
}
33+
34+
var enumString = reader.ReadString();
35+
switch (enumString.ToUpperInvariant())
36+
{
37+
case "CLOCKWISE":
38+
case "LEFT":
39+
case "CW":
40+
return ShapeOrientation.ClockWise;
41+
}
42+
43+
// Default
44+
return ShapeOrientation.CounterClockWise;
45+
}
46+
}
47+
48+
internal class NullableShapeOrientationFormatter : IJsonFormatter<ShapeOrientation?>
49+
{
50+
public void Serialize(ref JsonWriter writer, ShapeOrientation? value, IJsonFormatterResolver formatterResolver)
51+
{
52+
if (!value.HasValue)
53+
{
54+
writer.WriteNull();
55+
return;
56+
}
57+
58+
switch (value)
59+
{
60+
case ShapeOrientation.CounterClockWise:
61+
writer.WriteString("counterclockwise");
62+
break;
63+
case ShapeOrientation.ClockWise:
64+
writer.WriteString("clockwise");
65+
break;
66+
}
67+
}
68+
69+
public ShapeOrientation? Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
70+
{
71+
if (reader.ReadIsNull())
72+
{
73+
return null;
74+
}
75+
76+
var enumString = reader.ReadString();
77+
78+
switch (enumString.ToUpperInvariant())
79+
{
80+
case "COUNTERCLOCKWISE":
81+
case "RIGHT":
82+
case "CCW":
83+
return ShapeOrientation.CounterClockWise;
84+
case "CLOCKWISE":
85+
case "LEFT":
86+
case "CW":
87+
return ShapeOrientation.ClockWise;
88+
default:
89+
return null;
90+
}
91+
}
92+
}
93+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
using System.Diagnostics;
2+
using System.Runtime.Serialization;
3+
using Elasticsearch.Net.Utf8Json;
4+
5+
namespace Nest
6+
{
7+
/// <summary>
8+
/// Maps a property as a shape field
9+
/// </summary>
10+
[InterfaceDataContract]
11+
public interface IShapeProperty : IDocValuesProperty
12+
{
13+
/// <summary>
14+
/// If <c>true</c>, malformed geojson shapes are ignored. If false (default),
15+
/// malformed geojson shapes throw an exception and reject the whole document.
16+
/// </summary>
17+
[DataMember(Name ="ignore_malformed")]
18+
bool? IgnoreMalformed { get; set; }
19+
20+
/// <summary>
21+
/// If true (default) three dimension points will be accepted (stored in source) but
22+
/// only latitude and longitude values will be indexed; the third dimension is ignored. If false,
23+
/// geo-points containing any more than latitude and longitude (two dimensions) values throw
24+
/// an exception and reject the whole document.
25+
/// </summary>
26+
[DataMember(Name ="ignore_z_value")]
27+
bool? IgnoreZValue { get; set; }
28+
29+
/// <summary>
30+
/// Defines how to interpret vertex order for polygons and multipolygons.
31+
/// Defaults to <see cref="ShapeOrientation.CounterClockWise" />
32+
/// </summary>
33+
[DataMember(Name ="orientation")]
34+
ShapeOrientation? Orientation { get; set; }
35+
36+
/// <summary>
37+
/// Should the data be coerced into becoming a valid geo shape (for instance closing a polygon)
38+
/// </summary>
39+
[DataMember(Name ="coerce")]
40+
bool? Coerce { get; set; }
41+
}
42+
43+
/// <inheritdoc cref="IShapeProperty" />
44+
[DebuggerDisplay("{DebugDisplay}")]
45+
public class ShapeProperty : DocValuesPropertyBase, IShapeProperty
46+
{
47+
public ShapeProperty() : base(FieldType.Shape) { }
48+
49+
/// <inheritdoc />
50+
public bool? IgnoreMalformed { get; set; }
51+
52+
/// <inheritdoc />
53+
public bool? IgnoreZValue { get; set; }
54+
55+
/// <inheritdoc />
56+
public ShapeOrientation? Orientation { get; set; }
57+
58+
/// <inheritdoc />
59+
public bool? Coerce { get; set; }
60+
}
61+
62+
/// <inheritdoc cref="IShapeProperty" />
63+
[DebuggerDisplay("{DebugDisplay}")]
64+
public class ShapePropertyDescriptor<T>
65+
: DocValuesPropertyDescriptorBase<ShapePropertyDescriptor<T>, IShapeProperty, T>, IShapeProperty
66+
where T : class
67+
{
68+
public ShapePropertyDescriptor() : base(FieldType.Shape) { }
69+
70+
bool? IShapeProperty.IgnoreMalformed { get; set; }
71+
bool? IShapeProperty.IgnoreZValue { get; set; }
72+
ShapeOrientation? IShapeProperty.Orientation { get; set; }
73+
bool? IShapeProperty.Coerce { get; set; }
74+
75+
/// <inheritdoc cref="IShapeProperty.Orientation" />
76+
public ShapePropertyDescriptor<T> Orientation(ShapeOrientation? orientation) =>
77+
Assign(orientation, (a, v) => a.Orientation = v);
78+
79+
/// <inheritdoc cref="IShapeProperty.IgnoreMalformed" />
80+
public ShapePropertyDescriptor<T> IgnoreMalformed(bool? ignoreMalformed = true) =>
81+
Assign(ignoreMalformed, (a, v) => a.IgnoreMalformed = v);
82+
83+
/// <inheritdoc cref="IShapeProperty.IgnoreZValue" />
84+
public ShapePropertyDescriptor<T> IgnoreZValue(bool? ignoreZValue = true) =>
85+
Assign(ignoreZValue, (a, v) => a.IgnoreZValue = v);
86+
87+
/// <inheritdoc cref="IShapeProperty.Coerce" />
88+
public ShapePropertyDescriptor<T> Coerce(bool? coerce = true) =>
89+
Assign(coerce, (a, v) => a.Coerce = v);
90+
}
91+
}

src/Nest/Mapping/Visitor/IMappingVisitor.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ public interface IMappingVisitor
2828

2929
void Visit(IGeoShapeProperty property);
3030

31+
void Visit(IShapeProperty property);
32+
3133
void Visit(INumberProperty property);
3234

3335
void Visit(ICompletionProperty property);
@@ -91,6 +93,8 @@ public virtual void Visit(IGeoPointProperty property) { }
9193

9294
public virtual void Visit(IGeoShapeProperty property) { }
9395

96+
public virtual void Visit(IShapeProperty property) { }
97+
9498
public virtual void Visit(ICompletionProperty property) { }
9599

96100
public virtual void Visit(IMurmur3HashProperty property) { }

src/Nest/Mapping/Visitor/IPropertyVisitor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ public interface IPropertyVisitor
2626

2727
void Visit(IGeoShapeProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
2828

29+
void Visit(IShapeProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
30+
2931
void Visit(ICompletionProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
3032

3133
void Visit(IIpProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);

src/Nest/Mapping/Visitor/MappingWalker.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ public void Accept(IProperties properties)
154154
Accept(t.Fields);
155155
});
156156
break;
157+
case FieldType.Shape:
158+
Visit<IShapeProperty>(field, t =>
159+
{
160+
_visitor.Visit(t);
161+
Accept(t.Fields);
162+
});
163+
break;
157164
case FieldType.Completion:
158165
Visit<ICompletionProperty>(field, t =>
159166
{

src/Nest/Mapping/Visitor/NoopPropertyVisitor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ public virtual void Visit(IObjectProperty type, PropertyInfo propertyInfo, Elast
1414

1515
public virtual void Visit(IGeoShapeProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
1616

17+
public virtual void Visit(IShapeProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
18+
1719
public virtual void Visit(ICompletionProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
1820

1921
public virtual void Visit(IMurmur3HashProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
@@ -94,6 +96,9 @@ public void Visit(IProperty type, PropertyInfo propertyInfo, ElasticsearchProper
9496
case IGeoShapeProperty geoShapeType:
9597
Visit(geoShapeType, propertyInfo, attribute);
9698
break;
99+
case IShapeProperty shapeType:
100+
Visit(shapeType, propertyInfo, attribute);
101+
break;
97102
case IGeoPointProperty geoPointType:
98103
Visit(geoPointType, propertyInfo, attribute);
99104
break;

src/Nest/Search/FieldCapabilities/FieldCapabilitiesResponse.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public class FieldTypes : IsADictionaryBase<string, FieldCapabilities>
4242
public FieldCapabilities FloatRange => BackingDictionary.TryGetValue("float_range", out var f) ? f : null;
4343
public FieldCapabilities GeoPoint => BackingDictionary.TryGetValue("geo_point", out var f) ? f : null;
4444
public FieldCapabilities GeoShape => BackingDictionary.TryGetValue("geo_shape", out var f) ? f : null;
45+
public FieldCapabilities Shape => BackingDictionary.TryGetValue("shape", out var f) ? f : null;
4546
public FieldCapabilities HalfFloat => BackingDictionary.TryGetValue("half_float", out var f) ? f : null;
4647
public FieldCapabilities Id => BackingDictionary.TryGetValue("_id", out var f) ? f : null;
4748
public FieldCapabilities Index => BackingDictionary.TryGetValue("_index", out var f) ? f : null;

src/Tests/Tests.Core/ManagedElasticsearch/NodeSeeders/DefaultSeeder.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,9 @@ public static PropertiesDescriptor<TProject> ProjectProperties<TProject>(Propert
342342
.GeoShape(g => g
343343
.Name(p => p.LocationShape)
344344
)
345+
.Shape(g => g
346+
.Name(p => p.ArbitraryShape)
347+
)
345348
.Completion(cm => cm
346349
.Name(p => p.Suggest)
347350
.Contexts(cx => cx

0 commit comments

Comments
 (0)