From 409804ca5f70403b40b68ffd8e74d33c323344e4 Mon Sep 17 00:00:00 2001 From: Mpdreamz Date: Mon, 12 Sep 2016 11:52:27 +0200 Subject: [PATCH] Append #2231 Made field_masking_span a top level query As per elastic/elasticsearch#3007 this is now possible (before 1.x GA) Added additional serialization tests --- src/Nest/DSL/Query/QueryDescriptor.cs | 21 +++++ .../Query/SpanFieldMaskingQueryDescriptor.cs | 86 +++++++++---------- .../Nest.Tests.Unit/Nest.Tests.Unit.csproj | 1 + .../Queries/FieldMaskingSpanQueryTests.cs | 24 ++++++ 4 files changed, 89 insertions(+), 43 deletions(-) create mode 100644 src/Tests/Nest.Tests.Unit/QueryParsers/Queries/FieldMaskingSpanQueryTests.cs diff --git a/src/Nest/DSL/Query/QueryDescriptor.cs b/src/Nest/DSL/Query/QueryDescriptor.cs index 9e7094ebf5d..a192f12a83b 100644 --- a/src/Nest/DSL/Query/QueryDescriptor.cs +++ b/src/Nest/DSL/Query/QueryDescriptor.cs @@ -886,6 +886,27 @@ public QueryContainer SpanMultiTerm(Action> sele return this.New(span, q => q.SpanMultiTerm = span); } + /// + /// Wrapper to allow span queries participate in composite single-field span queries by + /// 'lying' about their search field. The span field masking query maps to Lucene `SpanFieldMaskingQuery` + /// + /// This can be used to support queries like `span-near` or `span-or` across different fields, which is not ordinarily permitted. + /// Span field masking query is invaluable in conjunction with *multi-fields* when same content is + /// indexed with multiple analyzers. For instance we could index a field with the standard analyzer + /// which breaks text up into words, and again with the english analyzer which stems words into their root + /// form. That will add more precision to queries. 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 SpanFieldMasking(Action> selector) + { + selector.ThrowIfNull("selector"); + var span = new SpanFieldMaskingQueryDescriptor(); + selector(span); + + return this.New(span, q => q.SpanFieldMasking= 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/SpanFieldMaskingQueryDescriptor.cs b/src/Nest/DSL/Query/SpanFieldMaskingQueryDescriptor.cs index f248b0545f8..9102406b323 100644 --- a/src/Nest/DSL/Query/SpanFieldMaskingQueryDescriptor.cs +++ b/src/Nest/DSL/Query/SpanFieldMaskingQueryDescriptor.cs @@ -10,16 +10,16 @@ namespace Nest [JsonObject(MemberSerialization = MemberSerialization.OptIn)] [JsonConverter(typeof(ReadAsTypeConverter>))] public interface ISpanFieldMaskingQuery : ISpanSubQuery, IFieldNameQuery - { - [JsonProperty(PropertyName = "field")] - PropertyPathMarker Field { get; set; } - - [JsonProperty(PropertyName = "query")] + { + [JsonProperty(PropertyName = "field")] + PropertyPathMarker Field { get; set; } + + [JsonProperty(PropertyName = "query")] ISpanQuery Query { get; set; } } public class SpanFieldMaskingQuery : PlainQuery, ISpanFieldMaskingQuery - { + { protected override void WrapInContainer(IQueryContainer container) { container.SpanFieldMasking = this; @@ -27,30 +27,30 @@ protected override void WrapInContainer(IQueryContainer container) bool IQuery.IsConditionless { get { return false; } } - public string Name { get; set; } - public PropertyPathMarker Field { get; set; } - public ISpanQuery Query { get; set; } + public string Name { get; set; } + public PropertyPathMarker Field { get; set; } + public ISpanQuery Query { get; set; } - PropertyPathMarker IFieldNameQuery.GetFieldName() - { - return this.Field; - } + PropertyPathMarker IFieldNameQuery.GetFieldName() + { + return this.Field; + } - void IFieldNameQuery.SetFieldName(string fieldName) - { - this.Field = fieldName; - } - } + void IFieldNameQuery.SetFieldName(string fieldName) + { + this.Field = fieldName; + } + } public class SpanFieldMaskingQueryDescriptor : ISpanFieldMaskingQuery where T : class { ISpanFieldMaskingQuery Self { get { return this; } } - bool IQuery.IsConditionless { get { return false; } } + bool IQuery.IsConditionless { get { return false; } } - ISpanQuery ISpanFieldMaskingQuery.Query { get; set; } - PropertyPathMarker ISpanFieldMaskingQuery.Field { get; set; } - string IQuery.Name { get; set; } - + ISpanQuery ISpanFieldMaskingQuery.Query { get; set; } + PropertyPathMarker ISpanFieldMaskingQuery.Field { get; set; } + string IQuery.Name { get; set; } + public SpanFieldMaskingQueryDescriptor Name(string name) { Self.Name = name; @@ -71,26 +71,26 @@ public SpanFieldMaskingQueryDescriptor OnField(string field) return this; } - public SpanFieldMaskingQueryDescriptor OnField(Expression> field) - { - Self.Field = field; - return this; - } + public SpanFieldMaskingQueryDescriptor OnField(Expression> field) + { + Self.Field = field; + return this; + } - public SpanFieldMaskingQueryDescriptor OnField(Expression> field) - { - Self.Field = field; - return this; - } - - public PropertyPathMarker GetFieldName() - { - return Self.Field; - } + public SpanFieldMaskingQueryDescriptor OnField(Expression> field) + { + Self.Field = field; + return this; + } + + public PropertyPathMarker GetFieldName() + { + return Self.Field; + } - public void SetFieldName(string fieldName) - { - Self.Field = fieldName; - } - } + public void SetFieldName(string fieldName) + { + Self.Field = fieldName; + } + } } diff --git a/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj b/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj index de104211273..f8337e5c3bc 100644 --- a/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj +++ b/src/Tests/Nest.Tests.Unit/Nest.Tests.Unit.csproj @@ -406,6 +406,7 @@ + diff --git a/src/Tests/Nest.Tests.Unit/QueryParsers/Queries/FieldMaskingSpanQueryTests.cs b/src/Tests/Nest.Tests.Unit/QueryParsers/Queries/FieldMaskingSpanQueryTests.cs new file mode 100644 index 00000000000..710bb3f1f47 --- /dev/null +++ b/src/Tests/Nest.Tests.Unit/QueryParsers/Queries/FieldMaskingSpanQueryTests.cs @@ -0,0 +1,24 @@ +using FluentAssertions; +using Nest.Tests.MockData.Domain; +using NUnit.Framework; + +namespace Nest.Tests.Unit.QueryParsers.Queries +{ + [TestFixture] + public class FieldMaskingSpanQueryTests : ParseQueryTestsBase + { + [Test] + public void FieldMaskingSpan_Deserializes() + { + var q = this.SerializeThenDeserialize( + f => f.SpanFieldMasking, + f => f.SpanFieldMasking(s => s.OnField(p => p.Name).Query(qq => qq.SpanTerm("x", "y"))) + ); + + + q.Field.Should().NotBeNull().And.Be("name"); + q.Query.Should().NotBeNull(); + q.Query.SpanTermQueryDescriptor.Should().NotBeNull(); + } + } +} \ No newline at end of file