一、搜索日志基础:什么是搜索日志、日志的采集原理、日志的存储格式
大家好,我是这次课程的主讲人。做了十几年搜索架构,我每天打交道最多的东西,其实就是日志。你可能觉得日志就是些文本记录,没什么了不起。但说实话,搜索系统的优化、用户行为的洞察、甚至线上故障的排查,全都得靠它。
这一章,我们就来聊聊搜索日志的基础。我会从三个角度展开:日志到底是什么、它是怎么被采集上来的、以及最终存成什么样子。嗯,内容不深,但都是基本功。
1.1 什么是搜索日志
搜索日志,说白了就是用户每一次搜索行为留下的「脚印」。你想想看,用户在搜索框里输入了什么、点了哪个结果、停留了多久、有没有翻页……这些信息都会被记录下来。
我个人习惯把搜索日志分成两类:
- 行为日志:记录用户干了什么。比如 query、点击、翻页、退出。
- 系统日志:记录系统发生了什么。比如检索耗时、排序耗时、缓存命中情况。
为什么要区分?因为用途不同。行为日志用来分析用户意图,系统日志用来排查性能瓶颈。我在项目中遇到过好几次,运维同学把两种日志混在一起存,结果查问题时数据量爆炸,根本没法快速定位。
核心观点:搜索日志是搜索系统的「黑匣子」。没有它,你就像在黑暗中开车。
1.2 日志的采集原理
日志采集听起来简单,不就是写文件嘛?但到了大规模场景下,事情就没那么简单了。
我经历过一个项目,日搜索量过亿。刚开始我们直接在业务代码里写日志文件,结果磁盘 IO 被打满,搜索响应时间从 50ms 飙到了 500ms。那次教训让我明白:日志采集不能影响主流程。
现在主流的采集方案,一般分三步走:
- 埋点:在搜索请求的入口、出口、关键节点插入日志代码。
- 异步发送:日志数据不直接写磁盘,而是先发到内存队列(比如 Kafka、RocketMQ)。
- 落盘/存储:消费者从队列拉取数据,批量写入存储系统。
举个例子,一个典型的搜索日志采集流程:
用户请求 → 搜索网关(埋点) → Kafka Topic(search_log)
→ Logstash 消费 → 写入 HDFS / ClickHouse
这里有个坑,我曾经踩过:埋点代码一定要做降级。如果 Kafka 挂了,你的日志采集不能把搜索服务也拖死。我一般会在埋点层加一个本地缓冲队列,队列满了就直接丢弃日志,保证主流程不受影响。
避坑指南:我曾经因为日志采集阻塞导致搜索服务雪崩。从那以后,所有日志采集代码都必须设置超时和熔断。
1.3 日志的存储格式
日志采集上来之后,存成什么格式?这问题看似简单,但选错了后面会非常痛苦。我见过有人把所有日志都存成文本文件,结果一个月后磁盘满了,查个数据要 grep 半小时。
目前主流的存储格式有三种:JSON、CSV、Parquet。它们各有各的适用场景。
1.3.1 JSON 格式
JSON 是最灵活的格式。它的优点是可以嵌套、可以动态扩展字段。比如一条搜索日志:
{
"timestamp": "2025-01-15T10:30:00Z",
"user_id": "u12345",
"query": "Python 教程",
"results": [
{"doc_id": "d001", "rank": 1, "click": true},
{"doc_id": "d002", "rank": 2, "click": false}
],
"latency_ms": 45
}
你看,results 字段里可以嵌套多个结果。这在分析用户点击行为时非常方便。但 JSON 也有缺点:存储空间大。同样的数据,JSON 比 Parquet 大 3-5 倍。
我个人建议:实时流处理用 JSON,离线分析别用。因为 JSON 解析慢,而且不支持列式压缩。
1.3.2 CSV 格式
CSV 是最古老的格式。简单、直观、任何工具都能打开。但它的缺点也很明显:不支持嵌套、没有 schema 约束、字段顺序一变就乱。
举个例子,上面那条 JSON 日志转成 CSV 会变成这样:
timestamp,user_id,query,result_ids,result_clicks,latency_ms
2025-01-15T10:30:00Z,u12345,Python 教程,"d001;d002","true;false",45
看到了吗?嵌套结构被强行拍平了。而且如果某个字段里包含逗号,你还得加引号转义。我在项目中遇到过 CSV 解析出错导致数据丢失的情况,从那以后我就很少用 CSV 存日志了。
小技巧:如果你非要用 CSV,记得加一个 schema 文件来描述字段类型和顺序。否则三个月后你自己都看不懂。
1.3.3 Parquet 格式
Parquet 是我现在最常用的格式。它是列式存储,专门为大数据分析设计的。优点非常突出:
- 压缩率高:同样的数据,Parquet 比 JSON 小 70% 以上。
- 查询快:列式存储可以只读取需要的列,不用全量扫描。
- 支持复杂结构:嵌套、数组、Map 都能存。
用 Parquet 存日志,一般会配合 Hive 或 Spark 使用。比如:
-- 创建 Parquet 格式的 Hive 表
CREATE TABLE search_log (
timestamp TIMESTAMP,
user_id STRING,
query STRING,
results ARRAY<STRUCT<doc_id:STRING, rank:INT, click:BOOLEAN>>,
latency_ms INT
)
STORED AS PARQUET;
嗯,这里要注意:Parquet 不适合小文件场景。如果你每条日志都单独存一个 Parquet 文件,那性能反而会下降。我一般建议每 10 万条日志合并成一个 Parquet 文件。
1.4 三种格式对比
为了方便你选择,我整理了一张对比表:
| 特性 | JSON | CSV | Parquet |
|---|---|---|---|
| 存储空间 | 大 | 中 | 小 |
| 解析速度 | 慢 | 快 | 快(列式) |
| 嵌套支持 | ✅ 好 | ❌ 差 | ✅ 好 |
| Schema 约束 | 弱 | 无 | 强 |
| 适用场景 | 实时流、调试 | 小数据、临时分析 | 离线分析、数仓 |
我个人习惯是:实时链路用 JSON,离线数仓用 Parquet,CSV 基本不用。当然,如果你只是临时分析几百条日志,CSV 也够用。
1.5 本章小结
这一章我们聊了搜索日志的基础。说白了,日志就是搜索系统的「病历本」。采集时要保证不影响主流程,存储时要根据场景选格式。
下一章,我会带你看看如何从日志中提取用户行为特征。到时候我们会用到一些实际的数据,手把手分析。嗯,敬请期待。
一句话总结:日志是搜索优化的起点。格式选对了,后面事半功倍。