Elasticsearch - 使用NEST自动完成

时间:2015-11-12 17:11:52

标签: .net elasticsearch nest

我正在尝试使用NEST客户端进行自动完成。

代码如下:

Poco(浓缩):

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
            };
        }
    }
}   

索引:

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()
                    )
                )                
            ));

我的建议查询:

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

导致此错误:

    "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"
               }
            }
         }

为什么我的建议字段未被识别为完成字段?

GET _mapping / course

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

1 个答案:

答案 0 :(得分:3)

您可能会收到此错误的原因有几个,但最明显的原因是索引course中类型myindex的映射与您查询的查询有关。 #39;重新发送。

您可以使用

轻松检查类型的映射
curl -XGET "http://localhost:9200/myindex/course/_mapping"

应该看起来像

{
   "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
               }
            }
         }
      }
   }
}

如果它不需要解决此问题,可以通过删除索引中的类型并重新创建(或完全删除索引并重新创建),或者通过使用正确的映射创建新索引如果您想 *尝试* 以保留您已有的任何数据(这可能是也可能不存在),并从旧索引复制文档。

以下内容将按预期创建索引并执行您尝试运行的suggest查询。请注意,我已将查询范围限定为仅针对索引myindex运行。类型

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; }
}

并创建索引和查询

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
}

这会将以下内容注销到控制台

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}}

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