Skip to content

Commit 24e99fc

Browse files
russcamcodebrain
andcommitted
Add wildcard and prefix interval rules (#4060)
* Add wildcard and prefix interval rules Relates: #4001 This commit adds wildcard and prefix rules support to the Intervals query. Neither wildcard or prefix rules support filters, so a new IIntervalsNoFilter interface is introduced for these rules. Added TODO to consolidate rules in 8.0 Co-Authored-By: Stuart Cam <[email protected]> (cherry picked from commit c26530b)
1 parent 49e92e2 commit 24e99fc

File tree

5 files changed

+304
-5
lines changed

5 files changed

+304
-5
lines changed

src/CodeGeneration/DocGenerator/StringExtensions.cs

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static class StringExtensions
3838
{ "_ctxNumberofCommits", "\"_source.numberOfCommits > 0\"" },
3939
{ "Project.First.Name", "\"Lesch Group\"" },
4040
{ "Project.First.NumberOfCommits", "775" },
41+
{ "IntervalsPrefix", "\"lorem\"" },
4142
{ "LastNameSearch", "\"Stokes\"" },
4243
{ "_first.Language", "\"painless\"" },
4344
{ "_first.Init", "\"state.map = [:]\"" },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
using System.Runtime.Serialization;
4+
5+
namespace Nest
6+
{
7+
/// <summary>
8+
/// Matches terms that start with a specified set of characters. This prefix can expand to match at most 128 terms.
9+
/// If the prefix matches more than 128 terms, Elasticsearch returns an error.
10+
/// You can use the index-prefixes option in the field mapping to avoid this limit.
11+
/// <para />
12+
/// Available in Elasticsearch 7.3.0+
13+
/// </summary>
14+
[ReadAs(typeof(IntervalsPrefix))]
15+
public interface IIntervalsPrefix : IIntervalsNoFilter
16+
{
17+
/// <summary>
18+
/// Analyzer used to normalize the prefix. Defaults to the top-level field's analyzer.
19+
/// </summary>
20+
[DataMember(Name = "analyzer")]
21+
string Analyzer { get; set; }
22+
23+
/// <summary>
24+
/// Beginning characters of terms you wish to find in the top-level field
25+
/// </summary>
26+
[DataMember(Name = "prefix")]
27+
string Prefix { get; set; }
28+
29+
/// <summary>
30+
/// If specified, then match intervals from this field rather than the top-level field.
31+
/// The prefix is normalized using the search analyzer from this field, unless a separate analyzer is specified.
32+
/// </summary>
33+
[DataMember(Name = "use_field")]
34+
Field UseField { get; set; }
35+
}
36+
37+
/// <inheritdoc cref="IIntervalsPrefix" />
38+
public class IntervalsPrefix : IntervalsNoFilterBase, IIntervalsPrefix
39+
{
40+
/// <inheritdoc />
41+
public string Analyzer { get; set; }
42+
43+
/// <inheritdoc />
44+
public string Prefix { get; set; }
45+
46+
/// <inheritdoc />
47+
public Field UseField { get; set; }
48+
49+
internal override void WrapInContainer(IIntervalsContainer container) => container.Prefix = this;
50+
}
51+
52+
/// <inheritdoc cref="IIntervalsPrefix" />
53+
public class IntervalsPrefixDescriptor : DescriptorBase<IntervalsPrefixDescriptor, IIntervalsPrefix>, IIntervalsPrefix
54+
{
55+
string IIntervalsPrefix.Analyzer { get; set; }
56+
string IIntervalsPrefix.Prefix { get; set; }
57+
Field IIntervalsPrefix.UseField { get; set; }
58+
59+
/// <inheritdoc cref="IIntervalsPrefix.Analyzer" />
60+
public IntervalsPrefixDescriptor Analyzer(string analyzer) => Assign(analyzer, (a, v) => a.Analyzer = v);
61+
62+
/// <inheritdoc cref="IIntervalsPrefix.Prefix" />
63+
public IntervalsPrefixDescriptor Prefix(string prefix) => Assign(prefix, (a, v) => a.Prefix = v);
64+
65+
/// <inheritdoc cref="IIntervalsPrefix.UseField" />
66+
public IntervalsPrefixDescriptor UseField<T>(Expression<Func<T, object>> objectPath) => Assign(objectPath, (a, v) => a.UseField = v);
67+
68+
/// <inheritdoc cref="IIntervalsPrefix.UseField" />
69+
public IntervalsPrefixDescriptor UseField(Field useField) => Assign(useField, (a, v) => a.UseField = v);
70+
}
71+
}

src/Nest/QueryDsl/FullText/Intervals/IntervalsQuery.cs

+70-2
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@ public class IntervalsQuery : FieldNameQueryBase, IIntervalsQuery
2626
/// <inheritdoc cref="IIntervalsMatch"/>
2727
public IIntervalsMatch Match { get; set; }
2828

29+
/// <inheritdoc cref="IIntervalsPrefix"/>
30+
public IIntervalsPrefix Prefix { get; set; }
31+
32+
/// <inheritdoc cref="IIntervalsWildcard"/>
33+
public IIntervalsWildcard Wildcard { get; set; }
34+
2935
protected override bool Conditionless => IsConditionless(this);
3036

3137
internal static bool IsConditionless(IIntervalsQuery q) =>
32-
q.Field.IsConditionless() || q.Match == null && q.AllOf == null && q.AnyOf == null;
38+
q.Field.IsConditionless() || q.Match == null && q.AllOf == null && q.AnyOf == null && q.Prefix == null && q.Wildcard == null;
3339

3440
internal override void InternalWrapInContainer(IQueryContainer container) => container.Intervals = this;
3541
}
@@ -45,11 +51,21 @@ public class IntervalsQueryDescriptor<T>
4551
IIntervalsAllOf IIntervalsContainer.AllOf { get; set; }
4652
IIntervalsAnyOf IIntervalsContainer.AnyOf { get; set; }
4753
IIntervalsMatch IIntervalsContainer.Match { get; set; }
54+
IIntervalsPrefix IIntervalsContainer.Prefix { get; set; }
55+
IIntervalsWildcard IIntervalsContainer.Wildcard { get; set; }
4856

