How to implement suggest completion with NEST 6.1.

2019-06-10 12:14发布

问题:

So far I have this (for indexing):

var createIndexResponse = await elasticClient.CreateIndexAsync(indexName, c => c
    .InitializeUsing(indexConfig)
    .Mappings(m => m
        .Map<ElasticsearchModel>(mm => mm
            .Properties(
            p => p
            .Completion(cp => cp
                .Name(elasticsearchModel => elasticsearchModel.StringTest)
                .Analyzer("simple")
                .SearchAnalyzer("simple")
            )
            .Text(t => t.Name(elasticsearchModel => elasticsearchModel.StringTest).Analyzer("customAnalyzerLowercaseSynonymAsciifolding"))
            )
        )
    )
);

I got to this with the help of this post (but I'm not sure if this is correct as I think that I'm missing some properties to set min. suggestion length etc.): https://stackoverflow.com/a/33796953/7199922

Now I can't figure out how to query it to get the suggestion results.

I have googled the git repo like search suggest site:https://github.com/elastic/elasticsearch-net/ and checked the documentation but can't find much.

回答1:

I have ended up with the following:

Model

public class ElasticsearchModel
{
  public int IntTest { get; set; }
  public string StringTest { get; set; }
  public CompletionField StringTestSuggest
  {
      get
      {
          return new CompletionField
          {
              Input = new[] { StringTest + " ThisIsTheStringTestSuggestField" }
          };
      }
  }
}

Indexing

var indexSettings = new IndexSettings
{
    NumberOfReplicas = 0, // If this is set to 1 or more, then the index becomes yellow.
    NumberOfShards = 5 
};

var indexConfig = new IndexState
{
    Settings = indexSettings
};

var createIndexResponse = elasticClient.CreateIndex(indexName, c => c
   .InitializeUsing(indexConfig)
   .Mappings(m => m
       .Map<ElasticsearchModel>(mm => mm
           .Properties(
           p => p
           .Completion(cp => cp
               .Name(elasticsearchModel => elasticsearchModel.StringTestSuggest)
               .Analyzer("customAnalyzerLowercaseSynonymAsciifolding")
               .SearchAnalyzer("customAnalyzerLowercaseSynonymAsciifolding")
           )
           .Text(t => t.Name(product => product.IntTest).Analyzer("keyword"))
           .Text(t => t.Name(elasticsearchModel => elasticsearchModel.StringTest).Analyzer("customAnalyzerLowercaseSynonymAsciifolding")) // You can use "standard" here or some other default analyzer.               
           )
       )
   )
);

elasticClient.Refresh(indexName);

Querying

public List<ElasticsearchModel> Suggest(string indexName, string query)
{
    var elasticClient = ElasticsearchHelper.DatabaseConnection();

    var response = elasticClient.Search<ElasticsearchModel>(s => s
       .Index(indexName)
        .Suggest(su => su
            .Completion("StringTest", cs => cs
                .Field(f => f.StringTestSuggest)
                .Prefix(query)
                .Fuzzy(f => f
                    .Fuzziness(Fuzziness.Auto)
                )
                .Size(5)
            )
        )
     );

    var suggestions =
        from suggest in response.Suggest["StringTest"]
        from option in suggest.Options
        select new ElasticsearchModel
        {
            IntTest = option.Source.IntTest,
            StringTest = option.Source.StringTest
        };

    return suggestions.ToList();
}

Other things (to easier understand the methods)

public void Refresh(string indexName)
{
    var elasticClient = ElasticsearchHelper.DatabaseConnection();
    elasticClient.Refresh(indexName); // This should be called before every query or everytime documents get indexed! Else some results might be missing.
}

Initiate the connection to the ES DB

public static class ElasticsearchHelper
{
    public static ElasticClient DatabaseConnection()
    {
        var node = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
        //var node = new Uri("http://localhost:9200");
        var settings = new ConnectionSettings(node)
            .PrettyJson()
            .DisableDirectStreaming() // Enable for API HTTP request/response debugging.
            .OnRequestCompleted(callDetails =>
            {
                // log out the request
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("REQUEST:");
                Console.ResetColor();

                if (callDetails.RequestBodyInBytes != null)
                {
                    Console.WriteLine(
                        $"{callDetails.HttpMethod} {callDetails.Uri} \n" +
                        $"{Encoding.UTF8.GetString(callDetails.RequestBodyInBytes)}");
                }
                else
                {
                    Console.WriteLine($"{callDetails.HttpMethod} {callDetails.Uri}");
                }

                // log out the response
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("RESPONSE:");
                Console.ResetColor();

                if (callDetails.ResponseBodyInBytes != null)
                {
                    Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                             $"{Encoding.UTF8.GetString(callDetails.ResponseBodyInBytes)}\n" +
                             $"{new string('-', 30)}\n");
                }
                else
                {
                    Console.WriteLine($"Status: {callDetails.HttpStatusCode}\n" +
                             $"{new string('-', 30)}\n");
                }
            }) // For debugging...
        ; // Index name must be lowercase, cannot begin with an underscore, and cannot contain commas.
        var client = new ElasticClient(settings);

        return client;
    }






}

All credits and thanks for helping to Russ Cam.