news 2026/7/25 11:46:02

近10万亿轨迹点底库:ClickHouse+S2编码,实现任意区域秒级可视化检索!

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
近10万亿轨迹点底库:ClickHouse+S2编码,实现任意区域秒级可视化检索!

导读 introduction

地图情报核实需判断“某段路到底有没有车走过”。车少的长尾路段(乡道、新修路、偏远低频路)需把时间拉长到半年才能攒够轨迹,而这180天、近10万亿点的历史轨迹存于离线数仓,查询一次要耗时数小时。通过一套基于ClickHouse的检索服务,实现了在线查询,任意区域检索TTFB仅0.35s。

本文复盘了如何利用ClickHouse + S2地理编码 + 流式检索,在近10万亿轨迹点的底库上实现任意区域秒级可视化。其中包括存储引擎选型、地理索引设计的原理解析(第5节),以及一线实践中的避坑经验(第6节),适合关注海量数据检索、时空数据处理、OLAP实战的人士。

01 业务背景:长尾路段的轨迹从哪来

这套服务是地图情报团队“情报核实图灵平台”的底层能力。核实平台每日需挖掘、核实地图上的各类要素,如新增道路、路网变化、通行规则等,而核实过程中常需回答一个问题:“这段路,到底有没有车真实走过?”

轨迹是最直接的证据,逻辑简单,但难点在于“长尾路段”,即乡道、新修路、偏远低频路。主干道车流量大,取几天数据就能获得足够轨迹;而长尾路段车少,近几天甚至几周可能都没有车辆经过,难以查询到是否有人走过。

解决方案是将时间拉长到180天,即便每天只有一辆车经过,半年也能积累上百条轨迹,使长尾路段具有统计意义。为控制数据规模,入库时过滤掉了1 - 4级路(高速、国道、主干道等高等级路,本身车流量大,不缺证据),仅保留低等级路。即便如此,180天积累下来仍有近10万亿个轨迹点。

问题在于,这批数据存于“离线数仓”中,查询“某区域某时段的轨迹”需要提交任务、排队、扫描全表,动辄耗时数小时,无法满足地图上点选即看结果的交互式核实需求。核心矛盾在于,要在近10万亿行的底库上,将查询时间从“几个小时”压缩到“0.35秒”。

从成本角度看,该方案基于ClickHouse冷热分级(SSD热层 + BOS冷层),覆盖180天、近10万亿行,年成本仅约25万,大部分存量数据存储在低价的对象存储上,比纯内存方案节省成本。

实现小时到亚秒的量级差距(约5个数量级),并非依靠增加机器,而是通过存储引擎选型、索引设计和查询策略三者配合。接下来将先介绍数据规模,再逐步拆解。

02 一组开门见山的数字

核心事实为:在近10万亿行的底库上,对任意一块地图区域、任意180天时间窗进行检索,用户0.35秒即可看到第一条轨迹。

底库实测`count()`结果显示:trajectory_all_bos为9,868,628,881,572,约9.87万亿(近10万亿)。

按天统计的日写入量趋势如下:1月中下旬为节前出行高峰,日写入量达680 - 1020亿,是全周期最活跃的时段;2月春节前后回落到300 - 400亿/天,符合假期出行下降的规律;3月稳定在330 - 360亿/天,是全年的基线水位;4月中起明显抬升,从400亿跃升至800亿档并持续,对应有新数据源接入放量;5 - 7月常态维持在400 - 900亿之间,且呈现明显的隔日节律,约450亿与约800亿交替出现,说明某个大数据源是按批次、非每日均匀写入的。

这对检索服务意味着,写入量的季节波动不应影响读侧的检索延迟。后续的技术设计旨在确保,无论底库当日灌入多少数据,用户的检索TTFB都稳定在0.35秒。

03 服务定位与整体架构

