> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-mintlify-8c05c8a2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Полигональные словари

> Настройка полигональных словарей для проверки попадания точки в полигон.

Полигональный словарь `polygon` (`POLYGON`) оптимизирован для запросов на проверку вхождения точки в полигон — по сути, для поиска по принципу «обратного геокодирования».
Для заданной координаты (широты/долготы) он эффективно определяет, какой полигон/регион (из множества полигонов, например границ стран или регионов) содержит эту точку.
Он хорошо подходит для сопоставления географических координат с регионом, в который они попадают.

<Frame>
  <iframe src="https://www.youtube.com/embed/FyRsriQp46E?si=Kf8CXoPKEpGQlC-Y" title="Полигональные словари в ClickHouse" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />
</Frame>

Пример настройки полигонального словаря:

<Tip>
  Если вы используете словарь в ClickHouse Cloud, для создания словарей используйте вариант с DDL-запросом, а сам словарь создавайте от имени пользователя `default`.
  Также проверьте список поддерживаемых источников для словарей в [руководстве по совместимости с Cloud](/ru/products/cloud/guides/cloud-compatibility).
</Tip>

<Tabs>
  <Tab title="DDL">
    ```sql theme={null}
    CREATE DICTIONARY polygon_dict_name (
        key Array(Array(Array(Array(Float64)))),
        name String,
        value UInt64
    )
    PRIMARY KEY key
    LAYOUT(POLYGON(STORE_POLYGON_KEY_COLUMN 1))
    ...
    ```
  </Tab>

  <Tab title="Файл конфигурации">
    ```xml theme={null}
    <dictionary>
        <structure>
            <key>
                <attribute>
                    <name>key</name>
                    <type>Array(Array(Array(Array(Float64))))</type>
                </attribute>
            </key>

            <attribute>
                <name>name</name>
                <type>String</type>
                <null_value></null_value>
            </attribute>

            <attribute>
                <name>value</name>
                <type>UInt64</type>
                <null_value>0</null_value>
            </attribute>
        </structure>

        <layout>
            <polygon>
                <store_polygon_key_column>1</store_polygon_key_column>
            </polygon>
        </layout>

        ...
    </dictionary>
    ```
  </Tab>
</Tabs>

<br />

При настройке полигонального словаря ключ должен быть одного из двух типов:

* Простой полигон. Это массив точек.
* MultiPolygon. Это массив полигонов. Каждый полигон представляет собой двумерный массив точек. Первый элемент этого массива — внешняя граница полигона, а последующие элементы задают области, которые должны быть из него исключены.

Точки можно задавать в виде массива или кортежа координат. В текущей реализации поддерживаются только двумерные точки.

Можно загружать собственные данные во всех форматах, поддерживаемых ClickHouse.

Доступны 3 типа [хранилищ в памяти](/ru/reference/statements/create/dictionary/layouts/overview#storing-dictionaries-in-memory):

| Layout               | Описание                                                                                                                                                                                                                                                                                                                                                                               |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POLYGON_SIMPLE`     | Наивная реализация. Для каждого запроса выполняется линейный проход по всем полигонам с проверкой вхождения без дополнительных индексов.                                                                                                                                                                                                                                               |
| `POLYGON_INDEX_EACH` | Для каждого полигона строится отдельный индекс, что в большинстве случаев позволяет быстро проверять вхождение (оптимизировано для географических регионов). На область накладывается сетка, рекурсивно разделяющая ячейки на 16 равных частей. Разделение останавливается, когда глубина рекурсии достигает `MAX_DEPTH` или ячейка пересекает не более `MIN_INTERSECTIONS` полигонов. |
| `POLYGON_INDEX_CELL` | Также создаёт описанную выше сетку с теми же параметрами. Для каждой конечной ячейки строится индекс по всем частям полигонов, которые в неё попадают, что позволяет быстро отвечать на запросы.                                                                                                                                                                                       |
| `POLYGON`            | Синоним `POLYGON_INDEX_CELL`.                                                                                                                                                                                                                                                                                                                                                          |

Запросы к словарю выполняются с использованием стандартных [функций](/ru/reference/functions/regular-functions/ext-dict-functions) для работы со словарями.
Важное отличие состоит в том, что здесь ключами будут точки, для которых нужно найти содержащий их полигон.

**Пример**

Пример работы со словарём, определённым выше:

```sql theme={null}
CREATE TABLE points (
    x Float64,
    y Float64
)
...
SELECT tuple(x, y) AS key, dictGet(dict_name, 'name', key), dictGet(dict_name, 'value', key) FROM points ORDER BY x, y;
```

В результате выполнения последней команды для каждой точки в таблице 'points' будет найден содержащий её многоугольник наименьшей площади, и будут выведены запрошенные атрибуты.

**Пример**

Вы можете читать столбцы из полигональных словарей с помощью запроса SELECT — для этого просто включите `store_polygon_key_column = 1` в конфигурации словаря или соответствующем DDL-запросе.

```sql title="Query" theme={null}
CREATE TABLE polygons_test_table
(
    key Array(Array(Array(Tuple(Float64, Float64)))),
    name String
) ENGINE = MergeTree
ORDER BY tuple();

INSERT INTO polygons_test_table VALUES ([[[(3, 1), (0, 1), (0, -1), (3, -1)]]], 'Value');

CREATE DICTIONARY polygons_test_dictionary
(
    key Array(Array(Array(Tuple(Float64, Float64)))),
    name String
)
PRIMARY KEY key
SOURCE(CLICKHOUSE(TABLE 'polygons_test_table'))
LAYOUT(POLYGON(STORE_POLYGON_KEY_COLUMN 1))
LIFETIME(0);

SELECT * FROM polygons_test_dictionary;
```

```text title="Response" theme={null}
┌─key─────────────────────────────┬─name──┐
│ [[[(3,1),(0,1),(0,-1),(3,-1)]]] │ Value │
└─────────────────────────────────┴───────┘
```
