ElasticSearch - Return 字段值的唯一结果

ElasticSearch - Return unique result by field values

我有 3 个 "places",每个都有一个类型和一个位置:

PUT places
{
  "mappings": {
    "test": {
      "properties": {
        "type": { "type": "keyword" },
        "location": { "type": "geo_point" }
      }
    }
  }
}

POST places/test
{
   "type" : "A",
   "location": {
      "lat": 1.378446,
      "lon": 103.763427
   }
}

POST places/test
{
   "type" : "B",
   "location": {
      "lat": 1.478446,
      "lon": 104.763427
   }
}

POST places/test
{
   "type" : "A",
   "location": {
      "lat": 1.278446,
      "lon": 102.763427
   }
}

我只想检索每个 "type" 的一个位置:离随机位置最近的位置可以说 "lat":1.178446,"lon":101.763427

在我的示例中,结果答案应该正好由 2 个元素组成(一个用于 "type: A",一个用于 "type: B")。

我也希望避免使用 "aggregations",因为我需要每个地方的 _source。

任何帮助都会很棒。

如果没有聚合,这样的操作似乎不可能执行一个查询。 这可以通过 top-hits-aggregation.

来实现

下面已经用 elasticsearch 6 测试过:

POST /places/_search?size=0
{
  "aggs" : {
     "group-by-type" : {
        "terms" : { "field" : "type" },
        "aggs": {
            "min-distance": {
               "top_hits": {
                  "sort": {
                    "_script": { 
                       "type": "number",
                       "script": {
                          "source": "def x = doc['location'].lat; def y = doc['location'].lon; return Math.abs(x-1.178446) + Math.abs(y-101.763427)",
                          "lang": "painless"
                       },
                      "order": "asc"
                    }
                  },
                  "_source": {
                       "includes": [ "type", "location" ]
                    },
                    "size" : 1
                 }
             }
        }
     }
  }
}

注意,我计算的距离为:
|location.x - givenPoint.x| + |location.y - givenPoint.y|

这是回复:

{
  "took": 2,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
     "total": 3,
     "max_score": 0.0,
     "hits": []
  },
  "aggregations": {
     "group-by-type": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [{
           "key": "A",
           "doc_count": 2,
           "min-distance": {
              "hits": {
                "total": 2,
                "max_score": null,
                   "hits": [{
                      "_index": "places",
                      "_type": "test",
                      "_id": "3",
                      "_score": null,
                      "_source": {
                         "location": {
                           "lon": 102.763427,
                           "lat": 1.278446
                         },
                         "type": "A"
                      },
                      "sort": [1.1000006934661934]
                   }]
                 }
              }
          }, {
            "key": "B",
            "doc_count": 1,
            "min-distance": {
                "hits": {
                   "total": 1,
                   "max_score": null,
                   "hits": [{
                     "_index": "places",
                     "_type": "test",
                     "_id": "2",
                     "_score": null,
                     "_source": {
                         "location": {
                            "lon": 104.763427,
                             "lat": 1.478446 
                          },
                          "type": "B"
                      },
                      "sort": [3.3000007411499093]
                   }]
                 }
               }
            }]
          }
       }
 }