首先明确边界,track - search是情报核实图灵平台的底层能力,负责将离线180天的长尾历史轨迹转化为“秒级可查”。轨迹数据的生产链路,即由Spark从离线数仓读取,进行清洗编码(入库时过滤掉1 - 4级路、计算S2、转换为定点整数),再批量灌入ClickHouse,在离线侧完成,不在本文讨论范围内。本文仅聚焦于读侧,track - search是一个纯在线检索服务,将离线的“要跑几个小时”的数据转化为“秒级可查”。

整体架构如图所示。选择ClickHouse而非继续使用离线数仓,是因为离线数仓为批处理吞吐设计,交互式点查需进行任务调度、扫描全表,延迟以小时计。而ClickHouse是列式OLAP引擎,结合排序键稀疏索引,能够实现“只解压真正命中的数据块”,这是将小时级延迟压缩到亚秒级的物理基础。技术栈仅包含Go(GDP框架)、ClickHouse和S2地理库,在线链路直接访问CK,不经过Redis缓存或中间存储。

该检索引擎通过参数适配可应用于三类典型场景:场景A为轨迹挖路(全覆盖),采用180天全量数据并进行空间抽稀,以发现路网上未被采集的新路;场景B为实时交通观察,使用单天数据并进行速度过滤,以查看某片区域的实时通行情况;场景C为数据源质量审核,指定单一数据源并进行GPS精度过滤,以逐源分析数据质量。

3.1 平台可视化效果

实际的检索可视化界面(半径5.5km、卫星影像底图)展示了真实的GPS轨迹,图上每一条绿色的线都是车辆、终端实际走过的路径。一次框选即可将该区域180天内的所有轨迹铺在卫星影像上。

通过观察可以发现,轨迹勾勒出了真实路网,绿线密集的地方表明确实有人反复走过;有绿线但卫星图上看不出明显道路的位置可能是未被采集的新路或地图上标注但实际少车通行的“误挖”路段;越是偏远、车少的长尾路段,越依赖这张图,通过180天的累积才使稀疏的轨迹显现出来。

3.2 回到最初的问题:这段路到底有没有车走过

绕了一圈,回到第1节中核实平台反复要回答的问题:“这段路,到底有没有车真实走过?”答案就在上面的图中,绿轨迹所到之处即“有人走过”,绿轨迹密集却与现有路网不匹配的地方,就是需要挖掘的新路或潜在的误挖路段。

这套服务的真正意义并非“查得快”本身,而是将轨迹检索转变为要素核实与挖路工艺的交互式验证工具。

04 检索性能实测

4.1 实测数据

测试环境为5节点ClickHouse集群。从实测数据来看,30天和180天的TTFB均为0.35秒,时间窗拉长5倍,首字节时间几乎不变。这表明检索延迟主要由空间索引和流式返回决定,而非受时间范围影响,即首屏速度不受数据总量拖累,这也是后续所有技术设计的目标。

其中,TTFB约为0.3 - 0.5秒,前端收到第一条轨迹即可开始渲染,无需等待全部计算完成;总耗时随数据量线性增长,但由于采用流式处理,用户的体感仅与TTFB相关。

05 技术细节:0.35s是怎么抠出来的

技术栈仅包含Go(GDP框架)、ClickHouse和S2地理库。在线检索链路直接访问CK,不经过Redis缓存或中间存储,依靠CK自身的稀疏索引和本服务的查询策略应对万亿量级的数据。

5.1 地基:用S2把“区域”变成CK排序键上的整数

对万亿行数据进行全表扫描是不可行的。核心思路是将地理区域转换为排序键上的整数区间,让CK利用稀疏索引进行跳读,仅解压真正命中的数据块。

轨迹表`trajectory_all_bos`(分布式表)每行包含一个GPS点,关键列如图所示。该表按`event_day`分区、`(event_day, s2_id_18, traj_id)`排序,这个排序键是性能的基础,时间在前可进行时间范围裁剪分区,空间紧随其后可通过S2范围命中稀疏索引进行跳读,这也解释了第4节中时间窗拉长不影响S2定位首字节速度的现象。

