Skip to content

Fix #3327 Add span_gap query for use with span_near query #3361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist

protected TReadAs ReadAs(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{

return this.Reader.ReadJson(reader, objectType, existingValue, serializer) as TReadAs;
}

Expand Down
79 changes: 79 additions & 0 deletions src/Nest/QueryDsl/Span/Gap/SpanGapQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System;
using System.Linq.Expressions;
using Newtonsoft.Json;

namespace Nest
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
[JsonConverter(typeof(SpanGapQueryJsonConverter))]
public interface ISpanGapQuery : ISpanSubQuery
{
Field Field { get; set; }
int? Width { get; set; }
}

public class SpanGapQuery : QueryBase, ISpanGapQuery
{
protected override bool Conditionless => SpanGapQuery.IsConditionless(this);

internal static bool IsConditionless(ISpanGapQuery q) => q?.Width == null || q.Field.IsConditionless();

public Field Field { get; set; }
public int? Width { get; set; }

internal override void InternalWrapInContainer(IQueryContainer c) =>
throw new Exception("span_gap may only appear as a span near clause");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class SpanGapQueryDescriptor<T> : QueryDescriptorBase<SpanGapQueryDescriptor<T>, ISpanGapQuery>, ISpanGapQuery
where T : class
{
protected override bool Conditionless => SpanGapQuery.IsConditionless(this);

Field ISpanGapQuery.Field { get; set; }

int? ISpanGapQuery.Width { get; set; }

public SpanGapQueryDescriptor<T> Field(Field field) => Assign(a => a.Field = field);

public SpanGapQueryDescriptor<T> Field(Expression<Func<T, object>> objectPath) => Assign(a => a.Field = objectPath);

public SpanGapQueryDescriptor<T> Width(int? width) => Assign(a => a.Width = width);
}

internal class SpanGapQueryJsonConverter : JsonConverter
{
public override bool CanRead => true;
public override bool CanWrite => true;
public override bool CanConvert(Type objectType) => typeof(ISpanGapQuery).IsAssignableFrom(objectType);

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var gapQuery = value as ISpanGapQuery;
if (value == null || SpanGapQuery.IsConditionless(gapQuery))
{
writer.WriteNull();
return;
}
var settings = serializer.GetConnectionSettings();
var fieldName = settings.Inferrer.Field(gapQuery.Field);
writer.WriteStartObject();
writer.WritePropertyName(fieldName);
writer.WriteValue(gapQuery.Width);
writer.WriteEndObject();
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.StartObject) return null;
reader.Read();
var field = (Field)reader.Value.ToString(); // field
var width = reader.ReadAsInt32();
reader.Read();
return new SpanGapQuery {Field = field, Width = width};
}

}
}
59 changes: 34 additions & 25 deletions src/Nest/QueryDsl/Span/SpanQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,20 @@ public interface ISpanQuery : IQuery
[JsonProperty("span_near")]
ISpanNearQuery SpanNear { get; set; }

[JsonProperty("span_gap")]
ISpanGapQuery SpanGap { get; set; }

[JsonProperty("span_or")]
ISpanOrQuery SpanOr { get; set; }

[JsonProperty("span_not")]
ISpanNotQuery SpanNot { get; set; }
[JsonProperty("span_containing")]
ISpanContainingQuery SpanContaining { get; set; }
[JsonProperty("span_within")]
ISpanWithinQuery SpanWithin { get; set; }

[JsonProperty("span_containing")]
ISpanContainingQuery SpanContaining { get; set; }

[JsonProperty("span_within")]
ISpanWithinQuery SpanWithin { get; set; }

[JsonProperty("span_multi")]
ISpanMultiTermQuery SpanMultiTerm { get; set; }
Expand All @@ -50,14 +53,15 @@ public class SpanQuery : ISpanQuery
public ISpanTermQuery SpanTerm { get; set; }
public ISpanFirstQuery SpanFirst { get; set; }
public ISpanNearQuery SpanNear { get; set; }
public ISpanGapQuery SpanGap { get; set; }
public ISpanOrQuery SpanOr { get; set; }
public ISpanNotQuery SpanNot { get; set; }
public ISpanMultiTermQuery SpanMultiTerm { get; set; }
public ISpanContainingQuery SpanContaining{ get; set; }
public ISpanWithinQuery SpanWithin { get; set; }
public ISpanFieldMaskingQuery SpanFieldMasking { get; set; }
public void Accept(IQueryVisitor visitor) => new QueryWalker().Walk(this, visitor);
public ISpanMultiTermQuery SpanMultiTerm { get; set; }
public ISpanContainingQuery SpanContaining{ get; set; }
public ISpanWithinQuery SpanWithin { get; set; }
public ISpanFieldMaskingQuery SpanFieldMasking { get; set; }

