# Autocomplete across multiple fields with NEST client

**URL:** <https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878>\
**Category:** Elasticsearch\
**Created:** [February 21, 2018, 3:40pm UTC](https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878 "2018-02-21T15:40:15Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![rdcm](https://avatars.discourse-cdn.com/v4/letter/r/9dc877/32.png) [@rdcm](https://discuss.elastic.co/u/rdcm)\
**Post date:** [February 21, 2018, 3:40pm UTC](https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878/1 "2018-02-21T15:40:15Z")

</div>

Hi!

I`am trying implement autocomplete feature for multiple fields with official high-level NEST client.  
But quick and dirty solution looks like this:

```
        public async Task<IEnumerable<string>> Complete(string text)
    {
        var sd1 = new SearchDescriptor<Assignment>().Suggest(
            scd => scd.Completion(
                "n1",
                csd => csd
                    .Field(x => x.Title)
                    .Prefix(text)));

        var sd2 = new SearchDescriptor<Assignment>().Suggest(
            scd => scd.Completion(
                "n2",
                csd => csd
                    .Field(x => x.Theme)
                    .Prefix(text)));

        var sd3 = new SearchDescriptor<Assignment>().Suggest(
            scd => scd.Completion(
                "n3",
                csd => csd
                    .Field(x => x.TrainingKit)
                    .Prefix(text)));

        var task1 = _elasticClient.SearchAsync<Assignment>(sd1);
        var task2 = _elasticClient.SearchAsync<Assignment>(sd2);
        var task3 = _elasticClient.SearchAsync<Assignment>(sd3);

        await Task.WhenAll(task1, task2, task3);

        var resp1 = task1.Result.Suggest.SelectMany(x => x.Value).SelectMany(x => x.Options).Select(x => x.Text).Distinct();
        var resp2 = task2.Result.Suggest.SelectMany(x => x.Value).SelectMany(x => x.Options).Select(x => x.Text).Distinct();
        var resp3 = task3.Result.Suggest.SelectMany(x => x.Value).SelectMany(x => x.Options).Select(x => x.Text).Distinct();

        return resp1.Concat(resp2).Concat(resp3);
    }

```

`Completion` dsl method have only `Field` option, but not `Fields`. Can i implement this fearure without call `Task.WhenAll(...)` with NEST?

---

<div class="post-metadata">

**Author:** ![forloop](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/forloop/32/9021_2.png) [@forloop](https://discuss.elastic.co/u/forloop)\
**Post date:** [February 22, 2018, 8:29am UTC](https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878/2 "2018-02-22T08:29:42Z")

</div>

Here's an example of supplying multiple inputs to Completion Suggester

```auto
void Main()
{
	var index = "assignments";
	var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
		.DefaultIndex(index);

	var client = new ElasticClient(settings);

	if (client.IndexExists(index).Exists)
	{
		client.DeleteIndex(index);
	}
	
	client.CreateIndex(index, c => c
		.Mappings(m => m
			.Map<Assignment>(mm => mm
				.AutoMap()
			)
		)
	);

	client.IndexMany(new[]
		{
			new Assignment
			{
				Id = 1,
				Title = "An assignment about Elasticsearch",
				Theme = "Data analytics",
				TrainingKit = "Developer course",
				Suggest = new CompletionField
				{
					Input = new []
					{
						"An assignment about Elasticsearch",
						"Data analytics",
						"Developer course",
					},
					Weight = 100
				}
			},
			new Assignment
			{
				Id = 2,
				Title = "All about Kibana",
				Theme = "Diagrams and Graphs",
				TrainingKit = "Youtube videos",
				Suggest = new CompletionField
				{
					Input = new []
					{
						"All about Kibana",
						"Diagrams and Graphs",
						"Youtube videos",
					},
					Weight = 80
				}
			},
		});
		
	client.Refresh(index);
	
	var input = "d";

	var response = client.Search<Assignment>(s => s
		.Index<Assignment>()
        .Source(so => so
            .Includes(f => f
                .Field(ff => ff.Id)
            )
        )
        .Suggest(su => su
    		.Completion("suggest", cs => cs
    			.Field(f => f.Suggest)
    			.Prefix(input)
    			.Fuzzy(f => f
    				.Fuzziness(Fuzziness.Auto)
    			)
    			.Size(10)
    		)
        )
    );

    // do something with the suggestions
    var suggestions =
        from suggest in response.Suggest["suggest"]
        from option in suggest.Options
        select new
        {
            Id = option.Source.Id,
            Text = option.Text,
            Votes = option.Score
        };

}

public class Assignment
{
	public int Id { get;set; }	
	public string Title { get; set; }	
	public string Theme { get;set; }	
	public string TrainingKit { get;set; }
	public CompletionField Suggest { get; set; }	
}

```

Some important points:

1. Completion suggester works with [the `completion` data type field mapping](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html#completion-suggester-mapping). With [NEST's automapping](https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/auto-map.html), `Nest.CompletionField` will be mapped as `completion` field
2. `CompletionField`'s `Input` property takes an `IEnumerable<string>` to allow multiple inputs
3. Use `"suggest"` on the `_search` API to make the call, targeting the `Suggest` property of the POCO, which will map to the `"suggest"` field in Elasticsearch
4. Completion Suggester is designed for _fast "search as you type"_. If your search needs are more complex, you may need to build [custom analyzers](https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/writing-analyzers.html) and take a multi-faceted approach to search.

The response from the search request looks like

```json
{
  "took" : 28,
  "timed_out" : false,
  "_shards" : {
    "total" : 5,
    "successful" : 5,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : 0,
    "max_score" : 0.0,
    "hits" : []
  },
  "suggest" : {
    "completion#suggest" : [
      {
        "text" : "d",
        "offset" : 0,
        "length" : 1,
        "options" : [
          {
            "text" : "Data analytics",
            "_index" : "assignments",
            "_type" : "assignment",
            "_id" : "1",
            "_score" : 100.0,
            "_source" : {
              "id" : 1
            }
          },
          {
            "text" : "Diagrams and Graphs",
            "_index" : "assignments",
            "_type" : "assignment",
            "_id" : "2",
            "_score" : 80.0,
            "_source" : {
              "id" : 2
            }
          }
        ]
      }
    ]
  }
}

```

---

<div class="post-metadata">

**Author:** ![rdcm](https://avatars.discourse-cdn.com/v4/letter/r/9dc877/32.png) [@rdcm](https://discuss.elastic.co/u/rdcm)\
**Post date:** [February 26, 2018, 1:45pm UTC](https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878/3 "2018-02-26T13:45:21Z")

</div>

> [@forloop](#):
>
> CompletionField

🙏 Thanks, very helpfull example!

One more common question about autocomplete. For example, completions must appear ahead based on some query statistics over the last week. I'm not sure how correctly implement this feature. Should i use aggregation for this or other functionality and how elastic could tracking query statistics?

---

<div class="post-metadata">

**Author:** ![forloop](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/forloop/32/9021_2.png) [@forloop](https://discuss.elastic.co/u/forloop)\
**Post date:** [February 26, 2018, 8:30pm UTC](https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878/4 "2018-02-26T20:30:29Z")

</div>

> [@rdcm](#):
>
> For example, completions must appear ahead based on some query statistics over the last week.

Completion suggester may not be the best API to use for this. Take a look at [`function_score` query with decay function](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html#function-decay) on the document field that represents the date of interest.

> [@rdcm](#):
>
> Should i use aggregation for this or other functionality and how elastic could tracking query statistics?

Elasticsearch does not currently have a feature that captures data about the search queries that are executed, so you would need to implement something to fit your needs here. This may be as simple as capturing data such as:

1. The terms searched for
2. The number of searches performed before result is selected (or abandoned)
3. The position of the selected result (if one is selected)

---

<div class="post-metadata">

**Author:** ![rdcm](https://avatars.discourse-cdn.com/v4/letter/r/9dc877/32.png) [@rdcm](https://discuss.elastic.co/u/rdcm)\
**Post date:** [March 1, 2018, 3:39pm UTC](https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878/5 "2018-03-01T15:39:19Z")

</div>

A bit more about your code sample. If user type "about Elasticsearch..." the string "An assignment about Elasticsearch" not suggested, becuse elasticsearch provide only prefix suggestions. Could i use for this any standart suggester or i need write own java plugin for elasticsearch?

For inputs, "foo", "bar", "baz", "foo bar baz", "foo bar", "bar baz", "foo baz" my application should suggest string "foo bar baz";

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [March 29, 2018, 3:39pm UTC](https://discuss.elastic.co/t/autocomplete-across-multiple-fields-with-nest-client/120878/6 "2018-03-29T15:39:56Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
