Skip to content
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
1 change: 1 addition & 0 deletions src/Nest.Tests.Unit/Nest.Tests.Unit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
<Compile Include="Internals\Inferno\MapTypeNamesTests.cs" />
<Compile Include="Internals\Serialize\OptOutTests.cs" />
<Compile Include="Search\Filter\Singles\HasParentFilterJson.cs" />
<Compile Include="Search\Query\Singles\FunctionScoreQueryJson.cs" />
<Compile Include="Search\Query\Singles\HasParentQueryJson.cs" />
<Compile Include="Search\Query\Singles\MultiMatch\MultiMatchJson.cs" />
<Compile Include="Search\Query\Singles\Term\TermToStringJson.cs" />
Expand Down
47 changes: 47 additions & 0 deletions src/Nest.Tests.Unit/Search/Query/Singles/FunctionScoreQueryJson.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using NUnit.Framework;
using Nest.DSL.Query;
using Nest.Tests.MockData.Domain;

namespace Nest.Tests.Unit.Search.Query.Singles
{
[TestFixture]
public class FunctionScoreQueryTests
{
[Test]
public void FunctionScoreQuery()
{
var s = new SearchDescriptor<ElasticSearchProject>().From(0).Size(10)
.Query(q => q
.FunctionScore(fs => fs
.Query(qq => qq.MatchAll())
.Functions(
f => f.Gauss(x=>x.StartedOn, d=>d.Scale("42w")),
f => f.Linear(x => x.FloatValue, d => d.Scale("0.3")),
f => f.Exp(x => x.DoubleValue, d => d.Scale("0.5")),
f => f.BoostFactor(2)
)
.ScoreMode(FunctionScoreMode.sum)
)
).Fields(x=>x.Content);

var json = TestElasticClient.Serialize(s);
var expected = @"{
from: 0, size: 10,
query : {
function_score : {
functions: [
{gauss: { startedOn : { scale: '42w'}}},
{linear: { floatValue : { scale: '0.3'}}},
{exp: { doubleValue: { scale: '0.5'}}},
{boost_factor: 2.0 }
],
query : { match_all : {} },
score_mode: 'sum'
}
},
fields: [""content""]
}";
Assert.True(json.JsonEquals(expected), json);
}
}
}
6 changes: 6 additions & 0 deletions src/Nest/DSL/Query.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nest.DSL.Query;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Nest.Resolvers.Converters;
Expand Down Expand Up @@ -237,6 +238,11 @@ public static BaseQuery Wildcard(string field, string value, double? Boost = nul
{
return new QueryDescriptor<T>().Wildcard(field, value, Boost);
}

public static BaseQuery FunctionScore(Action<FunctionScoreQueryDescriptor<T>> functionScoreQuery)
{
return new QueryDescriptor<T>().FunctionScore(functionScoreQuery);
}
}


