课程Apache Doris 黑客松自主安排进度 · 随时开始 · 无需报名

赛道 A · 任务 A3

日志检索 工具

构建完全基于 SQL 的迷你 Kibana,再用它排查 11:40 开始出现的 checkout 故障。

  • 60–120 分钟
  • 新手友好
  • 任意语言 · CLI 或网页
  • 欢迎使用 AI 工具

遇到问题? 可在 #dev 提问,频道位于 Apache Doris Slack。维护者和其他参与者会提供帮助。

1

准备环境

了解构建目标、Doris 如何简化实现,并启动集群。

构建目标

构建日志检索工具,并用它解决一次故障。

200,000 条日志、六个服务和一个出现故障的上午。在同一张 Doris 表上,使用原生 SQL 实现 BM25 关键词检索,按服务、级别和时间过滤,并实时统计结果。

构建一个小型日志检索工具,包含:

  • 一个 搜索框 ,支持关键词、短语和相关性排序;
  • 过滤器 ,可选择服务、级别和时间范围;
  • 分面计数 ,在结果旁展示各服务、各级别的命中数量;
  • 还可提供 时间线 ,按 5 分钟统计错误数。

随后完成真正的排查: 11:40 开始出现 checkout 失败,哪个服务是根因,问题究竟从何时开始? 工具应让答案清晰可见。

界面草图待构建的界面 · 线框图,非实际截图

草图位于代码面板顶部

Doris 为何适合这个项目

  • 同一张表兼顾搜索与分析。 倒排索引用于关键词查询,相同的 WHERE 条件还可用于 GROUP BY 以统计分面,无需同步第二套系统。

  • 真正的相关性排序。 score() 通过 BM25 对结果排序,使最相关的日志优先,而非仅按时间新旧排列。

  • 低成本过滤。 service 和 level 分别有倒排索引;时间范围则通过排序键裁剪。

代码面板:表定义中的索引语句

开始之前

  • docker pull apache/doris:all-in-one-4.1.3
  • docker run -d --name doris -p 9030:9030 -p 8030:8030 -p 8040:8040 apache/doris:all-in-one-4.1.3
  • docker exec -it doris mysql -uroot -h127.0.0.1 -P9030
  • curl -LO https://github.com/morningman/demo-env/releases/download/for-hackathon/doris-hackathon-glasgow-2026.zip && unzip doris-hackathon-glasgow-2026.zip && cd doris-hackathon-glasgow-2026
主机
127.0.0.1
端口
9030
用户
root无密码
数据库
hackathon

数据

hackathon.app_logs :六个服务共用一张表。

数据表hackathon.app_logs · sql
CREATE TABLE app_logs (  ts          DATETIME(3)  NOT NULL,  service     VARCHAR(32)  NOT NULL,   -- api-gateway, auth, catalog, search, checkout, payment  level       VARCHAR(8)   NOT NULL,   -- DEBUG / INFO / WARN / ERROR  host        VARCHAR(32),  trace_id    VARCHAR(32),  status      INT,                     -- HTTP status, when relevant  latency_ms  INT,  message     STRING       NOT NULL,  INDEX idx_msg (message) USING INVERTED PROPERTIES ("parser" = "english", "support_phrase" = "true"),  INDEX idx_service (service) USING INVERTED,  INDEX idx_level (level) USING INVERTED)DUPLICATE KEY(ts)DISTRIBUTED BY HASH(trace_id) BUCKETS 1PROPERTIES ("replication_num" = "1");

seed/a3_app_logs.sql 会生成 2026 年 10 月 13 日的 200,000 条日志 ,仅需一条 INSERT … SELECT … FROM numbers("number" = "200000") ,无需下载。其中包含待排查的故障。

代码面板 → 建表:完整表定义

借助 AI 构建

推荐与 AI 编程助手协作完成任务。 Doris 4.x 的搜索与 AI 能力较新,可能晚于多数模型的训练数据。在让助手编写 SQL 前,请先提供正确上下文:

  1. 将下方 上下文提示词 粘贴给编程助手。

  2. 让助手阅读本页列出的 参考文档 以及入门包中的 AGENTS.md 文件。许多编程助手会自动读取该文件。

  3. 将 SQL 接入代码前,要求助手先在您的实际集群中运行每条语句。

  4. 还可以连接 Doris MCP Server ,参见 任务 A2,让助手自行检查 Schema 和测试查询。