public void Accept(IQueryVisitor visitor) => new QueryWalker().Walk(this, visitor);

internal static bool IsConditionless(ISpanQuery q) => new[]
{
Expand All @@ -67,6 +71,7 @@ internal static bool IsConditionless(ISpanQuery q) => new[]
q.SpanOr ,
q.SpanNot,
q.SpanMultiTerm,
q.SpanGap,
q.SpanFieldMasking
}.All(sq => sq == null || sq.Conditionless);
}
Expand All @@ -78,10 +83,11 @@ public class SpanQueryDescriptor<T> : QueryDescriptorBase<SpanQueryDescriptor<T>
ISpanTermQuery ISpanQuery.SpanTerm { get; set; }
ISpanFirstQuery ISpanQuery.SpanFirst { get; set; }
ISpanNearQuery ISpanQuery.SpanNear { get; set; }
ISpanGapQuery ISpanQuery.SpanGap { get; set; }
ISpanOrQuery ISpanQuery.SpanOr { get; set; }
ISpanNotQuery ISpanQuery.SpanNot { get; set; }
ISpanMultiTermQuery ISpanQuery.SpanMultiTerm { get; set; }
ISpanContainingQuery ISpanQuery.SpanContaining{ get; set; }
ISpanMultiTermQuery ISpanQuery.SpanMultiTerm { get; set; }
ISpanContainingQuery ISpanQuery.SpanContaining{ get; set; }
ISpanWithinQuery ISpanQuery.SpanWithin { get; set; }
ISpanFieldMaskingQuery ISpanQuery.SpanFieldMasking { get; set; }

Expand All @@ -94,6 +100,9 @@ public SpanQueryDescriptor<T> SpanFirst(Func<SpanFirstQueryDescriptor<T>, ISpanF
public SpanQueryDescriptor<T> SpanNear(Func<SpanNearQueryDescriptor<T>, ISpanNearQuery> selector) =>
Assign(a => a.SpanNear = selector?.Invoke(new SpanNearQueryDescriptor<T>()));

public SpanQueryDescriptor<T> SpanGap(Func<SpanGapQueryDescriptor<T>, ISpanGapQuery> selector) =>
Assign(a => a.SpanGap = selector?.Invoke(new SpanGapQueryDescriptor<T>()));

public SpanQueryDescriptor<T> SpanOr(Func<SpanOrQueryDescriptor<T>, ISpanOrQuery> selector) =>
Assign(a => a.SpanOr = selector?.Invoke(new SpanOrQueryDescriptor<T>()));

Expand All @@ -102,17 +111,17 @@ public SpanQueryDescriptor<T> SpanNot(Func<SpanNotQueryDescriptor<T>, ISpanNotQu

public SpanQueryDescriptor<T> SpanMultiTerm(Func<SpanMultiTermQueryDescriptor<T>, ISpanMultiTermQuery> selector) =>
Assign(a => a.SpanMultiTerm = selector?.Invoke(new SpanMultiTermQueryDescriptor<T>()));
public SpanQueryDescriptor<T> SpanContaining(Func<SpanContainingQueryDescriptor<T>, ISpanContainingQuery> selector) =>
Assign(a => a.SpanContaining = selector?.Invoke(new SpanContainingQueryDescriptor<T>()));
public SpanQueryDescriptor<T> SpanWithin(Func<SpanWithinQueryDescriptor<T>, ISpanWithinQuery> selector) =>
Assign(a => a.SpanWithin = selector?.Invoke(new SpanWithinQueryDescriptor<T>()));
public SpanQueryDescriptor<T> SpanFieldMasking(Func<SpanFieldMaskingQueryDescriptor<T>, ISpanFieldMaskingQuery> selector) =>
Assign(a => a.SpanFieldMasking = selector?.Invoke(new SpanFieldMaskingQueryDescriptor<T>()));
void ISpanQuery.Accept(IQueryVisitor visitor) => new QueryWalker().Walk(this, visitor);

public SpanQueryDescriptor<T> SpanContaining(Func<SpanContainingQueryDescriptor<T>, ISpanContainingQuery> selector) =>
Assign(a => a.SpanContaining = selector?.Invoke(new SpanContainingQueryDescriptor<T>()));

public SpanQueryDescriptor<T> SpanWithin(Func<SpanWithinQueryDescriptor<T>, ISpanWithinQuery> selector) =>
Assign(a => a.SpanWithin = selector?.Invoke(new SpanWithinQueryDescriptor<T>()));

public SpanQueryDescriptor<T> SpanFieldMasking(Func<SpanFieldMaskingQueryDescriptor<T>, ISpanFieldMaskingQuery> selector) =>
Assign(a => a.SpanFieldMasking = selector?.Invoke(new SpanFieldMaskingQueryDescriptor<T>()));

void ISpanQuery.Accept(IQueryVisitor visitor) => new QueryWalker().Walk(this, visitor);

}
}
2 changes: 1 addition & 1 deletion src/Tests/Tests.Configuration/tests.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# tracked by git).

