2016-04-16 8 views
2

Ich implementiere ein Programm mit der Fähigkeit, die 10 nächsten Objekt zu erhalten. Als Datenbank verwende ich ElasticSearch, mein Modell sieht so aus.C# berechnen Geodistanz mit elastischer Suche (nest 2)

[Nest.ElasticsearchType(Name = "eventelastic", IdProperty = "Id")] 
public class EventElastic:BaseElastic 
{ 
    [Nest.String] 
    public string EventName { get; set; } 
    [Nest.Date] 
    public DateTime CreateTime { get; set; } 
    [Nest.String] 
    public string Country { get; set; } 
    [Nest.String] 
    public string City { get; set; } 
    [Nest.String] 
    public string Place { get; set; } 
    [Nest.Boolean] 
    public bool IsPrivate { get; set; } 
    [Nest.Boolean] 
    public bool IsSponsored { get; set; } 
    [Nest.String] 
    public string ImageWeb { get; set; } 
    [Nest.Number] 
    public int MaxPersons { get; set; } 
    [Nest.GeoPoint] 
    public LocationModel Location { get; set; } 


} 

[Nest.ElasticsearchType(Name = "location", IdProperty = "Id")] 
public class LocationModel 
{ 
    public LocationModel(double lon, double lat) 
    { 
     Lon = lon; 
     Lat = lat; 
    } 

    public double Lon { get; set; } 

    public double Lat { get; set; } 
} 

habe ich einen Index wie dieser

connection.CreateIndex("index", s => s.Mappings(f => f.Map<EventElastic>(m => m.AutoMap().Properties(p=> p.GeoPoint(g => g.Name(n => n.Location)))))); 

Und ich einfügen neue Dokumente wie diese

var response = connection.IndexAsync<EventElastic>(model, idx => idx.Index("index")); 
      response.ContinueWith(t => 
      { 
       if (!t.Result.IsValid) 
       { 
        log.Error(t.Result.ServerError.Error.Reason); 
       } 
      }); 

Alle Werte des Modells festgelegt sind, und es funktioniert ohne Probleme.

Aber jetzt möchte ich die 10 am nächsten in einer Reichweite von 10 km bekommen. ich fragen diese ähnliche

var geoResult = connection.Search<EventElastic>(s => s.From(0).Size(10) 
      .Query(query => query.Bool(b => b.Filter(filter => filter 
        .GeoDistance(geo => geo 
         .Field(f => f.Location) //<- this 
         .Distance("10km").Location(lon, lat) 
         .DistanceType(GeoDistanceType.SloppyArc) 
         )) 
       ) 
      ) 
     ); 

aber es tut jedes Dokument zurück, aber es gibt ein Dokument, wenn ich den Abstandswert auf 10000km gesetzt.

Die Daten i im Modell verwendet wird: LAT: 47,4595248 LON: 9,6385962

Die Lage i bei der Suche verwendet werden: LAT: 47,4640298 LON: 9,6389685

Diese Orte sind 100 Meter voneinander weg. Kann mir jemand helfen, den Fehler in meinem Code zu finden? Und ist es möglich, die berechnete Entfernung vom elastischenSuchserver zu erhalten?

btw: ich habe die Einrichtung eines Standardindex

var settings = new ConnectionSettings(pool).DefaultIndex("index"); 

bearbeiten ich den Fehler gefunden:

var geoResult = connection.Search<EventElastic>(s => s.From(0).Size(10) 
     .Query(query => query.Bool(b => b.Filter(filter => filter 
       .GeoDistance(geo => geo 
        .Field(f => f.Location) 
        .Distance("10km").Location(lat, lon) //wrong parameter 
        .DistanceType(GeoDistanceType.SloppyArc) 
        )) 
      ) 
     ) 
    ); 

i Position von lat und lon ändern musste.

Aber ich bekomme nicht die berechnete Entfernung, weiß jemand, wie ich die Entfernung bekommen kann?

freundlichen Grüßen

+0

Möchten Sie für jedes Dokument in elasticsearch response? – Rob

+0

Ja, wenn elasticsearch mir 5 Ergebnisse zurückgibt, möchte ich, dass sie nach Entfernung sortieren, und ich möchte, dass die Entfernung dem Benutzer angezeigt wird. –

Antwort

0

Sie können Distance zu Ihrem Dokument hinzufügen und sctipt fields mit Ihrer Abfrage verwenden, um diesen Wert zu aktualisieren.

var geoResult = client.Search<EventElastic>(s => s.From(0).Size(10) 
    .ScriptFields(sf => sf 
     .ScriptField("distance", descriptor => descriptor 
      .Inline("doc[\u0027location\u0027].distanceInKm(lat,lon)") 
      .Lang("groovy") 
      .Params(f => f.Add("lat", lat).Add("lon", lon)))) 
    .Query(query => query.Bool(b => b.Filter(filter => filter 
     .GeoDistance(geo => geo 
      .Field(f => f.Location) 
      .Distance("10km").Location(lat, lon) 
      .DistanceType(GeoDistanceType.SloppyArc) 
     )) 
     ) 
    ) 
    .Sort(sort => sort 
     .GeoDistance(g => g 
      .Field(f => f.Location) 
      .Order(SortOrder.Ascending) 
      .PinTo(new GeoLocation(1.5, 1)) 
      .DistanceType(GeoDistanceType.SloppyArc))) 
    ); 


public class EventElastic 
{ 
    .. 
    public double Distance {get;set;} 
} 

Antwort von Elasticsearch:

{ 
    "took": 3, 
    "timed_out": false, 
    "_shards": { 
     "total": 5, 
     "successful": 5, 
     "failed": 0 
    }, 
    "hits": { 
     "total": 2, 
     "max_score": null, 
     "hits": [ 
     { 
      "_index": "my_index", 
      "_type": "data", 
      "_id": "1", 
      "_score": null, 
      "fields": { 
       "distance": [ 
        55.65975203179589 
       ] 
      }, 
      "sort": [ 
       55659.66677843493 
      ] 
     }, 
     { 
      "_index": "my_index", 
      "_type": "data", 
      "_id": "2", 
      "_score": null, 
      "fields": { 
       "distance": [ 
        124.45896068602408 
       ] 
      }, 
      "sort": [ 
       124411.81715215484 
      ] 
     } 
     ] 
    } 
} 

Hoffe, es hilft.

+0

Thx das "Sort" was ich brauchte. Für mich funktioniert es ohne die ScriptFields, verbessert das ScriptFields etwas? Weil die Werte, die Sie bekommen, leicht unterschiedlich sind. "fields": { "distance": [ 55.65975203179589 ] }, "sort": [ 55659,66677843493 ] –

Verwandte Themen