Skip to content

Commit e7d5821

Browse files
committed
Multi Match support fixes #270
1 parent e21d51d commit e7d5821

File tree

8 files changed

+271
-47
lines changed

8 files changed

+271
-47
lines changed

src/Nest.Tests.Unit/Nest.Tests.Unit.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@
108108
<Compile Include="Internals\Inferno\MapTypeNamesTests.cs" />
109109
<Compile Include="Internals\Serialize\OptOutTests.cs" />
110110
<Compile Include="Search\Filter\Singles\HasParentFilterJson.cs" />
111+
<Compile Include="Search\Query\Singles\MultiMatch\TermQueryJson.cs" />
111112
<Compile Include="Search\Rescore\RescoreTests.cs" />
112113
<Compile Include="Search\Facets\DateHistogramFacetJson.cs" />
113114
<Compile Include="Search\Facets\FacetJson.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Reflection;
2+
using NUnit.Framework;
3+
using Nest.Tests.MockData.Domain;
4+
5+
namespace Nest.Tests.Unit.Search.Query.Singles.MultiMatch
6+
{
7+
[TestFixture]
8+
public class MultiMatchJson : BaseJsonTests
9+
{
10+
[Test]
11+
public void TestMultiMatchJson()
12+
{
13+
var s = new SearchDescriptor<ElasticSearchProject>()
14+
.From(0)
15+
.Size(10)
16+
.Query(q => q
17+
.MultiMatch(m=>m
18+
.OnFields(p=>p.Name, p=>p.Country)
19+
.QueryString("this is a query")
20+
.UseDisMax(true)
21+
.TieBreaker(0.7)
22+
)
23+
);
24+
this.JsonEquals(s, MethodInfo.GetCurrentMethod());
25+
}
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"from": 0,
3+
"size": 10,
4+
"query": {
5+
"multi_match": {
6+
"query": "this is a query",
7+
"use_dis_max": true,
8+
"tie_breaker": 0.7,
9+
"fields": [
10+
"name",
11+
"country"
12+
]
13+
}
14+
}
15+
}

src/Nest/DSL/IQueryDescriptor.cs

+48-47
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,52 @@
22
using System.Collections.Generic;
33
namespace Nest
44
{
5-
interface IQueryDescriptor<T>
6-
where T : class
7-
{
8-
BaseQuery Bool(Action<BoolQueryDescriptor<T>> booleanQuery);
9-
BaseQuery Boosting(Action<BoostingQueryDescriptor<T>> boostingQuery);
10-
BaseQuery ConstantScore(Action<ConstantScoreQueryDescriptor<T>> selector);
11-
BaseQuery CustomBoostFactor(Action<CustomBoostFactorQueryDescriptor<T>> selector);
12-
BaseQuery CustomScore(Action<CustomScoreQueryDescriptor<T>> customScoreQuery);
13-
BaseQuery Dismax(Action<DismaxQueryDescriptor<T>> selector);
14-
BaseQuery Filtered(Action<FilteredQueryDescriptor<T>> selector);
15-
BaseQuery Fuzzy(Action<FuzzyQueryDescriptor<T>> selector);
16-
BaseQuery FuzzyDate(Action<FuzzyDateQueryDescriptor<T>> selector);
17-
BaseQuery FuzzyLikeThis(Action<FuzzyLikeThisDescriptor<T>> selector);
18-
BaseQuery FuzzyNumeric(Action<FuzzyNumericQueryDescriptor<T>> selector);
19-
BaseQuery HasChild<K>(Action<HasChildQueryDescriptor<K>> selector) where K : class;
20-
BaseQuery Ids(IEnumerable<string> types, IEnumerable<string> values);
21-
BaseQuery Ids(IEnumerable<string> values);
22-
BaseQuery Ids(string type, IEnumerable<string> values);
23-
BaseQuery Indices(Action<IndicesQueryDescriptor<T>> selector);
24-
BaseQuery MatchAll(double? Boost = null, string NormField = null);
25-
BaseQuery MoreLikeThis(Action<MoreLikeThisQueryDescriptor<T>> selector);
26-
BaseQuery Nested(Action<NestedQueryDescriptor<T>> selector);
27-
BaseQuery Prefix(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
28-
BaseQuery Prefix(string field, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
29-
BaseQuery QueryString(Action<QueryStringDescriptor<T>> selector);
30-
BaseQuery Range(Action<RangeQueryDescriptor<T>> selector);
31-
BaseQuery SpanFirst(Action<SpanFirstQueryDescriptor<T>> selector);
32-
BaseQuery SpanNear(Action<SpanNearQueryDescriptor<T>> selector);
33-
BaseQuery SpanNot(Action<SpanNotQueryDescriptor<T>> selector);
34-
BaseQuery SpanOr(Action<SpanOrQueryDescriptor<T>> selector);
35-
BaseQuery SpanTerm(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null);
36-
BaseQuery SpanTerm(string field, string value, double? Boost = null);
37-
BaseQuery Term(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null);
38-
BaseQuery Term(string field, string value, double? Boost = null);
39-
BaseQuery Terms(System.Linq.Expressions.Expression<Func<T, object>> objectPath, params string[] terms);
40-
BaseQuery Terms(string field, params string[] terms);
41-
BaseQuery TermsDescriptor(Action<TermsQueryDescriptor<T>> selector);
42-
BaseQuery Text(Action<TextQueryDescriptor<T>> selector);
43-
BaseQuery TextPhrase(Action<TextPhraseQueryDescriptor<T>> selector);
44-
BaseQuery TextPhrasePrefix(Action<TextPhrasePrefixQueryDescriptor<T>> selector);
45-
BaseQuery Match(Action<MatchQueryDescriptor<T>> selector);
46-
BaseQuery MatchPhrase(Action<MatchPhraseQueryDescriptor<T>> selector);
47-
BaseQuery MatchPhrasePrefix(Action<MatchPhrasePrefixQueryDescriptor<T>> selector);
48-
BaseQuery TopChildren<K>(Action<TopChildrenQueryDescriptor<K>> selector) where K : class;
49-
BaseQuery Wildcard(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
50-
BaseQuery Wildcard(string field, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
51-
}
5+
interface IQueryDescriptor<T>
6+
where T : class
7+
{
8+
BaseQuery Bool(Action<BoolQueryDescriptor<T>> booleanQuery);
9+
BaseQuery Boosting(Action<BoostingQueryDescriptor<T>> boostingQuery);
10+
BaseQuery ConstantScore(Action<ConstantScoreQueryDescriptor<T>> selector);
11+
BaseQuery CustomBoostFactor(Action<CustomBoostFactorQueryDescriptor<T>> selector);
12+
BaseQuery CustomScore(Action<CustomScoreQueryDescriptor<T>> customScoreQuery);
13+
BaseQuery Dismax(Action<DismaxQueryDescriptor<T>> selector);
14+
BaseQuery Filtered(Action<FilteredQueryDescriptor<T>> selector);
15+
BaseQuery Fuzzy(Action<FuzzyQueryDescriptor<T>> selector);
16+
BaseQuery FuzzyDate(Action<FuzzyDateQueryDescriptor<T>> selector);
17+
BaseQuery FuzzyLikeThis(Action<FuzzyLikeThisDescriptor<T>> selector);
18+
BaseQuery FuzzyNumeric(Action<FuzzyNumericQueryDescriptor<T>> selector);
19+
BaseQuery HasChild<K>(Action<HasChildQueryDescriptor<K>> selector) where K : class;
20+
BaseQuery Ids(IEnumerable<string> types, IEnumerable<string> values);
21+
BaseQuery Ids(IEnumerable<string> values);
22+
BaseQuery Ids(string type, IEnumerable<string> values);
23+
BaseQuery Indices(Action<IndicesQueryDescriptor<T>> selector);
24+
BaseQuery MatchAll(double? Boost = null, string NormField = null);
25+
BaseQuery MoreLikeThis(Action<MoreLikeThisQueryDescriptor<T>> selector);
26+
BaseQuery Nested(Action<NestedQueryDescriptor<T>> selector);
27+
BaseQuery Prefix(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
28+
BaseQuery Prefix(string field, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
29+
BaseQuery QueryString(Action<QueryStringDescriptor<T>> selector);
30+
BaseQuery Range(Action<RangeQueryDescriptor<T>> selector);
31+
BaseQuery SpanFirst(Action<SpanFirstQueryDescriptor<T>> selector);
32+
BaseQuery SpanNear(Action<SpanNearQueryDescriptor<T>> selector);
33+
BaseQuery SpanNot(Action<SpanNotQueryDescriptor<T>> selector);
34+
BaseQuery SpanOr(Action<SpanOrQueryDescriptor<T>> selector);
35+
BaseQuery SpanTerm(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null);
36+
BaseQuery SpanTerm(string field, string value, double? Boost = null);
37+
BaseQuery Term(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null);
38+
BaseQuery Term(string field, string value, double? Boost = null);
39+
BaseQuery Terms(System.Linq.Expressions.Expression<Func<T, object>> objectPath, params string[] terms);
40+
BaseQuery Terms(string field, params string[] terms);
41+
BaseQuery TermsDescriptor(Action<TermsQueryDescriptor<T>> selector);
42+
BaseQuery Text(Action<TextQueryDescriptor<T>> selector);
43+
BaseQuery TextPhrase(Action<TextPhraseQueryDescriptor<T>> selector);
44+
BaseQuery TextPhrasePrefix(Action<TextPhrasePrefixQueryDescriptor<T>> selector);
45+
BaseQuery Match(Action<MatchQueryDescriptor<T>> selector);
46+
BaseQuery MatchPhrase(Action<MatchPhraseQueryDescriptor<T>> selector);
47+
BaseQuery MatchPhrasePrefix(Action<MatchPhrasePrefixQueryDescriptor<T>> selector);
48+
BaseQuery MultiMatch(Action<MultiMatchQueryDescriptor<T>> selector);
49+
BaseQuery TopChildren<K>(Action<TopChildrenQueryDescriptor<K>> selector) where K : class;
50+
BaseQuery Wildcard(System.Linq.Expressions.Expression<Func<T, object>> fieldDescriptor, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
51+
BaseQuery Wildcard(string field, string value, double? Boost = null, RewriteMultiTerm? Rewrite = null);
52+
}
5253
}

src/Nest/DSL/Query.cs

+6
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,12 @@ public static BaseQuery MatchPhrasePrefix(Action<MatchPhrasePrefixQueryDescripto
217217
return new QueryDescriptor<T>().MatchPhrasePrefix(selector);
218218
}
219219

220+
public static BaseQuery MultiMatch(Action<MultiMatchQueryDescriptor<T>> selector)
221+
{
222+
return new QueryDescriptor<T>().MultiMatch(selector);
223+
}
224+
225+
220226
public static BaseQuery TopChildren<K>(Action<TopChildrenQueryDescriptor<K>> selector) where K : class
221227
{
222228
return new QueryDescriptor<T>().TopChildren<K>(selector);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using Newtonsoft.Json;
6+
using Newtonsoft.Json.Converters;
7+
using System.Linq.Expressions;
8+
using Nest.Resolvers;
9+
10+
namespace Nest
11+
{
12+
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
13+
public class MultiMatchQueryDescriptor<T> : IQuery where T : class
14+
{
15+
[JsonProperty(PropertyName = "type")]
16+
internal virtual string _Type { get { return null; } }
17+
18+
[JsonProperty(PropertyName = "query")]
19+
internal string _Query { get; set; }
20+
21+
[JsonProperty(PropertyName = "analyzer")]
22+
internal string _Analyzer { get; set; }
23+
24+
[JsonProperty(PropertyName = "rewrite")]
25+
[JsonConverter(typeof(StringEnumConverter))]
26+
internal RewriteMultiTerm? _Rewrite { get; set; }
27+
28+
[JsonProperty(PropertyName = "fuzziness")]
29+
internal double? _Fuzziness { get; set; }
30+
31+
[JsonProperty(PropertyName = "cutoff_frequency")]
32+
internal double? _CutoffFrequency { get; set; }
33+
34+
[JsonProperty(PropertyName = "prefix_length")]
35+
internal int? _PrefixLength { get; set; }
36+
37+
[JsonProperty(PropertyName = "max_expansions")]
38+
internal int? _MaxExpansions { get; set; }
39+
40+
[JsonProperty(PropertyName = "slop")]
41+
internal int? _Slop { get; set; }
42+
43+
[JsonProperty(PropertyName = "boost")]
44+
internal double? _Boost { get; set; }
45+
46+
[JsonProperty(PropertyName = "use_dis_max")]
47+
internal bool? _UseDisMax { get; set; }
48+
49+
[JsonProperty(PropertyName = "tie_breaker")]
50+
internal double? _TieBreaker { get; set; }
51+
52+
53+
[JsonProperty(PropertyName = "operator")]
54+
[JsonConverter(typeof(StringEnumConverter))]
55+
internal Operator? _Operator { get; set; }
56+
57+
internal bool IsConditionless
58+
{
59+
get
60+
{
61+
return !this._Fields.HasAny() || this._Query.IsNullOrEmpty();
62+
}
63+
}
64+
65+
[JsonProperty(PropertyName = "fields")]
66+
internal IEnumerable<string> _Fields { get; set; }
67+
68+
public MultiMatchQueryDescriptor<T> OnFields(IEnumerable<string> fields)
69+
{
70+
this._Fields = fields;
71+
return this;
72+
}
73+
public MultiMatchQueryDescriptor<T> OnFields(
74+
params Expression<Func<T, object>>[] objectPaths)
75+
{
76+
var fieldNames = objectPaths
77+
.Select(o => new PropertyNameResolver().Resolve(o));
78+
return this.OnFields(fieldNames);
79+
}
80+
81+
public MultiMatchQueryDescriptor<T> QueryString(string queryString)
82+
{
83+
this._Query = queryString;
84+
return this;
85+
}
86+
public MultiMatchQueryDescriptor<T> Analyzer(string analyzer)
87+
{
88+
analyzer.ThrowIfNullOrEmpty("analyzer");
89+
this._Analyzer = analyzer;
90+
return this;
91+
}
92+
public MultiMatchQueryDescriptor<T> Fuzziness(double fuzziness)
93+
{
94+
fuzziness.ThrowIfNull("fuzziness");
95+
this._Fuzziness = fuzziness;
96+
return this;
97+
}
98+
public MultiMatchQueryDescriptor<T> CutoffFrequency(double cutoffFrequency)
99+
{
100+
cutoffFrequency.ThrowIfNull("cutoffFrequency");
101+
this._CutoffFrequency = cutoffFrequency;
102+
return this;
103+
}
104+
105+
public MultiMatchQueryDescriptor<T> Rewrite(RewriteMultiTerm rewrite)
106+
{
107+
rewrite.ThrowIfNull("rewrite");
108+
this._Rewrite = rewrite;
109+
return this;
110+
}
111+
112+
public MultiMatchQueryDescriptor<T> Boost(double boost)
113+
{
114+
boost.ThrowIfNull("boost");
115+
this._Boost = boost;
116+
return this;
117+
}
118+
public MultiMatchQueryDescriptor<T> PrefixLength(int prefixLength)
119+
{
120+
prefixLength.ThrowIfNull("prefixLength");
121+
this._PrefixLength = prefixLength;
122+
return this;
123+
}
124+
public MultiMatchQueryDescriptor<T> MaxExpansions(int maxExpansions)
125+
{
126+
maxExpansions.ThrowIfNull("maxExpansions");
127+
this._MaxExpansions = maxExpansions;
128+
return this;
129+
}
130+
public MultiMatchQueryDescriptor<T> Slop(int slop)
131+
{
132+
slop.ThrowIfNull("slop");
133+
this._Slop = slop;
134+
return this;
135+
}
136+
public MultiMatchQueryDescriptor<T> Operator(Operator op)
137+
{
138+
this._Operator = op;
139+
return this;
140+
}
141+
142+
public MultiMatchQueryDescriptor<T> UseDisMax(bool useDismax)
143+
{
144+
this._UseDisMax = useDismax;
145+
return this;
146+
}
147+
148+
public MultiMatchQueryDescriptor<T> TieBreaker(double tieBreaker)
149+
{
150+
this._TieBreaker = tieBreaker;
151+
return this;
152+
}
153+
}
154+
}

src/Nest/DSL/QueryDescriptor.cs

+19
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ public QueryDescriptor()
4949
internal FilteredQueryDescriptor<T> FilteredQueryDescriptor { get; set; }
5050
[JsonProperty(PropertyName = "text")]
5151
internal IDictionary<string, object> TextQueryDescriptor { get; set; }
52+
[JsonProperty(PropertyName = "multi_match")]
53+
internal MultiMatchQueryDescriptor<T> MultiMatchQueryDescriptor { get; set; }
5254
[JsonProperty(PropertyName = "match")]
5355
internal IDictionary<string, object> MatchQueryDescriptor { get; set; }
5456
[JsonProperty(PropertyName = "fuzzy")]
@@ -394,6 +396,23 @@ public BaseQuery MatchPhrasePrefix(Action<MatchPhrasePrefixQueryDescriptor<T>> s
394396
return new QueryDescriptor<T> { MatchQueryDescriptor = this.MatchQueryDescriptor };
395397
}
396398

399+
/// <summary>
400+
//The multi_match query builds further on top of the match query by allowing multiple fields to be specified.
401+
//The idea here is to allow to more easily build a concise match type query over multiple fields instead of using a
402+
//relatively more expressive query by using multiple match queries within a bool query.
403+
/// </summary>
404+
public BaseQuery MultiMatch(Action<MultiMatchQueryDescriptor<T>> selector)
405+
{
406+
var query = new MultiMatchQueryDescriptor<T>();
407+
selector(query);
408+
409+
if (query.IsConditionless)
410+
return CreateConditionlessQueryDescriptor(query);
411+
412+
this.MultiMatchQueryDescriptor = query;
413+
return new QueryDescriptor<T> { MultiMatchQueryDescriptor = this.MultiMatchQueryDescriptor };
414+
}
415+
397416
/// <summary>
398417
/// Nested query allows to query nested objects / docs (see nested mapping). The query is executed against the
399418
/// nested objects / docs as if they were indexed as separate docs (they are, internally) and resulting in the

src/Nest/Nest.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
<Compile Include="DSL\Filter\HasParentFilterDescriptor.cs" />
7474
<Compile Include="DSL\PercolatorDescriptor.cs" />
7575
<Compile Include="DSL\PercolateDescriptor.cs" />
76+
<Compile Include="DSL\Query\MultiMatchQueryDescriptor.cs" />
7677
<Compile Include="Extensions\NameValueCollectionExtensions.cs" />
7778
<Compile Include="Extensions\StringExtensions.cs" />
7879
<Compile Include="Extensions\TypeExtensions.cs" />

0 commit comments

Comments
 (0)