SelectDB search() 实战教程:从 Elasticsearch 迁移到一条 SQL 搞定搜索与分析

还在维护 ES + ClickHouse 两套系统做日志搜索和分析?本教程带你从零开始,在 SelectDB(基于 Apache Doris)中用 search() 函数替代 ES 全文检索功能,实现搜索 + 分析同一条 SQL、同一份数据。含完整建表、索引配置、数据导入、15 种查询算子用法和 ES 迁移指南。

关键词:SelectDB · Apache Doris · search() · 全文检索 · Elasticsearch 迁移 · 倒排索引 · 日志分析 · 实战教程


前言:你的日志架构还能更简单吗?

当前主流日志架构:

复制代码
应用日志 → Kafka → Logstash → Elasticsearch(搜索)
                          └──→ ClickHouse(分析)

维护两套集群 + 一条同步链路,成本高、运维累。本教程的目标:用一套 SelectDB 集群替代这个双系统,搜索和分析用同一条 SQL 完成。


第 1 步:环境准备

组件 最低版本 作用
SelectDB 或 Apache Doris 2.1+(需支持 V3 倒排索引) 核心引擎
MySQL Client 或其他 SQL 客户端 任意 执行 SQL

确保 SelectDB 集群已启动并可通过 MySQL 协议连接(默认端口 9030)。


第 2 步:创建带倒排索引的日志表

sql 复制代码
-- 1. 创建数据库
CREATE DATABASE IF NOT EXISTS log_search;
​
-- 2. 创建日志表 + 倒排索引
CREATE TABLE IF NOT EXISTS log_search.inference_logs (
  log_time          DATETIME,           -- 日志时间
  request_id        VARCHAR(64),        -- 请求 ID
  model_name        VARCHAR(32),        -- 模型名称
   level             VARCHAR(16),        -- 日志级别
  error_msg         TEXT,               -- 错误信息(需全文检索)
  context           TEXT,               -- 上下文(需全文检索)
  prompt_tokens     INT,                -- prompt token 数
  completion_tokens INT,                -- 回复 token 数
  latency_ms        INT,                -- 延迟(毫秒)
   -- ===== 倒排索引定义 =====
   INDEX idx_level(level) USING INVERTED,
   INDEX idx_error(error_msg) USING INVERTED PROPERTIES(
       "parser" = "unicode",            -- 中英文混合分词
       "support_phrase" = "true"        -- 支持精确短语搜索
   ),
   INDEX idx_context(context) USING INVERTED PROPERTIES(
       "parser" = "unicode",
       "support_phrase" = "true"
   ),
   INDEX idx_model(model_name) USING INVERTED
) ENGINE = OLAP
DUPLICATE KEY(log_time)
DISTRIBUTED BY HASH(request_id) BUCKETS 16
PROPERTIES (
   "inverted_index_storage_format" = "V3",   -- V3 格式,压缩效率高
   "compression" = "ZSTD"
);

配置说明:

  • USING INVERTED:为字段创建倒排索引,search() 函数依赖此索引加速检索
  • support_phrase = "true":如需搜索 "CUDA out of memory" 这样的精确短语,必须开启
  • parser = "unicode":中英文混合分词,不需要像 ES 那样额外安装 IK 分词器
  • V3 倒排格式:支持 ZSTD 字典压缩,索引体积比 ES 减少约 20%

重点 :SelectDB 的倒排索引加减不需要重写数据文件 ------可以先导入数据,再根据查询需求针对性添加索引,也可以随时删除冗余的索引释放空间。整个操作无需停服、无需重建表。


第 3 步:导入测试数据

sql 复制代码
-- Stream Load 方式导入(示例)
-- 也可以通过 INSERT INTO SELECT 从其他表导入
​
INSERT INTO log_search.inference_logs VALUES
('2026-03-20 10:00:01', 'req_001', 'gpt-4', 'ERROR', 'CUDA out of memory at layer 12', 'model inference context...', 2048, 512,3200),
('2026-03-20 10:00:02', 'req_002', 'gpt-4', 'ERROR', 'connection refused to backend', 'routing context...', 512, 128, 500),
('2026-03-20 10:00:03', 'req_003', 'gpt-4o', 'ERROR', 'CUDA out of memory at layer 8', 'model inference context...', 4096, 1024,5800),
('2026-03-20 10:00:04', 'req_004', 'gpt-4o', 'WARN', 'high latency detected', 'monitoring context...', 1024, 256, 4500),
('2026-03-20 10:00:05', 'req_005', 'gpt-4', 'ERROR', 'timeout waiting for response', 'routing context...', 256, 64, 8000),
('2026-03-20 10:00:06', 'req_006', 'gpt-4o', 'ERROR', 'CUDA out of memory at layer 24', 'model inference context...', 8192, 2048,9200);

第 4 步:基础搜索 ------ 你的第一个 search() 查询

sql 复制代码
-- 搜索所有 GPU OOM 错误
SELECT request_id, model_name, error_msg, latency_ms
FROM log_search.inference_logs
WHERE search('level:ERROR AND error_msg:"CUDA out of memory"')
ORDER BY latency_ms DESC;

