Skip to content

Commit ce1ec84

Browse files
committed
Add field_masking_span query
Forward port of #2231
1 parent b9fded9 commit ce1ec84

File tree

12 files changed

+162
-24
lines changed

12 files changed

+162
-24
lines changed

src/Nest/Nest.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,7 @@
10241024
<Compile Include="QueryDsl\Operator.cs" />
10251025
<Compile Include="QueryDsl\Query.cs" />
10261026
<Compile Include="QueryDsl\Span\Containing\SpanContainingQuery.cs" />
1027+
<Compile Include="QueryDsl\Span\FieldMasking\SpanFieldMaskingQuery.cs" />
10271028
<Compile Include="QueryDsl\Span\First\SpanFirstQuery.cs" />
10281029
<Compile Include="QueryDsl\Span\ISpanSubQuery.cs" />
10291030
<Compile Include="QueryDsl\Span\MultiTerm\SpanMultiTermQuery.cs" />

src/Nest/QueryDsl/Abstractions/Container/IQueryContainer.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ public interface IQueryContainer
111111
[JsonProperty("span_multi")]
112112
ISpanMultiTermQuery SpanMultiTerm { get; set; }
113113

114+
[JsonProperty("field_masking_span")]
115+
ISpanFieldMaskingQuery SpanFieldMasking { get; set; }
116+
114117
[JsonProperty("nested")]
115118
INestedQuery Nested { get; set; }
116119

src/Nest/QueryDsl/Abstractions/Container/QueryContainer-Assignments.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ public partial class QueryContainer : IQueryContainer, IDescriptor
4343
private ISpanContainingQuery _spanContaining;
4444
private ISpanWithinQuery _spanWithin;
4545
private ISpanMultiTermQuery _spanMultiTerm;
46+
private ISpanFieldMaskingQuery _spanFieldMasking;
4647
private INestedQuery _nested;
4748
private IIndicesQuery _indices;
4849
private IFunctionScoreQuery _functionScore;
@@ -109,6 +110,7 @@ private T Set<T>(T value) where T : IQuery
109110
ISpanContainingQuery IQueryContainer.SpanContaining { get { return _spanContaining; } set { _spanContaining = Set(value); } }
110111
ISpanWithinQuery IQueryContainer.SpanWithin { get { return _spanWithin; } set { _spanWithin = Set(value); } }
111112
ISpanMultiTermQuery IQueryContainer.SpanMultiTerm { get { return _spanMultiTerm; } set { _spanMultiTerm = Set(value); } }
113+
ISpanFieldMaskingQuery IQueryContainer.SpanFieldMasking { get { return _spanFieldMasking; } set { _spanFieldMasking = Set(value); } }
112114
INestedQuery IQueryContainer.Nested { get { return _nested; } set { _nested = Set(value); } }
113115
IIndicesQuery IQueryContainer.Indices { get { return _indices; } set { _indices = Set(value); } }
114116
IFunctionScoreQuery IQueryContainer.FunctionScore { get { return _functionScore; } set { _functionScore = Set(value); } }
@@ -122,8 +124,5 @@ private T Set<T>(T value) where T : IQuery
122124
IExistsQuery IQueryContainer.Exists { get { return _exists; } set { _exists = Set(value); } }
123125
IMissingQuery IQueryContainer.Missing { get { return _missing; } set { _missing = Set(value); } }
124126
ITypeQuery IQueryContainer.Type { get { return _type; } set { _type = Set(value); } }
125-
126-
127127
}
128-
129128
}

