Skip to content

Commit 453a608

Browse files
authored
Add rank_feature, rank_feature fields and rank_feature query (#3941)
This commit adds the rank_feature, rank_feature fields and rank_feature query * Add rank_feature property * Add rank_features property * Add rank_feature query * fix FieldCapabilities integration test Closes #3938
1 parent 8e6afad commit 453a608

File tree

34 files changed

+739
-8
lines changed

34 files changed

+739
-8
lines changed

docs/code-standards/descriptors.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ var methods = from d in YieldAllDescriptors()
204204
where !(m.Name == nameof(RuleConditionDescriptor.AppliesTo) && dt == typeof(RuleConditionDescriptor))
205205
where !(m.Name == nameof(RuleConditionDescriptor.Operator) && dt == typeof(RuleConditionDescriptor))
206206
where !(m.Name == nameof(RuleConditionDescriptor.Value) && dt == typeof(RuleConditionDescriptor))
207+
where !(m.Name == nameof(RankFeatureLogarithmFunctionDescriptor.ScalingFactor) && dt == typeof(RankFeatureLogarithmFunctionDescriptor))
208+
where !(m.Name == nameof(RankFeatureSigmoidFunctionDescriptor.Exponent) && dt == typeof(RankFeatureSigmoidFunctionDescriptor))
209+
where !(m.Name == nameof(RankFeatureSigmoidFunctionDescriptor.Pivot) && dt == typeof(RankFeatureSigmoidFunctionDescriptor))
207210
208211
select new {m, d, p};
209212

docs/query-dsl.asciidoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ Specialized types of queries that do not fit into other groups
273273

274274
* <<percolate-query-usage,Percolate Query Usage>>
275275

276+
* <<rank-feature-query-usage,Rank Feature Query Usage>>
277+
276278
* <<script-query-usage,Script Query Usage>>
277279

278280
* <<script-score-query-usage,Script Score Query Usage>>
@@ -287,6 +289,8 @@ include::query-dsl/specialized/more-like-this/more-like-this-query-usage.asciido
287289

288290
include::query-dsl/specialized/percolate/percolate-query-usage.asciidoc[]
289291

292+
include::query-dsl/specialized/rank-feature/rank-feature-query-usage.asciidoc[]
293+
290294
include::query-dsl/specialized/script/script-query-usage.asciidoc[]
291295

292296
include::query-dsl/specialized/script-score/script-score-query-usage.asciidoc[]
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
:ref_current: https://www.elastic.co/guide/en/elasticsearch/reference/7.0
2+
3+
:github: https://github.com/elastic/elasticsearch-net
4+
5+
:nuget: https://www.nuget.org/packages
6+
7+
////
8+
IMPORTANT NOTE
9+
==============
10+
This file has been generated from https://github.com/elastic/elasticsearch-net/tree/master/src/Tests/Tests/QueryDsl/Specialized/RankFeature/RankFeatureQueryUsageTests.cs.
11+
If you wish to submit a PR for any spelling mistakes, typos or grammatical errors for this file,
12+
please modify the original csharp file found at the link and submit the PR with that change. Thanks!
13+
////
14+
15+
[[rank-feature-query-usage]]
16+
=== Rank Feature Query Usage
17+
18+
The rank_feature query is a specialized query that only works on `rank_feature` fields and `rank_features` fields.
19+
Its goal is to boost the score of documents based on the values of numeric features. It is typically put in a should clause of a bool query
20+
so that its score is added to the score of the query.
21+
22+
Compared to using `function_score` or other ways to modify the score, this query has the benefit of being able to efficiently
23+
skip non-competitive hits when track_total_hits is not set to true. Speedups may be spectacular.
24+
25+
See the Elasticsearch documentation on {ref_current}/query-dsl-rank-feature-query.html[rank feature query] for more details.
26+
27+
==== Fluent DSL example
28+
29+
[source,csharp]
30+
----
31+
q
32+
.RankFeature(rf => rf
33+
.Name("named_query")
34+
.Boost(1.1)
35+
.Field(f => f.Rank)
36+
.Saturation()
37+
)
38+
----
39+
40+
==== Object Initializer syntax example
41+
42+
[source,csharp]
43+
----
44+
new RankFeatureQuery()
45+
{
46+
Name = "named_query",
47+
Boost = 1.1,
48+
Field = Infer.Field<Project>(f => f.Rank),
49+
Function = new RankFeatureSaturationFunction()
50+
}
51+
----
52+
53+
[source,javascript]
54+
.Example json output
55+
----
56+
{
57+
"rank_feature": {
58+
"_name": "named_query",
59+
"boost": 1.1,
60+
"field": "rank",
61+
"saturation": {}
62+
}
63+
}
64+
----
65+
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace Nest
2+
{
3+
/// <inheritdoc cref="IRankFeatureProperty"/>
4+
public class RankFeatureAttribute : ElasticsearchPropertyAttributeBase, IRankFeatureProperty
5+
{
6+
public RankFeatureAttribute() : base(FieldType.RankFeature) { }
7+
8+
private IRankFeatureProperty Self => this;
9+
10+
/// <inheritdoc cref="IRankFeatureProperty.PositiveScoreImpact"/>
11+
public bool PositiveScoreImpact
12+
{
13+
get => Self.PositiveScoreImpact.GetValueOrDefault(true);
14+
set => Self.PositiveScoreImpact = value;
15+
}
16+
17+
bool? IRankFeatureProperty.PositiveScoreImpact { get; set; }
18+
}
19+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System.Diagnostics;
2+
using System.Runtime.Serialization;
3+
using Elasticsearch.Net.Utf8Json;
4+
5+
namespace Nest
6+
{
7+
/// <summary>
8+
/// A field that can index numbers so that they can later be used
9+
/// to boost documents in queries with a rank_feature query.
10+
/// </summary>
11+
[InterfaceDataContract]
12+
public interface IRankFeatureProperty : IProperty
13+
{
14+
/// <summary>
15+
/// Rank features that correlate negatively with the score should set <see cref="PositiveScoreImpact"/>
16+
/// to false (defaults to true). This will be used by the rank_feature query to modify the scoring
17+
/// formula in such a way that the score decreases with the value of the feature instead of
18+
/// increasing. For instance in web search, the url length is a commonly used feature
19+
/// which correlates negatively with scores.
20+
/// </summary>
21+
[DataMember(Name = "positive_score_impact")]
22+
bool? PositiveScoreImpact { get; set; }
23+
}
24+
25+
/// <inheritdoc cref="IRankFeatureProperty" />
26+
public class RankFeatureProperty : PropertyBase, IRankFeatureProperty
27+
{
28+
public RankFeatureProperty() : base(FieldType.RankFeature) { }
29+
30+
/// <inheritdoc />
31+
public bool? PositiveScoreImpact { get; set; }
32+
}
33+
34+
/// <inheritdoc cref="IRankFeatureProperty" />
35+
[DebuggerDisplay("{DebugDisplay}")]
36+
public class RankFeaturePropertyDescriptor<T>
37+
: PropertyDescriptorBase<RankFeaturePropertyDescriptor<T>, IRankFeatureProperty, T>, IRankFeatureProperty
38+
where T : class
39+
{
40+
public RankFeaturePropertyDescriptor() : base(FieldType.RankFeature) { }
41+
42+
bool? IRankFeatureProperty.PositiveScoreImpact { get; set; }
43+
44+
/// <inheritdoc cref="IRankFeatureProperty.PositiveScoreImpact" />
45+
public RankFeaturePropertyDescriptor<T> PositiveScoreImpact(bool? positiveScoreImpact = true) =>
46+
Assign(positiveScoreImpact, (a, v) => a.PositiveScoreImpact = v);
47+
}
48+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Nest
2+
{
3+
/// <inheritdoc cref="IRankFeaturesProperty"/>
4+
public class RankFeaturesAttribute : ElasticsearchPropertyAttributeBase, IRankFeaturesProperty
5+
{
6+
public RankFeaturesAttribute() : base(FieldType.RankFeatures) { }
7+
}
8+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System.Diagnostics;
2+
using System.Runtime.Serialization;
3+
using Elasticsearch.Net.Utf8Json;
4+
5+
namespace Nest
6+
{
7+
/// <summary>
8+
/// A field that can index numeric feature vectors, so that they can later be used to boost documents in queries with a rank_feature query.
9+
/// It is analogous to the <see cref="IRankFeatureProperty"/> datatype, but is better suited when the list of features is sparse so that it
10+
/// wouldn't be reasonable to add one field to the mappings for each of them.
11+
/// </summary>
12+
[InterfaceDataContract]
13+
public interface IRankFeaturesProperty : IProperty
14+
{
15+
}
16+
17+
/// <inheritdoc cref="IRankFeaturesProperty" />
18+
public class RankFeaturesProperty : PropertyBase, IRankFeaturesProperty
19+
{
20+
public RankFeaturesProperty() : base(FieldType.RankFeatures) { }
21+
}
22+
23+
/// <inheritdoc cref="IRankFeaturesProperty" />
24+
[DebuggerDisplay("{DebugDisplay}")]
25+
public class RankFeaturesPropertyDescriptor<T>
26+
: PropertyDescriptorBase<RankFeaturesPropertyDescriptor<T>, IRankFeaturesProperty, T>, IRankFeaturesProperty
27+
where T : class
28+
{
29+
public RankFeaturesPropertyDescriptor() : base(FieldType.RankFeatures) { }
30+
}
31+
}

src/Nest/Mapping/Types/FieldType.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,5 +118,11 @@ public enum FieldType
118118

119119
[EnumMember(Value = "join")]
120120
Join,
121+
122+
[EnumMember(Value = "rank_feature")]
123+
RankFeature,
124+
125+
[EnumMember(Value = "rank_features")]
126+
RankFeatures
121127
}
122128
}

src/Nest/Mapping/Types/Properties.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,12 @@ public PropertiesDescriptor<T> Object<TChild>(Func<ObjectTypeDescriptor<T, TChil
154154

155155
public PropertiesDescriptor<T> FieldAlias(Func<FieldAliasPropertyDescriptor<T>, IFieldAliasProperty> selector) => SetProperty(selector);
156156

157+
/// <inheritdoc cref="IRankFeatureProperty"/>
158+
public PropertiesDescriptor<T> RankFeature(Func<RankFeaturePropertyDescriptor<T>, IRankFeatureProperty> selector) => SetProperty(selector);
159+
160+
/// <inheritdoc cref="IRankFeaturesProperty"/>
161+
public PropertiesDescriptor<T> RankFeatures(Func<RankFeaturesPropertyDescriptor<T>, IRankFeaturesProperty> selector) => SetProperty(selector);
162+
157163
public PropertiesDescriptor<T> Custom(IProperty customType) => SetProperty(customType);
158164

159165
private PropertiesDescriptor<T> SetProperty<TDescriptor, TInterface>(Func<TDescriptor, TInterface> selector)

src/Nest/Mapping/Types/PropertyBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public interface IProperty : IFieldMapping
2323
/// <summary>
2424
/// The name of the property
2525
/// </summary>
26-
//[DataMember(Name = "name")]
26+
[IgnoreDataMember]
2727
PropertyName Name { get; set; }
2828

2929
/// <summary>

src/Nest/Mapping/Types/PropertyFormatter.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ public IProperty Deserialize(ref JsonReader reader, IJsonFormatterResolver forma
8787
case FieldType.IpRange: return Deserialize<IpRangeProperty>(ref segmentReader, formatterResolver);
8888
case FieldType.Join: return Deserialize<JoinProperty>(ref segmentReader, formatterResolver);
8989
case FieldType.Alias: return Deserialize<FieldAliasProperty>(ref segmentReader, formatterResolver);
90+
case FieldType.RankFeature: return Deserialize<RankFeatureProperty>(ref segmentReader, formatterResolver);
91+
case FieldType.RankFeatures: return Deserialize<RankFeaturesProperty>(ref segmentReader, formatterResolver);
9092
case FieldType.None:
9193
// no "type" field in the property mapping
9294
return Deserialize<ObjectProperty>(ref segmentReader, formatterResolver);
@@ -181,6 +183,12 @@ public void Serialize(ref JsonWriter writer, IProperty value, IJsonFormatterReso
181183
case "alias":
182184
Serialize<IFieldAliasProperty>(ref writer, value, formatterResolver);
183185
break;
186+
case "rank_feature":
187+
Serialize<IRankFeatureProperty>(ref writer, value, formatterResolver);
188+
break;
189+
case "rank_features":
190+
Serialize<IRankFeaturesProperty>(ref writer, value, formatterResolver);
191+
break;
184192
default:
185193
if (value is IGenericProperty genericProperty)
186194
Serialize<IGenericProperty>(ref writer, genericProperty, formatterResolver);

src/Nest/Mapping/Visitor/IMappingVisitor.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ public interface IMappingVisitor
4949
void Visit(IIpRangeProperty property);
5050

5151
void Visit(IJoinProperty property);
52+
53+
void Visit(IRankFeatureProperty property);
54+
55+
void Visit(IRankFeaturesProperty property);
5256
}
5357

5458
public class NoopMappingVisitor : IMappingVisitor
@@ -100,5 +104,9 @@ public virtual void Visit(IDateRangeProperty property) { }
100104
public virtual void Visit(IIpRangeProperty property) { }
101105

102106
public virtual void Visit(IJoinProperty property) { }
107+
108+
public virtual void Visit(IRankFeatureProperty property) { }
109+
110+
public virtual void Visit(IRankFeaturesProperty property) { }
103111
}
104112
}

src/Nest/Mapping/Visitor/IPropertyVisitor.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ public interface IPropertyVisitor
4848

4949
void Visit(IJoinProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
5050

51+
void Visit(IRankFeatureProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
52+
53+
void Visit(IRankFeaturesProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
54+
5155
void Visit(IProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);
5256

5357
IProperty Visit(PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute);

src/Nest/Mapping/Visitor/MappingWalker.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,18 @@ public void Accept(IProperties properties)
211211
case FieldType.Join:
212212
Visit<IJoinProperty>(field, t => { _visitor.Visit(t); });
213213
break;
214+
case FieldType.RankFeature:
215+
Visit<IRankFeatureProperty>(field, t =>
216+
{
217+
_visitor.Visit(t);
218+
});
219+
break;
220+
case FieldType.RankFeatures:
221+
Visit<IRankFeaturesProperty>(field, t =>
222+
{
223+
_visitor.Visit(t);
224+
});
225+
break;
214226
}
215227
}
216228
}

src/Nest/Mapping/Visitor/NoopPropertyVisitor.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ public void Visit(IIpRangeProperty type, PropertyInfo propertyInfo, Elasticsearc
3636

3737
public void Visit(IJoinProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
3838

39+
public virtual void Visit(IRankFeatureProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
40+
41+
public virtual void Visit(IRankFeaturesProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
42+
3943
public virtual void Visit(IIpProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
4044

4145
public virtual void Visit(IGeoPointProperty type, PropertyInfo propertyInfo, ElasticsearchPropertyAttributeBase attribute) { }
@@ -122,6 +126,12 @@ public void Visit(IProperty type, PropertyInfo propertyInfo, ElasticsearchProper
122126
case IIpRangeProperty ipRangeType:
123127
Visit(ipRangeType, propertyInfo, attribute);
124128
break;
129+
case IRankFeatureProperty rankFeature:
130+
Visit(rankFeature, propertyInfo, attribute);
131+
break;
132+
case IRankFeaturesProperty rankFeatures:
133+
Visit(rankFeatures, propertyInfo, attribute);
134+
break;
125135
}
126136
}
127137
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ public interface IQueryContainer
161161
[DataMember(Name = "wildcard")]
162162
IWildcardQuery Wildcard { get; set; }
163163

164+
/// <inheritdoc cref="IRankFeatureQuery"/>
165+
[DataMember(Name = "rank_feature")]
166+
IRankFeatureQuery RankFeature { get; set; }
167+
164168
void Accept(IQueryVisitor visitor);
165169
}
166170
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public partial class QueryContainer : IQueryContainer, IDescriptor
5353
private ITermsQuery _terms;
5454
private ITermsSetQuery _termsSet;
5555
private IWildcardQuery _wildcard;
56+
private IRankFeatureQuery _rankFeature;
5657

5758
[IgnoreDataMember]
5859
private IQueryContainer Self => this;
@@ -342,6 +343,12 @@ IWildcardQuery IQueryContainer.Wildcard
342343
set => _wildcard = Set(value);
343344
}
344345

346+
IRankFeatureQuery IQueryContainer.RankFeature
347+
{
348+
get => _rankFeature;
349+
set => _rankFeature = Set(value);
350+
}
351+
345352
private T Set<T>(T value) where T : IQuery
346353
{
347354
if (ContainedQuery != null)

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,10 @@ public QueryContainer Ids(Func<IdsQueryDescriptor, IIdsQuery> selector) =>
353353
public QueryContainer Intervals(Func<IntervalsQueryDescriptor<T>, IIntervalsQuery> selector) =>
354354
WrapInContainer(selector, (query, container) => container.Intervals = query);
355355

356+
/// <inheritdoc cref="IRankFeatureQuery"/>
357+
public QueryContainer RankFeature(Func<RankFeatureQueryDescriptor<T>, IRankFeatureQuery> selector) =>
358+
WrapInContainer(selector, (query, container) => container.RankFeature = query);
359+
356360
/// <summary>
357361
/// Matches spans containing a term. The span term query maps to Lucene SpanTermQuery.
358362
/// </summary>

src/Nest/QueryDsl/Query.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ public static QueryContainer LongRange(Func<LongRangeQueryDescriptor<T>, ILongRa
114114
public static QueryContainer Regexp(Func<RegexpQueryDescriptor<T>, IRegexpQuery> selector) =>
115115
new QueryContainerDescriptor<T>().Regexp(selector);
116116

117+
/// <inheritdoc cref="IRankFeatureQuery"/>
118+
public static QueryContainer RankFeature(Func<RankFeatureQueryDescriptor<T>, IRankFeatureQuery> selector) =>
119+
new QueryContainerDescriptor<T>().RankFeature(selector);
120+
117121
public static QueryContainer Script(Func<ScriptQueryDescriptor<T>, IScriptQuery> selector) =>
118122
new QueryContainerDescriptor<T>().Script(selector);
119123

0 commit comments

Comments
 (0)