КурсХакатон Apache DorisЗадания в своём темпе · начните в любое время · без регистрации

Трек A · Задание A3

Обозреватель поиска по логам

Мини-Kibana, где всё работает на SQL. С её помощью выясните причину сбоя оформления заказов в 11:40.

  • 60–120 мин
  • Для начинающих
  • Любой язык · CLI или веб
  • ИИ-инструменты приветствуются

Нужна помощь? Спросите в #dev в Slack Apache Doris. Разработчики и другие участники помогут вам.

1

Подготовка

Что вы создаёте, почему Doris упрощает задачу и как запустить кластер.

Что вы создадите

Создайте обозреватель логов и разберите с его помощью сбой.

200,000 строк логов, шесть сервисов, одно неудачное утро. Ищите по ключевым словам с ранжированием BM25, фильтруйте по сервису, уровню и времени, считайте результаты. Всё на обычном SQL в одной таблице Doris.

Небольшой обозреватель логов с:

  • одним полем поиска (ключевые слова, фразы) с ранжированием по релевантности,
  • фильтрами по сервису, уровню и диапазону времени,
  • счётчиками фасетов рядом с результатами (совпадения по сервисам и уровням),
  • необязательной хронологией числа ошибок за каждые 5 минут.

Затем настоящее испытание: В 11:40 оформление заказов начало сбоить. Какой сервис стал причиной и когда проблема началась на самом деле? Ваш обозреватель должен сделать ответ очевидным.

ЭскизЧто вы создадите · схема интерфейса, не снимок экрана

Эскиз находится в верхней части панели кода

Почему это интересно на 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 генерирует 200,000 строк за 13 октября 2026 г. одним INSERT … SELECT … FROM numbers("number" = "200000") . Скачивать ничего не нужно. Где-то в этих данных скрыт сбой.

Панель → Таблица: полное определение таблицы

Разработка с ИИ

Работайте вместе с ИИ-агентом для программирования, это приветствуется. Поисковые и ИИ-функции Doris 4.x появились позже обучающих данных большинства моделей. Поэтому перед написанием SQL дайте агенту правильный контекст:

  1. Вставьте контекстный промпт ниже в своего агента.

  2. Укажите ему справочные страницы из этого задания и AGENTS.md из стартового набора. Многие агенты читают этот файл самостоятельно.

  3. Перед встраиванием в код пусть агент выполнит каждый SQL-запрос на вашем работающем кластере.

  4. Ещё лучше подключите Doris MCP Server (см. задание A2), чтобы агент сам изучал схему и тестировал запросы.

Контекстный промптвставьте в своего агента
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.

Типичные ловушки 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 13 октября.

  2. Этап 115 мин

    Поиск по ключевым словам с BM25

    M1 · Поиск по ключевым словам с BM25sql
    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;
    Проверка

    Каждый результат: строка ERROR с упоминанием timeout. Отображается только один из двух сервисов.

  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. В остальное время ни один сервис не пишет больше 4 ошибок за 5 минут.

  6. Этап 5

    Разберите сбой

    Ответьте с помощью обозревателя: Какой сервис вызвал сбои оформления заказов и в какую минуту это началось? Запишите в README ответ и подтверждающий его запрос.

3

Завершите работу

Пройдите проверку, покажите результат и получите значок.

Критерии готовности

Ваш контрольный список

Отправьте работу и получите значок

Участвуйте → отправьте работу → получите значок.

  1. Поместите свою работу в папку с именем вашего GitHub ID: код и README с описанием, инструкцией запуска, одним снимком экрана или GIF и перечнем использованных функций Doris.

  2. Откройте pull request и добавьте её в morningman/demo-env как doris-hackathon-glasgow-2026/<your-github-id>/. Сделайте fork и push или используйте в GitHub Add file → Upload files. Больше ничего заполнять не нужно.

  3. Поделитесь результатом в #dev в Slack Apache Doris: ссылкой на pull request или репозиторий и снимком экрана либо коротким демо. Вопросы, отправка работ и выдача значков происходят там.

Каждый участник задания получает значок участника Apache Doris: принятый pull request в 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 allocatedПорты 9030, 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 не менее 6 GB (Settings → Resources). На 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 в Slack Apache Doris

Справочные материалы

Полнотекстовый поискBM25Инвертированный индексФункция SEARCH

Хакатон Apache Doris

Все задания

Вернуться к курсу
  1. A160–120 минПриложение гибридного поискаОткрыть описание задания
  2. A245–90 минЗадавайте вопросы Doris через MCPОткрыть описание задания
  3. A360–120 минОбозреватель поиска по логамВы здесь
  4. A460–120 минОбозреватель трассировок агентовОткрыть описание задания
  5. B30–60 минТрек B · От документации к демоОткрыть описание задания