src/Nest/QueryDsl/Abstractions/Container/QueryContainerDescriptor.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,15 @@ public QueryContainer SpanContaining(Func<SpanContainingQueryDescriptor<T>, ISpa
475475
public QueryContainer SpanWithin(Func<SpanWithinQueryDescriptor<T>, ISpanWithinQuery> selector) =>
476476
WrapInContainer(selector, (query, container) => container.SpanWithin = query);
477477

478+
/// <summary>
479+
/// Wraps span queries to allow them to participate in composite single-field Span queries by 'lying' about their search field.
480+
/// That is, the masked span query will function as normal, but the field points back to the set field of the query.
481+
/// This can be used to support queries like SpanNearQuery or SpanOrQuery across different fields,
482+
/// which is not ordinarily permitted.
483+
/// </summary>
484+
public QueryContainer SpanFieldMasking(Func<SpanFieldMaskingQueryDescriptor<T>, ISpanFieldMaskingQuery> selector) =>
485+
WrapInContainer(selector, (query, container) => container.SpanFieldMasking = query);
486+
478487
/// <summary>
479488
/// custom_score query allows to wrap another query and customize the scoring of it optionally with a
480489
/// computation derived from other field values in the doc (numeric ones) using script or boost expression

src/Nest/QueryDsl/Query.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
using System;
2-
using System.Collections;
3-
using System.Collections.Generic;
42
using System.Linq.Expressions;
53

64
namespace Nest
75
{
8-
// TODO: Write a unit test for these using reflection to make sure all queries are covered
96
public static class Query<T> where T : class
107
{
118
public static QueryContainer Bool(Func<BoolQueryDescriptor<T>, IBoolQuery> selector) =>
@@ -161,8 +158,11 @@ public static QueryContainer SpanTerm(Func<SpanTermQueryDescriptor<T>, ISpanTerm
161158
public static QueryContainer SpanWithin(Func<SpanWithinQueryDescriptor<T>, ISpanWithinQuery> selector) =>
162159
new QueryContainerDescriptor<T>().SpanWithin(selector);
163160

161+
public static QueryContainer SpanFieldMasking(Func<SpanFieldMaskingQueryDescriptor<T>, ISpanFieldMaskingQuery> selector) =>
162+
new QueryContainerDescriptor<T>().SpanFieldMasking(selector);
163+
164164
#pragma warning disable 618
165-
[Obsolete("Scheduled to be removed in 5.0. Setting Strict() at the container level does is a noop and must be set on each individual query.")]
165+
[Obsolete("Scheduled to be removed in 5.0. Setting Strict() at the container level is a noop and must be set on each individual query.")]
166166
public static QueryContainerDescriptor<T> Strict(bool strict = true) =>
167167
new QueryContainerDescriptor<T>().Strict(strict);
168168
#pragma warning restore 618
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Linq.Expressions;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Newtonsoft.Json;
8+
9+
namespace Nest
10+
{
11+
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
12+
[JsonConverter(typeof(ReadAsTypeJsonConverter<SpanFieldMaskingQueryDescriptor<object>>))]
13+
public interface ISpanFieldMaskingQuery : ISpanSubQuery
14+
{
15+
[JsonProperty("field")]
16+
Field Field { get; set; }
17+
18+
[JsonProperty("query")]
19+
ISpanQuery Query { get; set; }
20+
}
21+
22+
public class SpanFieldMaskingQuery : QueryBase, ISpanFieldMaskingQuery
23+
{
24+
protected override bool Conditionless => IsConditionless(this);
25+
public ISpanQuery Query { get; set; }
26+
public Field Field { get; set; }
27+
28+
internal override void InternalWrapInContainer(IQueryContainer c) => c.SpanFieldMasking = this;
29+
internal static bool IsConditionless(ISpanFieldMaskingQuery q) =>
30+
q.Field.IsConditionless() || q.Query == null || q.Query.Conditionless;
31+
}
32+
33+
public class SpanFieldMaskingQueryDescriptor<T>
34+
: QueryDescriptorBase<SpanFieldMaskingQueryDescriptor<T>, ISpanFieldMaskingQuery>
35+
, ISpanFieldMaskingQuery where T : class
36+
{
37+
protected override bool Conditionless => SpanFieldMaskingQuery.IsConditionless(this);
38+
ISpanQuery ISpanFieldMaskingQuery.Query { get; set; }
39+
Field ISpanFieldMaskingQuery.Field { get; set; }
40+
41+
public SpanFieldMaskingQueryDescriptor<T> Field(Field field) => Assign(a => a.Field = field);
42+
43+
public SpanFieldMaskingQueryDescriptor<T> Field(Expression<Func<T, object>> objectPath) =>
44+
Assign(a => a.Field = objectPath);
45+
46+
public SpanFieldMaskingQueryDescriptor<T> Query(Func<SpanQueryDescriptor<T>, ISpanQuery> selector) =>
47+
Assign(a => a.Query = selector?.Invoke(new SpanQueryDescriptor<T>()));
48+
}
49+
}

src/Nest/QueryDsl/Span/SpanQuery.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,33 @@ namespace Nest
88
[JsonConverter(typeof(ReadAsTypeJsonConverter<SpanQueryDescriptor<object>>))]
99
public interface ISpanQuery : IQuery
1010
{
11-
[JsonProperty(PropertyName = "span_term")]
11+
[JsonProperty("span_term")]
1212
ISpanTermQuery SpanTerm { get; set; }
1313

14-
[JsonProperty(PropertyName = "span_first")]
14+
[JsonProperty("span_first")]
1515
ISpanFirstQuery SpanFirst { get; set; }
1616

17-
[JsonProperty(PropertyName = "span_near")]
17+
[JsonProperty("span_near")]
1818
ISpanNearQuery SpanNear { get; set; }
1919

20-
[JsonProperty(PropertyName = "span_or")]
20+
[JsonProperty("span_or")]
2121
ISpanOrQuery SpanOr { get; set; }
2222

23-
[JsonProperty(PropertyName = "span_not")]
23+
[JsonProperty("span_not")]
2424
ISpanNotQuery SpanNot { get; set; }
2525

26-
[JsonProperty(PropertyName = "span_containing")]
26+
[JsonProperty("span_containing")]
2727
ISpanContainingQuery SpanContaining { get; set; }
2828

29-
[JsonProperty(PropertyName = "span_within")]
29+
[JsonProperty("span_within")]
3030
ISpanWithinQuery SpanWithin { get; set; }
3131

32-
[JsonProperty(PropertyName = "span_multi")]
32+
[JsonProperty("span_multi")]
3333
ISpanMultiTermQuery SpanMultiTerm { get; set; }
3434

35+
[JsonProperty("field_masking_span")]
36+
ISpanFieldMaskingQuery SpanFieldMasking { get; set; }
37+
3538
void Accept(IQueryVisitor visitor);
3639
}
3740

@@ -52,6 +55,8 @@ public class SpanQuery : ISpanQuery
5255
public ISpanMultiTermQuery SpanMultiTerm { get; set; }
5356
public ISpanContainingQuery SpanContaining{ get; set; }
5457
public ISpanWithinQuery SpanWithin { get; set; }
58+
public ISpanFieldMaskingQuery SpanFieldMasking { get; set; }
59+
5560
public void Accept(IQueryVisitor visitor) => new QueryWalker().Walk(this, visitor);
5661

5762
internal static bool IsConditionless(ISpanQuery q) => new[]
@@ -61,7 +66,8 @@ internal static bool IsConditionless(ISpanQuery q) => new[]
6166
q.SpanNear,
6267
q.SpanOr ,
6368
q.SpanNot,
64-
q.SpanMultiTerm
69+
q.SpanMultiTerm,
70+
q.SpanFieldMasking
6571
}.All(sq => sq == null || sq.Conditionless);
6672
}
6773

@@ -77,6 +83,7 @@ public class SpanQueryDescriptor<T> : QueryDescriptorBase<SpanQueryDescriptor<T>
7783
ISpanMultiTermQuery ISpanQuery.SpanMultiTerm { get; set; }
7884
ISpanContainingQuery ISpanQuery.SpanContaining{ get; set; }
7985
ISpanWithinQuery ISpanQuery.SpanWithin { get; set; }
86+
ISpanFieldMaskingQuery ISpanQuery.SpanFieldMasking { get; set; }
8087

8188
public SpanQueryDescriptor<T> SpanTerm(Func<SpanTermQueryDescriptor<T>, ISpanTermQuery> selector) =>
8289
Assign(a => a.SpanTerm = selector?.Invoke(new SpanTermQueryDescriptor<T>()));
@@ -102,6 +109,9 @@ public SpanQueryDescriptor<T> SpanContaining(Func<SpanContainingQueryDescriptor<
102109
public SpanQueryDescriptor<T> SpanWithin(Func<SpanWithinQueryDescriptor<T>, ISpanWithinQuery> selector) =>
103110
Assign(a => a.SpanWithin = selector?.Invoke(new SpanWithinQueryDescriptor<T>()));
104111

112+
public SpanQueryDescriptor<T> SpanFieldMasking(Func<SpanFieldMaskingQueryDescriptor<T>, ISpanFieldMaskingQuery> selector) =>
113+
Assign(a => a.SpanFieldMasking = selector?.Invoke(new SpanFieldMaskingQueryDescriptor<T>()));
114+
105115
void ISpanQuery.Accept(IQueryVisitor visitor) => new QueryWalker().Walk(this, visitor);
106116

107117
}

src/Nest/QueryDsl/Visitor/DslPrettyPrintVisitor.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,8 @@ private void Write(string queryType, Field field = null)
142142

143143
public virtual void Visit(ISpanTermQuery query) => Write("span_term");
144144

145+
public virtual void Visit(ISpanFieldMaskingQuery query) => Write("field_masking_span");
146+
145147
public virtual void Visit(ITermQuery query) => Write("term", query.Field);
146148

147149
public virtual void Visit(IWildcardQuery query) => Write("wildcard");

src/Nest/QueryDsl/Visitor/QueryVisitor.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public interface IQueryVisitor
8383
void Visit(ISpanContainingQuery query);
8484
void Visit(ISpanWithinQuery query);
8585
void Visit(ISpanMultiTermQuery query);
86+
void Visit(ISpanFieldMaskingQuery query);
8687

8788
void Visit(IGeoIndexedShapeQuery query);
8889
void Visit(IGeoShapeQuery query);
@@ -193,6 +194,12 @@ public virtual void Visit(ISpanOrQuery query) { }
193194

194195
public virtual void Visit(ISpanTermQuery query) { }
195196

197+
public virtual void Visit(ISpanSubQuery query) { }
198+
199+
public virtual void Visit(ISpanMultiTermQuery query) { }
200+
201+
public virtual void Visit(ISpanFieldMaskingQuery query) { }
202+
196203
public virtual void Visit(ITermQuery query) { }
197204

198205
public virtual void Visit(IWildcardQuery query) { }
@@ -215,8 +222,6 @@ public virtual void Visit(IGeoHashCellQuery query) { }
215222

216223
public virtual void Visit(ITemplateQuery query) { }
217224

218-
public virtual void Visit(ISpanMultiTermQuery query) { }
219-
220225
public virtual void Visit(IGeoShapeMultiPointQuery query) { }
221226

222227
public virtual void Visit(IGeoShapeMultiPolygonQuery query) { }
@@ -231,8 +236,6 @@ public virtual void Visit(IGeoShapeLineStringQuery query) { }
231236

232237
public virtual void Visit(IGeoShapeEnvelopeQuery query) { }
233238

234-
public virtual void Visit(ISpanSubQuery query) { }
235-
236239
public virtual void Visit(IGeoShapeCircleQuery query) { }
237240

238241
public virtual void Visit(ISpanQuery query) { }

src/Nest/QueryDsl/Visitor/QueryWalker.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ public void Walk(IQueryContainer qd, IQueryVisitor visitor)
1313
VisitQuery(qd.MoreLikeThis, visitor, (v, d) => v.Visit(d));
1414
VisitQuery(qd.MultiMatch, visitor, (v, d) => v.Visit(d));
1515
VisitQuery(qd.CommonTerms, visitor, (v, d) => v.Visit(d));
16-
VisitQuery(qd.Fuzzy, visitor, (v, d) =>
16+
VisitQuery(qd.Fuzzy, visitor, (v, d) =>
1717
{
1818
v.Visit(d);
1919
VisitQuery(d as IFuzzyStringQuery, visitor, (vv, dd) => v.Visit(dd));
2020
VisitQuery(d as IFuzzyNumericQuery, visitor, (vv, dd) => v.Visit(dd));
2121
VisitQuery(d as IFuzzyDateQuery, visitor, (vv, dd) => v.Visit(dd));
2222
});
23-
VisitQuery(qd.Range, visitor, (v, d) =>
23+
VisitQuery(qd.Range, visitor, (v, d) =>
2424
{
2525
v.Visit(d);
2626
VisitQuery(d as IDateRangeQuery, visitor, (vv, dd) => v.Visit(dd));
2727
VisitQuery(d as INumericRangeQuery, visitor, (vv, dd) => v.Visit(dd));
2828
VisitQuery(d as ITermRangeQuery, visitor, (vv, dd) => v.Visit(dd));
2929
});
30-
VisitQuery(qd.GeoShape, visitor, (v, d) =>
30+
VisitQuery(qd.GeoShape, visitor, (v, d) =>
3131
{
3232
v.Visit(d);
3333
VisitQuery(d as IGeoIndexedShapeQuery, visitor, (vv, dd) => v.Visit(dd));
@@ -250,6 +250,11 @@ private static void VisitSpan<T>(T qd, IQueryVisitor visitor) where T : class, I
250250
Accept(visitor, d.Big);
251251
Accept(visitor, d.Little);
252252
});
253+
VisitSpanSubQuery(qd.SpanFieldMasking, visitor, (v, d) =>
254+
{
255+
v.Visit(d);
256+
Accept(visitor, d.Query);
257+
});
253258
}
254259

255260
private static void VisitQuery<T>(T qd, IQueryVisitor visitor, Action<IQueryVisitor, T> scoped)
@@ -269,7 +274,7 @@ private static void VisitSpanSubQuery<T>(T qd, IQueryVisitor visitor, Action<IQu
269274
if (qd == null) return;
270275
VisitQuery(qd, visitor, (v, d) =>
271276
{
272-
visitor.Visit(qd as ISpanSubQuery);
277+
visitor.Visit(qd);
273278
scoped(v, d);
274279
});
275280
}

0 commit comments

Comments
 (0)