# Geo Distance Aggregation(地理距离聚合)

原文链接 : [https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geodistance-aggregation.html](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-geodistance-aggregation.html)

译文链接 : [Geo Distance Aggregation(地理距离聚合)](http://apache.wiki/pages/viewpage.action?pageId=10028788&src=contextnavpagetreemode)

贡献者 : @于永超，[ApacheCN](/display/~apachecn)，[Apache中文网](/display/~apachechina)

## Geo Distance Aggregation

在geo_point字段上工作的多bucket聚合和概念上的工作非常类似于[range](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-range-aggregation.html)(范围)聚合.用户可以定义原点的点和距离范围的集合。聚合计算每个文档值与原点的距离，并根据范围确定其所属的bucket(桶)（如果文档和原点之间的距离落在bucket(桶)的距离范围内，则文档属于bucket(桶) )

```
PUT /museums
{
    "mappings": {
        "doc": {
            "properties": {
                "location": {
                    "type": "geo_point"
                }
            }
        }
    }
}

POST /museums/doc/_bulk?refresh
{"index":{"_id":1}}
{"location": "52.374081,4.912350", "name": "NEMO Science Museum"}
{"index":{"_id":2}}
{"location": "52.369219,4.901618", "name": "Museum Het Rembrandthuis"}
{"index":{"_id":3}}
{"location": "52.371667,4.914722", "name": "Nederlands Scheepvaartmuseum"}
{"index":{"_id":4}}
{"location": "51.222900,4.405200", "name": "Letterenhuis"}
{"index":{"_id":5}}
{"location": "48.861111,2.336389", "name": "Musée du Louvre"}
{"index":{"_id":6}}
{"location": "48.860000,2.327000", "name": "Musée d'Orsay"}

POST /museums/_search?size=0
{
    "aggs" : {
        "rings_around_amsterdam" : {
            "geo_distance" : {
                "field" : "location",
                "origin" : "52.3760, 4.894",
                "ranges" : [
                    { "to" : 100000 },
                    { "from" : 100000, "to" : 300000 },
                    { "from" : 300000 }
                ]
            }
        }
    }
}
```

响应结果：

```
{
    ...
    "aggregations": {
        "rings_around_amsterdam" : {
            "buckets": [
                {
                    "key": "*-100000.0",
                    "from": 0.0,
                    "to": 100000.0,
                    "doc_count": 3
                },
                {
                    "key": "100000.0-300000.0",
                    "from": 100000.0,
                    "to": 300000.0,
                    "doc_count": 1
                },
                {
                    "key": "300000.0-*",
                    "from": 300000.0,
                    "doc_count": 2
                }
            ]
        }
    }
}
```

指定的字段必须是geo_point类型（只能在映射中显式设置）。它还可以保存一个geo_point字段的数组，在这种情况下，在聚合期间将考虑所有这些字段。原点可以接受[geo_point](https://www.elastic.co/guide/en/elasticsearch/reference/current/geo-point.html)类型支持的所有格式:

*   对象格式：{ "lat" : 52.3760, "lon" : 4.894 }－ 这是最安全的格式，因为它是最明确的lat (纬度)& lon(经度)值
*   字符串格式："52.3760, 4.894"  － 第一个数值是lat(纬度)，第二个是lon(经度)
*   数组格式：[4.894, 52.3760]  － 它基于GeoJson标准，第一个数字是lon(经度)，第二个数字是lat(纬度)

在默认情况下，距离单位是m(米)，但它也可以接受:mi(英里)，in(英寸)，yd(码)，km(公里)，cm(厘米)，毫米(毫米)。

```
POST /museums/_search?size=0
{
    "aggs" : {
        "rings" : {
            "geo_distance" : {
                "field" : "location",
                "origin" : "52.3760, 4.894",
                "unit" : "km", ＃1
                "ranges" : [
                    { "to" : 100 },
                    { "from" : 100, "to" : 300 },
                    { "from" : 300 }
                ]
            }
        }
    }
}
```

＃1   距离将以公里计算

有两种距离计算模式：arc(默认) 和 plane， arc(电弧)计算模式是最准确的，plane模式是最快的，但是最不准确。当考虑搜索上下文是“narrow”,跨越较小的地理区域（约5km）可以用plane，plane将为非常大的区域（例如跨大陆搜索）的搜索返回更高的误差区间。距离计算类型可以使用distance_type参数设置。

```
POST /museums/_search?size=0
{
    "aggs" : {
        "rings" : {
            "geo_distance" : {
                "field" : "location",
                "origin" : "52.3760, 4.894",
                "unit" : "km",
                "distance_type" : "plane",
                "ranges" : [
                    { "to" : 100 },
                    { "from" : 100, "to" : 300 },
                    { "from" : 300 }
                ]
            }
        }
    }
}
```

### Keyed Response

将keyed标志设置为true会将一个惟一的字符串键与每个bucket(桶)关联起来，并将范围作为散列而不是数组返回:

```
POST /museums/_search?size=0
{
    "aggs" : {
        "rings_around_amsterdam" : {
            "geo_distance" : {
                "field" : "location",
                "origin" : "52.3760, 4.894",
                "ranges" : [
                    { "to" : 100000 },
                    { "from" : 100000, "to" : 300000 },
                    { "from" : 300000 }
                ],
                "keyed": true
            }
        }
    }
}
```

返回结果：

```
{
    ...
    "aggregations": {
        "rings_around_amsterdam" : {
            "buckets": {
                "*-100000.0": {
                    "from": 0.0,
                    "to": 100000.0,
                    "doc_count": 3
                },
                "100000.0-300000.0": {
                    "from": 100000.0,
                    "to": 300000.0,
                    "doc_count": 1
                },
                "300000.0-*": {
                    "from": 300000.0,
                    "doc_count": 2
                }
            }
        }
    }
}
```

也可以为每个范围自定义key

```
POST /museums/_search?size=0
{
    "aggs" : {
        "rings_around_amsterdam" : {
            "geo_distance" : {
                "field" : "location",
                "origin" : "52.3760, 4.894",
                "ranges" : [
                    { "to" : 100000, "key": "first_ring" },
                    { "from" : 100000, "to" : 300000, "key": "second_ring" },
                    { "from" : 300000, "key": "third_ring" }
                ],
                "keyed": true
            }
        }
    }
}
```

返回结果：

```
{
    ...
    "aggregations": {
        "rings_around_amsterdam" : {
            "buckets": {
                "first_ring": {
                    "from": 0.0,
                    "to": 100000.0,
                    "doc_count": 3
                },
                "second_ring": {
                    "from": 100000.0,
                    "to": 300000.0,
                    "doc_count": 1
                },
                "third_ring": {
                    "from": 300000.0,
                    "doc_count": 2
                }
            }
        }
    }
}
```