Skip to content

Commit

Permalink
Add script_score query support (#3919)
Browse files Browse the repository at this point in the history
This commit adds script_score query support to the high level client

Closes #3843

(cherry picked from commit a474194)
  • Loading branch information
russcam committed Jul 9, 2019
1 parent 865e1b9 commit dd6c997
Show file tree
Hide file tree
Showing 13 changed files with 381 additions and 9 deletions.
4 changes: 4 additions & 0 deletions docs/query-dsl.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,8 @@ Specialized types of queries that do not fit into other groups

* <<script-query-usage,Script Query Usage>>

* <<script-score-query-usage,Script Score Query Usage>>

See the Elasticsearch documentation on {ref_current}/specialized-queries.html[Specialized queries] for more details.

:includes-from-dirs: query-dsl/specialized
Expand All @@ -287,6 +289,8 @@ include::query-dsl/specialized/percolate/percolate-query-usage.asciidoc[]

include::query-dsl/specialized/script/script-query-usage.asciidoc[]

include::query-dsl/specialized/script-score/script-score-query-usage.asciidoc[]

[[span-queries]]
== Span queries

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,36 @@ q
.MaxBoost(20.0)
.MinScore(1.0)
.Functions(f => f
.Exponential(b => b.Field(p => p.NumberOfCommits).Decay(0.5).Origin(1.0).Scale(0.1).Weight(2.1))
.Exponential(b => b
.Field(p => p.NumberOfCommits)
.Decay(0.5)
.Origin(1.0)
.Scale(0.1)
.Weight(2.1)
.Filter(fi => fi
.Range(r => r
.Field(p => p.NumberOfContributors)
.GreaterThan(10)
)
)
)
.GaussDate(b => b.Field(p => p.LastActivity).Origin(DateMath.Now).Decay(0.5).Scale("1d"))
.LinearGeoLocation(b =>
b.Field(p => p.LocationPoint).Origin(new GeoLocation(70, -70)).Scale(Distance.Miles(1)).MultiValueMode(MultiValueMode.Average))
.LinearGeoLocation(b => b
.Field(p => p.LocationPoint)
.Origin(new GeoLocation(70, -70))
.Scale(Distance.Miles(1))
.MultiValueMode(MultiValueMode.Average)
)
.FieldValueFactor(b => b.Field(p => p.NumberOfContributors).Factor(1.1).Missing(0.1).Modifier(FieldValueFactorModifier.Square))
.RandomScore(r => r.Seed(1337).Field("_seq_no"))
.RandomScore(r => r.Seed("randomstring").Field("_seq_no"))
.Weight(1.0)
.ScriptScore(s => s.Script(ss => ss.Source("Math.log(2 + doc['numberOfCommits'].value)")))
.ScriptScore(s => s
.Script(ss => ss
.Source("Math.log(2 + doc['numberOfCommits'].value)")
)
.Weight(2)
)
)
)
----
Expand All @@ -57,7 +78,19 @@ new FunctionScoreQuery()
MinScore = 1.0,
Functions = new List<IScoreFunction>
{
new ExponentialDecayFunction { Origin = 1.0, Decay = 0.5, Field = Field<Project>(p => p.NumberOfCommits), Scale = 0.1, Weight = 2.1 },
new ExponentialDecayFunction
{
Origin = 1.0,
Decay = 0.5,
Field = Field<Project>(p => p.NumberOfCommits),
Scale = 0.1,
Weight = 2.1,
Filter = new NumericRangeQuery
{
Field = Field<Project>(f => f.NumberOfContributors),
GreaterThan = 10
}
},
new GaussDateDecayFunction
{ Origin = DateMath.Now, Field = Field<Project>(p => p.LastActivity), Decay = 0.5, Scale = TimeSpan.FromDays(1) },
new LinearGeoDecayFunction
Expand All @@ -72,7 +105,7 @@ new FunctionScoreQuery()
new RandomScoreFunction { Seed = 1337, Field = "_seq_no" },
new RandomScoreFunction { Seed = "randomstring", Field = "_seq_no" },
new WeightFunction { Weight = 1.0 },
new ScriptScoreFunction { Script = new InlineScript("Math.log(2 + doc['numberOfCommits'].value)") }
new ScriptScoreFunction { Script = new InlineScript("Math.log(2 + doc['numberOfCommits'].value)"), Weight = 2.0 }
}
}
----
Expand All @@ -94,7 +127,14 @@ new FunctionScoreQuery()
"decay": 0.5
}
},
"weight": 2.1
"weight": 2.1,
"filter": {
"range": {
"numberOfContributors": {
"gt": 10.0
}
}
}
},
{
"gauss": {
Expand Down Expand Up @@ -145,7 +185,8 @@ new FunctionScoreQuery()
"script": {
"source": "Math.log(2 + doc['numberOfCommits'].value)"
}
}
},
"weight": 2.0
}
],
"max_boost": 20.0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
:ref_current: https://www.elastic.co/guide/en/elasticsearch/reference/7.0

