range_hashed
Словарь хранится в памяти в виде хеш-таблицы с упорядоченным массивом диапазонов и соответствующих им значений.
Этот способ хранения работает так же, как hashed, и позволяет использовать диапазоны даты/времени (произвольного числового типа) в дополнение к ключу.
Пример: Таблица содержит скидки для каждого рекламодателя в следующем формате:
┌─advertiser_id─┬─discount_start_date─┬─discount_end_date─┬─amount─┐
│ 123 │ 2015-01-16 │ 2015-01-31 │ 0.25 │
│ 123 │ 2015-01-01 │ 2015-01-15 │ 0.15 │
│ 456 │ 2015-01-01 │ 2015-01-15 │ 0.05 │
└───────────────┴─────────────────────┴───────────────────┴────────┘Чтобы использовать диапазоны дат, определите элементы range_min и range_max в структуре. В этих элементах должны быть указаны name и type (если type не указан, будет использоваться тип по умолчанию — Date). type может быть любым числовым типом (Date / DateTime / UInt64 / Int32 / другие).
Пример:
CREATE DICTIONARY discounts_dict (
advertiser_id UInt64,
discount_start_date Date,
discount_end_date Date,
amount Float64
)
PRIMARY KEY id
SOURCE(CLICKHOUSE(TABLE 'discounts'))
LIFETIME(MIN 1 MAX 1000)
LAYOUT(RANGE_HASHED(range_lookup_strategy 'max'))
RANGE(MIN discount_start_date MAX discount_end_date)<layout>
<range_hashed>
<!-- Стратегия для перекрывающихся диапазонов (min/max). По умолчанию: min (возвращает подходящий диапазон с минимальным значением range_min -> range_max) -->
<range_lookup_strategy>min</range_lookup_strategy>
</range_hashed>
</layout>
<structure>
<id>
<name>advertiser_id</name>
</id>
<range_min>
<name>discount_start_date</name>
<type>Date</type>
</range_min>
<range_max>
<name>discount_end_date</name>
<type>Date</type>
</range_max>
...Чтобы работать с этими словарями, нужно передать в функцию dictGet дополнительный аргумент, по которому выбирается диапазон:
dictGet('dict_name', 'attr_name', id, date)Пример запроса:
SELECT dictGet('discounts_dict', 'amount', 1, '2022-10-20'::Date);Эта функция возвращает значение для указанных id и диапазона дат, в который попадает переданная дата.
Подробности алгоритма:
- Если
idне найден или дляidне найден диапазон, возвращается значение по умолчанию для типа атрибута. - Если есть перекрывающиеся диапазоны и
range_lookup_strategy=min, возвращается подходящий диапазон с минимальнымrange_min; если найдено несколько диапазонов, возвращается диапазон с минимальнымrange_max; если и после этого найдено несколько диапазонов (то есть несколько диапазонов имеют одинаковыеrange_minиrange_max), возвращается случайный диапазон из них. - Если есть перекрывающиеся диапазоны и
range_lookup_strategy=max, возвращается подходящий диапазон с максимальнымrange_min; если найдено несколько диапазонов, возвращается диапазон с максимальнымrange_max; если и после этого найдено несколько диапазонов (то есть несколько диапазонов имеют одинаковыеrange_minиrange_max), возвращается случайный диапазон из них. - Если
range_maxимеет значениеNULL, диапазон считается открытым.NULLрассматривается как максимально возможное значение. Дляrange_minв качестве открытого значения можно использовать1970-01-01или0(-MAX_INT).
Пример конфигурации:
CREATE DICTIONARY somedict(
Abcdef UInt64,
StartTimeStamp UInt64,
EndTimeStamp UInt64,
XXXType String DEFAULT ''
)
PRIMARY KEY Abcdef
RANGE(MIN StartTimeStamp MAX EndTimeStamp)<clickhouse>
<dictionary>
...
<layout>
<range_hashed />
</layout>
<structure>
<id>
<name>Abcdef</name>
</id>
<range_min>
<name>StartTimeStamp</name>
<type>UInt64</type>
</range_min>
<range_max>
<name>EndTimeStamp</name>
<type>UInt64</type>
</range_max>
<attribute>
<name>XXXType</name>
<type>String</type>
<null_value />
</attribute>
</structure>
</dictionary>
</clickhouse>Пример конфигурации с перекрывающимися и открытыми диапазонами:
CREATE TABLE discounts
(
advertiser_id UInt64,
discount_start_date Date,
discount_end_date Nullable(Date),
amount Float64
)
ENGINE = Memory;
INSERT INTO discounts VALUES (1, '2015-01-01', Null, 0.1);
INSERT INTO discounts VALUES (1, '2015-01-15', Null, 0.2);
INSERT INTO discounts VALUES (2, '2015-01-01', '2015-01-15', 0.3);
INSERT INTO discounts VALUES (2, '2015-01-04', '2015-01-10', 0.4);
INSERT INTO discounts VALUES (3, '1970-01-01', '2015-01-15', 0.5);
INSERT INTO discounts VALUES (3, '1970-01-01', '2015-01-10', 0.6);
SELECT * FROM discounts ORDER BY advertiser_id, discount_start_date;
┌complex_key_range_hashed
Словарь хранится в памяти в виде хеш-таблицы с упорядоченным массивом диапазонов и соответствующих им значений (см. range_hashed). Этот тип хранилища используется с составными ключами.
Пример конфигурации:
CREATE DICTIONARY range_dictionary
(
CountryID UInt64,
CountryKey String,
StartDate Date,
EndDate Date,
Tax Float64 DEFAULT 0.2
)
PRIMARY KEY CountryID, CountryKey
SOURCE(CLICKHOUSE(TABLE 'date_table'))
LIFETIME(MIN 1 MAX 1000)
LAYOUT(COMPLEX_KEY_RANGE_HASHED())
RANGE(MIN StartDate MAX EndDate);