Issue with CompletionSuggester query using DotNet Elastic.Clients.Elasticsearch

I am trying to query the CompletionSuggester using Elastic.Clients.Elasticsearch. I am able to query with the following (use either prefix OR regex gets the right result):

POST customer-catalog-test-0001/_search
{
  "_source": false,
  "suggest": {
    "product-suggest": {
      "prefix": "male",
      "regex": ".*male.*",
      "completion": {
        "field": "autoCompleteSuggest",
        "skip_duplicates": true,
        "size": 5
      }
    }
  }
}

BUT when I am converting it to DotNet Elastic.Clients.Elasticsearch (v8.17), in the CompletionSuggester class, there is not Prefix field, only Regex field that takes Elastic.Clients.Elasticsearch.Core.Search.RegexOptions. However, I cannot set the "expression" for the RegexOptions. This is what the RegexOptions like:

public sealed partial class RegexOptions
{
	/// <summary>
	/// <para>
	/// Optional operators for the regular expression.
	/// </para>
	/// </summary>
	[JsonInclude, JsonPropertyName("flags")]
	public object? Flags { get; set; }

	/// <summary>
	/// <para>
	/// Maximum number of automaton states required for the query.
	/// </para>
	/// </summary>
	[JsonInclude, JsonPropertyName("max_determinized_states")]
	public int? MaxDeterminizedStates { get; set; }
}

My current code:

public async void QuerySuggest()
{
    var client = new ElasticsearchClient(new ElasticsearchClientSettings(new Uri("http://localhost:9200")));

    var searchRequest = new SearchRequest("customer-catalog-test-0001")
    {
        // Exclude the _source
        Source = new SourceConfig(false),

        // Define the suggester
        Suggest = new Suggester
        {
            Suggesters =
            {
                {
                    "product-suggest",
                    new CompletionSuggester
                    {
                        Field = "autoCompleteSuggest",
                        Size = 5,
                        SkipDuplicates = true,
                        Regex = new RegexOptions
                        {
                            Value = "male.*"
                        }
                    }
                }
            }
        }
    };
}

So..., am I not doing it right OR there is something wrong with CompletionSuggester/RegexOptions defination?

Hi @Reed_M ,

you got tricked by implicit conversion operators here :confused:

Suggesters has a Dictionary<string, FieldSuggester> type. FieldSuggester is implicitly constructible from CompletionSuggester which is why your code compiles.

To achieve the regex/match lookup, you might use this code instead:

var suggester = FieldSuggester.Completion(new CompletionSuggester
{
	Field = "autoCompleteSuggest",
	Size = 5,
	SkipDuplicates = true,
					
});

suggester.Prefix = "match";
// ...

var searchRequest = new SearchRequest("customer-catalog-test-0001")
{
	// Exclude the _source
	Source = new SourceConfig(false),

	// Define the suggester
	Suggest = new Suggester
	{
		Suggesters =
		{
			{
				"product-suggest",
				suggester
			}
		}
	}
};

I'm going to improve this syntax a little bit for the next major version. The static factory method will be replaced by simple properties. This will at least allow you to initialize everything inline like this:

Suggesters =
{
    {
        "product-suggest",
        new FieldSuggester
        {
            Completion = new CompletionSuggester
            {
                Field = "autoCompleteSuggest",
                Size = 5,
                SkipDuplicates = true,			
            },
            Prefix = "match",
            // ...
        }
    }
}

I created an explanatory screenshot that hopefully demonstrates how these "container" types work to avoid confusion in the future:

Thank you so much. That explains everything. I have spent hours looking at source code, but I just seems ignored them somehow. I am sure this post will help so many others, because I have tried several AI tools even before looking at the source code, and they all gave wrong solutions...

After trying it out, I think there is a final piece to be added for a complete solution.
There is NullReferenceException at

Suggesters =
{
	{
		"product-suggest",
		suggester
	}
}

But addressing explicit type new Dictionary<string, FieldSuggester> solves it.

Suggesters = new Dictionary<string, FieldSuggester>
{
	{
		"product-suggest",
		suggester
	}
}

Making the completed solution to be:

var suggester = FieldSuggester.Completion(new CompletionSuggester
{
	Field = "autoCompleteSuggest",
	Size = 5,
	SkipDuplicates = true,
					
});

suggester.Prefix = "match";
// ...

var searchRequest = new SearchRequest("customer-catalog-test-0001")
{
	// Exclude the _source
	Source = new SourceConfig(false),

	// Define the suggester
	Suggest = new Suggester
	{
		// NullReferenceException if no explicit new Dictionary<string, FieldSuggester>
		Suggesters = new Dictionary<string, FieldSuggester>
		{
			{
				"product-suggest",
				suggester
			}
		}
	}
};

1 Like