Skip to content

Implemented _suggest endpoint as .Suggest() fix #397 and fix #518 #568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 8, 2014
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: 0 additions & 1 deletion src/Nest/DSL/SearchDescriptor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,6 @@ public SearchDescriptor<T> SuggestGlobalText(string globalSuggestText)
return this;
}


/// <summary>
/// The term suggester suggests terms based on edit distance. The provided suggest text is analyzed before terms are suggested.
/// The suggested terms are provided per analyzed suggest text token. The term suggester doesn’t take the query into account that is part of request.
Expand Down
90 changes: 90 additions & 0 deletions src/Nest/DSL/SuggestDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Elasticsearch.Net;
using Newtonsoft.Json;
using System.Linq.Expressions;
using Nest.Resolvers;
using Nest.Domain;

namespace Nest
{
[DescriptorFor("Suggest")]
public partial class SuggestDescriptor<T> :
IndicesOptionalPathDescriptor<SuggestDescriptor<T>, SuggestRequestParameters>
, IPathInfo<SuggestRequestParameters>
where T : class
{
internal IDictionary<string, object> _Suggest = new Dictionary<string, object>();

/// <summary>
/// To avoid repetition of the suggest text, it is possible to define a global text.
/// </summary>
public SuggestDescriptor<T> GlobalText(string globalSuggestText)
{
this._Suggest.Add("text", globalSuggestText);
return this;
}

/// <summary>
/// The term suggester suggests terms based on edit distance. The provided suggest text is analyzed before terms are suggested.
/// The suggested terms are provided per analyzed suggest text token. The term suggester doesn’t take the query into account that is part of request.
/// </summary>
public SuggestDescriptor<T> Term(string name, Func<TermSuggestDescriptor<T>, TermSuggestDescriptor<T>> suggest)
{
name.ThrowIfNullOrEmpty("name");
suggest.ThrowIfNull("suggest");
var desc = new TermSuggestDescriptor<T>();
var item = suggest(desc);
var bucket = new SuggestDescriptorBucket<T> { _Text = item._Text, TermSuggest = item };
this._Suggest.Add(name, bucket);
return this;
}

/// <summary>
/// The phrase suggester adds additional logic on top of the term suggester to select entire corrected phrases
/// instead of individual tokens weighted based on ngram-langugage models.
/// </summary>
public SuggestDescriptor<T> Phrase(string name, Func<PhraseSuggestDescriptor<T>, PhraseSuggestDescriptor<T>> suggest)
{
name.ThrowIfNullOrEmpty("name");
suggest.ThrowIfNull("suggest");
if (this._Suggest == null)
this._Suggest = new Dictionary<string, object>();

var desc = new PhraseSuggestDescriptor<T>();
var item = suggest(desc);
var bucket = new SuggestDescriptorBucket<T> { _Text = item._Text, PhraseSuggest = item };
this._Suggest.Add(name, bucket);
return this;
}

/// <summary>
/// The completion suggester is a so-called prefix suggester.
/// It does not do spell correction like the term or phrase suggesters but allows basic auto-complete functionality.
/// </summary>
public SuggestDescriptor<T> Completion(string name, Func<CompletionSuggestDescriptor<T>, CompletionSuggestDescriptor<T>> suggest)
{
name.ThrowIfNullOrEmpty("name");
suggest.ThrowIfNull("suggest");
if (this._Suggest == null)
this._Suggest = new Dictionary<string, object>();

var desc = new CompletionSuggestDescriptor<T>();
var item = suggest(desc);
var bucket = new SuggestDescriptorBucket<T> { _Text = item._Text, CompletionSuggest = item };
this._Suggest.Add(name, bucket);
return this;
}

ElasticsearchPathInfo<SuggestRequestParameters> IPathInfo<SuggestRequestParameters>.ToPathInfo(IConnectionSettingsValues settings)
{
var pathInfo = base.ToPathInfo<SuggestRequestParameters>(settings, this._QueryString);
pathInfo.HttpMethod = PathInfoHttpMethod.POST;

return pathInfo;
}
}
}
14 changes: 7 additions & 7 deletions src/Nest/DSL/_Descriptors.generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4788,53 +4788,53 @@ public SnapshotRestoreDescriptor WaitForCompletion(bool wait_for_completion = tr
///http://www.elasticsearch.org/guide/en/elasticsearch/reference/1.x/search-search.html
///</pre>
///</summary>
public partial class SuggestDescriptor
public partial class SuggestDescriptor<T>
{
internal SuggestRequestParameters _QueryString = new SuggestRequestParameters();


///<summary>Whether specified concrete indices should be ignored when unavailable (missing or closed)</summary>
public SuggestDescriptor IgnoreUnavailable(bool ignore_unavailable = true)
public SuggestDescriptor<T> IgnoreUnavailable(bool ignore_unavailable = true)
{
this._QueryString.IgnoreUnavailable(ignore_unavailable);
return this;
}


///<summary>Whether to ignore if a wildcard indices expression resolves into no concrete indices. (This includes `_all` string or when no indices have been specified)</summary>
public SuggestDescriptor AllowNoIndices(bool allow_no_indices = true)
public SuggestDescriptor<T> AllowNoIndices(bool allow_no_indices = true)
{
this._QueryString.AllowNoIndices(allow_no_indices);
return this;
}


///<summary>Whether to expand wildcard expression to concrete indices that are open, closed or both.</summary>
public SuggestDescriptor ExpandWildcards(ExpandWildcardsOptions expand_wildcards)
public SuggestDescriptor<T> ExpandWildcards(ExpandWildcardsOptions expand_wildcards)
{
this._QueryString.ExpandWildcards(expand_wildcards);
return this;
}


///<summary>Specify the node or shard the operation should be performed on (default: random)</summary>
public SuggestDescriptor Preference(string preference)
public SuggestDescriptor<T> Preference(string preference)
{
this._QueryString.Preference(preference);
return this;
}


///<summary>Specific routing value</summary>
public SuggestDescriptor Routing(string routing)
public SuggestDescriptor<T> Routing(string routing)
{
this._QueryString.Routing(routing);
return this;
}


///<summary>The URL-encoded request definition (instead of using request body)</summary>
public SuggestDescriptor Source(string source)
public SuggestDescriptor<T> Source(string source)
{
this._QueryString.Source(source);
return this;
Expand Down
26 changes: 26 additions & 0 deletions src/Nest/Domain/Responses/SuggestResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;

namespace Nest
{
public interface ISuggestResponse : IResponse
{
ShardsMetaData Shards { get; }
IDictionary<string, Suggest[]> Suggestions { get; set; }
}

[JsonObject]
public class SuggestResponse : BaseResponse, ISuggestResponse
{
public SuggestResponse()
{
this.IsValid = true;
this.Suggestions = new Dictionary<string, Suggest[]>();
}

public ShardsMetaData Shards { get; internal set; }

public IDictionary<string, Suggest[]> Suggestions { get; set;}
}
}
31 changes: 31 additions & 0 deletions src/Nest/ElasticClient-Suggest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Elasticsearch.Net;

namespace Nest
{
public partial class ElasticClient
{
/// <inheritdoc />
public ISuggestResponse Suggest<T>(Func<SuggestDescriptor<T>, SuggestDescriptor<T>> selector)
where T : class
{
return this.Dispatch<SuggestDescriptor<T>, SuggestRequestParameters, SuggestResponse>(
selector,
(p, d) => this.RawDispatch.SuggestDispatch<SuggestResponse>(p, d._Suggest)
);
}

/// <inheritdoc />
public Task<ISuggestResponse> SuggestAsync<T>(Func<SuggestDescriptor<T>, SuggestDescriptor<T>> selector)
where T : class
{
return this.DispatchAsync<SuggestDescriptor<T>, SuggestRequestParameters, SuggestResponse, ISuggestResponse>(
selector,
(p, d) => this.RawDispatch.SuggestDispatchAsync<SuggestResponse>(p, d._Suggest)
);
}
}
}
18 changes: 18 additions & 0 deletions src/Nest/IElasticClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -990,5 +990,23 @@ Task<IBulkResponse> IndexManyAsync<T>(IEnumerable<T> objects, string index = nul
/// </summary>
/// <param name="selector">An optional descriptor that further describes the status operation, i.e limiting it to certain indices</param>
Task<IStatusResponse> StatusAsync(Func<IndicesStatusDescriptor, IndicesStatusDescriptor> selector = null);

/// <summary>
/// The suggest feature suggests similar looking terms based on a provided text by using a suggester.
/// <para> </para>http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-status.html
/// </summary>
/// <typeparam name="T">The type used to strongly type parts of the suggest operation</typeparam>
/// <param name="selector">The suggesters to use this operation (can be multiple)</param>
ISuggestResponse Suggest<T>(Func<SuggestDescriptor<T>, SuggestDescriptor<T>> selector)
where T : class;

/// <summary>
/// The suggest feature suggests similar looking terms based on a provided text by using a suggester.
/// <para> </para>http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-status.html
/// </summary>
/// <typeparam name="T">The type used to strongly type parts of the suggest operation</typeparam>
/// <param name="selector">The suggesters to use this operation (can be multiple)</param>
Task<ISuggestResponse> SuggestAsync<T>(Func<SuggestDescriptor<T>, SuggestDescriptor<T>> selector)
where T : class;
}
}
4 changes: 4 additions & 0 deletions src/Nest/Nest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
<Compile Include="Domain\Bulk\BulkUpdateBody.cs" />
<Compile Include="Domain\Alias\IndexAliases.cs" />
<Compile Include="Domain\Responses\IShardsOperationResponse.cs" />
<Compile Include="Domain\Responses\SuggestResponse.cs" />
<Compile Include="DSL\Aggregations\AggregationDescriptor.cs" />
<Compile Include="DSL\Aggregations\BucketAggregationBaseDescriptor.cs" />
<Compile Include="DSL\Aggregations\DateHistogramAggregationDescriptor.cs" />
Expand All @@ -164,6 +165,7 @@
<Compile Include="DSL\Aggregations\SignificantTermsAggregationDescriptor.cs" />
<Compile Include="DSL\Aggregations\TermsAggregationDescriptor.cs" />
<Compile Include="DSL\Aggregations\ValueCountAggregationDescriptor.cs" />
<Compile Include="DSL\SuggestDescriptor.cs" />
<Compile Include="DSL\CloseIndexDescriptor.cs" />
<Compile Include="DSL\ClusterStateDescriptor.cs" />
<Compile Include="DSL\ClearCacheDescriptor.cs" />
Expand Down Expand Up @@ -220,6 +222,7 @@
<Compile Include="DSL\ScrollDescriptor.cs" />
<Compile Include="DSL\UpdateSettingsDescriptor.cs" />
<Compile Include="DSL\Paths\IndexOptionalPathDescriptor.cs" />
<Compile Include="ElasticClient-Suggest.cs" />
<Compile Include="ElasticClient-RootNodeInfo.cs" />
<Compile Include="ElasticClient-UpdateSettings.cs" />
<Compile Include="DSL\ISimpleGetDescriptor.cs" />
Expand Down Expand Up @@ -668,6 +671,7 @@
<Compile Include="Resolvers\Converters\BulkOperationResponseItemConverter.cs" />
<Compile Include="Resolvers\Converters\AggregationConverter.cs" />
<Compile Include="Resolvers\Converters\IndexSettingsResponseConverter.cs" />
<Compile Include="Resolvers\Converters\SuggestResponseConverter.cs" />
<Compile Include="Resolvers\Converters\PropertyPathMarkerConverter.cs" />
<Compile Include="Resolvers\Converters\DynamicMappingOptionConverter.cs" />
<Compile Include="Resolvers\Converters\DictionaryKeysAreNotPropertyNamesJsonConverter.cs" />
Expand Down
40 changes: 40 additions & 0 deletions src/Nest/Resolvers/Converters/SuggestResponseConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Elasticsearch.Net;
using Elasticsearch.Net.Connection;
using Nest.Domain;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Reflection;

namespace Nest.Resolvers.Converters
{

public class SuggestResponseConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var response = new SuggestResponse();
var jsonObject = JObject.Load(reader);
foreach (var prop in jsonObject.Properties())
{
if (prop.Name == "_shards")
response.Shards = prop.Value.ToObject<ShardsMetaData>();
else
response.Suggestions.Add(prop.Name, prop.Value.ToObject<Suggest[]>());
}

return response;
}

public override bool CanConvert(Type objectType)
{
return true;
}
}
}
3 changes: 3 additions & 0 deletions src/Nest/Resolvers/ElasticContractResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ protected override JsonContract CreateContract(Type objectType)
if (objectType == typeof(PropertyPathMarker))
contract.Converter = new PropertyPathMarkerConverter(this.ConnectionSettings);