“空间”通过S2编码塞进排序键。CK只识别`s2_id_18`上的大小比较,不识别“圆”或“矩形”,而Google的S2库(`library/util/s2tool.go`,841行)利用希尔伯特曲线将地表编码成一维cell id,实现了空间相邻则id相邻,从而将任意区域覆盖为一组连续整数区间。通过“网格 → 希尔伯特编号 → 整数区间SQL”三步完成转换,混合层级覆盖是关键,需平衡精度与条件数。至此,“检索一个圆/多边形”转变为CK擅长的“扫几段排序键整数区间”,这是后续过滤、跳读的前提。

需要注意的是,CK里`s2_id_18`基于GCJ - 02坐标计算,入参通常是WGS - 84,查询前必须进行坐标转换(`trajectory.go:1056`),否则会出现整体偏移几百米、召回结果错误的情况。

5.2 浮点转定点整数:经纬度、速度全部存Int

表中经纬度`lng`/`lat`不使用`Float64`/`Float32`存储,而是乘以1e6存为`Int32`;速度`l_speed`乘以10存为`UInt16`。这种设计在万亿行量级下,能带来多方面好处。

首先,省空间,经纬度小数点后6位对轨迹精度已足够,`Int32`只需4字节,相比`Float64`的8字节,单是经纬度两列每行就从16字节降至8字节,万亿行×2列可节省数十TB磁盘空间;速度用`UInt16`(2字节)比`Float32`(4字节)同理可再省一半。其次,压缩率更高,ClickHouse按列压缩,整数列的压缩比远高于浮点列,能进一步节省空间,加快检索速度。再次,比较更快、更准,整数范围过滤的CPU指令更快,且无浮点精度误差。最后,对S2索引友好,经纬度以整数形态存储,配合排序键使整行数据排列紧凑,跳读命中率更高。

虽然进出口需进行乘除转换,但与节省的磁盘空间和IO/压缩收益相比,CPU开销可忽略不计。这是海量数据存储中典型的“定点化”取舍,用可接受的精度上限换取存储和查询的全面优势。

通过线上实测,“定点整数化 → 列式排序 + delta编码 → LZ4压缩”逐级叠加,整表压缩比达6.42:1,排序键列压缩效果显著,定点整数的坐标列也有较好的压缩表现。这表明定点整数化设计同时实现了省空间、高压缩、快比较、S2友好的四重收益,压缩不仅节省成本,还能直接提升检索速度。

5.3 存储策略:SSD热层 + 对象存储冷层的冷热分级

数据存储介质和读取方式直接影响检索下限。但存在现实矛盾,180天近10万亿行、单节点数十TB的数据,全部存入本地SSD成本过高,全部存于远端对象存储又速度过慢。本服务采用冷热分级存储策略(策略名脱敏为`traj_tiered_policy`),将存储分为两层,数据可按冷热自动流转。

读路径方面:首先将框选区域通过S2覆盖为若干段`s2_id_18 BETWEEN ? AND ?`,将空间检索转换为排序键上的范围扫描;然后利用ClickHouse的稀疏索引定位命中的mark区间;接着进行granule跳读,只解压命中的granule,跳过区域外的数据块;最后通过多盘并行扫part,从多块SSD上同时拉取命中的part,提高IO吞吐。

冷热分级方面:热层SSD存储近期高频数据,多数检索可直接命中热层,实现亚秒返回;冷层BOS存储历史存量数据,容量大、单价低;当热层SSD用量达到水位时,ClickHouse会自动将最老的part下沉到BOS,并配合180天TTL滚动淘汰最旧分区,整个冷热迁移对查询透明,不影响应用层和SQL。

总之,稀疏索引和granule跳读决定“读多少”,多盘并行决定“读多快”,冷热分级决定“数据存储位置和成本”。从“存多少”“存储位置和读取速度”“读多少”三个维度层层递进,共同支撑亚秒检索。

