根据监控日志的特点,我们对 message 字段添加了 tokenbf_v1 索引。
tokenbf_v1 索引的工作原理如下:
- 对于每个列,ClickHouse 会生成一个 tokenbf_v1 过滤器。
- 当插入新数据行时,ClickHouse 会将所有列的值分成单独的标记,并将这些标记添加到相应的 tokenbf_v1 过滤器中。
- 在执行查询时,如果查询包含 WHERE 子句并使用了支持 tokenbf_v1 索引的列,则 ClickHouse 将从 tokenbf_v1 过滤器中获取所有相关的标记,并检查这些标记是否存在于该列的值中。如果标记存在于 tokenbf_v1 过滤器中但不存在于列的值中,则该行数据不符合查询条件,因此可以快速被过滤掉。
由于 tokenbf_v1 索引使用了布隆过滤器算法,因此其大小相对较小,可以有效地减少文件 I/O 和内存开销。同时,它还支持多列索引和复合索引,使得在复杂查询中也能够实现高效率的数据访问。
在Bloom filter设置之前需要一个额外的参数,即要索引的ngram的大小。一个ngram是长度为n的任何字符串,比如如果n是4,A short string
会被分割为'A sh', ' sho', 'shor', 'hort', 'ort ', 'rt s', 't st', ' str', 'stri', 'trin', 'ring'。这个索引对于文本搜索也很有用,特别是没有单词间断的语言,比如中文。
布隆过滤器参数与效果的查询:https://hur.st/bloomfilter/
根据评估不过过滤器的大小我们设置为 30720 ,hash次数 3;
加了 tokenbf_v1 索引的表结构:
CREATE TABLE monitor.qunhe_log
(
`timestamp` DateTime64(3, 'Asia/Shanghai'),
`hostGroup` String,
`ip` String,
`podname` String,
`level` String,
`cls` String,
`behavior` String,
`message` String,
`id` String DEFAULT '',
INDEX message_index message TYPE tokenbf_v1(30720, 3, 0) GRANULARITY 1
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/qunhelog', '{replica}')
PARTITION BY toYYYYMMDD(timestamp)
ORDER BY (level, hostGroup, podname, ip, timestamp)
SETTINGS storage_policy = 'hdd0_hdd1_only', index_granularity = 8192
支持的 函数:
虽然支持 like 函数,但是 像 like '%hunter%' 这样的查询显然是不会走索引的,因为clickhouse 不知道 hunter 是不是一个词。当使用 like 'hunter' 时等同于 = 方法,就会索引;
因此为了走索引,hasToken() 是一个比较常用的方法,使用 hasToken('hunter') 也就意味着告诉 clickhouse 'hunter' 是一个词,可以走分词索引,过滤结果是可靠的;
查询索引效果
以查询某服务最近10分钟 taskId=L3D607S41ENDPFVB2EAUWI5ACLUF3P3XG888 为例:
模糊查询
SELECT
ip,
timestamp,
podname,
cls,
message,
level,
behavior,
hostGroup
FROM
monitor.qunhe_log
WHERE
timestamp >= '2023-05-30 19:50:00.000'
AND timestamp < '2023-05-30 20:00:00.000'
AND hostGroup IN (
'*********隐私信息**********'
)
AND message LIKE '%L3D607S41ENDPFVB2EAUWI5ACLUF3P3XG888%'
ORDER BY
(timestamp,) DESC
LIMIT
50 OFFSET 0
耗时10s
查看索引过滤效果
- 用like查询:耗时 10S,读取了 2.47 million rows 行数据
分词查询
SELECT
ip,
timestamp,
podname,
cls,
message,
level,
behavior,
hostGroup
FROM
monitor.qunhe_log
WHERE
timestamp >= '2023-05-30 19:50:00.000'
AND timestamp < '2023-05-30 20:00:00.000'
AND hostGroup IN (
'*********隐私信息**********'
)
AND hasToken(message,'L3D607S41ENDPFVB2EAUWI5ACLUF3P3XG888')
ORDER BY
(timestamp,) DESC
LIMIT
50 OFFSET 0
耗时0.28s
查看索引过滤效果
- 用 hasToken查询:耗时 0.24S,读取了102.40 thousand rows 行数据;
- 分词索引筛掉了 95% 以上的数据,效果非常好,可以明显看到排掉了6个parts,查询速率明显提升。
总结
- 需要注意的是虽然很多查询方法支持tokenbf_v1索引查询,但是不一定能走索引,比如 like 查询;
- 使用 TokenBF_v1 索引需要考虑到索引大小、误判率、创建时间和资源消耗、更新和删除的限制,以及查询优化和版本兼容性等方面的因素。在实际应用中,根据数据集规模和查询需求做出合理的选择和平衡。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。