# mode either u (unit test), i (integration test) or m (mixed mode)
mode: i
mode: u
# the elasticsearch version that should be started
# Can be a snapshot version of sonatype or "latest" to get the latest snapshot of sonatype
elasticsearch_version: 6.3.0
Expand Down
8 changes: 7 additions & 1 deletion src/Tests/Tests/CodeStandards/Queries.doc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ [U] public void FluentDescriptorExposesAll()

[U] public void VisitorVisitsAll()
{
var skipQueryImplementations = new[] { typeof(IFieldNameQuery), typeof(IFuzzyQuery<,>), typeof(IConditionlessQuery) };
var skipQueryImplementations = new[]
{
typeof(IFieldNameQuery),
typeof(IFuzzyQuery<,>),
typeof(IConditionlessQuery),
typeof(ISpanGapQuery)
};
var queries = typeof(IQuery).Assembly().ExportedTypes
.Where(t => t.IsInterface() && typeof(IQuery).IsAssignableFrom(t))
.Where(t => !skipQueryImplementations.Contains(t))
Expand Down
15 changes: 9 additions & 6 deletions src/Tests/Tests/QueryDsl/Span/Near/SpanNearQueryUsageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ public SpanNearUsageTests(ReadOnlyCluster i, EndpointUsage usage) : base(i, usag
{
span_near = new
{
clauses = new[] {
clauses = new object[] {
new { span_term = new { field = new { value = "value1" } } },
new { span_term = new { field = new { value = "value2" } } },
new { span_term = new { field = new { value = "value3" } } }
new { span_term = new { field = new { value = "value3" } } },
new { span_gap = new { field = 2 } }
},
slop = 12,
in_order = false,
Expand All @@ -39,7 +40,8 @@ public SpanNearUsageTests(ReadOnlyCluster i, EndpointUsage usage) : base(i, usag
{
new SpanQuery { SpanTerm = new SpanTermQuery { Field = "field", Value = "value1" } },
new SpanQuery { SpanTerm = new SpanTermQuery { Field = "field", Value = "value2" } },
new SpanQuery { SpanTerm = new SpanTermQuery { Field = "field", Value = "value3" } }
new SpanQuery { SpanTerm = new SpanTermQuery { Field = "field", Value = "value3" } },
new SpanQuery { SpanGap = new SpanGapQuery { Field = "field", Width = 2 } }
},
Slop = 12,
InOrder = false,
Expand All @@ -50,9 +52,10 @@ protected override QueryContainer QueryFluent(QueryContainerDescriptor<Project>
.Name("named_query")
.Boost(1.1)
.Clauses(
c=>c.SpanTerm(st=>st.Field("field").Value("value1")),
c=>c.SpanTerm(st=>st.Field("field").Value("value2")),
c=>c.SpanTerm(st=>st.Field("field").Value("value3"))
c => c.SpanTerm(st => st.Field("field").Value("value1")),
c => c.SpanTerm(st => st.Field("field").Value("value2")),
c => c.SpanTerm(st => st.Field("field").Value("value3")),
c => c.SpanGap(st => st.Field("field").Width(2))
)
.Slop(12)
.InOrder(false)
Expand Down