С# вычислить георасстояние с эластичным поиском (гнездо 2)

Я реализую программу с возможностью получения 10 ближайших объектов. В качестве базы данных я использую ElasticSearch, моя модель выглядит так.

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

Я создал такой индекс

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

И я вставляю новые документы, как это

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

Все значения модели выставлены, работает без проблем.

Но теперь я хочу получить 10 ближайших в диапазоне 10 км. Я запрашиваю это так

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

но он не возвращает никакого документа, но возвращает документ, если я установил значение расстояния 10000 км.

Данные, которые я использовал в модели: LAT: 47.4595248 LON: 9.6385962

Местоположение, которое я использую в поиске: LAT: 47.4640298 LON: 9.6389685

Эти места находятся в 100 метрах друг от друга. Может ли кто-нибудь помочь мне найти ошибку в моем коде? И можно ли получить рассчитанное расстояние с сервера elasticsearch?

кстати: я устанавливаю индекс по умолчанию

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

Изменить Я нашел ошибку:

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

мне пришлось изменить положение широты и долготы.

Но я не получаю расчетное расстояние, кто-нибудь знает, как я могу получить расстояние?

наилучшие пожелания


person Helga Schneider    schedule 16.04.2016    source источник
comment
Вы хотите получить расстояние в ответе elasticsearch для каждого документа?   -  person Rob    schedule 21.04.2016
comment
Да, если elasticsearch возвращает мне 5 результатов, я хочу, чтобы они сортировались по расстоянию, и я хочу, чтобы расстояние показывало его пользователю   -  person Helga Schneider    schedule 25.04.2016


Ответы (1)


Вы можете добавить Distance в свой документ и использовать поля сценария с вашим запросом, чтобы обновить это значение.

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

Ответ от 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
            ]
         }
      ]
   }
}

Надеюсь, поможет.

person Rob    schedule 27.04.2016
comment
Спасибо, Сорт был тем, что мне было нужно. Для меня это работает без ScriptFields, улучшают ли ScriptFields что-то? Поскольку значения, которые вы получаете, представляют собой немного разные поля: { Distance: [ 55.65975203179589 ] }, sort: [ 55659.66677843493 ] - person Helga Schneider; 02.05.2016
comment
Не работает с версией 7 - person Tun; 28.01.2021