上下文提示词粘贴给编程助手
I'm building a log search explorer on Apache Doris 4.1 for a hackathon.Connection: MySQL protocol, 127.0.0.1:9030, user root, empty password, database `hackathon`.Use a plain MySQL driver and raw SQL.Table `app_logs`: ts DATETIME(3), service, level, host, trace_id, status INT, latency_ms INT,message STRING. Inverted indexes on message (english parser, phrase support), service, level.Doris SQL rules:1. Text search: `message MATCH_ANY 'a b'`, `MATCH_ALL`, `MATCH_PHRASE 'a b'`. Never LIKE.2. BM25: `score()` only with a MATCH_* predicate + `ORDER BY score() DESC LIMIT n`,   selected plain (`score() AS relevance`): no ROUND() or JOIN in that SELECT.   Bind the user's search text as a driver parameter.3. score() cannot be used with GROUP BY. For facet counts run a second query with the   same WHERE clause and GROUP BY service, level.4. Time buckets: `minute_floor(ts, 5)`.Build: search box, service/level/time filters, facet counts, and an error timeline.Run every SQL statement against the live cluster first.

AI 编程助手容易踩到的 Doris 问题

TrapWhat to do instead
使用 LIKE '%term%' 进行文本检索col MATCH_ANY 'a b' (OR)、 MATCH_ALL (AND)、 MATCH_PHRASE 'a b' ,这些运算符会使用倒排索引
在任意查询中调用 score() 函数score() 要求在查询中使用 MATCH_* 谓词,放在 WHERE 中,并提供 ORDER BY score() DESC LIMIT n,否则 Doris 会拒绝查询
在同一查询中对 score() 进行取整、关联或排名在单表查询中直接保留 score() AS relevance 。如需取整、关联或使用 ROW_NUMBER() ,请在外层查询中操作,并使用子查询,而非 WITH CTE
score() 位于 GROUP BY 或聚合函数内不支持。统计分面计数时,请复用相同的 WHERE 条件,但去掉 score()
使用 ORM建议使用普通 MySQL 驱动和原生 SQL,ORM 可能生成 Doris 不支持的语句
2

开始构建

6 个里程碑, M0 → M5。代码面板会跟随您阅读的步骤。

  1. 里程碑 05 分钟

    生成日志

    在入门包目录中执行:

    M0 · 生成日志bash
    docker exec -i doris mysql -uroot -h127.0.0.1 -P9030 < seed/a3_app_logs.sql
    检查点

    数秒后应得到: 200,000 条日志,时间从 00:00:00 到 23:59:59 ,日期为 10 月 13 日。

  2. 里程碑 115 分钟

    使用 BM25 进行关键词检索

    M1 · 使用 BM25 进行关键词检索sql
    USE hackathon;SELECT ts, service, level, message, score() AS relevanceFROM app_logsWHERE message MATCH_ANY 'timeout refused'ORDER BY relevance DESCLIMIT 20;

    接入搜索框时,将用户文本作为驱动参数传入(MATCH_ANY %s); a3/starter.py 入门包已提供对应实现。

    检查点

    前 20 条结果均为 connection refused 日志。BM25 会给稀有词更高权重: refused 出现在 68 条日志中, timeout 出现在 347 条中。单独搜索 timeout 即可看到其余结果。

  3. 里程碑 215 分钟

    过滤条件

    M2 · 过滤条件sql
    SELECT ts, service, level, message, score() AS relevanceFROM app_logsWHERE message MATCH_ANY 'timeout'  AND level = 'ERROR'  AND service IN ('checkout', 'payment')  AND ts >= '2026-10-13 11:00:00' AND ts < '2026-10-13 12:30:00'ORDER BY relevance DESCLIMIT 20;
    检查点

    每条结果都是提到 timeout 的 ERROR 日志,只出现两个服务中的一个。

  4. 里程碑 315 分钟

    分面计数

    score() 不能用于聚合,因此分面统计使用相同过滤条件,但不包含它:

    M3 · 分面计数sql
    SELECT service, level, COUNT(*) AS hitsFROM app_logsWHERE message MATCH_ANY 'timeout'  AND ts >= '2026-10-13 11:00:00' AND ts < '2026-10-13 12:30:00'GROUP BY service, levelORDER BY hits DESC;
    检查点

    该时间窗口中有 163 条匹配日志,全部为 ERROR。计数总和应等于不包含 GROUP BY,可使用 SELECT COUNT(*) 核对,并保持相同的 WHERE.

  5. 里程碑 415 分钟

    错误时间线

    M4 · 错误时间线sql
    SELECT minute_floor(ts, 5) AS bucket, service, COUNT(*) AS errorsFROM app_logsWHERE level = 'ERROR'  AND ts >= '2026-10-13 11:00:00' AND ts < '2026-10-13 12:30:00'GROUP BY bucket, serviceORDER BY bucket, service;
    检查点

    两个服务在 11:35 至 12:00 之间出现明显增长;当天其他时间,没有服务在 5 分钟内产生超过 4 条错误。

  6. 里程碑 5

    解决故障

    使用工具回答: 哪个服务导致 checkout 失败?具体从哪一分钟开始? 将答案及其验证查询写入 README。