4957
/// <inheritdoc cref="IntervalsQuery.Match" />
5058
public IntervalsQueryDescriptor<T> Match(Func<IntervalsMatchDescriptor, IIntervalsMatch> selector) =>
5159
Assign(selector, (a, v) => a.Match = v?.Invoke(new IntervalsMatchDescriptor()));
5260

61+
/// <inheritdoc cref="IntervalsQuery.Prefix" />
62+
public IntervalsQueryDescriptor<T> Prefix(Func<IntervalsPrefixDescriptor, IIntervalsPrefix> selector) =>
63+
Assign(selector, (a, v) => a.Prefix = v?.Invoke(new IntervalsPrefixDescriptor()));
64+
65+
/// <inheritdoc cref="IntervalsQuery.Wildcard" />
66+
public IntervalsQueryDescriptor<T> Wildcard(Func<IntervalsWildcardDescriptor, IIntervalsWildcard> selector) =>
67+
Assign(selector, (a, v) => a.Wildcard = v?.Invoke(new IntervalsWildcardDescriptor()));
68+
5369
/// <inheritdoc cref="IntervalsQuery.AnyOf" />
5470
public IntervalsQueryDescriptor<T> AnyOf(Func<IntervalsAnyOfDescriptor, IIntervalsAnyOf> selector) =>
5571
Assign(selector, (a, v) => a.AnyOf = v?.Invoke(new IntervalsAnyOfDescriptor()));
@@ -75,6 +91,14 @@ public interface IIntervalsContainer
7591
/// <inheritdoc cref="IIntervalsMatch" />
7692
[DataMember(Name = "match")]
7793
IIntervalsMatch Match { get; set; }
94+
95+
/// <inheritdoc cref="IIntervalsPrefix" />
96+
[DataMember(Name = "prefix")]
97+
IIntervalsPrefix Prefix { get; set; }
98+
99+
/// <inheritdoc cref="IIntervalsWildcard" />
100+
[DataMember(Name = "wildcard")]
101+
IIntervalsWildcard Wildcard { get; set; }
78102
}
79103

80104
/// <inheritdoc cref="IIntervalsContainer" />
@@ -88,13 +112,25 @@ public IntervalsContainer(IntervalsBase intervals)
88112
intervals.WrapInContainer(this);
89113
}
90114

115+
public IntervalsContainer(IntervalsNoFilterBase intervals)
116+
{
117+
intervals.ThrowIfNull(nameof(intervals));
118+
intervals.WrapInContainer(this);
119+
}
120+
91121
IIntervalsAllOf IIntervalsContainer.AllOf { get; set; }
92122
IIntervalsAnyOf IIntervalsContainer.AnyOf { get; set; }
93123
IIntervalsMatch IIntervalsContainer.Match { get; set; }
124+
IIntervalsPrefix IIntervalsContainer.Prefix { get; set; }
125+
IIntervalsWildcard IIntervalsContainer.Wildcard { get; set; }
94126

