Spec-Zone.ru › Elasticsearch 8
›Elasticsearch Guide [8.17] ›Агрегации ›Агрегации по корзинам

Агрегация по сетке геохэшей

Многокорзинная агрегация, которая группирует значения geo_point и geo_shape в корзины, представляющие сетку. Полученная сетка может быть разреженной и содержать только ячейки, содержащие соответствующие данные. Каждая ячейка обозначается с помощью геохэша, точность которого задаётся пользователем.

  • Геохэши высокой точности имеют длинную строку и представляют ячейки, охватывающие небольшую область.
  • Геохэши низкой точности имеют короткую строку и представляют ячейки, каждая из которых охватывает большую область.

Геохэши, используемые в этой агрегации, могут иметь точность от 1 до 12.

Геохэш наивысшей точности длиной 12 создаёт ячейки, покрывающие площадь менее одного квадратного метра, поэтому запросы высокой точности могут быть очень затратными в плане использования ОЗУ и размера результатов. Пожалуйста, смотрите пример ниже о том, как сначала отфильтровать агрегацию до меньшей географической области, прежде чем запрашивать высокую детализацию.

Можно использовать только geohash_grid для агрегирования явно сопоставленного поля geo_point или geo_shape. Если поле geo_point содержит массив, geohash_grid агрегирует все значения массива.

Простой запрос с низкой точностью

resp = client.indices.create(
    index="museums",
    mappings={
        "properties": {
            "location": {
                "type": "geo_point"
            }
        }
    },
)
print(resp)

resp1 = client.bulk(
    index="museums",
    refresh=True,
    operations=[
        {
            "index": {
                "_id": 1
            }
        },
        {
            "location": "POINT (4.912350 52.374081)",
            "name": "NEMO Science Museum"
        },
        {
            "index": {
                "_id": 2
            }
        },
        {
            "location": "POINT (4.901618 52.369219)",
            "name": "Museum Het Rembrandthuis"
        },
        {
            "index": {
                "_id": 3
            }
        },
        {
            "location": "POINT (4.914722 52.371667)",
            "name": "Nederlands Scheepvaartmuseum"
        },
        {
            "index": {
                "_id": 4
            }
        },
        {
            "location": "POINT (4.405200 51.222900)",
            "name": "Letterenhuis"
        },
        {
            "index": {
                "_id": 5
            }
        },
        {
            "location": "POINT (2.336389 48.861111)",
            "name": "Musée du Louvre"
        },
        {
            "index": {
                "_id": 6
            }
        },
        {
            "location": "POINT (2.327000 48.860000)",
            "name": "Musée d'Orsay"
        }
    ],
)
print(resp1)

resp2 = client.search(
    index="museums",
    size="0",
    aggregations={
        "large-grid": {
            "geohash_grid": {
                "field": "location",
                "precision": 3
            }
        }
    },
)
print(resp2)
response = client.indices.create(
  index: 'museums',
  body: {
    mappings: {
      properties: {
        location: {
          type: 'geo_point'
        }
      }
    }
  }
)
puts response

response = client.bulk(
  index: 'museums',
  refresh: true,
  body: [
    {
      index: {
        _id: 1
      }
    },
    {
      location: 'POINT (4.912350 52.374081)',
      name: 'NEMO Science Museum'
    },
    {
      index: {
        _id: 2
      }
    },
    {
      location: 'POINT (4.901618 52.369219)',
      name: 'Museum Het Rembrandthuis'
    },
    {
      index: {
        _id: 3
      }
    },
    {
      location: 'POINT (4.914722 52.371667)',
      name: 'Nederlands Scheepvaartmuseum'
    },
    {
      index: {
        _id: 4
      }
    },
    {
      location: 'POINT (4.405200 51.222900)',
      name: 'Letterenhuis'
    },
    {
      index: {
        _id: 5
      }
    },
    {
      location: 'POINT (2.336389 48.861111)',
      name: 'Musée du Louvre'
    },
    {
      index: {
        _id: 6
      }
    },
    {
      location: 'POINT (2.327000 48.860000)',
      name: "Musée d'Orsay"
    }
  ]
)
puts response