3

完成并提交

完成清单,展示成果,领取徽章。

完成标准

您的检查清单

提交并领取徽章

参与 → 提交 → 领取徽章。

  1. 请将成果放到以 您的 GitHub ID命名的目录中:包括代码和 README,说明项目功能、运行方式、使用的 Doris 能力,并附一张截图或 GIF。

  2. 提交 Pull Request ,将成果添加到 morningman/demo-env ,目录为 doris-hackathon-glasgow-2026/<your-github-id>/。可以先 Fork 后推送,或使用 GitHub 的 Add file → Upload files(添加文件 → 上传文件)。无需填写其他内容。

  3. 分享成果 到 #dev ( Apache Doris Slack):附上 Pull Request 或仓库链接,以及截图或简短演示。问题交流、成果提交和徽章领取都在该频道处理。

每位参与任务的开发者都可获得 Apache Doris 贡献者徽章,无需先有 PR 合入 Doris。任务没有截止日期,可按自己的节奏完成。可以组队,也可独立参与;请将每位成员的 GitHub ID 写入 README.

进阶目标

  • 短语检索与输入补全: MATCH_PHRASE 'connection refused', MATCH_PHRASE_PREFIX 实现边输入边搜索。

  • 链路视图:点击一条日志,按时间顺序展示具有相同 trace_id的全部日志。

  • 查询字符串检索:尝试 SEARCH() DSL,使用 Lucene 风格的 field:term AND …,参阅 SEARCH 函数.

  • 实时日志尾部视图:每秒插入少量新行,并自动刷新。

  • 索引与无索引对比:比较 MATCH_ANY 与 LIKE '%timeout%' 在完整表上的耗时,并展示结果。

故障排查与参考资料

SymptomFix
docker: command not found 出现在 macOS 上启动 Docker Desktop;若已运行,请为 CLI 创建链接: sudo ln -s /Applications/Docker.app/Contents/Resources/bin/docker /usr/local/bin/docker
error getting credentials 出现在拉取镜像时请移除 credsStore 字段,所在文件为 ~/.docker/config.json (仅适用于本地开发)
port is already allocated9030、8030 或 8040 已被其他程序占用,常见原因是另一个 Doris 实例。先查看运行中的容器(docker ps),再停止冲突的服务;也可映射其他主机端口,例如 -p 19030:9030,然后连接 19030
The container name "/doris" is already in use此前已启动过该容器,可执行: docker start doris。如需从头开始,请执行 docker rm -f doris ,此操作会删除容器数据
容器退出,或始终未变为 (healthy)请查看 docker logs doris。通常是内存不足,请在 Docker Desktop 的 Settings → Resources 中分配至少 6 GB。Apple Silicon 设备不要添加 --platform linux/amd64
permission denied: ./doris.sh解压工具可能丢失了可执行权限,请执行: chmod +x doris.sh,或运行 bash doris.sh start
Current database is not set请先执行 USE hackathon; ,或在连接时使用 -Dhackathon
score() function requires WHERE clause with MATCH function, ORDER BY and LIMIT请添加 MATCH_* 谓词、 ORDER BY score() DESC 以及 LIMIT,并保持 score() 不被其他表达式包裹,参见前文说明
超过 10 分钟仍未解决可在 #dev 频道提问,位于 Apache Doris Slack

参考资料

全文检索BM25倒排索引SEARCH 函数

Apache Doris 黑客松

全部任务

返回课程
  1. A160–120 分钟混合检索应用查看说明
  2. A245–90 分钟通过 MCP 询问 Doris查看说明
  3. A360–120 分钟日志检索工具当前步骤
  4. A460–120 分钟Agent 链路分析工具查看说明
  5. B30–60 分钟赛道 B · 从文档到演示查看说明