结果解读 :这条 SQL 在倒排索引中先定位包含 "CUDA out of memory" 短语 + level:ERROR 的行,再按延迟降序排列。语法和 ES query_string 几乎一致。


第 5 步:进阶查询 ------ 15 种算子实战

5.1 多条件组合定位故障

vbnet 复制代码
-- 5 种算子同时使用:TERM + PHRASE + RANGE + NOT + IN
SELECT *
FROM log_search.inference_logs
WHERE search('
level:ERROR 
AND error_msg:"out of" 
AND latency:[1000 TO *] 
AND NOT model_name:gpt-4o
AND request_id:IN(req_001 req_002)
');

5.2 正则匹配

sql 复制代码
-- 抓住所有 CUDA 相关错误,不管具体描述是什么
SELECT request_id, error_msg
FROM log_search.inference_logs
WHERE search('error_msg:/CUDA.*error/ AND level:ERROR');

5.3 BM25 相关性打分排序

sql 复制代码
-- 按搜索相关性排序,最匹配的排前面
SELECT request_id, error_msg, score() AS relevance_score
FROM log_search.inference_logs
WHERE search('error_msg:"memory allocation" OR error_msg:"CUDA error"')
ORDER BY relevance_score DESC
LIMIT 10;

score() 列暴露 BM25 评分(IDF 加权 + 文档长度归一化),配合存储层 TopN 优化,全量排序性能无忧。

5.4 搜索 + 聚合分析(融合模式)

sql 复制代码
-- 一条 SQL:搜索 + 统计分析,无需跨系统搬运数据
SELECT
  model_name,
   COUNT(*) AS error_count,
   AVG(prompt_tokens) AS avg_prompt_tokens,
   AVG(latency_ms) AS avg_latency
FROM log_search.inference_logs
WHERE search('level:ERROR AND error_msg:"out of"')
GROUP BY model_name
ORDER BY error_count DESC;

这一步是本教程的核心亮点:传统方案中,你需要在 ES 搜索 → 导出结果 → 在 OLAP 聚合。现在同一条 SQL 就能完成,延迟从分钟级降到秒级。

5.5 窗口函数:追踪错误趋势

sql 复制代码
-- 按小时统计错误数量,并计算环比变化
SELECT
  model_name,
  DATE_TRUNC('hour', log_time) AS hour,
   COUNT(*) AS error_count,
  LAG(COUNT(*)) OVER (PARTITION BY model_name ORDER BY DATE_TRUNC('hour', log_time)) AS prev_hour_errors
FROM log_search.inference_logs
WHERE search('level:ERROR')
GROUP BY model_name, DATE_TRUNC('hour', log_time)
ORDER BY hour;

第 6 步:从 Elasticsearch 迁移到 SelectDB

6.1 索引映射对照表

Elasticsearch SelectDB
"type": "text" TEXT + INDEX ... USING INVERTED
"type": "keyword" VARCHAR(32) + INDEX ... USING INVERTED
"type": "long" BIGINT
"type": "date" DATETIME

6.2 查询改写对照

sql 复制代码
-- === ES 查询 ===
GET /logs/_search
{
 "query": {
   "query_string": {
     "query": "level:ERROR AND error_msg:"timeout""
   }
 }
}
​
-- === SelectDB 查询 ===
SELECT * FROM log_search.inference_logs
WHERE search('level:ERROR AND error_msg:"timeout"');

90% 的查询只需要:REST API → SQL WHERE + 加个 search()

6.3 迁移收益

指标 双系统(ES + OLAP) SelectDB search()
集群数量 2 套 1 套
同步链路 Kafka → Logstash → ES 无(直写)
存储膨胀 ES 侧 2-3 倍 ZSTD 压缩
TB 级存储成本 基准 降 50%
查询延迟(搜+析) 分钟级(跨系统) 秒级(同引擎)

常见问题

Q:倒排索引对写入性能有影响吗? A:有一定开销,但在 DUPLICATE KEY 模型下日志场景以追加写为主,影响可控。V3 格式的压缩和索引构建性能已针对性优化。

Q:search() 和 ES query_string 语法有差异吗? A:query_string 模式下语法兼容,大部分查询可以直接移植。Lucene 模式支持 MUST/SHOULD/MUST_NOT 语义。

Q:能处理嵌套 JSON 日志吗? A:可以。配合 VARIANT 类型 + search() 的 NESTED 算子,可直接在数组内部检索,无需拆表。

Q:需要像 ES 一样提前规划索引 mapping 吗? A:不需要严格规划。先导入数据,后续可以随时添加或删除索引,无需停服、无需重建表。


扩展阅读


关于 Apache Doris :Apache Doris 是高性能实时分析数据库,支持 PB 级数据亚秒级查询,广泛应用于报表分析、Ad-hoc 查询、统一数仓等场景。SelectDB 是 Apache Doris 的商业化公司,提供企业级支持和云服务。欢迎加入 Doris 社区 交流更多实践。

相关推荐
金銀銅鐵6 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
念何架构之路6 小时前
go-grpc设计思想
开发语言·后端·golang
system_error_x7 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn9 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈9 小时前
AI 读你的提示词,其实很没耐心
后端
用户83562907805110 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我1234510 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒10 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记10 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk5987810 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端