response = client.search(
  index: 'museums',
  size: 0,
  body: {
    aggregations: {
      "large-grid": {
        geohash_grid: {
          field: 'location',
          precision: 3
        }
      }
    }
  }
)
puts response
const response = await client.indices.create({
  index: "museums",
  mappings: {
    properties: {
      location: {
        type: "geo_point",
      },
    },
  },
});
console.log(response);

const response1 = await client.bulk({
  index: "museums",
  refresh: "true",
  operations: [
    {
      index: {
        _id: 1,
      },
    },
    {
      location: "POINT (4.912350 52.374081)",
      name: "NEMO Science Museum",
    },
    {
      index: {
        _id: 2,
      },
    },
    {
      location: "POINT (4.901618 52.369219)",
      name: "Museum Het Rembrandthuis",
    },
    {
      index: {
        _id: 3,
      },
    },
    {
      location: "POINT (4.914722 52.371667)",
      name: "Nederlands Scheepvaartmuseum",
    },
    {
      index: {
        _id: 4,
      },
    },
    {
      location: "POINT (4.405200 51.222900)",
      name: "Letterenhuis",
    },
    {
      index: {
        _id: 5,
      },
    },
    {
      location: "POINT (2.336389 48.861111)",
      name: "Musée du Louvre",
    },
    {
      index: {
        _id: 6,
      },
    },
    {
      location: "POINT (2.327000 48.860000)",
      name: "Musée d'Orsay",
    },
  ],
});
console.log(response1);

const response2 = await client.search({
  index: "museums",
  size: 0,
  aggregations: {
    "large-grid": {
      geohash_grid: {
        field: "location",
        precision: 3,
      },
    },
  },
});
console.log(response2);
PUT /museums
{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      }
    }
  }
}

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

POST /museums/_search?size=0
{
  "aggregations": {
    "large-grid": {
      "geohash_grid": {
        "field": "location",
        "precision": 3
      }
    }
  }
}

Ответ:

{
  ...
  "aggregations": {
  "large-grid": {
    "buckets": [
      {
        "key": "u17",
        "doc_count": 3
      },
      {
        "key": "u09",
        "doc_count": 2
      },
      {
        "key": "u15",
        "doc_count": 1
      }
    ]
  }
}
}

Запросы высокой точности

При запросе детальных корзин (как правило, для отображения «приближенного» масштаба карты) следует применять фильтр, такой как geo_bounding_box, чтобы сузить область, иначе может быть создано и возвращено потенциально миллионы корзин.