95127
public static implicit operator IntervalsContainer(IntervalsBase intervals) => intervals == null
96128
? null
97129
: new IntervalsContainer(intervals);
130+
131+
public static implicit operator IntervalsContainer(IntervalsNoFilterBase intervals) => intervals == null
132+
? null
133+
: new IntervalsContainer(intervals);
98134
}
99135

100136
/// <summary>
@@ -109,6 +145,14 @@ private IntervalsDescriptor Assign<TValue>(TValue value, Action<IIntervalsContai
109145
public IntervalsDescriptor Match(Func<IntervalsMatchDescriptor, IIntervalsMatch> selector) =>
110146
Assign(selector, (a, v) => a.Match = v?.Invoke(new IntervalsMatchDescriptor()));
111147

148+
/// <inheritdoc cref="IntervalsPrefixDescriptor" />
149+
public IntervalsDescriptor Prefix(Func<IntervalsPrefixDescriptor, IIntervalsPrefix> selector) =>
150+
Assign(selector, (a, v) => a.Prefix = v?.Invoke(new IntervalsPrefixDescriptor()));
151+
152+
/// <inheritdoc cref="IntervalsWildcardDescriptor" />
153+
public IntervalsDescriptor Wildcard(Func<IntervalsWildcardDescriptor, IIntervalsWildcard> selector) =>
154+
Assign(selector, (a, v) => a.Wildcard = v?.Invoke(new IntervalsWildcardDescriptor()));
155+
112156
/// <inheritdoc cref="IntervalsAnyOfDescriptor" />
113157
public IntervalsDescriptor AnyOf(Func<IntervalsAnyOfDescriptor, IIntervalsAnyOf> selector) =>
114158
Assign(selector, (a, v) => a.AnyOf = v?.Invoke(new IntervalsAnyOfDescriptor()));
@@ -118,8 +162,9 @@ public IntervalsDescriptor AllOf(Func<IntervalsAllOfDescriptor, IIntervalsAllOf>
118162
Assign(selector, (a, v) => a.AllOf = v?.Invoke(new IntervalsAllOfDescriptor()));
119163
}
120164

165+
// TODO: Rename this to IIntervalsWithFilter and IIntervalsNoFilter to IIntervals in 8.0
121166
/// <summary>
122-
/// An <see cref="IIntervalsQuery" /> rule
167+
/// An <see cref="IIntervalsQuery" /> rule with an optional filter
123168
/// </summary>
124169
public interface IIntervals
125170
{
@@ -130,6 +175,13 @@ public interface IIntervals
130175
IIntervalsFilter Filter { get; set; }
131176
}
132177

178+
/// <summary>
179+
/// An <see cref="IIntervalsQuery" /> rule
180+
/// </summary>
181+
public interface IIntervalsNoFilter
182+
{
183+
}
184+
133185
/// <summary>
134186
/// Base type for an <see cref="IIntervals" /> implementation
135187
/// </summary>
@@ -141,6 +193,14 @@ public abstract class IntervalsBase : IIntervals
141193
internal abstract void WrapInContainer(IIntervalsContainer container);
142194
}
143195

196+
/// <summary>
197+
/// Base type for an <see cref="IIntervalsNoFilter" /> implementation
198+
/// </summary>
199+
public abstract class IntervalsNoFilterBase : IIntervalsNoFilter
200+
{
201+
internal abstract void WrapInContainer(IIntervalsContainer container);
202+
}
203+
144204
/// <summary>
145205
/// Base type for descriptors that define <see cref="IIntervals" />
146206
/// </summary>
@@ -166,6 +226,14 @@ public IntervalsListDescriptor() : base(new List<IntervalsContainer>()) { }
166226
public IntervalsListDescriptor Match(Func<IntervalsMatchDescriptor, IIntervalsMatch> selector) =>
167227
Assign(selector, (a, v) => a.AddIfNotNull(new IntervalsDescriptor().Match(v)));
168228

