External dictionaries topic is restructured and updated.

This commit is contained in:
BayoNet 2017-07-31 11:31:30 +03:00 committed by alexey-milovidov
parent d3118b6e92
commit 7dae4f9f7b
11 changed files with 877 additions and 328 deletions

View File

@ -1,345 +1,44 @@
.. _dicts-external_dicts:
***************
Внешние словари
===============
***************
Существует возможность подключать свои собственные словари из различных источников данных.
Источником данных для словаря может быть файл на локальной файловой системе, сервер ClickHouse, сервер MySQL, MongoDB или любой ODBC источник.
Словарь может полностью храниться в оперативке и периодически обновляться, или быть частично закэшированным в оперативке и динамически подгружать отсутствующие значения.
Существует возможность подключать собственные словари из различных источников данных. Источником данных для словаря может быть локальный текстовый/исполняемый файл, HTTP(s) ресурс или другая СУБД. Подробнее смотрите в разделе ":ref:`dicts-external_dicts_dict_sources`".
Конфигурация внешних словарей находится в отдельном файле или файлах, указанных в конфигурационном параметре :ref:`dictionaries_config <server_settings-dictionaries_config>`.
Этот параметр содержит абсолютный или относительный путь к файлу с конфигурацией словарей. Относительный путь - относительно директории с конфигурационным файлом сервера. Путь может содержать wildcard-ы \* и ? - тогда рассматриваются все подходящие файлы. Пример: ``dictionaries/*.xml``.
ClickHouse может полностью или частично хранить словари в оперативной памяти, периодически обновлять их и динамически подгружать отсутствующие значения.
Конфигурация словарей, а также множество файлов с конфигурацией, может обновляться без перезапуска сервера. Сервер проверяет обновления каждые 5 секунд. То есть, словари могут подключаться динамически.
Конфигурация внешних словарей находится в одном или нескольких файлах. Путь к конфигурации указывается в параметре :ref:`server_settings-dictionaries_config`.
Создание словарей может производиться при старте сервера или при первом использовании. Это определяется конфигурационном параметром :ref:`dictionaries_lazy_load <server_settings-dictionaries_lazy_load>` (в основном конфигурационном файле сервера). Параметр не обязателен, по умолчанию - ``true``. Если true, то каждый словарь создаётся при первом использовании; если словарь не удалось создать - вызов функции, использующей словарь, кидает исключение. Если ``false``, то все словари создаются при старте сервера, и в случае ошибки, сервер завершает работу.
Периодически ClickHouse обновляет конфигурацию словарей и словари. Т.о. словари можно подгружать динамически.
Словари могут загружаться при старте сервера или при первом использовании, в зависимости от настройки :ref:`server_settings-dictionaries_lazy_load`.
Конфигурационный файл словарей имеет вид:
.. code-block:: xml
<dictionaries>
<comment>Не обязательный элемент с любым содержимым; полностью игнорируется.</comment>
<comment>Необязательный элемент с любым содержимым. Полностью игнорируется.</comment>
<!-- Можно задать произвольное количество разных словарей. -->
<dictionary>
<!-- Имя словаря. Под этим именем словарь будет доступен для использования. -->
<name>os</name>
<!-- Источник данных. -->
<source>
<!-- Источник - файл на локальной файловой системе. -->
<file>
<!-- Путь на локальной файловой системе. -->
<path>/opt/dictionaries/os.tsv</path>
<!-- С помощью какого формата понимать файл. -->
<format>TabSeparated</format>
</file>
<!-- или источник - таблица на сервере MySQL.
<mysql>
<!- - Эти параметры могут быть указаны как снаружи (общие для всех реплик), так и внутри конкретной реплики - ->
<port>3306</port>
<user>clickhouse</user>
<password>qwerty</password>
<!- - Можно указать от одной до произвольного количества реплик для отказоустойчивости. - ->
<replica>
<host>example01-1</host>
<priority>1</priority> <!- - Меньше значение - больше приоритет. - ->
</replica>
<replica>
<host>example01-2</host>
<priority>1</priority>
</replica>
<db>conv_main</db>
<table>counters</table>
</mysql>
-->
<!-- или источник - таблица на сервере ClickHouse.
<clickhouse>
<host>example01-01-1</host>
<port>9000</port>
<user>default</user>
<password></password>
<db>default</db>
<table>counters</table>
</clickhouse>
<!- - Если адрес похож на localhost, то запрос будет идти без сетевого взаимодействия.
Для отказоустойчивости, вы можете создать Distributed таблицу на localhost и прописать её. - ->
-->
<!-- Для <mysql> и <clickhouse> доступен атрибут <where>, позволяющий задать условие выбора
<clickhouse>
<host>example01-01-1</host>
<port>9000</port>
<user>default</user>
<password></password>
<db>default</db>
<table>ids</table>
<where>id=10</where>
</clickhouse>
-->
<!-- Конфигурация словаря -->
</dictionary>
<!-- или источник - исполняемый файл. Если layout.cache - список нужных ключей будет записан в поток STDIN программы -->
<executable>
<!-- Путь или имя программы (если директория есть в переменной окружения PATH) и параметры -->
<command>cat /opt/dictionaries/os.tsv</command>
<!-- С помощью какого формата понимать вывод и формировать список ключей. -->
<format>TabSeparated</format>
</executable>
<!-- или источник - http сервер. Если layout.cache - список нужных ключей будет послан как POST запрос -->
<http>
<url>http://[::1]/os.tsv</url>
<!-- С помощью какого формата понимать ответ и формировать список ключей. -->
<format>TabSeparated</format>
</http>
</source>
<!-- Периодичность обновления для полностью загружаемых словарей. 0 - никогда не обновлять. -->
<lifetime>
<min>300</min>
<max>360</max>
<!-- Периодичность обновления выбирается равномерно-случайно между min и max,
чтобы размазать по времени нагрузку при обновлении словарей на большом количестве серверов. -->
</lifetime>
<!-- или
<!- - Периодичность обновления для полностью загружаемых словарей или время инвалидации для кэшируемых словарей.
0 - никогда не обновлять. - ->
<lifetime>300</lifetime>
-->
<layout> <!-- Способ размещения в памяти. -->
<flat />
<!-- или
<hashed />
или
<cache>
<!- - Размер кэша в количестве ячеек; округляется вверх до степени двух. - ->
<size_in_cells>1000000000</size_in_cells>
</cache>
-->
</layout>
<!-- Структура. -->
<structure>
<!-- Описание столбца, являющегося идентификатором (ключом) словаря. -->
<id>
<!-- Имя столбца с идентификатором. -->
<name>Id</name>
</id>
<attribute> <!-- id уже входит в атрибуты и дополнительно указывать его здесь не нужно. -->
<!-- Имя столбца. -->
<name>Name</name>
<!-- Тип столбца. (Как столбец понимается при загрузке.
В случае MySQL, в таблице может быть TEXT, VARCHAR, BLOB, но загружается всё как String) -->
<type>String</type>
<!-- Какое значение использовать для несуществующего элемента. В примере - пустая строка. -->
<null_value></null_value>
</attribute>
<!-- Может быть указано произвольное количество атрибутов. -->
<attribute>
<name>ParentID</name>
<type>UInt64</type>
<null_value>0</null_value>
<!-- Определяет ли иерархию - отображение в идентификатор родителя (по умолчанию, false). -->
<hierarchical>true</hierarchical>
<!-- Можно считать отображение id -> attribute инъективным, чтобы оптимизировать GROUP BY. (по умолчанию, false) -->
<injective>true</injective>
</attribute>
...
<!-- Атрибут может быть выражением -->
<attribute>
<name>expr</name>
<type>UInt64</type>
<expression>rand64()</expression>
<null_value>0</null_value>
</attribute>
</structure>
<dictionary>
<!-- Конфигурация словаря -->
</dictionary>
</dictionaries>
Идентификатор (ключевой атрибут) словаря должен быть числом, помещающимся в UInt64.
Также есть возможность задавать произвольные составные ключи (см. раздел "Словари с составными ключами"). Замечание: составной ключ может состоять и из одного элемента, что даёт возможность использовать в качестве ключа, например, строку.
В одном файле можно :ref:`сконфигурировать <dicts-external_dicts_dict>` произвольное количество словарей. Формат файла сохраняется даже если словарь один (т.е. ``<dictionaries><dictionary> <!--configuration--> </dictionary></dictionaries>``).
Смотрите также ":ref:`ext_dict_functions`" .
Существует шесть способов размещения словаря в памяти.
.. attention:: Вы можете преобразовать значения по небольшому словарю, описав его в запросе ``SELECT`` (см. функцию ":ref:`other_functions-transform`"). Эта функциональность не связана с внешними словарями.
flat
-----
В виде плоских массивов. Самый эффективный способ. Он подходит, если все ключи меньше 500 000. Если при создании словаря обнаружен ключ больше, то кидается исключение и словарь не создаётся. Словарь загружается в оперативку целиком. Словарь использует количество оперативки, пропорциональное максимальному значению ключа. Ввиду ограничения на 500 000, потребление оперативки вряд ли может быть большим.
Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком.
hashed
------
В виде хэш-таблиц. Слегка менее эффективный способ. Словарь тоже загружается в оперативку целиком, и может содержать произвольное количество элементов с произвольными идентификаторами. На практике, имеет смысл использовать до десятков миллионов элементов, пока хватает оперативки.
Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком.
cache
-----
Наименее эффективный способ. Подходит, если словарь не помещается в оперативку. Представляет собой кэш из фиксированного количества ячеек, в которых могут быть расположены часто используемые данные. Поддерживается источник MySQL, ClickHouse, executable, http; источник-файл не поддерживается. При поиске в словаре, сначала просматривается кэш. На каждый блок данных, все не найденные в кэше ключи (или устаревшие ключи) собираются в пачку, и с этой пачкой делается запрос к источнику вида SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...). Затем полученные данные записываются в кэш.
range_hashed
------------
В таблице прописаны какие-то данные для диапазонов дат, для каждого ключа. Дать возможность доставать эти данные для заданного ключа, для заданной даты.
Пример: таблица содержит скидки для каждого рекламодателя в виде:
+------------------+-----------------------------+------------+----------+
| id рекламодателя | дата начала действия скидки | дата конца | величина |
+==================+=============================+============+==========+
| 123 | 2015-01-01 | 2015-01-15 | 0.15 |
+------------------+-----------------------------+------------+----------+
| 123 | 2015-01-16 | 2015-01-31 | 0.25 |
+------------------+-----------------------------+------------+----------+
| 456 | 2015-01-01 | 2015-01-15 | 0.05 |
+------------------+-----------------------------+------------+----------+
Добавляем ``layout = range_hashed``.
При использовании такого layout, в structure должны быть элементы ``range_min``, ``range_max``.
Пример:
.. code-block:: xml
<structure>
<id>
<name>Id</name>
</id>
<range_min>
<name>first</name>
</range_min>
<range_max>
<name>last</name>
</range_max>
...
Эти столбцы должны иметь тип Date. Другие типы пока не поддерживаем.
Столбцы обозначают закрытый диапазон дат.
Для работы с такими словарями, функции dictGetT должны принимать ещё один аргумент - дату:
``dictGetT('dict_name', 'attr_name', id, date)``
Функция достаёт значение для данного id и для диапазона дат, в который входит переданная дата. Если не найден id или для найденного id не найден диапазон, то возвращается значение по умолчанию для словаря.
Если есть перекрывающиеся диапазоны, то можно использовать любой подходящий.
Если граница диапазона является NULL или является некорректной датой (1900-01-01, 2039-01-01), то диапазон следует считать открытым. Диапазон может быть открытым с обеих сторон.
В оперативке данные представлены в виде хэш-таблицы со значением в виде упорядоченного массива диапазонов и соответствующих им значений.
Пример словаря по диапазонам:
.. code-block:: xml
<dictionaries>
<dictionary>
<name>xxx</name>
<source>
<mysql>
<password>xxx</password>
<port>3306</port>
<user>xxx</user>
<replica>
<host>xxx</host>
<priority>1</priority>
</replica>
<db>dicts</db>
<table>xxx</table>
</mysql>
</source>
<lifetime>
<min>300</min>
<max>360</max>
</lifetime>
<layout>
<range_hashed />
</layout>
<structure>
<id>
<name>Abcdef</name>
</id>
<range_min>
<name>StartDate</name>
</range_min>
<range_max>
<name>EndDate</name>
</range_max>
<attribute>
<name>XXXType</name>
<type>String</type>
<null_value />
</attribute>
</structure>
</dictionary>
</dictionaries>
complex_key_hashed
------------------
Для использования с составными ключами. Аналогичен hashed.
complex_key_cache
-----------------
Для использования с составными ключами. Аналогичен cache.
Примечания
----------
Рекомендуется использовать способ ``flat``, если возможно, или ``hashed``, ``complex_key_hashed``. Скорость работы словарей с таким размещением в памяти является безупречной.
Способы ``cache`` и ``complex_key_cache`` следует использовать лишь если это неизбежно. Скорость работы кэша очень сильно зависит от правильности настройки и сценария использования. Словарь типа cache нормально работает лишь при достаточно больших hit rate-ах (рекомендуется 99% и выше). Посмотреть средний hit rate можно в таблице system.dictionaries. Укажите достаточно большой размер кэша. Количество ячеек следует подобрать экспериментальным путём - выставить некоторое значение, с помощью запроса добиться полной заполненности кэша, посмотреть на потребление оперативки (эта информация находится в таблице system.dictionaries); затем пропорционально увеличить количество ячеек так, чтобы расходовалось разумное количество оперативки. В качестве источника для кэша рекомендуется MySQL, MongoDB, так как ClickHouse плохо обрабатывает запросы со случайными чтениями.
Во всех случаях, производительность будет выше, если вызывать функцию для работы со словарём после ``GROUP BY``, или если доставаемый атрибут помечен как инъективный. Для cache словарей, производительность будет лучше, если вызывать функцию после LIMIT-а - для этого можно использовать подзапрос с LIMIT-ом, и снаружи вызывать функцию со словарём.
Атрибут называется инъективным, если разным ключам соответствуют разные значения атрибута. Тогда при использовании в ``GROUP BY`` функции, достающей значение атрибута по ключу, эта функция автоматически выносится из GROUP BY.
При обновлении словарей из файла, сначала проверяется время модификации файла, и загрузка производится только если файл изменился.
При обновлении из MySQL, для flat и hashed словарей, сначала делается запрос ``SHOW TABLE STATUS`` и смотрится время обновления таблицы. И если оно не NULL, то оно сравнивается с запомненным временем. Это работает для MyISAM таблиц, а для InnoDB таблиц время обновления неизвестно, поэтому загрузка из InnoDB делается при каждом обновлении.
Для cache-словарей может быть задано время устаревания (``lifetime``) данных в кэше. Если от загрузки данных в ячейке прошло больше времени, чем lifetime, то значение не используется, и будет запрошено заново при следующей необходимости его использовать.
Если словарь не удалось ни разу загрузить, то при попытке его использования, будет брошено исключение.
Если при запросе к источнику cached словаря возникла ошибка, то будет брошено исключение.
Обновление словарей (кроме загрузки при первом использовании) не блокирует запросы - во время обновления используется старая версия словаря. Если при обновлении возникнет ошибка, то ошибка пишется в лог сервера, а запросы продолжат использовать старую версию словарей.
Список внешних словарей и их статус можно посмотреть в таблице ``system.dictionaries``.
Для использования внешних словарей, смотрите раздел "Функции для работы с внешними словарями".
Обратите внимание, что вы можете преобразовать значения по небольшому словарю, указав всё содержимое словаря прямо в запросе SELECT - смотрите раздел "Функция transform". Эта функциональность никак не связана с внешними словарями.
Словари с составными ключами
----------------------------
В качестве ключа может выступать кортеж (tuple) из полей произвольных типов. Параметр layout в этом случае должен быть равен complex_key_hashed или complex_key_cache.
Структура ключа задаётся не в элементе ``<id>``, а в элементе ``<key>``. Поля ключа задаются в том же формате, что и атрибуты словаря. Пример:
.. code-block:: xml
<structure>
<key>
<attribute>
<name>field1</name>
<type>String</type>
</attribute>
<attribute>
<name>field2</name>
<type>UInt32</type>
</attribute>
...
</key>
...
При использовании такого словаря, в функции dictGet* в качестве ключа передаётся Tuple со значениями полей. Пример: ``dictGetString('dict_name', 'attr_name', tuple('field1', 123))``.
.. toctree::
:glob:
external_dicts_dict*

View File

@ -0,0 +1,35 @@
.. _dicts-external_dicts_dict:
**************************
Настройка внешнего словаря
**************************
Конфигурация словаря имеет следующую структуру:
.. code-block:: xml
<dictionary>
<name>dict_name</name>
<source>
<!-- Source configuration -->
</source>
<layout>
<!-- Memory layout configuration -->
</layout>
<structure>
<!-- Complex key configuration -->
</structure>
<lifetime>
<!-- Lifetime of dictionary in memory -->
</lifetime>
</dictionary>
* name - Идентификатор, под которым словарь будет доступен для использования. Используйте символы ``[a-zA-Z0-9_\-]``.
* :ref:`source <dicts-external_dicts_dict_sources>` - Источник словаря.
* :ref:`layout <dicts-external_dicts_dict_layout>` - Размещение словаря в памяти.
* :ref:`structure <dicts-external_dicts_dict_structure>` - Ключ словаря.
* :ref:`lifetime <dicts-external_dicts_dict_lifetime>` - Периодичность обновления словарей.

View File

@ -0,0 +1,250 @@
.. _dicts-external_dicts_dict_layout:
**************************
Хранение словарей в памяти
**************************
Словари можно размещать в памяти :ref:`множеством способов <dicts-external_dicts_dict_layout-manner>`.
Рекомендуем :ref:`dicts-external_dicts_dict_layout-flat`, :ref:`dicts-external_dicts_dict_layout-hashed` и :ref:`dicts-external_dicts_dict_layout-complex_key_hashed`. Скорость обработки словарей при этом максимальна.
Размещение с кэшированием не рекомендуется использовать из-за потенциально низкой производительности и сложностей в подборе оптимальных параметров. Читайте об этом подробнее в разделе ":ref:`dicts-external_dicts_dict_layout-cache`".
Повысить производительнось словарей можно следующими способами:
* Вызывать функцию для работы со словарём после ``GROUP BY``.
* Помечать извлекаемые атрибуты как инъективные. Атрибут называется инъективным, если разным ключам соответствуют разные значения атрибута. Тогда при использовании в ``GROUP BY`` функции, достающей значение атрибута по ключу, эта функция автоматически выносится из ``GROUP BY``.
ClickHouse периодически обновляет словари. Сначала проверяется время модификации файла/таблицы, затем, если файл/таблица обновились, обновляется словарь. Если словарь хранится в таблице типа MyISAM, то время модификации проверяется запросом ``SHOW TABLE STATUS``. Для таблиц InnoDB нельзя получить время модификации, поэтому словарь обновляется каждый раз.
Обновление словарей (кроме загрузки при первом использовании) не блокирует запросы - во время обновления используется старая версия словаря. Если при обновлении возникнет ошибка, то ошибка пишется в лог сервера, а запросы продолжат использовать старую версию словарей.
При ошибках работы со словарями ClickHouse генерирует исключения. Например, в следующих ситуациях:
* При обращении к словарю, который не удалось загрузить.
* При ошибке запроса к ``cached``-словарю.
Список внешних словарей и их статус можно посмотреть в таблице ``system.dictionaries``.
Общий вид конфигурации:
.. code-block:: xml
<dictionaries>
<dictionary>
...
<layout>
<layout_type>
<!-- layout settings -->
</layout_type>
</layout>
...
</dictionary>
</dictionaries>
.. _dicts-external_dicts_dict_layout-manner:
Способы размещения словарей в памяти
====================================
* :ref:`dicts-external_dicts_dict_layout-flat`
* :ref:`dicts-external_dicts_dict_layout-hashed`
* :ref:`dicts-external_dicts_dict_layout-cache`
* :ref:`dicts-external_dicts_dict_layout-range_hashed`
* :ref:`dicts-external_dicts_dict_layout-complex_key_hashed`
* :ref:`dicts-external_dicts_dict_layout-complex_key_cache`
.. _dicts-external_dicts_dict_layout-flat:
flat
----
Словарь полностью хранится в оперативной памяти в виде плоских массивов. Объем памяти, занимаемой словарем? пропорционален размеру самого большого (по размеру) ключа.
Ключ словаря имеет тип ``UInt64`` и его величина ограничена 500 000. Если при создании словаря обнаружен ключ больше, то ClickHouse бросает исключение и не создает словарь.
Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком.
Это метод обеспечивает максимальную производительность среди всех доступных способов размещения словаря.
Пример конфигурации:
.. code-block:: xml
<layout>
<flat />
</layout>
.. _dicts-external_dicts_dict_layout-hashed:
hashed
------
Словарь полностью хранится в оперативной памяти в виде хэш-таблиц. Словарь может содержать произвольное количество элементов с произвольными идентификаторами. На практике, количество ключей может достигать десятков миллионов элементов.
Поддерживаются все виды источников. При обновлении, данные (из файла, из таблицы) читаются целиком.
Пример конфигурации:
.. code-block:: xml
<layout>
<hashed />
</layout>
.. _dicts-external_dicts_dict_layout-complex_key_hashed:
complex_key_hashed
------------------
Тип размещения предназначен для использования с составными :ref:`ключами <dicts-external_dicts_dict_structure>`. Аналогичен hashed.
Пример конфигурации:
.. code-block:: xml
<layout>
<complex_key_hashed />
</layout>
.. _dicts-external_dicts_dict_layout-range_hashed:
range_hashed
------------
Словарь хранится в оперативной памяти в виде хэш-таблицы с упорядоченным массивом диапазонов и соответствующих им значений.
Этот способ размещения работает также как и hashed и позволяет дополнительно к ключу использовать дипазоны по дате/времени, если они указаны в словаре.
Пример: таблица содержит скидки для каждого рекламодателя в виде:
+------------------+-----------------------------+------------+----------+
| id рекламодателя | дата начала действия скидки | дата конца | величина |
+==================+=============================+============+==========+
| 123 | 2015-01-01 | 2015-01-15 | 0.15 |
+------------------+-----------------------------+------------+----------+
| 123 | 2015-01-16 | 2015-01-31 | 0.25 |
+------------------+-----------------------------+------------+----------+
| 456 | 2015-01-01 | 2015-01-15 | 0.05 |
+------------------+-----------------------------+------------+----------+
Столбцы с датами в словаре должны иметь тип ``Date``.
Чтобы использовать выборку по диапазонам дат, необходимо в :ref:`structure <dicts-external_dicts_dict_structure>` определить элементы ``range_min``, ``range_max``.
Пример:
.. code-block:: xml
<structure>
<id>
<name>Id</name>
</id>
<range_min>
<name>first</name>
</range_min>
<range_max>
<name>last</name>
</range_max>
...
Для работы с такими словарями в функцию ``dictGetT`` необходимо передавать дополнительный аргумент - дату: ::
dictGetT('dict_name', 'attr_name', id, date)
Функция возвращает значение для заданных ``id`` и диапазона дат, в который входит переданная дата.
Особенности алгоритма:
* Если не найден ``id`` или для найденного ``id`` не найден диапазон, то возвращается значение по умолчанию для словаря.
* Если есть перекрывающиеся диапазоны, то можно использовать любой подходящий.
* Если граница диапазона ``NULL`` или некорректная дата (1900-01-01, 2039-01-01), то диапазон считается открытым. Диапазон может быть открытым с обеих сторон.
Пример конфигурации:
.. code-block:: xml
<dictionaries>
<dictionary>
...
<layout>
<range_hashed />
</layout>
<structure>
<id>
<name>Abcdef</name>
</id>
<range_min>
<name>StartDate</name>
</range_min>
<range_max>
<name>EndDate</name>
</range_max>
<attribute>
<name>XXXType</name>
<type>String</type>
<null_value />
</attribute>
</structure>
</dictionary>
</dictionaries>
.. _dicts-external_dicts_dict_layout-cache:
cache
-----
Словарь хранится в кэше, состоящем из фиксированного количества ячеек. Ячейки содержат часто используемые элементы.
При поиске в словаре сначала просматривается кэш. На каждый блок данных, все не найденные в кэше или устаревшие ключи запрашиваются у источника с помощью ``SELECT attrs... FROM db.table WHERE id IN (k1, k2, ...)``. Затем, полученные данные записываются в кэш.
Для cache-словарей может быть задано время устаревания (:ref:`lifetime <dicts-external_dicts_dict_lifetime>`) данных в кэше. Если от загрузки данных в ячейке прошло больше времени, чем ``lifetime``, то значение не используется, и будет запрошено заново при следующей необходимости его использовать.
Это наименее эффективный из всех способов размещения словарей. Скорость работы кэша очень сильно зависит от правильности настройки и сценария использования. Словарь типа cache показывает высокую производительность лишь при достаточно больших hit rate-ах (рекомендуется 99% и выше). Посмотреть средний hit rate можно в таблице ``system.dictionaries``.
Чтобы увеличить производительность кэша, используйте подзапрос с ``LIMIT``, а снаружи вызывайте функцию со словарём.
Поддерживаются :ref:`источники <dicts-external_dicts_dict_sources>`: MySQL, ClickHouse, executable, HTTP.
Пример настройки:
.. code-block:: xml
<layout>
<cache>
<!-- Размер кэша в количестве ячеек. Округляется вверх до степени двух. -->
<size_in_cells>1000000000</size_in_cells>
</cache>
</layout>
Укажите достаточно большой размер кэша. Количество ячеек следует подобрать экспериментальным путём:
1. Выставить некоторое значение.
2. Запросами добиться полной заполненности кэша.
3. Оценить потребление оперативной памяти с помощью таблицы ``system.dictionaries``.
4. Увеличивать/уменьшать количество ячеек до получения требуемого расхода оперативной памяти.
.. warning:: Не используйте в качестве источника ClickHouse, поскольку он медленно обрабатывает запросы со случайным чтением.
.. _dicts-external_dicts_dict_layout-complex_key_cache:
complex_key_cache
-----------------
Тип размещения предназначен для использования с составными :ref:`ключами <dicts-external_dicts_dict_structure>`. Аналогичен ``cache``.

View File

@ -0,0 +1,38 @@
.. _dicts-external_dicts_dict_lifetime:
*******************
Обновление словарей
*******************
ClickHouse периодически обновляет словари. Интервал обновления для полностью загружаемых словарей и интервал инвалидации для кэшируемых словарей определяется в теге ``<lifetime>`` в секундах.
Обновление словарей (кроме загрузки при первом использовании) не блокирует запросы, во время обновления используется старая версия словаря. Если при обновлении возникнет ошибка, то ошибка пишется в лог сервера, а запросы продолжат использовать старую версию словарей.
Пример настройки:
.. code-block:: xml
<dictionary>
...
<lifetime>300</lifetime>
...
</dictionary>
Настройка ``<lifetime>0</lifetime>`` запрещает обновление словарей.
Можно задать интервал, внутри которого ClickHouse равномерно-случайно выберет время для обновления. Это необходимо для распределения нагрузки на источник словаря при обновлении на большом количестве серверов.
Пример настройки:
.. code-block:: xml
<dictionary>
...
<lifetime>
<min>300</min>
<max>360</max>
</lifetime>
...
</dictionary>

View File

@ -0,0 +1,388 @@
.. _dicts-external_dicts_dict_sources:
**************************
Источники внешних словарей
**************************
Внешний словарь можно подключить из множества источников.
Общий вид конфигурации:
.. code-block:: xml
<dictionaries>
<dictionary>
...
<source>
<source_type>
<!-- Source configuration -->
</source_type>
</source>
...
</dictionary>
...
</dictionaries>
Источник настраивается в разделе ``source``.
Типы источников (``source_type``):
* :ref:`dicts-external_dicts_dict_sources-local_file`
* :ref:`dicts-external_dicts_dict_sources-executable`
* :ref:`dicts-external_dicts_dict_sources-http`
* :ref:`dicts-external_dicts_dict_sources-odbc`
* СУБД:
* :ref:`dicts-external_dicts_dict_sources-mysql`
* :ref:`dicts-external_dicts_dict_sources-clickhouse`
* :ref:`dicts-external_dicts_dict_sources-mongodb`
.. _dicts-external_dicts_dict_sources-local_file:
Локальный файл
==============
Пример настройки:
.. code-block:: xml
<source>
<file>
<path>/opt/dictionaries/os.tsv</path>
<format>TabSeparated</format>
</file>
</source>
Поля настройки:
* ``path`` - Абсолютный путь к файлу.
* ``format`` - Формат файла. Поддерживаются все форматы, описанные в разделе ":ref:`formats`".
.. _dicts-external_dicts_dict_sources-executable:
Исполняемый файл
================
Работа с исполняемым файлом зависит от :ref:`размещения словаря в памяти <dicts-external_dicts_dict_layout>`. Если тип размещения словаря ``cache`` и ``complex_key_cache``, то ClickHouse запрашивает необходимые ключи, отправляя запрос в ``STDIN`` исполняемого файла.
Пример настройки:
.. code-block:: xml
<source>
<executable>
<command>cat /opt/dictionaries/os.tsv</command>
<format>TabSeparated</format>
</executable>
</source>
Поля настройки:
* ``command`` - Абсолютный путь к исполняемому файлу или имя файла (если каталог программы прописан в ``PATH``).
* ``format`` - Формат файла. Поддерживаются все форматы, описанные в разделе ":ref:`formats`".
.. _dicts-external_dicts_dict_sources-http:
HTTP(s)
=======
Работа с HTTP(s) сервером зависит от :ref:`размещения словаря в памяти <dicts-external_dicts_dict_layout>`. Если тип размещения словаря ``cache`` и ``complex_key_cache``, то ClickHouse запрашивает необходимые ключи, отправляя запрос методом ``POST``.
Пример настройки:
.. code-block:: xml
<source>
<http>
<url>http://[::1]/os.tsv</url>
<format>TabSeparated</format>
</http>
</source>
Чтобы ClickHouse смог обратиться к HTTPS-ресурсу, необходимо прописать :ref:`настройки openSSL <server_settings-openSSL>` в конфигурации сервера.
Поля настройки:
* ``url`` - URL источника.
* ``format`` - Формат файла. Поддерживаются все форматы, описанные в разделе ":ref:`formats`".
.. _dicts-external_dicts_dict_sources-odbc:
ODBC
====
Этим способом можно подключить любую базу данных, имеющую ODBC драйвер.
Пример настройки:
.. code-block:: xml
<odbc>
<db>DatabaseName</db>
<table>TableName</table>
<connection_string>DSN=some_parameters</connection_string>
</odbc>
Поля настройки:
* ``db`` - Имя базы данных. Не указывать, если имя базы задано в параметрах ``<connection_string>``.
* ``table`` - Имя таблицы.
* ``connection_string`` - Строка соединения.
Пример подключения PostgreSQL
-----------------------------
ОС Ubuntu.
Установка unixODBC и ODBC-драйвера для PostgreSQL: ::
sudo apt-get install -y unixodbc odbcinst odbc-postgresql
Настройка ``/etc/odbc.ini`` (или ``~/.odbc.ini``): ::
[DEFAULT]
Driver = myconnection
[myconnection]
Description = PostgreSQL connection to my_db
Driver = PostgreSQL Unicode
Database = my_db
Servername = 127.0.0.1
UserName = username
Password = password
Port = 5432
Protocol = 9.3
ReadOnly = No
RowVersioning = No
ShowSystemTables = No
ConnSettings =
Конфигурация словаря в ClickHouse:
.. code-block:: xml
<dictionary>
<name>table_name</name>
<source>
<odbc>
<!-- в connection_string можно указывать следующие параметры: -->
<!-- DSN=myconnection;UID=username;PWD=password;HOST=127.0.0.1;PORT=5432;DATABASE=my_db -->
<connection_string>DSN=myconnection</connection_string>
<table>postgresql_table</table>
</odbc>
</source>
<lifetime>
<min>300</min>
<max>360</max>
</lifetime>
<layout>
<hashed/>
</layout>
<structure>
<id>
<name>id</name>
</id>
<attribute>
<name>some_column</name>
<type>UInt64</type>
<null_value>0</null_value>
</attribute>
</structure>
</dictionary>
Может понадобиться в ``odbc.ini`` указать полный путь до библиотеки с драйвером ``DRIVER=/usr/local/lib/psqlodbcw.so``.
Пример подключения MS SQL Server
--------------------------------
ОС Ubuntu.
Установка драйвера: ::
sudo apt-get install tdsodbc freetds-bin sqsh
Настройка драйвера: ::
$ cat /etc/freetds/freetds.conf
...
[MSSQL]
host = 192.168.56.101
port = 1433
tds version = 7.0
client charset = UTF-8
$ cat /etc/odbcinst.ini
...
[FreeTDS]
Description = FreeTDS
Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so
Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so
FileUsage = 1
UsageCount = 5
$ cat ~/.odbc.ini
...
[MSSQL]
Description = FreeTDS
Driver = FreeTDS
Servername = MSSQL
Database = test
UID = test
PWD = test
Port = 1433
Настройка словаря в ClickHouse:
.. code-block:: xml
<dictionaries>
<dictionary>
<name>test</name>
<source>
<odbc>
<table>dict</table>
<connection_string>DSN=MSSQL;UID=test;PWD=test</connection_string>
</odbc>
</source>
<lifetime>
<min>300</min>
<max>360</max>
</lifetime>
<layout>
<flat />
</layout>
<structure>
<id>
<name>k</name>
</id>
<attribute>
<name>s</name>
<type>String</type>
<null_value></null_value>
</attribute>
</structure>
</dictionary>
</dictionaries>
СУБД
====
.. _dicts-external_dicts_dict_sources-mysql:
MySQL
-----
Пример настройки:
.. code-block:: xml
<source>
<mysql>
<port>3306</port>
<user>clickhouse</user>
<password>qwerty</password>
<replica>
<host>example01-1</host>
<priority>1</priority>
</replica>
<replica>
<host>example01-2</host>
<priority>1</priority>
</replica>
<db>conv_main</db>
<table>counters</table>
<where>id=10</where>
</mysql>
</source>
Поля настройки:
* ``port`` - порт сервера MySQL. Можно указать для всех реплик или для каждой в отдельности (внутри ``<replica>``).
* ``user`` - имя пользователя MySQL. Можно указать для всех реплик или для каждой в отдельности (внутри ``<replica>``).
* ``password`` - пароль пользователя MySQL. Можно указать для всех реплик или для каждой в отдельности (внутри ``<replica>``).
* ``replica`` - блок конфигурации реплики. Блоков может быть несколько.
* ``replica/host`` - хост MySQL.
* ``replica/priority`` - приоритет реплики. При попытке соединения ClickHouse обходит реплики в соответствии с приоритетом. Чем меньше цифра, тем выше приоритет.
* ``db`` - имя базы данных.
* ``table`` - имя таблицы.
* ``where`` - условие выбора. Может отсутствовать.
.. _dicts-external_dicts_dict_sources-clickhouse:
ClickHouse
----------
Пример настройки:
.. code-block:: xml
<source>
<clickhouse>
<host>example01-01-1</host>
<port>9000</port>
<user>default</user>
<password></password>
<db>default</db>
<table>ids</table>
<where>id=10</where>
</clickhouse>
</source>
Поля настройки:
* ``host`` - хост ClickHouse. Если host локальный, то запрос выполняется без сетевого взаимодействия. Чтобы повысить отказоустойчивость решения, можно создать таблицу типа :ref:`Distributed <table_engines-distributed>` и прописать её в дальнейших настройках.
* ``port`` - порт сервера ClickHouse.
* ``user`` - имя пользователя ClickHouse.
* ``password`` - пароль пользователя ClickHouse.
* ``db`` - имя базы данных.
* ``table`` - имя таблицы.
* ``where`` - условие выбора. Может отсутствовать.
.. _dicts-external_dicts_dict_sources-mongodb:
MongoDB
-------
Пример настройки:
.. code-block:: xml
<source>
<mongodb>
<host>localhost</host>
<port>27017</port>
<user></user>
<password></password>
<db>test</db>
<collection>dictionary_source</collection>
</mongodb>
</source>
Поля настройки:
* ``host`` - хост MongoDB.
* ``port`` - порт сервера MongoDB.
* ``user`` - имя пользователя MongoDB.
* ``password`` - пароль пользователя MongoDB.
* ``db`` - имя базы данных.
* ``collection`` - имя коллекции.

View File

@ -0,0 +1,125 @@
.. _dicts-external_dicts_dict_structure:
*******************
Ключ и поля словаря
*******************
Секция ``<structure>`` описывает ключ словаря и поля, доступные для запросов.
Общий вид структуры:
.. code-block:: xml
<dictionary>
<structure>
<id>
<name>Id</name>
</id>
<attribute>
<!-- Attribute parameters -->
</attribute>
...
</structure>
</dictionary>
В структуре описываются столбцы:
* ``<id>`` - :ref:`ключевой столбец <dicts-external_dicts_dict_structure-key>`.
* ``<attribute>`` - :ref:`столбец данных <dicts-external_dicts_dict_structure-attributes>`. Столбцов может быть много.
.. _dicts-external_dicts_dict_structure-key:
Ключ
====
ClickHouse поддерживает следующие виды ключей:
* Числовой ключ. Формат UInt64. Описывается в теге ``<id>``.
* Составной ключ. Набор значений разного типа. Описывается в теге ``<key>``.
Структура может содержать либо ``<id>`` либо ``<key>``.
.. attention:: Ключ не надо дополнительно описывать в атрибутах.
Числовой ключ
--------------
Формат: ``UInt64``.
Пример конфигурации:
.. code-block:: xml
<id>
<name>Id</name>
</id>
Поля конфигурации:
* name - имя столбца с ключами.
Составной ключ
---------------
Ключем может быть кортеж (``tuple``) из полей произвольных типов. :ref:`layout <dicts-external_dicts_dict_layout>` в этом случае должен быть ``complex_key_hashed`` или ``complex_key_cache``.
.. tip:: Cоставной ключ может состоять и из одного элемента, что даёт возможность использовать в качестве ключа, например, строку.
Структура ключа задаётся в элементе ``<key>``. Поля ключа задаются в том же формате, что и :ref:`атрибуты <dicts-external_dicts_dict_structure-attributes>` словаря. Пример:
.. code-block:: xml
<structure>
<key>
<attribute>
<name>field1</name>
<type>String</type>
</attribute>
<attribute>
<name>field2</name>
<type>UInt32</type>
</attribute>
...
</key>
...
При запросе в функции ``dictGet*`` в качестве ключа передаётся кортеж. Пример: ``dictGetString('dict_name', 'attr_name', tuple('string for field1', num_for_field2))``.
.. _dicts-external_dicts_dict_structure-attributes:
Атрибуты
========
Пример конфигурации:
.. code-block:: xml
<structure>
...
<attribute>
<name>Name</name>
<type>Type</type>
<null_value></null_value>
<expression>rand64()</expression>
<hierarchical>true</hierarchical>
<injective>true</injective>
</attribute>
</structure>
Поля конфигурации:
* ``name`` - Имя столбца.
* ``type`` - Тип столбца. Задает способ интерпретации данных в источнике. Например, в случае MySQL, в таблице-источнике поле может быть ``TEXT``, ``VARCHAR``, ``BLOB``, но загружено может быть как ``String``.
* ``null_value`` - Значение по умолчанию для несуществующего элемента. В примере - пустая строка.
* ``expression`` - Атрибут может быть выражением. Тег не обязательный.
* ``hierarchical`` - Поддержка иерархии. Отображение в идентификатор родителя. По умолчанию, ``false``.
* ``injective`` - Признак инъективности отображения ``id -> attribute``. Если ``true``, то можно оптимизировать ``GROUP BY``. По умолчанию, ``false``.

View File

@ -7,6 +7,6 @@
Существуют встроенные и подключаемые (внешние) словари.
.. toctree::
:glob:
*
external_dicts
internal_dicts

View File

@ -1,3 +1,5 @@
.. _formats:
Форматы
=======

View File

@ -1,6 +1,8 @@
.. _ext_dict_functions:
Функции для работы с внешними словарями
---------------------------------------
Подробнее смотрите в разделе "Внешние словари".
Информация о подключении и настройке внешних словарей смотрите в разделе :ref:`dicts-external_dicts`.
dictGetUInt8, dictGetUInt16, dictGetUInt32, dictGetUInt64
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -108,6 +108,8 @@ bar
│ 23 │ 400397 │ █████████████▎ │
└────┴────────┴────────────────────┘
.. _other_functions-transform:
transform
~~~~~~~~~
Преобразовать значение согласно явно указанному отображению одних элементов на другие.

View File

@ -98,9 +98,13 @@ default_profile
dictionaries_config
-------------------
Конфигурация внешних словарей.
Путь к конфигурации внешних словарей.
Смотрите раздел :ref:`dicts-external_dicts`.
Путь:
* Указывается абсолютным или относительно конфигурационного файла сервера.
* Может содержать wildcard-ы \* и ?.
Про внешние словари читайте в разделе :ref:`dicts-external_dicts`.
**Пример**
@ -116,7 +120,11 @@ dictionaries_lazy_load
Отложенная загрузка словарей.
С установленным параметром словари подгружаются не при запуске сервера, а при первом обращении.
Если ``true``, то каждый словарь создаётся при первом использовании. Если словарь не удалось создать, то вызов функции, использующей словарь, сгенерирует исключение.
Если ``false``, то все словари создаются при старте сервера, и в случае ошибки сервер завершает работу.
По умолчанию - ``true``.
**Пример**