1
votes

I am using completion suggesters to provide search suggestions as the user types. I added an IsActive property to my C# class, and I cannot figure out how to use that in the .Suggest.Completion query. I know it has something to do with contexts but I cannot find any examples for elasticsearch / nest 6.8.

How do I update my mappings and query to prevent documents with IsActive=false from being suggested?

This is my backing class:

[ElasticsearchType(
       IdProperty = "search"
   )]
public class SearchCompletion
{
    public string search { get; set; }


    /// <summary>
    /// Use this field for aggregations and sorts
    /// </summary>
    [Keyword]
    public string search_keyword { get; set; }

    public bool isActive { get; set; }

    /// <summary>
    /// To use for sorting results when searching SearchCompletions 
    /// directly since you can't sort by the Completionfield.Weight 
    /// property for some reason
    /// </summary>
    public int weight { get; set; }

    public CompletionField suggest { get; set; }
}

This is my Mapping Method:

public static void MapSearchCompletions(ElasticClient client, string index)
{
    var mapResponse = client.Map<SearchCompletion>(m => m
        .Index(index)
        .AutoMap()


        //  WHAT GOES HERE??
        .Properties(props => props
            .Completion(c => c
                .Name(n => n.isActive)  
                .Contexts(context => context
                    .Category(cat => cat.Name("isActive"))
                )
            )
        )         
    ); //re-apply the index mapping
}

This is My Query

var response = client.Search<SearchCompletion>(s => s
    .Index(suggest_index)
    .Suggest(su => su
        .Completion("search", cs => cs
            .Field(f => f.suggest)
            .Contexts(con => con.Context("")) //  WHAT GOES HERE??
            .Prefix(search)
            .Size(size)
        )
    )
);
1

1 Answers

1
votes

I don't think you can use boolean as a category value. I haven't tried that in ES but NEST is accepting string for category type. So, I suggest you to update your mappings. (I'm updating it to string to continue) Looks like you are creating index at some other place. Your code is just creating mappings. It could be as:

        var mapResponse = client.Map<SearchCompletion>(m => m
            .Index("index")
            .AutoMap()
            .Properties(props => props
                .Completion(c => c
                    .Name(n => n.suggest)
                    .Contexts(context => context
                        .Category(cat => cat.Name("isActive"))
                    )
                )
            )
        );

        // let's create data
        var r1 = client.Index(new SearchCompletion
        {
            search = "plate", suggest = new CompletionField
            {
                Input = new[] {"plate", "dish"}, // this one has two suggestions
                Contexts = new Dictionary<string, IEnumerable<string>>
                {
                    {
                        "isActive",
                        new[] {"yes"} // isActive is 'yes'
                    }
                }
            }
        }, d => d.Index("index"));

        var r2 = client.Index(new SearchCompletion
        {
            search = "fork",
            suggest = new CompletionField
            {
                Input = new[] { "fork", "dis_example" }, // this has two suggestions
                Contexts = new Dictionary<string, IEnumerable<string>>
                {
                    {
                        "isActive",
                        new[] {"no"} // isActive is 'no'
                    }
                }
            }
        }, d => d.Index("index"));

        var r3 = client.Index(new SearchCompletion
        {
            search = "spoon",
            suggest = new CompletionField
            {
                Input = new[] { "spoon" },
                Contexts = new Dictionary<string, IEnumerable<string>>
                {
                    {
                        "isActive",
                        new[] {"yes"} // isActive is 'yes'
                    }
                }
            }
        }, d => d.Index("index"));

        // Let's search for the dish using 'dis' and limiting it to IsActive == 'yes'
        var searchResponse = client.Search<SearchCompletion>(s => s.Index("index").Suggest(su => su
            .Completion("search", cs => cs
                .Field(f => f.suggest)
                .Contexts(con => con.Context("isActive", aa => aa.Context("yes")))
                .Prefix("dis")
                .Size(10)
            )
        ));

And indeed we are getting plate suggestion:

{
...
  "suggest" : {
    "search" : [
      {
        "text" : "dis",
        "offset" : 0,
        "length" : 3,
        "options" : [
          {
            "text" : "dish",
            "_index" : "testindex",
            "_type" : "searchcompletion",
            "_id" : "plate",
            "_score" : 1.0,
            "_source" : {
              "search" : "plate",
              "weight" : 0,
              "suggest" : {
                "input" : [
                  "plate",
                  "dish"
                ],
                "contexts" : {
                  "isActive" : [
                    "yes"
                  ]
                }
              }
            },
            "contexts" : {
              "isActive" : [
                "yes"
              ]
            }
          }
        ]
      }
    ]
  }
}