# Cловари полигонов {#slovari-polygonov} ClickHouse поддерживает словари полигонов. Данный словарь является одной из реализаций внешних словарей, у которого задана специфичная структура. Общий вид кофигурации выглядит следующим образом: ``` xml key Array(Array(Array(Array(Float64)))) name String value UInt64 0 ``` Соответствущий [DDL-запрос](../../../sql-reference/statements/create.md#create-dictionary-query): ``` sql CREATE DICTIONARY polygon_dict_name ( key Array(Array(Array(Array(Float64)))), name String, value UInt64 ) PRIMARY KEY key ... ``` Ключом словаря является сам полигон, что довольно необычно. Все атрибуты являются опциональными, при желании туда можно добавить более подробную информацию. К примеру, может быть добавлен атрибут, содержащий информацию о числе людей, проживающих в данном регионе. На данный момент доступно 4 типа [хранения в памяти](../../../sql-reference/dictionaries/external-dictionaries/external-dicts-dict-layout.md): - POLYGON. Это наивная реализация, все полигоны хранятся в памяти и на каждый запрос делается линейный проход по памяти, и проверяется принадлежность точки текущему полигону с помощью алгоритма, реализованного в Boost Geometry. - GRID_POLYGON. Данная реализация предлагает разбить рассматриваемую области на сетку, и внутри ячейки сетки использовать наивный линейный алгоритм. Для этого выбирается минимальный прямоугольник, содержащий рассматриваемую область, после чего он разбивается на k^2 равных ячеек, где k - конфигурируемый параметр. (TODO: написать как.) - ONE_BUCKET_POLYGON. Вся плоскость разбивается на вертикальные полоски, проходящие через вершины полигонов. После этого для данной точки находися ее полоска, и из точки выпускается вертикальный луч. По четности числа пересечений ребер полигона определяется, внутри лежит точка или снаружи. В данный момент для хранения ребер используется дерево отрезков для сокращения используемой памяти - каждое ребро принадлежит отрезку полосок, из-за чего можно хранить каждое ребро не более чем в log(n) вершинах, где n - число полосок. Таким образом, потребление памяти есть n log n вместо n^2. - BUCKET_POLYGON. Данная реализация является объединением двух предыдущих идей. Тип хранения можно выбрать при создании словаря, указав его в соответствующем параметре `LAYOUT`. Пример `DDL-запроса`: ``` sql CREATE DICTIONARY polygon_dict_name ( key Array(Array(Array(Array(Float64)))), name String, value UInt64 ) PRIMARY KEY key LAYOUT(POLYGON()); ... ``` Пользователь может [загружать свои собственные данные](../../../sql-reference/dictionaries/external-dictionaries/external-dicts-dict-sources.md), представленные во всех поддерживаемых ClickHouse форматах. Дальнейшие запросы к словарю осуществляются с помощью [dictGet](../../../sql-reference/functions/ext-dict-functions.md/#dictget), где ключами являются заданные точки. Один из возможных решений может быть использование таблицы ClickHouse: Пользователь инициализирует таблицу с интересующими его точками. Это можно сделать следующим `DDL-запросом`: ``` sql CREATE TABLE points ( x Float64, y Float64 ) ... ``` В качестве источника данных таблицы можно указать все поддерживаемые ClickHouse форматы данных, к примеру можно передать в таблицу файл с точками в формате `TSV`. После этого, для выполнения запросов к словарю можно использовать следующую команду: ``` sql SELECT tuple(x, y) AS key, dictGet(dict_name, 'name', key), dictGet(dict_name, 'value', key) FROM points ORDER BY x, y; ``` В результате ее исполнения для каждой точки в таблице `points` будет найден полигон минимальной площади, содержащий данную точку. Для этого полигона будут выведены все атрибуты, указанные в запросе (в данном случае это `name` и `value`). Если точка не лежит ни в каком из полигонов, то для всех атрибутов будут возвращены их значения по умолчанию.