:github: https://github.com/elastic/elasticsearch-net

:nuget: https://www.nuget.org/packages

////
IMPORTANT NOTE
==============
This file has been generated from https://github.com/elastic/elasticsearch-net/tree/master/src/Tests/Tests/QueryDsl/Specialized/ScriptScore/ScriptScoreQueryUsageTests.cs.
If you wish to submit a PR for any spelling mistakes, typos or grammatical errors for this file,
please modify the original csharp file found at the link and submit the PR with that change. Thanks!
////

[[script-score-query-usage]]
=== Script Score Query Usage

A query allowing you to modify the score of documents that are retrieved by a query.
This can be useful if, for example, a score function is computationally expensive and
it is sufficient to compute the score on a filtered set of documents.

See the Elasticsearch documentation on {ref_current}/query-dsl-script-score-query.html[script_score query] for more details.

==== Fluent DSL example

[source,csharp]
----
q
.ScriptScore(sn => sn
.Name("named_query")
.Boost(1.1)
.Query(qq => qq
.Range(r => r
.Field(f => f.NumberOfCommits)
.GreaterThan(50)
)
)
.Script(s => s
.Source(_scriptScoreSource)
.Params(p => p
.Add("origin", 100)
.Add("scale", 10)
.Add("decay", 0.5)
.Add("offset", 0)
)
)
)
----

==== Object Initializer syntax example

[source,csharp]
----
new ScriptScoreQuery
{
Name = "named_query",
Boost = 1.1,
Query = new NumericRangeQuery
{
Field = Infer.Field<Project>(f => f.NumberOfCommits),
GreaterThan = 50
},
Script = new InlineScript(_scriptScoreSource)
{
Params = new Dictionary<string, object>
{
{ "origin", 100 },
{ "scale", 10 },
{ "decay", 0.5 },
{ "offset", 0 }
}
},
}
----

[source,javascript]
.Example json output
----
{
"script_score": {
"_name": "named_query",
"boost": 1.1,
"query": {
"range": {
"numberOfCommits": {
"gt": 50.0
}
}
},
"script": {
"source": "decayNumericLinear(params.origin, params.scale, params.offset, params.decay, doc['numberOfCommits'].value)",
"params": {
"origin": 100,
"scale": 10,
"decay": 0.5,
"offset": 0
}
}
}
}
----

3 changes: 2 additions & 1 deletion src/CodeGeneration/DocGenerator/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ public static class StringExtensions
new []{ new [] {8.2, 18.2}, new [] {8.2, -18.8}, new [] {-8.8, -10.8}, new [] {8.8, 18.2}}
}"
},
{ "ProjectFilterExpectedJson", "new {term = new {type = new {value = \"project\"}}}" }
{ "ProjectFilterExpectedJson", "new {term = new {type = new {value = \"project\"}}}" },
{ "_scriptScoreSource", "\"decayNumericLinear(params.origin, params.scale, params.offset, params.decay, doc['numberOfCommits'].value)\""}
};

