Elasticsearch 获取不同排序顺序的距离

Elasticsearch getting distance with different sort order

背景:

我们有以下要求:

  1. Data matching keyword should be returned.
  2. Data has longitude and latitude fields, result should be near specified lat long.
  3. Returned result should contain distance field, which specified distance between given lat long and lat long contained in data.
  4. Data should be sorted accouding to MultiMatch score.

阅读此 link 中的教程 Spatial Search ElasticSearch tutorial 我在 C# 中构建了以下查询。

 var res = await _elasticClient
            .SearchAsync<Results>(
                s =>
                    s.Type("Data")
                        .Skip(skip)
                        .Take(limit)
                      .SortGeoDistance(es => 
                            es.Ascending().OnField("Coordinates").Unit(GeoUnit.Kilometers).PinTo(lat,lng))
                      .Query(
                        q1 =>
                            q1.Filtered(
                                f1 =>
                                    f1.Query(q2 => q2.MultiMatch(mm => mm.OnFields(MultiMatchFieldsArray)
                                    .Query(keyword)
                                    .Type(TextQueryType.MostFields)))
                                    .Filter(f2 => f2.GeoDistance("Coordinates",gf => gf.Distance(10,GeoUnit.Kilometers)
                                    .Location(lat,lng))))));

根据教程,我必须使用 SortGeoDistance 方法来获取结果中的距离。使用 SortGeoDistance 将根据距离对结果进行排序,但需要根据 MultiMatch 分数对结果进行排序。

下面的 Whosebug answer 展示了如何在不使用排序的情况下获取距离。

下面是 C# 等效的答案。

var esSearch = await _elasticClient
            .SearchAsync<Results>(
                s =>
                    s.Type("Data")
                      .Skip(skip)
                      .Take(limit)
                      .Fields("_source")
                      .ScriptFields(sf => sf.Add("Distance", des => des.Params(param => param.Add("lat", lat).Add("lon", lng)).Script("doc[\u0027Coordinates\u0027].arcDistanceWithDefault(lat,lon,-1)")))
                      .Query(
                        q1 =>
                            q1.Filtered(
                                f1 =>
                                    f1.Query(q2 => q2.MultiMatch(mm => mm.OnFields(MultiMatchFields)
                                    .Query(keyword)
                                    .Type(TextQueryType.MostFields)))
                                    .Filter(f2 => f2.GeoDistance("Coordinates",gf => gf.Distance(10,GeoUnit.Kilometers)
                                    .Location(lat,lng))))));