基于Elasticsearch进行地理检索,计算距离值

时间:2023-03-08 22:40:05
基于Elasticsearch进行地理检索,计算距离值

实现步骤:
1、定义属性
    [Serializable]
    public class Coordinate
    {
        public double Lat { get; set; }
        public double Lon { get; set; }
    }
        /// <summary>
        /// 位置坐标
        /// </summary>
        [ElasticProperty(Type = FieldType.GeoPoint)]
        public Coordinate location { get; set; }
        /// <summary>
        /// 返回字段,距离值,适用于地理位置检索和排序  2016-03-25
        /// </summary>
        public double distance { get; set; }

2、创建索引时,设置Mapping:
_clientES.CreateIndex(indexName, s => s.AddMapping<DTOCarInfoIndexField>(f => f.MapFromAttributes().Properties(p => p.GeoPoint(g => g.Name(n => n.location).IndexLatLon()).String(fullinfo => fullinfo.Name(n => n.fullinfo).Index(FieldIndexOption.Analyzed).Analyzer("ik").Store(false)).String(description => description.Name(n => n.statedescription).Index(FieldIndexOption.Analyzed).Analyzer("ik").Store(false))).AllField(af => af.Enabled(false))).NumberOfReplicas(0));

3、向ES写入数据时,给location属性赋值:
#region 车源坐标  2015-11-30
string[] arrValue = ConvertHelper.ToStringArray(value.ToString(), ',');
if (arrValue.Length == 2)
{
    var point = new Coordinate();
    point.Lat = 0.0;
    point.Lon = 0.0;
    double x = ConvertHelper.ToDouble(arrValue[0]);
    double y = ConvertHelper.ToDouble(arrValue[1]);
    if (x > 0 && y > 0)
    {
        point.Lat = x;
        point.Lon = y;
    }
    prop.SetValue(obj, point, null);
}
#endregion

4、搜索过程中按照距离排序并返回距离值(单位:km)(Nest组件):
//构建排序对象
List<KeyValuePair<PropertyPathMarker, ISort>> oneSortList = new List<KeyValuePair<PropertyPathMarker, ISort>>();
SortOrder ordertype = SortOrder.Ascending;
GeoDistanceSort sort = new GeoDistanceSort();
sort.Field = "location";
sort.Order = ordertype;
sort.GeoUnit = GeoUnit.Kilometers;
sort.PinLocation = locationpoint;
oneSortList.Add(new KeyValuePair<PropertyPathMarker, ISort>("_geo_distance", sort));
//构建ES检索对象
string[] returnFields=new[]{"id","distance"};
var searchRequest = new SearchRequest();
searchRequest.From = 0;
searchRequest.Size = 20;
searchRequest.Sort = oneSortList;
//定义返回列属性
searchRequest.Fields = returnFields.Select(f => (PropertyPathMarker)f.ToLower()).ToList();
//添加其他检索条件
//searchRequest.Query = queryList[i];
//searchRequest.Filter = listFilter[i];
#region 地理检索,添加距离返回值字段
if (!string.IsNullOrEmpty(locationPoint) && returnFields.Contains("distance"))
{
    var distancefield = new Dictionary<string, IScriptFilter>();
    var tempfield = new ScriptFilter();
    tempfield.Params = new Dictionary<string, object>();
    tempfield.Params.Add("lat", 116.403951);
    tempfield.Params.Add("lon", 39.915031);
    tempfield.Script = "doc['location'].arcDistanceInKm(lat,lon)";
    distancefield.Add("distance", tempfield);
    searchRequest.ScriptFields = distancefield;
}
#endregion
//执行检索,获取返回值
var resultSearch = esClient.Search<T>(searchRequest);
foreach (var doc in sResponse.FieldSelections)
{
    var id = doc.FieldValues<object[]>("id").ToList()[0];
    var distancevalue = doc.FieldValues<object[]>("distance").ToList()[0]; 
}
5、搜索过程中按照距离排序并返回距离值(单位:km)(Linq方式)
ESClient.Instance_TaocheCar().GetElasticClient().Search<DTOCarInfoIndexField>(s => s.From(0).Size(200).Fields(arrField).Filter(filter => filter.Terms("userid", list)).ScriptFields(sf => sf.Add("distance", descriptor => descriptor.Params(p => p.Add("lat", lat).Add("lon", lon)).Script("doc['location'].arcDistanceInKm(lat,lon)"))).SortGeoDistance(sg => sg.OnField("location").PinTo(lat, lon).Unit(GeoUnit.Kilometers).Ascending()));