private static readonly Regex LeadingSpacesAndAsterisk = new Regex(@"^(?<value>[ \t]*\*\s?).*", RegexOptions.Compiled);
Expand Down
4 changes: 4 additions & 0 deletions src/Nest/QueryDsl/Abstractions/Container/IQueryContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ public interface IQueryContainer
[DataMember(Name ="script")]
IScriptQuery Script { get; set; }

/// <inheritdoc cref="IScriptScoreQuery"/>
[DataMember(Name ="script_score")]
IScriptScoreQuery ScriptScore { get; set; }

[DataMember(Name ="simple_query_string")]
ISimpleQueryStringQuery SimpleQueryString { get; set; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public partial class QueryContainer : IQueryContainer, IDescriptor
private IRawQuery _raw;
private IRegexpQuery _regexp;
private IScriptQuery _script;
private IScriptScoreQuery _scriptScore;
private ISimpleQueryStringQuery _simpleQueryString;
private ISpanContainingQuery _spanContaining;
private ISpanFieldMaskingQuery _spanFieldMasking;
Expand Down Expand Up @@ -251,6 +252,12 @@ IScriptQuery IQueryContainer.Script
set => _script = Set(value);
}

IScriptScoreQuery IQueryContainer.ScriptScore
{
get => _scriptScore;
set => _scriptScore = Set(value);
}

