Elasticsearch - Autocomplete with NEST

你离开我真会死。 提交于 2019-11-30 17:25:19

问题


I'm trying to do autocomplete with the NEST client.

The code looks as follows:

Poco (condensed):

public class Course
{
    [ElasticProperty(Name="id")]
    public int ID { get; set; }
    public string Name { get; set; }   
    [ElasticProperty(Type = FieldType.Completion)]
    public CompletionField Suggest { get; set; }

    public Course(sm.Models.Course c)
    {
        if (c != null)
        {
            this.ID = c.ID;
            this.Name = c.Name;
            this.Suggest = new CompletionField
            {
                Input = new List<string>(this.Name.Split(' ')) { this.Name },
                Output = this.Name,
                Payload = new
                {
                    id = this.Name
                },
                Weight = 1
            };
        }
    }
}   

Indexing:

Client.CreateIndex("myindex", c => c
            .NumberOfReplicas(1)
            .NumberOfShards(5)
            .Settings(s => s
                .Add("merge.policy.merge_factor", "10")
                .Add("search.slowlog.threshold.fetch.warn", "1s")
            )
            .AddMapping<Course>(m => m.MapFromAttributes()
                .Properties(props => props
                    .Completion(s=>s
                        .Name(p=>p.Suggest)
                        .IndexAnalyzer("simple")
                        .SearchAnalyzer("simple")
                        .MaxInputLength(20)
                        .Payloads()
                        .PreservePositionIncrements()
                        .PreserveSeparators()
                    )
                )                
            ));

My suggest query:

GET _suggest
{
  "course-suggest": {
   "text": "Nothilfe",
   "completion": {
     "field": "suggest",
     "size": 10
   }
  }
}

Which results in this error:

    "failures": [
         {
            "shard": 1,
            "index": "myindex",
            "status": "INTERNAL_SERVER_ERROR",
            "reason": {
               "type": "exception",
               "reason": "failed to execute suggest",
               "caused_by": {
                  "type": "exception",
                  "reason": "Field [suggest] is not a completion suggest field"
               }
            }
         }

Why is my suggest field not recognized as a completion field?

GET _mapping/course

"suggest": {
  "properties": {
     "input": {
        "type": "string"
     },
     "output": {
        "type": "string"
     },
     "payload": {
        "properties": {
           "id": {
              "type": "string"
           }
        }
     },
     "weight": {
        "type": "long"
     }
  }

回答1:


There are a few possible reasons why you might be receiving this error, but the most obvious one is that your mapping for type course in index myindex is out of date in relation to the query you're sending through.

You can easily check the the mapping for the type with

curl -XGET "http://localhost:9200/myindex/course/_mapping"

It should look like

{
   "myindex": {
      "mappings": {
         "course": {
            "properties": {
               "id": {
                  "type": "integer"
               },
               "name": {
                  "type": "string"
               },
               "suggest": {
                  "type": "completion",
                  "analyzer": "simple",
                  "payloads": true,
                  "preserve_separators": true,
                  "preserve_position_increments": true,
                  "max_input_length": 20
               }
            }
         }
      }
   }
}

If it doesn't you'll need to fix this, either by deleting the type in the index and recreating (or deleting the index altogether and recreating), or by creating a new index with the correct mapping and copying documents over from the old index if you want to *try* to keep any data you already have (this may or may not be possible here).

The following will create the index as expected and perform the suggest query you're trying to run. Note that I have scoped the query to run only against the index myindex. The types

public class Course
{
    [ElasticProperty(Name = "id")]
    public int ID { get; set; }

    public string Name { get; set; }

    [ElasticProperty(Type = FieldType.Completion)]
    public CompletionField Suggest { get; set; }

    public Course(Course c)
    {
        if (c != null)
        {
            this.ID = c.ID;
            this.Name = c.Name;
            this.Suggest = new CompletionField
            {
                Input = new List<string>(this.Name.Split(' ')) { this.Name },
                Output = this.Name,
                Payload = new
                {
                    id = this.Name
                },
                Weight = 1
            };
        }
    }
}

// I'm guessing CompletionField looks something like this?
public class CompletionField
{
    public List<string> Input { get; set; }
    public string Output { get; set; }
    public object Payload { get; set; }
    public double Weight { get; set; }
}

and the creation of the index and query

void Main()
{
    var settings = new ConnectionSettings(new Uri("http://localhost:9200"))
        .ExposeRawResponse(true)
        .SetConnectionStatusHandler(response =>
        {
            // log out the requests
            if (response.Request != null)
            {
                Console.WriteLine("{0} {1} \n{2}\n", response.RequestMethod.ToUpperInvariant(), response.RequestUrl,
                    Encoding.UTF8.GetString(response.Request));
            }
            else
            {
                Console.WriteLine("{0} {1}\n", response.RequestMethod.ToUpperInvariant(), response.RequestUrl);
            }

            if (response.ResponseRaw != null)
            {
                Console.WriteLine("{0}\n{1}\n\n{2}\n", response.HttpStatusCode, Encoding.UTF8.GetString(response.ResponseRaw), new String('-', 30));
            }
            else
            {
                Console.WriteLine("{0}\n\n{1}\n", response.HttpStatusCode, new String('-', 30));
            }
        });

    var client = new ElasticClient(settings);

    var indexResponse = client.CreateIndex("myindex", c => c
        .NumberOfReplicas(1)
        .NumberOfShards(5)
        .Settings(s => s
            .Add("merge.policy.merge_factor", "10")
            .Add("search.slowlog.threshold.fetch.warn", "1s")
        )
        .AddMapping<Course>(m => m.MapFromAttributes()
                .Properties(props => props
                    .Completion(s => s
                        .Name(p => p.Suggest)
                        .IndexAnalyzer("simple")
                        .SearchAnalyzer("simple")
                        .MaxInputLength(20)
                        .Payloads()
                        .PreservePositionIncrements()
                        .PreserveSeparators()
                    )
                )
        ));

    // give Elasticsearch some time to initialize the index
    Thread.Sleep(TimeSpan.FromSeconds(5));

    var suggestResponse = client.Suggest<Course>(s => s
        .Index("myindex")
        .Completion("course-suggest", c => c
            .Text("Nothilfe")
            .OnField("suggest")
            .Size(10)
        )
    );

    // do something with suggestResponse
}

This logs out the following to the console

POST http://localhost:9200/myindex 
{
  "settings": {
    "index": {
      "number_of_replicas": 1,
      "number_of_shards": 5,
      "merge.policy.merge_factor": "10",
      "search.slowlog.threshold.fetch.warn": "1s"
    }
  },
  "mappings": {
    "course": {
      "properties": {
        "id": {
          "type": "integer"
        },
        "name": {
          "type": "string"
        },
        "suggest": {
          "type": "completion",
          "search_analyzer": "simple",
          "index_analyzer": "simple",
          "payloads": true,
          "preserve_separators": true,
          "preserve_position_increments": true,
          "max_input_len": 20
        }
      }
    }
  }
}

200
{"acknowledged":true}

------------------------------

POST http://localhost:9200/myindex/_suggest 
{
  "course-suggest": {
    "text": "Nothilfe",
    "completion": {
      "field": "suggest",
      "size": 10
    }
  }
}

200
{"_shards":{"total":5,"successful":5,"failed":0}}

------------------------------


来源:https://stackoverflow.com/questions/33677298/elasticsearch-autocomplete-with-nest

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!