5.4 两级过滤:粗筛跳块 + 精筛去空隙

区域较大时,S2区间会覆盖到不属于目标的空隙。查询采用两级过滤兼顾速度和准确性,先用`PREWHERE`进行粗筛,命中稀疏索引,跳过远处granule;再用`WHERE`进行精筛,去掉区间内的空隙误命中。使用`PREWHERE`可先读最少的列判断是否读取其余列,节省IO。

5.5 两阶段查询:先找轨迹,再取点

点查接口`TrajS2Search`分两步进行,避免一次拖出海量点。第一步通过两级过滤只`SELECT DISTINCT traj_id`,数据量小、速度快;第二步拿traj_id集合回表取完整点,按`traj_id, point_id`排序,进行精确点查,不再依赖空间索引。

5.6 主力接口:流式 + 高并发(TTFB 0.35s的直接来源)

前端拖拽/缩放使用的`TrajS2SearchStream`接口通过四个优化叠加实现了0.35秒的TTFB。首先采用流式NDJSON,结果进入`chan`(缓冲8000),主协程边读边写,每50条主动flush,使用户秒级看到首屏,解耦TTFB与总耗时。其次进行空间交错分组并发,将大range拆分成若干段,交错分配到各组,每组并发查询两张表,均匀利用集群资源。然后达标即取消查询,拉够目标量后其余查询随context取消,节省集群算力。最后进行均匀采样和CK深度调优,按半径动态调整`perCellLimit`,并设置相关参数。

5.7 流式后处理:抽稀、降噪、简化都在服务端做

从CK查出来的原始GPS点存在抖动、跳变、冗余等问题,直接渲染会压垮前端。因此在流式吐出之前,需在服务端进行后处理,将原始数据加工成成品轨迹。

后处理管线分五步:空间抽稀在结果≥1万条时触发,有四种策略可选,保证空间均匀覆盖的同时减少数据量;跳点截断在降噪之前进行,判定并处理相邻两点距离超过阈值的情况;降噪提供五种算法,去除GPS抖动毛刺;平滑 + 简化使用EMA指数平滑和道格拉斯 - 普克算法,使线条自然并减少冗余点;噪声段过滤 + 路网匹配,丢掉过短的碎段,对保留轨迹进行路网匹配,标注“新路候选”或“误挖”,服务于挖路工艺验证。

这套后处理不在前端进行的原因有三点:前端无法处理卡尔曼、DP等算法;服务端加工后前端渲染零负担;全部在流式管线里完成,不额外增加TTFB,用户仍能0.35秒看到首屏。

5.8 连接层与兜底

连接层通过设置相关参数,如`dial_timeout`、`max_execution_time`、`connection_open_strategy`、`compress`等,同时设置最大打开连接数和最大空闲连接数,以应对并发请求。

Schema降级兜底方面,上游写入的表结构可能会演进,查询先按全字段查,`Scan`失败后退回精简字段集重查,保证表结构变更期间不停服。

06 复盘:万亿量级读服务的关键决策与避坑

将上小时级离线查询压缩到亚秒级在线检索的项目,关键在于几个方向性决策、性能优化和避坑经验。以下按这三条线进行复盘。

6.1 三个关键决策

决策一:放弃离线数仓,选择ClickHouse。离线数仓不适合交互式点查,而ClickHouse的列式和排序键稀疏索引适合“大范围过滤、小范围命中”的点查,选型正确是后续优化的基础。

决策二:使用S2将地理问题降维为整数区间问题。数据库擅长排序键上的范围扫描,S2通过希尔伯特曲线将二维坐标编码成一维整数,将空间检索难题转化为ClickHouse擅长的任务。

决策三:采用全链路流式,而非查完再返。面对百万级结果集,边查边吐可解耦TTFB与总数据量,定义了产品的“快”。

6.2 性能优化清单