ISimpleQueryStringQuery IQueryContainer.SimpleQueryString
{
get => _simpleQueryString;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,9 @@ public QueryContainer FunctionScore(Func<FunctionScoreQueryDescriptor<T>, IFunct
public QueryContainer Script(Func<ScriptQueryDescriptor<T>, IScriptQuery> selector) =>
WrapInContainer(selector, (query, container) => container.Script = query);

public QueryContainer ScriptScore(Func<ScriptScoreQueryDescriptor<T>, IScriptScoreQuery> selector) =>
WrapInContainer(selector, (query, container) => container.ScriptScore = query);

public QueryContainer Exists(Func<ExistsQueryDescriptor<T>, IExistsQuery> selector) =>
WrapInContainer(selector, (query, container) => container.Exists = query);

Expand Down
4 changes: 4 additions & 0 deletions src/Nest/QueryDsl/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ public static QueryContainer Regexp(Func<RegexpQueryDescriptor<T>, IRegexpQuery>
public static QueryContainer Script(Func<ScriptQueryDescriptor<T>, IScriptQuery> selector) =>
new QueryContainerDescriptor<T>().Script(selector);

/// <inheritdoc cref="IScriptScoreQuery"/>
public static QueryContainer ScriptScore(Func<ScriptScoreQueryDescriptor<T>, IScriptScoreQuery> selector) =>
new QueryContainerDescriptor<T>().ScriptScore(selector);

public static QueryContainer SimpleQueryString(Func<SimpleQueryStringQueryDescriptor<T>, ISimpleQueryStringQuery> selector) =>
new QueryContainerDescriptor<T>().SimpleQueryString(selector);

Expand Down
77 changes: 77 additions & 0 deletions src/Nest/QueryDsl/Specialized/ScriptScore/ScriptScoreQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Runtime.Serialization;
using Elasticsearch.Net.Utf8Json;

namespace Nest
{
/// <summary>
/// A query allowing you to modify the score of documents that are retrieved by a query.
/// This can be useful if, for example, a score function is computationally expensive and it is sufficient to
/// compute the score on a filtered set of documents.
/// </summary>
[ReadAs(typeof(ScriptScoreQuery))]
[InterfaceDataContract]
public interface IScriptScoreQuery : IQuery
{
/// <summary>
/// The query to execute
/// </summary>
[DataMember(Name = "query")]
QueryContainer Query { get; set; }

/// <summary>
/// The script to execute
/// </summary>
[DataMember(Name = "script")]
IScript Script { get; set; }
}

/// <inheritdoc cref="IScriptScoreQuery" />
public class ScriptScoreQuery : QueryBase, IScriptScoreQuery
{
/// <inheritdoc />
public QueryContainer Query { get; set; }

/// <inheritdoc />
public IScript Script { get; set; }

protected override bool Conditionless => IsConditionless(this);

internal override void InternalWrapInContainer(IQueryContainer c) => c.ScriptScore = this;

internal static bool IsConditionless(IScriptScoreQuery q)
{
if (q.Script == null || q.Query.IsConditionless())
return true;

switch (q.Script)
{
case IInlineScript inlineScript:
return inlineScript.Source.IsNullOrEmpty();
case IIndexedScript indexedScript:
return indexedScript.Id.IsNullOrEmpty();
}

return false;
}
}

/// <inheritdoc cref="IScriptScoreQuery" />
public class ScriptScoreQueryDescriptor<T>
: QueryDescriptorBase<ScriptScoreQueryDescriptor<T>, IScriptScoreQuery>
, IScriptScoreQuery where T : class
{
protected override bool Conditionless => ScriptScoreQuery.IsConditionless(this);
QueryContainer IScriptScoreQuery.Query { get; set; }

IScript IScriptScoreQuery.Script { get; set; }

/// <inheritdoc cref="IScriptScoreQuery.Query" />
public ScriptScoreQueryDescriptor<T> Query(Func<QueryContainerDescriptor<T>, QueryContainer> selector) =>
Assign(selector, (a, v) => a.Query = v?.Invoke(new QueryContainerDescriptor<T>()));

/// <inheritdoc cref="IScriptScoreQuery.Script" />
public ScriptScoreQueryDescriptor<T> Script(Func<ScriptDescriptor, IScript> selector) =>
Assign(selector, (a, v) => a.Script = v?.Invoke(new ScriptDescriptor()));
}
}
2 changes: 2 additions & 0 deletions src/Nest/QueryDsl/Visitor/DslPrettyPrintVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ public virtual void Visit(IGeoShapeQuery query)

public virtual void Visit(IScriptQuery query) => Write("script");

public virtual void Visit(IScriptScoreQuery query) => Write("script_score");

public virtual void Visit(IRawQuery query) => Write("raw");

public virtual void Visit(IPercolateQuery query) => Write("percolate");
Expand Down
4 changes: 4 additions & 0 deletions src/Nest/QueryDsl/Visitor/QueryVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ public interface IQueryVisitor

void Visit(IScriptQuery query);

void Visit(IScriptScoreQuery query);

void Visit(IGeoPolygonQuery query);

void Visit(IGeoDistanceQuery query);
Expand Down Expand Up @@ -237,6 +239,8 @@ public virtual void Visit(ITermsQuery query) { }

public virtual void Visit(IScriptQuery query) { }

public virtual void Visit(IScriptScoreQuery query) { }

public virtual void Visit(IGeoPolygonQuery query) { }

public virtual void Visit(IGeoDistanceQuery query) { }
Expand Down
1 change: 1 addition & 0 deletions src/Nest/QueryDsl/Visitor/QueryWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public void Walk(IQueryContainer qd, IQueryVisitor visitor)
VisitQuery(qd.MatchPhrase, visitor, (v, d) => v.Visit(d));
VisitQuery(qd.MatchPhrasePrefix, visitor, (v, d) => v.Visit(d));
VisitQuery(qd.Script, visitor, (v, d) => v.Visit(d));
VisitQuery(qd.ScriptScore, visitor, (v, d) => v.Visit(d));
VisitQuery(qd.Exists, visitor, (v, d) => v.Visit(d));
VisitQuery(qd.GeoPolygon, visitor, (v, d) => v.Visit(d));
VisitQuery(qd.GeoDistance, visitor, (v, d) => v.Visit(d));
Expand Down
Loading

0 comments on commit dd6c997

Please sign in to comment.