如何限制elasticsearch中返回的嵌套对象

时间:2016-06-20 10:15:14

标签: elasticsearch

我有一个索引,用于在嵌套对象中存储一组地理位置。

{
  ......,
  "geo_points" : [
     {
        "lat" : ...
        "lon" : ...
     },
    .......
  ]
}

和查询

{
 sort: {
     _geo_distance: {
         geo_points: {
             lat: "",
             lon: ""
         },
         order: 'asc',
         unit: 'km'
     }
 },
 query: {
     filtered: {
         query: {
             bool: {
                 must: [
                     {
                         range: {
                             endtime: {gte: ""}
                         }
                     },
                     {
                         range:{
                             starttime: {lte: ""}
                         }
                     }
                 ],
                 should: [
                     {
                         nested: {
                             path: 'categories',
                             filter: {
                                 bool: {
                                     should: { terms: { 'categories.id' => [1,2,3,4]} }
                                 }
                             }
                         }
                     }
                 ],
                 minimum_number_should_match: 1
             }
         },
         filter: {
             geo_distance: {
                 distance: "25km",
                 geo_points: {lat: "",lon: ""}
             }
         }
     }

 },
 from: 0, size: 100
}

它用于地理查询(按距离排序),我想知道是否可以返回只有匹配位置或

的geo_points

我可以说只返回X位置吗?

是否有现成的方法inner_hits?而且,如果可能的话,你可以给我一个样本查询吗?

感谢。

1 个答案:

答案 0 :(得分:0)

I solved my issue with custom ES script since I couldn't find a proper inbuilt way so here what I did

import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.geo.GeoPoint;

/***
 *
 * usage
 * "script_fields": {
 *        "closest_points": {
 *           "script": {
 *              "lang": "groovy",
 *              "file": "sortedGeoPoints",
 *              "params": {
 *                 "field": "lokasyonlar",
 *                 "lon": 26.954897,
 *                 "lat": 38.7762021,
 *                 "method": "PLANE",
 *                 "unit": "km",
 *                 "order": "asc",
 *                 "limit": 5
 *              }
 *           }
 *        }
 *     }
 *
 */

if (doc[field].values.size() < limit){
    return doc[field]
}
else{
    def distanceUnit
    def geoCalculator
    switch (method){
        case "ARC" :
            geoCalculator = GeoDistance.ARC
            break
        case "FACTOR" :
            geoCalculator = GeoDistance.FACTOR
            break
        default:
            geoCalculator = GeoDistance.PLANE
            break
    }
    switch (unit) {
        case "in" : //inch
            distanceUnit = DistanceUnit.INCH
            break
        case "yd": //yards
            distanceUnit = DistanceUnit.YARD
            break
        case "ft": //feet
            distanceUnit = DistanceUnit.FEET
            break
        case "nmi": //NAUTICALMILES
            distanceUnit = DistanceUnit.NAUTICALMILES
            break
        case "mm": // MILLIMETERS
            distanceUnit = DistanceUnit.MILLIMETERS
            break
        case "cm": // CENTIMETERS
            distanceUnit = DistanceUnit.CENTIMETERS
            break
        case "mi": // MILES
            distanceUnit = DistanceUnit.MILES
            break
        case "m": // MILES
            distanceUnit = DistanceUnit.METERS
            break
        default:
            distanceUnit = DistanceUnit.KILOMETERS
            break
    }
    def sortedGeoPoints = new TreeMap<Double, GeoPoint>()
    for(i = 0; i < doc[field].values.size(); i++){
        def loc = doc[field].values[i]
        sortedGeoPoints.put(geoCalculator.calculate(loc.lon, loc.lat, lon, lat, distanceUnit), loc)
    }
    def list
    if(order == "desc"){
        list = new ArrayList<GeoPoint>(sortedGeoPoints.descendingMap().values()) //reversed
    }
    else{
        list = new ArrayList<GeoPoint>(sortedGeoPoints.values())
    }
    return list.subList(0, limit)
}

and sample query

curl -XPOST /geo/test/_search -d '{
    "fields": [
       "_source",
       "distances"
    ], 
   "query": {
      "bool": {
         "must": [
            {
               "geo_distance": {
                  "distance": "100km",
                  "locations": {
                     "lon": 28.442826999999966,
                     "lat": 37.101167
                  }
               }
            }
         ]
      }
   },
   "script_fields": {
         "closest_points": {
            "script": {
                "lang": "groovy",
                "file": "sortedGeoPoints",
                "params": {
                   "field" : "locations",
                   "lon": 28.442826999999966,
                   "lat": 37.101167,
                   "method" : "PLANE",
                   "unit" : "km",
                   "order" : "asc",
                   "limit" : 3
                }
            }
         }
      },
   "sort": {
      "_geo_distance": {
         "locations": {
            "lon": 28.442826999999966,
            "lat": 37.101167
         },
         "order": "asc",
         "unit": "km"
      }
   }
}'

Use case & full story can be found in gist

In fact, it can be extracted from _geo_distance sort. However, I don't believe enough to have such functionality at there.

I will keep this open for better inbuilt options if there is, please let us know