if (objectType == typeof(SuggestResponse))
contract.Converter = new SuggestResponseConverter();

if (objectType == typeof(MultiSearchResponse))
contract.Converter = new MultiSearchConverter();

Expand Down
44 changes: 44 additions & 0 deletions src/Tests/Nest.Tests.Integration/Core/Suggest/SuggestTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Linq;
using FluentAssertions;
using NUnit.Framework;
using Nest.Tests.MockData.Domain;
using Nest.Resolvers;
using Elasticsearch.Net;

namespace Nest.Tests.Integration.Core.Suggest
{
[TestFixture]
public class SuggestTests : IntegrationTests
{
[Test]
public void TestSuggest()
{
var country = this._client.Search<ElasticsearchProject>(s => s.Size(1)).Documents.First().Country;
var wrongCountry = country + "x";

var suggestResults = ((ElasticClient)_client).Suggest<ElasticsearchProject>(s => s
.Term("mySuggest", m => m
.SuggestMode(SuggestMode.Always)
.Text(wrongCountry)
.Size(1)
.OnField("country")
)
);

suggestResults.IsValid.Should().BeTrue();

suggestResults.Shards.Should().NotBeNull();
suggestResults.Suggestions.Should().NotBeNull().And.HaveCount(1);
var suggestions = suggestResults.Suggestions["mySuggest"];
suggestions.Should().NotBeNull().And.NotBeEmpty();

var suggestion = suggestions.First();
suggestion.Text.Should().Be(wrongCountry);
var option = suggestion.Options.First();
option.Text.Should().Be(country);

}


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<Compile Include="Connection\Thrift\ThiftBugReportTests.cs" />
<Compile Include="Core\Bulk\BulkTests.cs" />
<Compile Include="Core\Bulk\BulkUpdateTests.cs" />
<Compile Include="Core\Suggest\SuggestTests.cs" />
<Compile Include="Core\MultiSearch\MultiSearchTests.cs" />
<Compile Include="DebugTests\MemoryUsageTests.cs" />
<Compile Include="ElasticsearchConfiguration.cs" />
Expand Down