性能优化的主线是降扫描量优先于加机器,5节点集群能处理近10万亿行数据,依靠的是让每个请求只处理真正需要的几千万行数据。

6.3 避坑经验

以下是一些实际踩过的坑及应对方法:坑一,坐标系不一致会导致召回结果错误,CK里`s2_id_18`基于GCJ - 02计算,入参多为WGS - 84,查询前必须进行坐标转换;坑二,为“聚合加速”建立的摘要表在明细场景中不适用,应回归主表排序键本身解决;坑三,统计每日写入量时需剔除未完成分区,避免误判数据下降;坑四,上游schema演进可能导致查询失败,可采用降级兜底策略,先按全字段查,失败后退回精简字段集重查。

总之,万亿级读服务的性能依靠“选对存储引擎 + 让每个请求只处理真正需要的数据 + 让集群被均匀、可中止地使用”的整套配合。

07 写在最后:这套方法能迁移到哪

本文介绍的轨迹检索方法,抽离业务外壳后,是一套“海量时空/点数据的在线检索”通用范式,可迁移到多个相似场景,如任何“空间 + 时间”的海量点查、“离线数仓扛不动在线交互”的场景以及被结果集大小拖慢体感的接口等。

需要强调的是,近10万亿行是数据规模,而非架构瓶颈。该架构的单请求开销与“命中的数据量”相关,几乎不随“底库总量”增长,即便底库数据量大幅增加,检索延迟也不会线性劣化,扩容可通过增加节点、扩展SSD热层、调大并发度等常规手段实现。

这套服务最终服务于百度地图路网的持续更新,使路网信息查询从耗时数小时变为随点随看,当基础设施的检索速度能够支撑交互式探索时,将改变整个工艺的工作方式。”

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/25 11:45:07

YOLOv5主干网络替换为MSPANet的实践与优化

1. 项目背景与核心价值 在目标检测领域,YOLO系列算法因其出色的实时性和准确性一直备受关注。而主干网络作为特征提取的核心部件,其性能直接决定了整个检测系统的上限。MSPANet(Multi-Scale Pyramid Attention Network)作为EAAI 2…

作者头像 李华
网站建设 2026/7/25 11:39:11

AR点检巡检平台:工业4.0下的智能运维实践

1. AR点检巡检平台概述 在工业4.0和数字化转型浪潮下,AR(增强现实)点检巡检平台正成为制造业、能源、交通等重资产行业的重要技术支撑。这类平台通过将数字信息叠加到真实工作场景中,大幅提升了设备维护、安全检查等日常作业的效率…

作者头像 李华
网站建设 2026/7/25 11:38:30

基于Faster-RCNN的电力线缆智能缺陷检测系统

1. 项目背景与核心价值在电力运维和通信工程领域,线缆的健康状态直接关系到整个系统的稳定运行。传统的人工巡检方式不仅效率低下,而且容易因视觉疲劳导致漏检。我们团队开发的这套基于Faster-RCNN的智能检测系统,能够自动识别线缆表面常见的…

作者头像 李华
网站建设 2026/7/25 11:37:27

OnmyojiAutoScript防封机制深度解析:5大核心策略与实现方案

OnmyojiAutoScript防封机制深度解析:5大核心策略与实现方案 【免费下载链接】OnmyojiAutoScript Onmyoji Auto Script | 阴阳师脚本 项目地址: https://gitcode.com/gh_mirrors/on/OnmyojiAutoScript OnmyojiAutoScript作为阴阳师游戏自动化脚本的高级解决方…

作者头像 李华
网站建设 2026/7/25 11:35:26

MCAN模块与CAN FD协议:从硬件实现到ECC保护的嵌入式通信指南

1. MCAN模块与CAN FD协议:从理论到硬件的深度解析在汽车电子和工业控制领域,数据的可靠、实时传输是系统稳定运行的命脉。控制器局域网(Controller Area Network, CAN)协议自诞生以来,就以其卓越的抗干扰能力和基于优先…

作者头像 李华