跳转到主要内容

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 │
└───────────────┴─────────────────────┴───────────────────┴────────┘
要为日期范围使用样本,请在 structure 中定义 range_minrange_max 元素。这些元素必须包含 nametype 元素 (如果未指定 type,则使用默认类型 Date) 。type 可以是任意数值类型 (Date / DateTime / UInt64 / Int32 / 其他) 。
range_minrange_max 的值应能适配 Int64 类型。
示例:
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)

要使用这些字典,你需要向 dictGet 函数额外传递一个参数,用于指定要选择的范围:
dictGet('dict_name', 'attr_name', id, date)
查询示例:
SELECT dictGet('discounts_dict', 'amount', 1, '2022-10-20'::Date);
此函数返回指定 id 的值,以及包含传入日期的日期范围。 算法细节:
  • 如果未找到 id,或未找到该 id 对应的范围,则返回该 attribute 类型的默认值。
  • 如果存在重叠范围且 range_lookup_strategy=min,则返回 range_min 最小的匹配范围;如果找到多个范围,则返回 range_max 最小的范围;如果仍然找到多个范围 (多个范围具有相同的 range_minrange_max) ,则从中随机返回一个范围。
  • 如果存在重叠范围且 range_lookup_strategy=max,则返回 range_min 最大的匹配范围;如果找到多个范围,则返回 range_max 最大的范围;如果仍然找到多个范围 (多个范围具有相同的 range_minrange_max) ,则从中随机返回一个范围。
  • 如果 range_maxNULL,则该范围为开放区间。NULL 被视为可能的最大值。对于 range_min,可使用 1970-01-010 (-MAX_INT) 作为开放值。
配置示例:
CREATE DICTIONARY somedict(
    Abcdef UInt64,
    StartTimeStamp UInt64,
    EndTimeStamp UInt64,
    XXXType String DEFAULT ''
)
PRIMARY KEY Abcdef
RANGE(MIN StartTimeStamp MAX EndTimeStamp)

包含重叠范围和开放区间的配置示例:
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;
┌─advertiser_id─┬─discount_start_date─┬─discount_end_date─┬─amount─┐
12015-01-01 │              ᴺᵁᴸᴸ │    0.1
12015-01-15 │              ᴺᵁᴸᴸ │    0.2
22015-01-012015-01-150.3
22015-01-042015-01-100.4
31970-01-012015-01-150.5
31970-01-012015-01-100.6
└───────────────┴─────────────────────┴───────────────────┴────────┘

-- RANGE_LOOKUP_STRATEGY 'max'(最大值策略)

CREATE DICTIONARY discounts_dict
(
    advertiser_id UInt64,
    discount_start_date Date,
    discount_end_date Nullable(Date),
    amount Float64
)
PRIMARY KEY advertiser_id
SOURCE(CLICKHOUSE(TABLE discounts))
LIFETIME(MIN 600 MAX 900)
LAYOUT(RANGE_HASHED(RANGE_LOOKUP_STRATEGY 'max'))
RANGE(MIN discount_start_date MAX discount_end_date);

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-14')) res;
┌─res─┐
0.1-- 只有一个范围匹配:2015-01-01 - Null
└─────┘

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-16')) res;
┌─res─┐
0.2-- 两个范围均匹配,range_min 2015-01-15 (0.2) 大于 2015-01-01 (0.1)
└─────┘

select dictGet('discounts_dict', 'amount', 2, toDate('2015-01-06')) res;
┌─res─┐
0.4-- 两个范围均匹配,range_min 2015-01-04 (0.4) 大于 2015-01-01 (0.3)
└─────┘

select dictGet('discounts_dict', 'amount', 3, toDate('2015-01-01')) res;
┌─res─┐
0.5-- 两个范围均匹配,range_min 相等,2015-01-15 (0.5) 大于 2015-01-10 (0.6)
└─────┘

DROP DICTIONARY discounts_dict;

-- RANGE_LOOKUP_STRATEGY 'min'(最小值策略)

CREATE DICTIONARY discounts_dict
(
    advertiser_id UInt64,
    discount_start_date Date,
    discount_end_date Nullable(Date),
    amount Float64
)
PRIMARY KEY advertiser_id
SOURCE(CLICKHOUSE(TABLE discounts))
LIFETIME(MIN 600 MAX 900)
LAYOUT(RANGE_HASHED(RANGE_LOOKUP_STRATEGY 'min'))
RANGE(MIN discount_start_date MAX discount_end_date);

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-14')) res;
┌─res─┐
0.1-- 只有一个范围匹配:2015-01-01 - Null
└─────┘

select dictGet('discounts_dict', 'amount', 1, toDate('2015-01-16')) res;
┌─res─┐
0.1-- 两个范围均匹配,range_min 2015-01-01 (0.1) 小于 2015-01-15 (0.2)
└─────┘

select dictGet('discounts_dict', 'amount', 2, toDate('2015-01-06')) res;
┌─res─┐
0.3-- 两个范围均匹配,range_min 2015-01-01 (0.3) 小于 2015-01-04 (0.4)
└─────┘

select dictGet('discounts_dict', 'amount', 3, toDate('2015-01-01')) res;
┌─res─┐
0.6-- 两个范围均匹配,range_min 相等,2015-01-10 (0.6) 小于 2015-01-15 (0.5)
└─────┘

complex_key_range_hashed

字典以哈希表的形式存储在内存中,其中包含按顺序排列的范围数组及其对应的值 (参见 range_hashed) 。这种存储类型适用于复合keys 配置示例:
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);
最后修改于 2026年6月10日