resp = client.search(
    index="museums",
    size="0",
    aggregations={
        "zoomed-in": {
            "filter": {
                "geo_bounding_box": {
                    "location": {
                        "top_left": "POINT (4.9 52.4)",
                        "bottom_right": "POINT (5.0 52.3)"
                    }
                }
            },
            "aggregations": {
                "zoom1": {
                    "geohash_grid": {
                        "field": "location",
                        "precision": 8
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'museums',
  size: 0,
  body: {
    aggregations: {
      "zoomed-in": {
        filter: {
          geo_bounding_box: {
            location: {
              top_left: 'POINT (4.9 52.4)',
              bottom_right: 'POINT (5.0 52.3)'
            }
          }
        },
        aggregations: {
          "zoom1": {
            geohash_grid: {
              field: 'location',
              precision: 8
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "museums",
  size: 0,
  aggregations: {
    "zoomed-in": {
      filter: {
        geo_bounding_box: {
          location: {
            top_left: "POINT (4.9 52.4)",
            bottom_right: "POINT (5.0 52.3)",
          },
        },
      },
      aggregations: {
        zoom1: {
          geohash_grid: {
            field: "location",
            precision: 8,
          },
        },
      },
    },
  },
});
console.log(response);
POST /museums/_search?size=0
{
  "aggregations": {
    "zoomed-in": {
      "filter": {
        "geo_bounding_box": {
          "location": {
            "top_left": "POINT (4.9 52.4)",
            "bottom_right": "POINT (5.0 52.3)"
          }
        }
      },
      "aggregations": {
        "zoom1": {
          "geohash_grid": {
            "field": "location",
            "precision": 8
          }
        }
      }
    }
  }
}

Геохэши, возвращаемые агрегацией geohash_grid, также могут использоваться для приближения. Чтобы приблизиться к первому геохэшу u17, возвращённому в предыдущем примере, он должен быть указан как угол top_left и bottom_right.

resp = client.search(
    index="museums",
    size="0",
    aggregations={
        "zoomed-in": {
            "filter": {
                "geo_bounding_box": {
                    "location": {
                        "top_left": "u17",
                        "bottom_right": "u17"
                    }
                }
            },
            "aggregations": {
                "zoom1": {
                    "geohash_grid": {
                        "field": "location",
                        "precision": 8
                    }
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'museums',
  size: 0,
  body: {
    aggregations: {
      "zoomed-in": {
        filter: {
          geo_bounding_box: {
            location: {
              top_left: 'u17',
              bottom_right: 'u17'
            }
          }
        },
        aggregations: {
          "zoom1": {
            geohash_grid: {
              field: 'location',
              precision: 8
            }
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "museums",
  size: 0,
  aggregations: {
    "zoomed-in": {
      filter: {
        geo_bounding_box: {
          location: {
            top_left: "u17",
            bottom_right: "u17",
          },
        },
      },
      aggregations: {
        zoom1: {
          geohash_grid: {
            field: "location",
            precision: 8,
          },
        },
      },
    },
  },
});
console.log(response);
POST /museums/_search?size=0
{
  "aggregations": {
    "zoomed-in": {
      "filter": {
        "geo_bounding_box": {
          "location": {
            "top_left": "u17",
            "bottom_right": "u17"
          }
        }
      },
      "aggregations": {
        "zoom1": {
          "geohash_grid": {
            "field": "location",
            "precision": 8
          }
        }
      }
    }
  }
}
{
  ...
  "aggregations": {
    "zoomed-in": {
      "doc_count": 3,
      "zoom1": {
        "buckets": [
          {
            "key": "u173zy3j",
            "doc_count": 1
          },
          {
            "key": "u173zvfz",
            "doc_count": 1
          },
          {
            "key": "u173zt90",
            "doc_count": 1
          }
        ]
      }
    }
  }
}

Для «приближения» на системах, которые не поддерживают геохэши, ключи корзин должны быть переведены в прямоугольники с помощью одной из доступных библиотек геохэшей. Например, для JavaScript можно использовать библиотеку node-geohash:

var geohash = require('ngeohash');

// bbox will contain [ 52.03125, 4.21875, 53.4375, 5.625 ]
//                   [   minlat,  minlon,  maxlat, maxlon]
var bbox = geohash.decode_bbox('u17');

Запросы с дополнительной фильтрацией по прямоугольнику

Агрегация geohash_grid поддерживает необязательный параметр bounds, который ограничивает рассматриваемые ячейки теми, которые пересекают заданные границы. Параметр bounds принимает прямоугольник в тех же поддерживаемых форматах, что и прямоугольник, указанный в запросе геометрической фильтрации по прямоугольнику. Этот прямоугольник можно использовать с или без дополнительного запроса geo_bounding_box, фильтрующего точки перед агрегацией. Это независимый прямоугольник, который может пересекаться с, быть равен или не пересекаться с любыми дополнительными запросами geo_bounding_box, определёнными в контексте агрегации.

resp = client.search(
    index="museums",
    size="0",
    aggregations={
        "tiles-in-bounds": {
            "geohash_grid": {
                "field": "location",
                "precision": 8,
                "bounds": {
                    "top_left": "POINT (4.21875 53.4375)",
                    "bottom_right": "POINT (5.625 52.03125)"
                }
            }
        }
    },
)
print(resp)
response = client.search(
  index: 'museums',
  size: 0,
  body: {
    aggregations: {
      "tiles-in-bounds": {
        geohash_grid: {
          field: 'location',
          precision: 8,
          bounds: {
            top_left: 'POINT (4.21875 53.4375)',
            bottom_right: 'POINT (5.625 52.03125)'
          }
        }
      }
    }
  }
)
puts response
const response = await client.search({
  index: "museums",
  size: 0,
  aggregations: {
    "tiles-in-bounds": {
      geohash_grid: {
        field: "location",
        precision: 8,
        bounds: {
          top_left: "POINT (4.21875 53.4375)",
          bottom_right: "POINT (5.625 52.03125)",
        },
      },
    },
  },
});
console.log(response);
POST /museums/_search?size=0
{
  "aggregations": {
    "tiles-in-bounds": {
      "geohash_grid": {
        "field": "location",
        "precision": 8,
        "bounds": {
          "top_left": "POINT (4.21875 53.4375)",
          "bottom_right": "POINT (5.625 52.03125)"
        }
      }
    }
  }
}
{
  ...
  "aggregations": {
    "tiles-in-bounds": {
      "buckets": [
        {
          "key": "u173zy3j",
          "doc_count": 1
        },
        {
          "key": "u173zvfz",
          "doc_count": 1
        },
        {
          "key": "u173zt90",
          "doc_count": 1
        }
      ]
    }
  }
}

Размеры ячеек на экваторе

В таблице ниже показаны метрические размеры ячеек, покрываемых геохэшами различной длины. Размеры ячеек изменяются в зависимости от широты, поэтому таблица отражает наихудший случай на экваторе.

Длина геохэша

Ширина x высота ячейки

1

5009,4км x 4992,6км

2

1252,3км x 624,1км

3

156,5км x 156км

4

39,1км x 19,5км

5

4,9км x 4,9км

6

1,2км x 609,4м

7

152,9м x 152,4м

8

38,2м x 19м

9

4,8м x 4,8м

10

1,2м x 59,5см

11

14,9см x 14,9см

12

3,7см x 1,9см

Агрегирование полей geo_shape

Агрегирование по полям типа Geoshape работает так же, как и для точек, за исключением того, что одну фигуру можно учитывать в нескольких тайлах. Фигура будет учитываться в подсчёте соответствующих значений, если любая её часть пересекает данный тайл. Ниже представлена иллюстрация:

geoshape grid

Параметры

field

Обязательно. Поле, содержащее индексированные значения geo-point или geo-shape. Должно быть явно сопоставлено как поле geo_point или geo_shape. Если поле содержит массив, geohash_grid агрегирует все значения массива.

precision

Необязательно. Длина строки геохэшей, используемых для определения ячеек/корзин в результатах. По умолчанию 5. Точность может быть задана в виде целочисленных значений, упомянутых выше. Значения вне диапазона [1,12] будут отклонены. Также точность можно приблизить по расстоянию, например, "1км", "10м". Уровень точности рассчитывается таким образом, чтобы ячейки не превышали заданный размер (диагональ) требуемой точности. Если это приведёт к уровням точности выше, чем поддерживаемые 12 уровней (например, для расстояний <5,6см), значение отклоняется.

bounds

Необязательно. Прямоугольник для фильтрации точек в корзине.

size

Необязательно. Максимальное количество корзин геохэшей для возврата (по умолчанию 10 000). При усечении результатов корзины упорядочиваются в зависимости от объёма документов, которые они содержат.

shard_size

Необязательно. Для более точного подсчёта верхних ячеек, возвращаемых в конечном результате, агрегация по умолчанию возвращает max(10,(size x number-of-shards)) корзины с каждого фрагмента. Если этот эвристический подход нежелателен, количество корзин с каждого фрагмента можно переопределить с помощью этого параметра.

© 2023-2025 Elasticsearch
As of September 2024, Elasticsearch is available under a choice of three licenses: the Server Side Public License (SSPL), the Elastic License, or the AGPLv3 (OSI approved).
Elasticsearch and the Elasticsearch logo are trademarks of Elasticsearch B.V., registered in the U.S. and in other countries.
https://www.elastic.co/guide/en/elasticsearch/reference/8.17/search-aggregations-bucket-geohashgrid-aggregation.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API