diff --git a/src/Nest/DSL/Search/SortFieldDescriptor.cs b/src/Nest/DSL/Search/SortFieldDescriptor.cs index 50344302967..681b5cdbcfe 100644 --- a/src/Nest/DSL/Search/SortFieldDescriptor.cs +++ b/src/Nest/DSL/Search/SortFieldDescriptor.cs @@ -18,24 +18,36 @@ public enum SortOrder Descending } + [JsonConverter(typeof(StringEnumConverter))] + public enum SortMode + { + [EnumMember(Value = "min")] + Min, + [EnumMember(Value = "max")] + Max, + [EnumMember(Value = "sum")] + Sum, + [EnumMember(Value = "avg")] + Average + } + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] public interface ISort { - [JsonProperty("missing")] string Missing { get; set; } [JsonProperty("order")] SortOrder? Order { get; set; } + + [JsonProperty("mode")] + SortMode? Mode { get; set; } } public interface IFieldSort : ISort { PropertyPathMarker Field { get; set; } - [JsonProperty("mode")] - ScoreMode? Mode { get; set; } - [JsonProperty("nested_filter")] FilterContainer NestedFilter { get; set; } @@ -51,7 +63,7 @@ public class Sort : IFieldSort public PropertyPathMarker Field { get; set; } public string Missing { get; set; } public SortOrder? Order { get; set; } - public ScoreMode? Mode { get; set; } + public SortMode? Mode { get; set; } public FilterContainer NestedFilter { get; set; } public PropertyPathMarker NestedPath { get; set; } public bool? IgnoreUnmappedFields { get; set; } @@ -67,7 +79,7 @@ public class SortFieldDescriptor : IFieldSort where T : class SortOrder? ISort.Order { get; set; } - ScoreMode? IFieldSort.Mode { get; set; } + SortMode? ISort.Mode { get; set; } FilterContainer IFieldSort.NestedFilter { get; set; } @@ -129,27 +141,33 @@ public virtual SortFieldDescriptor Order(SortOrder order) return this; } + public virtual SortFieldDescriptor Mode(SortMode mode) + { + Self.Mode = mode; + return this; + } + public virtual SortFieldDescriptor NestedMin() { - Self.Mode = ScoreMode.Min; + Self.Mode = SortMode.Min; return this; } public virtual SortFieldDescriptor NestedMax() { - Self.Mode = ScoreMode.Max; + Self.Mode = SortMode.Max; return this; } public virtual SortFieldDescriptor NestedSum() { - Self.Mode = ScoreMode.Sum; + Self.Mode = SortMode.Sum; return this; } public virtual SortFieldDescriptor NestedAvg() { - Self.Mode = ScoreMode.Average; + Self.Mode = SortMode.Average; return this; } diff --git a/src/Nest/DSL/Search/SortGeoDistanceDescriptor.cs b/src/Nest/DSL/Search/SortGeoDistanceDescriptor.cs index 52bc93c9923..0b5925a4c45 100644 --- a/src/Nest/DSL/Search/SortGeoDistanceDescriptor.cs +++ b/src/Nest/DSL/Search/SortGeoDistanceDescriptor.cs @@ -20,6 +20,7 @@ public class GeoDistanceSort : IGeoDistanceSort { public string Missing { get; set; } public SortOrder? Order { get; set; } + public SortMode? Mode { get; set; } public PropertyPathMarker Field { get; set; } public string PinLocation { get; set; } public GeoUnit? GeoUnit { get; set; } @@ -30,6 +31,7 @@ object ICustomJson.GetCustomJson() { { this.Field, this.PinLocation }, { "missing", this.Missing }, + { "mode", this.Mode }, { "order", this.Order }, { "unit", this.GeoUnit } }; @@ -46,6 +48,8 @@ public class SortGeoDistanceDescriptor : IGeoDistanceSort where T : class SortOrder? ISort.Order { get; set; } + SortMode? ISort.Mode { get; set; } + string IGeoDistanceSort.PinLocation { get; set; } GeoUnit? IGeoDistanceSort.GeoUnit { get; set; } @@ -114,12 +118,19 @@ public SortGeoDistanceDescriptor Order(SortOrder order) return this; } + public SortGeoDistanceDescriptor Mode(SortMode mode) + { + Self.Mode = mode; + return this; + } + object ICustomJson.GetCustomJson() { return new Dictionary { { Self.Field, Self.PinLocation }, { "missing", Self.Missing }, + { "mode", Self.Mode}, { "order", Self.Order }, { "unit", Self.GeoUnit } }; diff --git a/src/Nest/DSL/Search/SortScriptDescriptor.cs b/src/Nest/DSL/Search/SortScriptDescriptor.cs index 5fbb542ef17..844c94274fb 100644 --- a/src/Nest/DSL/Search/SortScriptDescriptor.cs +++ b/src/Nest/DSL/Search/SortScriptDescriptor.cs @@ -22,6 +22,7 @@ public class ScriptSort : IScriptSort { public string Missing { get; set; } public SortOrder? Order { get; set; } + public SortMode? Mode { get; set; } public string Type { get; set; } public string Script { get; set; } public Dictionary Params { get; set; } @@ -35,6 +36,8 @@ public class SortScriptDescriptor : IScriptSort SortOrder? ISort.Order { get; set; } + SortMode? ISort.Mode { get; set; } + string IScriptSort.Type { get; set; } string IScriptSort.Script { get; set; } @@ -97,5 +100,11 @@ public SortScriptDescriptor Order(SortOrder order) Self.Order = order; return this; } + + public SortScriptDescriptor Mode(SortMode mode) + { + Self.Mode = mode; + return this; + } } } diff --git a/src/Nest/DSL/SearchDescriptor.cs b/src/Nest/DSL/SearchDescriptor.cs index 444a24fa7e2..eea7d97b908 100644 --- a/src/Nest/DSL/SearchDescriptor.cs +++ b/src/Nest/DSL/SearchDescriptor.cs @@ -41,8 +41,8 @@ public interface ISearchRequest : IQueryPath IDictionary IndicesBoost { get; set; } [JsonProperty(PropertyName = "sort")] - [JsonConverter(typeof (DictionaryKeysAreNotPropertyNamesJsonConverter))] - IDictionary Sort { get; set; } + [JsonConverter(typeof(SortCollectionConverter))] + IList> Sort { get; set; } [JsonProperty(PropertyName = "facets")] [JsonConverter(typeof (DictionaryKeysAreNotPropertyNamesJsonConverter))] @@ -140,7 +140,7 @@ public partial class SearchRequest : QueryPathBase, ISe public IList Fields { get; set; } public IDictionary ScriptFields { get; set; } public ISourceFilter Source { get; set; } - public IDictionary Sort { get; set; } + public IList> Sort { get; set; } public IDictionary IndicesBoost { get; set; } public IFilterContainer Filter { get; set; } public IQueryContainer Query { get; set; } @@ -200,7 +200,7 @@ protected override void UpdatePathInfo(IConnectionSettingsValues settings, Elast public bool? TrackScores { get; set; } public double? MinScore { get; set; } public IDictionary IndicesBoost { get; set; } - public IDictionary Sort { get; set; } + public IList> Sort { get; set; } public IDictionary Facets { get; set; } public IDictionary Suggest { get; set; } public IHighlightRequest Highlight { get; set; } @@ -290,7 +290,7 @@ string ISearchRequest.Routing IDictionary ISearchRequest.IndicesBoost { get; set; } - IDictionary ISearchRequest.Sort { get; set; } + IList> ISearchRequest.Sort { get; set; } IDictionary ISearchRequest.Facets { get; set; } @@ -568,9 +568,9 @@ public SearchDescriptor ScriptFields( /// public SearchDescriptor SortAscending(Expression> objectPath) { - if (Self.Sort == null) Self.Sort = new Dictionary(); + if (Self.Sort == null) Self.Sort = new List>(); - Self.Sort.Add(objectPath, new Sort() { Order = SortOrder.Ascending}); + Self.Sort.Add(new KeyValuePair(objectPath, new Sort() { Order = SortOrder.Ascending})); return this; } @@ -584,9 +584,9 @@ public SearchDescriptor SortAscending(Expression> objectPath) /// public SearchDescriptor SortDescending(Expression> objectPath) { - if (Self.Sort == null) Self.Sort = new Dictionary(); + if (Self.Sort == null) Self.Sort = new List>(); - Self.Sort.Add(objectPath, new Sort() { Order = SortOrder.Descending}); + Self.Sort.Add(new KeyValuePair(objectPath, new Sort() { Order = SortOrder.Descending })); return this; } @@ -600,8 +600,8 @@ public SearchDescriptor SortDescending(Expression> objectPath /// public SearchDescriptor SortAscending(string field) { - if (Self.Sort == null) Self.Sort = new Dictionary(); - Self.Sort.Add(field, new Sort() { Order = SortOrder.Ascending }); + if (Self.Sort == null) Self.Sort = new List>(); + Self.Sort.Add(new KeyValuePair(field, new Sort() { Order = SortOrder.Ascending })); return this; } @@ -616,9 +616,9 @@ public SearchDescriptor SortAscending(string field) public SearchDescriptor SortDescending(string field) { if (Self.Sort == null) - Self.Sort = new Dictionary(); + Self.Sort = new List>(); - Self.Sort.Add(field, new Sort() { Order = SortOrder.Descending}); + Self.Sort.Add(new KeyValuePair(field, new Sort() { Order = SortOrder.Descending})); return this; } @@ -629,11 +629,11 @@ public SearchDescriptor SortDescending(string field) public SearchDescriptor Sort(Func, IFieldSort> sortSelector) { if (Self.Sort == null) - Self.Sort = new Dictionary(); + Self.Sort = new List>(); sortSelector.ThrowIfNull("sortSelector"); var descriptor = sortSelector(new SortFieldDescriptor()); - Self.Sort.Add(descriptor.Field, descriptor); + Self.Sort.Add(new KeyValuePair(descriptor.Field, descriptor)); return this; } @@ -644,11 +644,11 @@ public SearchDescriptor Sort(Func, IFieldSort> sortSel public SearchDescriptor SortGeoDistance(Func, IGeoDistanceSort> sortSelector) { if (Self.Sort == null) - Self.Sort = new Dictionary(); + Self.Sort = new List>(); sortSelector.ThrowIfNull("sortSelector"); var descriptor = sortSelector(new SortGeoDistanceDescriptor()); - Self.Sort.Add("_geo_distance", descriptor); + Self.Sort.Add(new KeyValuePair("_geo_distance", descriptor)); return this; } @@ -659,11 +659,11 @@ public SearchDescriptor SortGeoDistance(Func, IG public SearchDescriptor SortScript(Func, IScriptSort> sortSelector) { if (Self.Sort == null) - Self.Sort = new Dictionary(); + Self.Sort = new List>(); sortSelector.ThrowIfNull("sortSelector"); var descriptor = sortSelector(new SortScriptDescriptor()); - Self.Sort.Add("_script", descriptor); + Self.Sort.Add(new KeyValuePair("_script", descriptor)); return this; } diff --git a/src/Nest/Nest.csproj b/src/Nest/Nest.csproj index e82eee995ee..0d83b2b4b1f 100644 --- a/src/Nest/Nest.csproj +++ b/src/Nest/Nest.csproj @@ -791,6 +791,7 @@ + diff --git a/src/Nest/Resolvers/Converters/SortCollectionConverter.cs b/src/Nest/Resolvers/Converters/SortCollectionConverter.cs new file mode 100644 index 00000000000..38e1c2ee655 --- /dev/null +++ b/src/Nest/Resolvers/Converters/SortCollectionConverter.cs @@ -0,0 +1,42 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Nest.Resolvers.Converters +{ + public class SortCollectionConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return typeof(IList>).IsAssignableFrom(objectType); + } + + public override bool CanRead + { + get { return false; } + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return new InvalidOperationException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteStartArray(); + var sortItems = value as IList>; + foreach (var item in sortItems) + { + writer.WriteStartObject(); + var contract = serializer.ContractResolver as SettingsContractResolver; + var fieldName = contract.Infer.PropertyPath(item.Key); + writer.WritePropertyName(fieldName); + serializer.Serialize(writer, item.Value); + writer.WriteEndObject(); + } + writer.WriteEndArray(); + } + } +} diff --git a/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisBody.json b/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisBody.json index 40f8fe914a4..8fe71de521c 100644 --- a/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisBody.json +++ b/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisBody.json @@ -1,14 +1,16 @@ - { +{ "from": 0, "size": 20, "explain": true, "track_scores": true, - "sort": { - "field": { - "missing": "_first", - "order": "asc" + "sort": [ + { + "field": { + "missing": "_first", + "order": "asc" + } } - }, + ], "filter": { "bool": { "must": [ diff --git a/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisRequestTests.cs b/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisRequestTests.cs index c6c8b9568f9..71bf415c2ad 100644 --- a/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisRequestTests.cs +++ b/src/Tests/Nest.Tests.Unit/ObjectInitializer/MoreLikeThis/MoreLikeThisRequestTests.cs @@ -42,9 +42,9 @@ public MoreLikeThisRequestTests() }), TrackScores = true, Explain = true, - Sort = new Dictionary() + Sort = new List>() { - { "field", new Sort { Order = SortOrder.Ascending, Missing = "_first"}} + new KeyValuePair("field", new Sort { Order = SortOrder.Ascending, Missing = "_first"}) } }; var request = new MoreLikeThisRequest("some-index", "the-type","document-id-21") diff --git a/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchBody.json b/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchBody.json index 150b847da0d..0d7f55cd18c 100644 --- a/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchBody.json +++ b/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchBody.json @@ -1,4 +1,4 @@ - { +{ "from": 0, "size": 20, "explain": true, @@ -7,12 +7,14 @@ "indices_boost": { "nest_test_data": 2.3 }, - "sort": { - "field": { - "missing": "_first", - "order": "asc" + "sort": [ + { + "field": { + "missing": "_first", + "order": "asc" + } } - }, + ], "facets": { "name": { "terms": { diff --git a/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchRequestTests.cs b/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchRequestTests.cs index 388abcaf682..6bfede02032 100644 --- a/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchRequestTests.cs +++ b/src/Tests/Nest.Tests.Unit/ObjectInitializer/Search/SearchRequestTests.cs @@ -39,9 +39,9 @@ public SearchRequestTests() { { Infer.Index(), 2.3 } }, - Sort = new Dictionary() + Sort = new List>() { - { "field", new Sort { Order = SortOrder.Ascending, Missing = "_first"}} + new KeyValuePair("field", new Sort { Order = SortOrder.Ascending, Missing = "_first"}) }, Facets = new Dictionary() { diff --git a/src/Tests/Nest.Tests.Unit/Search/InitializerSyntax/InitializerExample.cs b/src/Tests/Nest.Tests.Unit/Search/InitializerSyntax/InitializerExample.cs index a5b6d89622f..8f3c8db66ed 100644 --- a/src/Tests/Nest.Tests.Unit/Search/InitializerSyntax/InitializerExample.cs +++ b/src/Tests/Nest.Tests.Unit/Search/InitializerSyntax/InitializerExample.cs @@ -69,9 +69,9 @@ public void FullExample_InitializerSyntax_Search() {"multiplier", 4} } }), - Sort = new Dictionary() + Sort = new List>() { - { "field", new Sort { Order = SortOrder.Ascending, Missing = "_first"}} + new KeyValuePair("field", new Sort { Order = SortOrder.Ascending, Missing = "_first"}) }, Source = new SourceFilter { diff --git a/src/Tests/Nest.Tests.Unit/Search/SearchOptions/SearchOptionTests.cs b/src/Tests/Nest.Tests.Unit/Search/SearchOptions/SearchOptionTests.cs index 54a65134f66..b123991d6f3 100644 --- a/src/Tests/Nest.Tests.Unit/Search/SearchOptions/SearchOptionTests.cs +++ b/src/Tests/Nest.Tests.Unit/Search/SearchOptions/SearchOptionTests.cs @@ -218,9 +218,9 @@ public void TestSort() .SortAscending(e => e.LOC.Suffix("sort")); var json = TestElasticClient.Serialize(s); var expected = @"{ from: 0, size: 10, - sort: { - ""loc.sort"": { order: ""asc"" } - }, + sort: [ + {""loc.sort"": { order: ""asc"" }} + ], fields: [""id"", ""name""] }"; Assert.True(json.JsonEquals(expected), json); @@ -236,10 +236,10 @@ public void TestSortDescending() .SortDescending(e => e.Name.Suffix("sort")); var json = TestElasticClient.Serialize(s); var expected = @"{ from: 0, size: 10, - sort: { - ""loc.sort"": { order: ""asc"" }, - ""name.sort"": { order: ""desc"" } - }, + sort: [ + {""loc.sort"": { order: ""asc"" }}, + {""name.sort"": { order: ""desc"" }} + ], fields: [""id"", ""name""] }"; Assert.True(json.JsonEquals(expected), json); diff --git a/src/Tests/Nest.Tests.Unit/Search/Sorting/RandomScriptSort.json b/src/Tests/Nest.Tests.Unit/Search/Sorting/RandomScriptSort.json index 1a9de1a8038..88569afcc7e 100644 --- a/src/Tests/Nest.Tests.Unit/Search/Sorting/RandomScriptSort.json +++ b/src/Tests/Nest.Tests.Unit/Search/Sorting/RandomScriptSort.json @@ -1,14 +1,16 @@ - { +{ "from": 0, "size": 10, - "sort": { - "_script": { - "type": "number", - "script": "(doc['_id'].stringValue + salt).hashCode()", - "params": { - "salt": "some_random_string" - }, - "order": "asc" + "sort": [ + { + "_script": { + "type": "number", + "script": "(doc['_id'].stringValue + salt).hashCode()", + "params": { + "salt": "some_random_string" + }, + "order": "asc" + } } - } -} \ No newline at end of file + ] +} diff --git a/src/Tests/Nest.Tests.Unit/Search/Sorting/SortTests.cs b/src/Tests/Nest.Tests.Unit/Search/Sorting/SortTests.cs index b2a22b34244..94e8051c168 100644 --- a/src/Tests/Nest.Tests.Unit/Search/Sorting/SortTests.cs +++ b/src/Tests/Nest.Tests.Unit/Search/Sorting/SortTests.cs @@ -24,13 +24,15 @@ public void TestSort() { from: 0, size: 10, - sort: { - country: { - ignore_unmapped: true, - missing: ""_last"", - order: ""desc"" + sort: [ + { + country: { + ignore_unmapped: true, + missing: ""_last"", + order: ""desc"" + } } - } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -45,18 +47,22 @@ public void TestSortOnSortField() .OnField(e => e.Name.Suffix("sort")) .MissingLast() .Descending() + .Mode(SortMode.Min) ); var json = TestElasticClient.Serialize(s); var expected = @" { from: 0, size: 10, - sort: { - ""name.sort"": { - missing: ""_last"", - order: ""desc"" - } - } + sort: [ + { + ""name.sort"": { + missing: ""_last"", + order: ""desc"", + mode: ""min"" + } + } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -77,12 +83,14 @@ public void TestSortOnNestedField() { from: 0, size: 10, - sort: { - ""contributors.age"": { - ""mode"": ""max"", - ""order"": ""desc"" - } - } + sort: [ + { + ""contributors.age"": { + ""order"": ""desc"", + ""mode"": ""max"" + } + } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -99,9 +107,9 @@ public void TestSortAscending() { from: 0, size: 10, - sort: { - country : { order: ""asc"" } - } + sort: [ + { country : { order: ""asc"" } } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -118,9 +126,9 @@ public void TestSortDescending() { from: 0, size: 10, - sort: { - country : { order: ""desc"" } - } + sort: [ + { country : { order: ""desc"" } } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -137,9 +145,9 @@ public void TestSortAscendingOnSortField() { from: 0, size: 10, - sort: { - ""name.sort"" : { order: ""asc"" } - } + sort: [ + {""name.sort"" : { order: ""asc"" } } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -156,9 +164,9 @@ public void TestSortDescendingOnSortField() { from: 0, size: 10, - sort: { - ""name.sort"" : { order: ""desc"" } - } + sort: [ + { ""name.sort"" : { order: ""desc"" } } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -175,20 +183,24 @@ public void TestSortGeo() .Descending() .PinTo(40, -70) .Unit(GeoUnit.Kilometers) + .Mode(SortMode.Max) ); var json = TestElasticClient.Serialize(s); var expected = @" { from: 0, size: 10, - sort: { - _geo_distance: { - ""origin"": ""40, -70"", - missing: ""_last"", - order: ""desc"", - unit: ""km"" - } - } + sort: [ + { + _geo_distance: { + ""origin"": ""40, -70"", + missing: ""_last"", + mode: ""max"", + order: ""desc"", + unit: ""km"" + } + } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -202,6 +214,7 @@ public void TestSortScript() .SortScript(sort => sort .MissingLast() .Descending() + .Mode(SortMode.Average) .Script("doc['field_name'].value * factor") .Params(p => p .Add("factor", 1.1) @@ -213,17 +226,20 @@ public void TestSortScript() { from: 0, size: 10, - sort: { - _script: { - type: ""number"", - script: ""doc['field_name'].value * factor"", - params: { - factor: 1.1 - }, - missing: ""_last"", - order: ""desc"" - } - } + sort: [ + { + _script: { + type: ""number"", + script: ""doc['field_name'].value * factor"", + params: { + factor: 1.1 + }, + missing: ""_last"", + order: ""desc"", + mode: ""avg"" + } + } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -239,16 +255,18 @@ public void TestNestedFilter() var json = TestElasticClient.Serialize(s); var expected = @" { - ""sort"": { - ""id"": { + ""sort"": [ + { + ""id"": { ""nested_filter"": { ""term"": { ""name"": ""value"" + } } } - } - } - }"; + } + ] + }"; Assert.True(json.JsonEquals(expected), json); } @@ -263,11 +281,13 @@ public void TestNestedPath() var json = TestElasticClient.Serialize(s); var expected = @" { - ""sort"": { - ""id"": { - ""nested_path"": ""name"" - } - } + ""sort"": [ + { + ""id"": { + ""nested_path"": ""name"" + } + } + ] }"; Assert.True(json.JsonEquals(expected), json); } @@ -283,11 +303,13 @@ public void TestNestedPathObject() var json = TestElasticClient.Serialize(s); var expected = @" { - ""sort"": { - ""id"": { - ""nested_path"": ""name"" - } - } + ""sort"": [ + { + ""id"": { + ""nested_path"": ""name"" + } + } + ] }"; Assert.True(json.JsonEquals(expected), json); }