diff --git a/src/Nest/DSL/Query/IQueryContainer.cs b/src/Nest/DSL/Query/IQueryContainer.cs index c2d1e0175d3..d5becbc8510 100644 --- a/src/Nest/DSL/Query/IQueryContainer.cs +++ b/src/Nest/DSL/Query/IQueryContainer.cs @@ -125,6 +125,9 @@ public interface IQueryContainer : ICustomJson [JsonProperty(PropertyName = "span_not")] ISpanNotQuery SpanNot { get; set; } + [JsonProperty(PropertyName = "span_multi")] + ISpanMultiTermQuery SpanMultiTerm { get; set; } + [JsonProperty(PropertyName = "top_children")] ITopChildrenQuery TopChildren { get; set; } diff --git a/src/Nest/DSL/Query/QueryContainer.cs b/src/Nest/DSL/Query/QueryContainer.cs index 2d0322ab7e0..df938fa5ff7 100644 --- a/src/Nest/DSL/Query/QueryContainer.cs +++ b/src/Nest/DSL/Query/QueryContainer.cs @@ -77,6 +77,8 @@ public class QueryContainer : IQueryContainer ISpanNearQuery IQueryContainer.SpanNear { get; set; } + ISpanMultiTermQuery IQueryContainer.SpanMultiTerm { get; set; } + ITopChildrenQuery IQueryContainer.TopChildren { get; set; } INestedQuery IQueryContainer.Nested { get; set; } diff --git a/src/Nest/DSL/Query/QueryDescriptor.cs b/src/Nest/DSL/Query/QueryDescriptor.cs index c695c7d4780..1b998f9ad37 100644 --- a/src/Nest/DSL/Query/QueryDescriptor.cs +++ b/src/Nest/DSL/Query/QueryDescriptor.cs @@ -819,6 +819,19 @@ public QueryContainer SpanNot(Action> selector) return this.New(span, q => q.SpanNot = span); } + /// + /// Wrap a multi term query (one of fuzzy, prefix, term range or regexp query) + /// as a span query so it can be nested. + /// + public QueryContainer SpanMultiTerm(Action> selector) + { + selector.ThrowIfNull("selector"); + var span = new SpanMultiTermQueryDescriptor(); + selector(span); + + return this.New(span, q => q.SpanMultiTerm = span); + } + /// /// custom_score query allows to wrap another query and customize the scoring of it optionally with a /// computation derived from other field values in the doc (numeric ones) using script or boost expression diff --git a/src/Nest/DSL/Query/SpanMultiTermQueryDescriptor.cs b/src/Nest/DSL/Query/SpanMultiTermQueryDescriptor.cs new file mode 100644 index 00000000000..36e09403487 --- /dev/null +++ b/src/Nest/DSL/Query/SpanMultiTermQueryDescriptor.cs @@ -0,0 +1,42 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Nest +{ + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + public interface ISpanMultiTermQuery : ISpanSubQuery + { + [JsonProperty("match")] + IQueryContainer Match { get; set; } + } + + public class SpanMultiTermQuery : PlainQuery, ISpanMultiTermQuery + { + protected override void WrapInContainer(IQueryContainer container) + { + container.SpanMultiTerm = this; + } + + public IQueryContainer Match { get; set; } + + public bool IsConditionless { get { return false; } } + } + + public class SpanMultiTermQueryDescriptor : ISpanMultiTermQuery + where T : class + { + IQueryContainer ISpanMultiTermQuery.Match { get; set; } + + bool IQuery.IsConditionless { get { return false; } } + + public SpanMultiTermQueryDescriptor Match(Func, QueryContainer> querySelector) + { + var q = new QueryDescriptor(); + ((ISpanMultiTermQuery)this).Match = querySelector(q); + return this; + } + } +} diff --git a/src/Nest/DSL/Query/SpanQueryDescriptor.cs b/src/Nest/DSL/Query/SpanQueryDescriptor.cs index 8478b4389f3..ada7b585722 100644 --- a/src/Nest/DSL/Query/SpanQueryDescriptor.cs +++ b/src/Nest/DSL/Query/SpanQueryDescriptor.cs @@ -25,6 +25,9 @@ public interface ISpanQuery : IQuery [JsonProperty(PropertyName = "span_not")] ISpanNotQuery SpanNot { get; set; } + + [JsonProperty(PropertyName = "span_multi")] + ISpanMultiTermQuery SpanMultiTerm { get; set; } } public class SpanQuery : ISpanQuery @@ -35,6 +38,7 @@ public class SpanQuery : ISpanQuery public ISpanNearQuery SpanNear { get; set; } public ISpanOrQuery SpanOr { get; set; } public ISpanNotQuery SpanNot { get; set; } + public ISpanMultiTermQuery SpanMultiTerm { get; set; } } public class SpanQuery : ISpanQuery where T : class @@ -49,6 +53,8 @@ public class SpanQuery : ISpanQuery where T : class ISpanNotQuery ISpanQuery.SpanNot { get; set; } + ISpanMultiTermQuery ISpanQuery.SpanMultiTerm { get; set; } + bool IQuery.IsConditionless { get @@ -59,7 +65,8 @@ bool IQuery.IsConditionless ((ISpanQuery)this).SpanFirst as IQuery, ((ISpanQuery)this).SpanNear as IQuery, ((ISpanQuery)this).SpanOr as IQuery, - ((ISpanQuery)this).SpanNot as IQuery + ((ISpanQuery)this).SpanNot as IQuery, + ((ISpanQuery)this).SpanMultiTerm as IQuery }; return queries.All(q => q == null || q.IsConditionless); } @@ -117,6 +124,12 @@ public SpanQuery SpanNot(Func, SpanNotQuery> selector) var q = selector(new SpanNotQuery()); return CreateQuery(q, (sq) => ((ISpanQuery)sq).SpanNot = q); } + public SpanQuery SpanMultiTerm(Func, SpanMultiTermQueryDescriptor> selector) + { + selector.ThrowIfNull("selector"); + var q= selector(new SpanMultiTermQueryDescriptor()); + return CreateQuery(q, (sq) => ((ISpanQuery)sq).SpanMultiTerm = q); + } private SpanQuery CreateQuery(K query, Action> setProperty) where K : ISpanSubQuery { diff --git a/src/Nest/Domain/DSL/Query.cs b/src/Nest/Domain/DSL/Query.cs index feb78209b6c..5f1c78f4273 100644 --- a/src/Nest/Domain/DSL/Query.cs +++ b/src/Nest/Domain/DSL/Query.cs @@ -205,6 +205,11 @@ public static QueryContainer SpanTerm(string field, string value, double? Boost return new QueryDescriptor().SpanTerm(field, value, Boost); } + public static QueryContainer SpanMultiTerm(Action> selector) + { + return new QueryDescriptor().SpanMultiTerm(selector); + } + public static QueryContainer Term(Expression> fieldDescriptor, K value, double? Boost = null) { return new QueryDescriptor().Term(fieldDescriptor, value, Boost); diff --git a/src/Nest/Nest.csproj b/src/Nest/Nest.csproj index 4d0b05434e0..72a96fe64b0 100644 --- a/src/Nest/Nest.csproj +++ b/src/Nest/Nest.csproj @@ -170,6 +170,7 @@ + diff --git a/src/Tests/Nest.Tests.Integration/Nest.Tests.Integration.csproj b/src/Tests/Nest.Tests.Integration/Nest.Tests.Integration.csproj index 4e6af051b22..d1a6b138da8 100644 --- a/src/Tests/Nest.Tests.Integration/Nest.Tests.Integration.csproj +++ b/src/Tests/Nest.Tests.Integration/Nest.Tests.Integration.csproj @@ -172,6 +172,7 @@ + diff --git a/src/Tests/Nest.Tests.Integration/Search/Query/SpanQueryTests.cs b/src/Tests/Nest.Tests.Integration/Search/Query/SpanQueryTests.cs new file mode 100644 index 00000000000..b41a96c0c27 --- /dev/null +++ b/src/Tests/Nest.Tests.Integration/Search/Query/SpanQueryTests.cs @@ -0,0 +1,34 @@ +using FluentAssertions; +using Nest.Tests.MockData.Domain; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Nest.Tests.Integration.Search.Query +{ + [TestFixture] + public class SpanQueryTests : IntegrationTests + { + [Test] + public void SpanMultiTermQuery() + { + var r = Client.Search(s => s + .Query(q => q + .SpanMultiTerm(sp => sp + .Match(m => m + .Prefix(p => p + .OnField(ep => ep.Name) + .Value("NEST") + ) + ) + ) + ) + ); + + r.IsValid.Should().BeTrue(); + } + } +} diff --git a/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj b/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj index 10c389f4067..b677075e882 100644 --- a/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj +++ b/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj @@ -398,6 +398,7 @@ + diff --git a/src/Tests/Nest.Tests.Unit/Search/Query/Singles/SpanMultiTermQueryJson.cs b/src/Tests/Nest.Tests.Unit/Search/Query/Singles/SpanMultiTermQueryJson.cs new file mode 100644 index 00000000000..d8ece7e4c72 --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/Search/Query/Singles/SpanMultiTermQueryJson.cs @@ -0,0 +1,42 @@ +using Nest.Tests.MockData.Domain; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Nest.Tests.Unit.Search.Query.Singles +{ + [TestFixture] + public class SpanMultiTermQueryJson : BaseJsonTests + { + [Test] + public void SpanMultiTermQuery() + { + var s = new SearchDescriptor() + .From(0) + .Size(10) + .Query(q => q + .SpanMultiTerm(sp => sp + .Match(m => m + .Prefix(p => p + .OnField(ep => ep.Name) + .Value("NEST") + ) + ) + ) + ); + var json = TestElasticClient.Serialize(s); + var expected = @"{ from: 0, size: 10, query : + { + span_multi:{ + match:{ + prefix : { name : { value : ""NEST"" } } + } + } + }}"; + Assert.True(json.JsonEquals(expected), json); + } + } +}