229+
/// <inheritdoc cref="IIntervalsPrefix" />
230+
public IntervalsListDescriptor Prefix(Func<IntervalsPrefixDescriptor, IIntervalsPrefix> selector) =>
231+
Assign(selector, (a, v) => a.AddIfNotNull(new IntervalsDescriptor().Prefix(v)));
232+
233+
/// <inheritdoc cref="IIntervalsWildcard" />
234+
public IntervalsListDescriptor Wildcard(Func<IntervalsWildcardDescriptor, IIntervalsWildcard> selector) =>
235+
Assign(selector, (a, v) => a.AddIfNotNull(new IntervalsDescriptor().Wildcard(v)));
236+
169237
/// <inheritdoc cref="IIntervalsAnyOf" />
170238
public IntervalsListDescriptor AnyOf(Func<IntervalsAnyOfDescriptor, IIntervalsAnyOf> selector) =>
171239
Assign(selector, (a, v) => a.AddIfNotNull(new IntervalsDescriptor().AnyOf(v)));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
using System;
2+
using System.Linq.Expressions;
3+
using System.Runtime.Serialization;
4+
5+
namespace Nest
6+
{
7+
/// <summary>
8+
/// Matches terms using a wildcard pattern. This pattern can expand to match at most 128 terms.
9+
/// If the pattern matches more than 128 terms, Elasticsearch returns an error.
10+
/// <para />
11+
/// Available in Elasticsearch 7.3.0+
12+
/// </summary>
13+
[ReadAs(typeof(IntervalsWildcard))]
14+
public interface IIntervalsWildcard : IIntervalsNoFilter
15+
{
16+
/// <summary>
17+
/// Analyzer used to normalize the prefix. Defaults to the top-level field's analyzer.
18+
/// </summary>
19+
[DataMember(Name = "analyzer")]
20+
string Analyzer { get; set; }
21+
22+
/// <summary>
23+
/// Wildcard pattern used to find matching terms. Supports two wildcard operators:
24+
/// <para />?, which matches any single character
25+
/// <para />*, which can match zero or more characters, including an empty one
26+
/// <para />Warning: Avoid beginning patterns with * or ?. This can increase the iterations needed to find matching terms and slow search performance.
27+
/// </summary>
28+
[DataMember(Name = "pattern")]
29+
string Pattern { get; set; }
30+
31+
/// <summary>
32+
/// If specified, then match intervals from this field rather than the top-level field.
33+
/// The prefix is normalized using the search analyzer from this field, unless a separate analyzer is specified.
34+
/// </summary>
35+
[DataMember(Name = "use_field")]
36+
Field UseField { get; set; }
37+
}
38+
39+
/// <inheritdoc cref="IIntervalsWildcard" />
40+
public class IntervalsWildcard : IntervalsNoFilterBase, IIntervalsWildcard
41+
{
42+
/// <inheritdoc />
43+
public string Analyzer { get; set; }
44+
45+
/// <inheritdoc />
46+
public string Pattern { get; set; }
47+
48+
/// <inheritdoc />
49+
public Field UseField { get; set; }
50+
51+
internal override void WrapInContainer(IIntervalsContainer container) => container.Wildcard = this;
52+
}
53+
54+
/// <inheritdoc cref="IIntervalsWildcard" />
55+
public class IntervalsWildcardDescriptor : DescriptorBase<IntervalsWildcardDescriptor, IIntervalsWildcard>, IIntervalsWildcard
56+
{
57+
string IIntervalsWildcard.Analyzer { get; set; }
58+
string IIntervalsWildcard.Pattern { get; set; }
59+
Field IIntervalsWildcard.UseField { get; set; }
60+
61+
/// <inheritdoc cref="IIntervalsWildcard.Analyzer" />
62+
public IntervalsWildcardDescriptor Analyzer(string analyzer) => Assign(analyzer, (a, v) => a.Analyzer = v);
63+
64+
/// <inheritdoc cref="IIntervalsWildcard.Pattern" />
65+
public IntervalsWildcardDescriptor Pattern(string pattern) => Assign(pattern, (a, v) => a.Pattern = v);
66+
67+
/// <inheritdoc cref="IIntervalsWildcard.UseField" />
68+
public IntervalsWildcardDescriptor UseField<T>(Expression<Func<T, object>> objectPath) => Assign(objectPath, (a, v) => a.UseField = v);
69+
70+
/// <inheritdoc cref="IIntervalsWildcard.UseField" />
71+
public IntervalsWildcardDescriptor UseField(Field useField) => Assign(useField, (a, v) => a.UseField = v);
72+
}
73+
}

0 commit comments

Comments
 (0)