Expand Down
242 changes: 242 additions & 0 deletions src/Nest/DSL/Query/FunctionScoreQueryDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Nest.Resolvers;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Nest.DSL.Query
{
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class FunctionScoreQueryDescriptor<T> : IQuery where T : class
{
[JsonProperty(PropertyName = "functions")]
internal IEnumerable<FunctionScoreFunction<T>> _Functions { get; set; }

[JsonProperty(PropertyName = "query")]
internal BaseQuery _Query { get; set; }

[JsonProperty(PropertyName = "score_mode")]
[JsonConverter(typeof(StringEnumConverter))]
FunctionScoreMode _ScoreMode { get; set; }


internal bool IsConditionless
{
get
{
return this._Query == null || this._Query.IsConditionless;
}
}

public FunctionScoreQueryDescriptor<T> Query(Func<QueryDescriptor<T>, BaseQuery> querySelector)
{
querySelector.ThrowIfNull("querySelector");
var query = new QueryDescriptor<T>();
var q = querySelector(query);

this._Query = q;
return this;
}

public FunctionScoreQueryDescriptor<T> Functions(params Func<FunctionScoreFunctionsDescriptor<T>, FunctionScoreFunction<T>>[] functions)
{
var descriptor = new FunctionScoreFunctionsDescriptor<T>();

foreach (var f in functions)
{
f(descriptor);
}

_Functions = descriptor;

return this;
}

public FunctionScoreQueryDescriptor<T> ScoreMode(FunctionScoreMode mode)
{
this._ScoreMode = mode;
return this;
}
}

public enum FunctionScoreMode
{
multiply,
sum,
avg,
first,
max,
min
}

public class FunctionScoreFunctionsDescriptor<T> : IEnumerable<FunctionScoreFunction<T>>
{
internal List<FunctionScoreFunction<T>> _Functions { get; set; }

public FunctionScoreFunctionsDescriptor()
{
this._Functions = new List<FunctionScoreFunction<T>>();
}

public FunctionScoreFunction<T> Gauss(Expression<Func<T, object>> objectPath, Action<FunctionScoreDecayFieldDescriptor> db)
{
var fn = new GaussFunction<T>(objectPath, db);
this._Functions.Add(fn);
return fn;
}

public FunctionScoreFunction<T> Linear(Expression<Func<T, object>> objectPath, Action<FunctionScoreDecayFieldDescriptor> db)
{
var fn = new LinearFunction<T>(objectPath, db);
this._Functions.Add(fn);
return fn;
}

public FunctionScoreFunction<T> Exp(Expression<Func<T, object>> objectPath, Action<FunctionScoreDecayFieldDescriptor> db)
{
var fn = new ExpFunction<T>(objectPath, db);
this._Functions.Add(fn);
return fn;
}

public BoostFactorFunction<T> BoostFactor(double value)
{
var fn = new BoostFactorFunction<T>(value);
this._Functions.Add(fn);
return fn;
}


public IEnumerator<FunctionScoreFunction<T>> GetEnumerator()
{
return _Functions.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator()
{
return _Functions.GetEnumerator();
}
}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class FunctionScoreFunction<T>
{
}

public class FunctionScoreDecayFieldDescriptor
{
[JsonProperty(PropertyName = "origin")]
internal string _Origin { get; set; }

[JsonProperty(PropertyName = "scale")]
internal string _Scale { get; set; }

[JsonProperty(PropertyName = "offset")]
internal string _Offset { get; set; }

[JsonProperty(PropertyName = "decay")]
internal double? _Decay { get; set; }

public FunctionScoreDecayFieldDescriptor Origin(string origin)
{
this._Origin = origin;
return this;
}

public FunctionScoreDecayFieldDescriptor Scale(string scale)
{
this._Scale = scale;
return this;
}

public FunctionScoreDecayFieldDescriptor Offset(string offset)
{
this._Offset = offset;
return this;
}

public FunctionScoreDecayFieldDescriptor Decay(double? decay)
{
this._Decay = decay;
return this;
}
}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class FunctionScoreDecayFunction<T> : FunctionScoreFunction<T>
{
}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class GaussFunction<T> : FunctionScoreDecayFunction<T>
{
[JsonProperty(PropertyName = "gauss")]
[JsonConverter(typeof(DictionaryKeysAreNotPropertyNamesJsonConverter))]
internal IDictionary<string, FunctionScoreDecayFieldDescriptor> _GaussDescriptor { get; set; }

public GaussFunction(Expression<Func<T, object>> objectPath, Action<FunctionScoreDecayFieldDescriptor> descriptorBuilder)
{
_GaussDescriptor = new Dictionary<string, FunctionScoreDecayFieldDescriptor>();

var resolver = new PropertyNameResolver();
var fieldName = resolver.Resolve(objectPath);
var descriptor = new FunctionScoreDecayFieldDescriptor();
descriptorBuilder(descriptor);
_GaussDescriptor[fieldName] = descriptor;
}
}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class LinearFunction<T> : FunctionScoreDecayFunction<T>
{
[JsonProperty(PropertyName = "linear")]
[JsonConverter(typeof(DictionaryKeysAreNotPropertyNamesJsonConverter))]
internal IDictionary<string, FunctionScoreDecayFieldDescriptor> _LinearDescriptor { get; set; }

public LinearFunction(Expression<Func<T, object>> objectPath, Action<FunctionScoreDecayFieldDescriptor> descriptorBuilder)
{
_LinearDescriptor = new Dictionary<string, FunctionScoreDecayFieldDescriptor>();

var resolver = new PropertyNameResolver();
var fieldName = resolver.Resolve(objectPath);
var descriptor = new FunctionScoreDecayFieldDescriptor();
descriptorBuilder(descriptor);
_LinearDescriptor[fieldName] = descriptor;
}
}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class ExpFunction<T> : FunctionScoreDecayFunction<T>
{
[JsonProperty(PropertyName = "exp")]
[JsonConverter(typeof(DictionaryKeysAreNotPropertyNamesJsonConverter))]
internal IDictionary<string, FunctionScoreDecayFieldDescriptor> _ExpDescriptor { get; set; }

public ExpFunction(Expression<Func<T, object>> objectPath, Action<FunctionScoreDecayFieldDescriptor> descriptorBuilder)
{
_ExpDescriptor = new Dictionary<string, FunctionScoreDecayFieldDescriptor>();

var resolver = new PropertyNameResolver();
var fieldName = resolver.Resolve(objectPath);
var descriptor = new FunctionScoreDecayFieldDescriptor();
descriptorBuilder(descriptor);
_ExpDescriptor[fieldName] = descriptor;
}
}

[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class BoostFactorFunction<T> : FunctionScoreFunction<T>
{
[JsonProperty(PropertyName = "boost_factor")]
internal double _BoostFactor { get; set; }

public BoostFactorFunction(double boostFactor)
{
_BoostFactor = boostFactor;
}
}
}
22 changes: 21 additions & 1 deletion src/Nest/DSL/QueryDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nest.DSL.Query;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Nest.Resolvers.Converters;
Expand Down Expand Up @@ -35,6 +36,9 @@ public QueryDescriptor()
internal BoostingQueryDescriptor<T> BoostingQueryDescriptor { get; set; }
[JsonProperty(PropertyName = "ids")]
internal IdsQuery IdsQuery { get; set; }

[JsonProperty(PropertyName = "function_score")]
internal FunctionScoreQueryDescriptor<T> FunctionScoreQueryDescriptor { get; set; }
[JsonProperty(PropertyName = "custom_score")]
internal CustomScoreQueryDescriptor<T> CustomScoreQueryDescriptor { get; set; }
[JsonProperty(PropertyName = "custom_filters_score")]
Expand Down Expand Up @@ -128,6 +132,7 @@ internal QueryDescriptor<T> Clone()

BoostingQueryDescriptor = BoostingQueryDescriptor,
IdsQuery = IdsQuery,
FunctionScoreQueryDescriptor = FunctionScoreQueryDescriptor,
CustomScoreQueryDescriptor = CustomScoreQueryDescriptor,
CustomBoostFactorQueryDescriptor = CustomBoostFactorQueryDescriptor,
ConstantScoreQueryDescriptor = ConstantScoreQueryDescriptor,
Expand Down Expand Up @@ -939,5 +944,20 @@ public BaseQuery SpanNot(Action<SpanNotQueryDescriptor<T>> selector)
return new QueryDescriptor<T> { SpanNotQueryDescriptor = this.SpanNotQueryDescriptor };
}

}
/// <summary>
/// Function score query
/// </summary>
/// <returns></returns>
public BaseQuery FunctionScore(Action<FunctionScoreQueryDescriptor<T>> functionScoreQuery)
{
var query = new FunctionScoreQueryDescriptor<T>();
functionScoreQuery(query);

if (query.IsConditionless)
return CreateConditionlessQueryDescriptor(query);

this.FunctionScoreQueryDescriptor = query;
return new QueryDescriptor<T> { FunctionScoreQueryDescriptor = this.FunctionScoreQueryDescriptor };
}
}
}
1 change: 1 addition & 0 deletions src/Nest/Nest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<ItemGroup>
<Compile Include="Domain\Connection\AsyncRequestOperation.cs" />
<Compile Include="Domain\Responses\RootVersionInfoResponse.cs" />
<Compile Include="DSL\Query\FunctionScoreQueryDescriptor.cs" />
<Compile Include="ExposedInternals\ElasticInferrer.cs" />
<Compile Include="ExposedInternals\ElasticSerializer.cs" />
<Compile Include="Exception\ConnectionException.cs" />
Expand Down