1
votes

I faced a problem using NEST in my Web Api Project for sorting by GeoDistance. I have:

  • server with Elasticsearch v5.1.1 (working good)
  • simple .NET Web Api application with NEST v5.0.1 installed (basic CRUD and search operations are working good)

Yesterday I decided to implement sorting by GeoDistance, however all possible solutions I had led me to this exception in Search/Sort requests:

Invalid NEST response built from a unsuccessful low level call on POST: /activities/activity/_search Audit trail of this API call:

[1] BadResponse: Node: http://MY_SERVER_IP:9200/ Took: 00:00:00.3129217 ServerError: ServerError: 400Type: search_phase_execution_exception Reason: "all shards failed" CausedBy: "Type:

illegal_argument_exception Reason:

"failed to find mapper for [geoposition] for geo distance based sort""

OriginalException: System.Net.WebException: The remote server returned an error: (400) Bad Request. at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)
at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean requiresSynchronization) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
at Elasticsearch.Net.HttpConnection.d__9`1.MoveNext() in C:\Users\russ\source\elasticsearch-net-5.x\src\Elasticsearch.Net\Connection\HttpConnection.cs:line 199

Request:

force it to be set on the response.>

Response:

ConnectionSettings to force it to be set on the response.>

My Model:

[ElasticsearchType(IdProperty = nameof(Id), Name = "activity")]
public class Activity
{
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }
    [JsonProperty(PropertyName = "title")]
    public string Title { get; set; }
    [JsonProperty(PropertyName = "description")]
    public string Description { get; set; }
    [GeoPoint(Name = "geoposition")]
    public GeoLocation Geoposition { get; set; }
    [Date(Name = "date_published")]
    public DateTime DatePublished { get; set; }
}

My NEST client initialization:

var settings = new ConnectionSettings(_node)
                .DefaultIndex(_defaultIndex)
                .MapDefaultTypeIndices(m => m.Add(typeof(Activity), _defaultIndex));
ElasticClient _client = new ElasticClient(settings);

I tried two different mapping approaches, because I didn't really get how to do this in a new NEST client:

  1. _client.Map<Activity>(m => m.AutoMap().Properties(p => p.GeoPoint(geo => geo.Name(n => n.Geoposition))));
  2. _client.Map<Activity>(m => m.Properties(p => p.GeoPoint(geo => geo.Name(n => n.Geoposition))));

My current query (give me error described above):

var result = await _client.SearchAsync<Activity>(s => s.Index(_defaultIndex)
//I removed search query to analyze only sorting problem
                        .Sort(
                            ss =>
                                ss.Descending(p => p.DatePublished)
                                    .GeoDistance(
                                        g => g
                                            .Field(p => p.Geoposition)
                                            .DistanceType(GeoDistanceType.Plane)
                                            .Unit(DistanceUnit.Kilometers)
                                            .Order(SortOrder.Ascending)
                                            .PinTo(pin))));

My mapping response from elasticsearch server:

{
  "activities": {
    "mappings": {
      "activity": {
        "properties": {
          "date_published": {
            "type": "date"
          },
          "description": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "geoposition": {
            "properties": {
              "lat": {
                "type": "float"
              },
              "lon": {
                "type": "float"
              }
            }
          },
          "title": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          }
        }
      }
    }
  }
}

Can somebody help me to solve this problem? I can not understand why it's not working and why mapping is not working.

1

1 Answers

2
votes

The main rule I got using stackoverflow by far is: The problem was created by me, so solution is already inside me. Search for it.

If you ever face the same error check if you have an index creation code. I didn't have one. So my index and it's mapping was created on inserting of first document (found out with tests).

The answer is this missing string:

_client.CreateIndex(_defaultIndex, descriptor => descriptor.Mappings(ms => ms.Map<Activity>(m => m.AutoMap())));

right after elastic client initialized

ElasticClient _client = new ElasticClient(settings);