Elasticsearch filter suggestions

I have a requirement to provide suggestions that work fine, but I also need to filter the suggestions by another field in the document.

Can this be achieved? While I found out, Elasticsearch cannot do this. Any alternative ideas?

public async Task<ISuggestResponse> Suggest(string index, string projectId, string field, string text) { var suggestResponse = await _client.SuggestAsync<TDocument>(s => s .Index(index) .Completion("suggest", c => c .Text(text) .Context(con => con.Add("projectId", projectId)) .Field(field) .Size(20) ) ); return suggestResponse; } 

----------- Update --------------------

ElasticsearchConfig.cs

 client.Map<Component>(d => d .Properties(props => props .String(s => s .Name("name")) .Completion(c => c .Name("componentSuggestion") .Analyzer("simple") .SearchAnalyzer("simple") .Context(context => context .Category("projectId", cat => cat .Field(field => field.ProjectId))) .Payloads())) .Properties(props => props.String(s => s.Name("id").NotAnalyzed())) .Properties(props => props.String(s => s.Name("projectId").NotAnalyzed()))); 

enter image description here

+6
source share
2 answers

The pointer context extends the version of Completion Suggestester to provide a basic filtering element either in a category or in Geolocation. This may be enough for your purposes.

An alternative approach that you might want to use is to use Context Suggestester to provide suggestions such as "search by your type", indexing the identifier of each document in a display type payload of completion type; then use the identifiers returned within the payloads to search for documents, applying your additional filtering at this point and returning only the identifiers of documents that match the filtering. Finally, use these document identifiers to receive offers from the original offer.

EDIT:

Here is a complete example of working with Context Suggestester

 void Main() { var componentsIndex = "components"; var connectionPool = new SingleNodeConnectionPool(new Uri("http://localhost:9200")); var settings = new ConnectionSettings(connectionPool) // use component index when working with // Component Poco type .InferMappingFor<Component>(m => m .IndexName(componentsIndex) ); var client = new ElasticClient(settings); // make this example repeatable, so delete index if // it already exists if (client.IndexExists(componentsIndex).Exists) client.DeleteIndex(componentsIndex); // for example purposes, only use one shard and no replicas // NOT RECOMMENDED FOR PRODUCTION client.CreateIndex(componentsIndex, c => c .Settings(s => s .NumberOfShards(1) .NumberOfReplicas(0) ) ); client.Map<Component>(d => d .Index(componentsIndex) // infer mapping of fields from property of the POCO. // This means we don't need to explicitly specify all // mappings in .Properties() .AutoMap() // Now, override any inferred mappings from automapping .Properties(props => props .Completion(c => c .Name(n => n.ComponentSuggestion) .Context(context => context .Category("projectId", cat => cat .Field(field => field.ProjectId) ) ) .Payloads() ) .String(s => s .Name(n => n.Id) .NotAnalyzed() ) .String(s => s .Name(n => n.ProjectId) .NotAnalyzed() ) ) ); var components = new[] { new Component { Id = "1", Name = "Component Name 1", ComponentSuggestion = new CompletionField<object> { Input = new [] { "Component Name 1" }, Output = "Component Name 1" }, ProjectId = "project_id" }, new Component { Id = "2", Name = "Component Name 2", ComponentSuggestion = new CompletionField<object> { Input = new [] { "Component Name 2" }, Output = "Component Name 2" }, ProjectId = "project_id_2" } }; // index some components with different project ids client.IndexMany(components); // refresh the index to make the newly indexed documents available for // search. Useful for demo purposes but, // TRY TO AVOID CALLING REFRESH IN PRODUCTION client.Refresh(componentsIndex); var projectId = "project_id"; var suggestResponse = client.Suggest<Component>(s => s .Index(componentsIndex) .Completion("suggester", c => c .Field(f => f.ComponentSuggestion) .Text("Compon") .Context(con => con.Add("projectId", projectId)) .Size(20) ) ); foreach (var suggestion in suggestResponse.Suggestions["suggester"].SelectMany(s => s.Options)) { Console.WriteLine(suggestion.Text); } } public class Component { public string Id { get; set; } public string Name { get; set; } public string ProjectId { get; set; } public CompletionField<object> ComponentSuggestion { get; set; } } 

This gives only one Component Name 1 clause, based on the context of the projectId "project_id"

+2
source

Instead of the completion assistant, you should use a contextual consultant whose purpose is to specify an additional category or geolocation context for your clarification.

If I'm not mistaken, NEST provides a context tester as a complement to the completion exam via the Context property.

 public async Task<ISuggestResponse> Suggest(string index, string field, string text) { var suggestResponse = await _client.SuggestAsync<TDocument>(s => s .Index(index) .Completion("suggest", c => c .Text(text) .Context(con => con.Add("your_field", "text")) .Field(field) .Size(20) ) ); return suggestResponse; } 

You also need to change the completion field in your mapping to declare a context.

+2
source

All Articles