智能网联汽车在车联网的应用上,通常是以智能传感器、物联网、GIS技术为基础,结合大数据、人工智能技术,通过OT(Operationtecnology)和IT(informationtecnology)融合的方式,实现智能车辆的辅助驾驶、状态监控、远程管理、数据分析及决策等功能。同时,通过对云端大数据的实时分析,还可以对运营车辆实现行程报警、路径规划、电子围栏、订单跟踪等企业级功能。 车联网云端大数据最重要的工作之一,是处理海量的GPS轨迹数据。GPS轨迹数据本质上是带时间标签的时序数据(timeseriesdata),市面上很多时序数据库都能够满足时序数据的简单存储和简单查询需求。 但在完整的车联网应用场景中,绝大部分时序数据库是无法直接输出最终业务所需结果的,也无法将时序数据与业务数据进行关联查询。 因此通常做法是在时序数据库的基础上,配合复杂的系统架构来支撑业务需求。例如,当我们想要将GPS轨迹跟车辆识别码、订单关联时,需要将GPS轨迹数据提取到应用端,使用关系数据库和编程工具进行二次处理。 这种方式虽然能解决业务查询问题,但是在一定程度上增加了系统的复杂性,并且在性能、开发难度、数据挖掘等方面受到架构限制。有没有更简单、更轻量化的架构呢? 作为一个基于时序数据库管理系统,支持数据分析、流计算的低延时平台,DolphinDB具有轻量化、一站式的特点,不仅可以高速存储海量结构化数据,还能在库内直接进行复杂计算,内置的高性能流数据处理框架满足了实时流计算的需求,且脚本语言对标准SQL高度兼容,简单易上手。 这里我们给大家介绍一个基于DolphinDB的车联网大数据处理架构。 在这一架构中,时间信息、车牌、经纬度、速度等多数据源的海量数据从采集层进入DolphinDB大数据平台,注入流数据表中。DolphinDB通过订阅流数据表,并与订单业务、车辆配置等数据进行关联查询,实现分析与监测预警。输出的结果进入应用层,对接业务系统、消息中间件,或通过多种接口进行可视化展示。架构图如下所示: 基于DolphinDB的车联网大数据处理架构图 使用这一架构可以实现海量轨迹数据的存储,车辆、订单的关联聚合查询,以及结果直接输出的完整流程。 下面我们给出一段查询案例,完整的脚本代码在附件中,任何开发人员都可以花10分钟左右的时间进行复现。数据集 表描述 表名 数据量 车辆信息表 tcar 10万 订单信息表 torder 100万 GPS轨迹表 tdrive 8。64亿环境配置 项目 参数 操作系统 DELLLatitude5420笔记本电脑windows11(22621。521) CPU 11thGenIntel(R)Core(TM)i51145G72。60GHz1。50GHz 内存 16G 磁盘 SSD512G 服务端 DolphinDB2。00。9SQL语句及参考耗时 序号 场景 耗时 SQL语句 1hr统计车辆经纬数据总数 1ms selectcount()fromdrives 2hr按车牌时间,查询车辆经纬数据 4ms selectfromdriveswherets2022。07。0122:10:10。000,code浙A100207 3hr按车牌,统计数据总数 5ms selectcount()fromdriveswherecode浙A100207 4hr按车牌,查看车辆与总部距离 3ms selectts,code,string(long(distance(poi,point(lng,lat)))1000)kmasdistancefromdriveswherets2022。07。0122:10:10。000,code浙A105207 5hr按车牌,查询一天的所有数据 3ms selectfromdriveswherecode浙A165207andtsbetween2023。01。0100:00:00。000:2023。01。0123:59:59。999 6hr按车牌按每小时统计平均车速 12ms selectavg(velocity)fromdriveswherecode浙A165207groupbybar(ts,1H) 7hr按订单ID,查询该订单所有路径 112ms 定义存储过程orderQuery orderQuery(1000006) 8hr以60倍速回放某订单的车辆行驶轨迹 replay函数 以场景7为例,将轨迹表(8。6亿)和订单表(100w)进行关联,返回某个配送订单的全部车辆运行轨迹,耗时在112毫秒左右: 场景8中,将某个订单的数据,按60倍速持续写入一个新表中,读取新表数据并输出到GIS系统的地图中,就可以非常方便的实现某个订单车辆配送轨迹的实时播放,轻松回放行驶路径,用于异常排查。10分钟轻松验证(Windows版) 步骤 任务 预计耗时 操作描述 1hr部署DolphinDB大数据环境 1分钟 下载DolphinDB,并解压(免安装) 2hr运行 1秒 双击dolphindb。exe文件,开启实例 3hr运行开发环境 10秒 打开http:localhost:8848,网页上可执行SQL等脚本 4hr模拟生成8。64亿数据 8分钟 复制《data。txt》脚本,执行。 (注意,此处模拟的是仿真数据,即每一条数据都是单独生成的,而不是简单的把一份数据重复复制。) 5hr验证查询性能 3分钟 复制《query。txt》脚本,依次执行,观察耗时安装部署下载官网社区最新版,建议2。00。9及以上版本。 传送门:https:www。dolphindb。cndownloadsDolphinDBWin64V2。00。9。3。zip 2。windows解压路径,不能有空格,避免安装到ProgramFiles路径下。 官网教程:https:gitee。comdolphindbTutorialsCNblobmasterstandaloneserver。md 3。本次测试使用免费的社区版,企业版license可申请免费试用。 联系方式:https:dolphindb。cnalonealone。php?id23 4。安装及测试过程中,有任何问题,可添加小助手微信(dolphindb1)咨询。验证说明统计耗时使用timer函数,即排除网络传输和序列化影响,仅统计服务端全部数据处理完成的时间。 2。性能受磁盘IO、CPU、网络等系统资源的影响,如测试环境不同,表格中的性能实测数据可能会有差异。 3。web端的交互编程执行方式,可以框选单条脚本,按CtrlE执行。也可以全选,按CtrlE执行。 4。模拟车辆轨迹写入的性能接近200万条秒(1000万点秒),可以作为真实数据写入性能的参考(排除协议连接、网络传输、序列化等耗时)。 5。性能测试优先保障性能,配置文件dolphindb。cfg中可以限制资源(核数、内存等)。 欢迎大家动手尝试,一起来验证一下吧!附录《data。txt》:建库建表,模拟数据生成步骤一:登录login(admin,123456)步骤二:建库、建表1。车辆信息表:tcarif(existsDatabase(dfs:tcar)){dropDatabase(dfs:tcar)}createdatabasedfs:tcarpartitionedbyVALUE(〔code〕)createtabledfs:tcar。car(codeSYMBOL,车牌modelSYMBOL,型号emissionsSYMBOL,排量brandSYMBOL品牌)2。配送订单表:torderif(existsDatabase(dfs:torder)){dropDatabase(dfs:torder)}createdatabasedfs:torderpartitionedbyVALUE(〔date(now())〕),engineTSDBcreatetabledfs:torder。order(orderidLONG,订单号tsTIMESTAMP,下单时间btimeTIMESTAMP,配送起始时间etimeTIMESTAMP,配送截止时间codeSYMBOL,车牌blngDOUBLE,起始经度blatDOUBLE,起始纬度elngDOUBLE,目的地经度elatDOUBLE目的地纬度)partitionedbytssortColumns〔orderid,ts〕,sortKeyMappingFunction〔hashBucket{,9}〕3。车辆行驶路径表:dfsdriveif(existsDatabase(dfs:dfsdrive)){dropDatabase(dfs:dfsdrive)}createdatabasedfs:dfsdrivepartitionedbyVALUE(〔date(now())〕),HASH(〔SYMBOL,30〕),engineTSDBcreatetabledfs:dfsdrive。drive(tsTIMESTAMP,时间戳codeSYMBOL,车牌lngDOUBLE,经度latDOUBLE,纬度velocityINT,速度altitudeINT,海拔directionINT方向)partitionedbyts,codesortColumns〔code,ts〕,sortKeyMappingFunction〔hashBucket{,99}〕步骤三:模拟写入仿真数据写入车辆信息表:tcar(1万条)n100000code100001。。200000产生序列数据code浙Astring(code)modelrand(搅拌车泵车砂石车,n)rand随机函数,用于产生数量为n的向量值emissionsstring(rand(5。。10,n))升brandrand(SANYZOOMLIONXCMGLOXAFANGYUANRJST,n)ttable(code,model,emissions,brand)tcarloadTable(dfs:tcar,car)tcar。append!(t)selectcount()fromtcar数据检查selecttop10fromtcar写入订单信息表:torder(100万条)n1000000orderid1000001。。2000000产生序列数据tstake(2023。01。01。。2023。01。10,n)产生10天的订单tssort(ts)向量结构排序:10w条1月1日10w条1月2日。。。10w条1月10日codesselectcodefromloadTable(dfs:tcar,car)获取1万车牌号码codetake(codes。code,n)向量结构:10w条车牌序列x10天100wbtimetemporalAdd(datetime(ts),rand(14400,n)32400,s)开始配送时间:9点13点随机etimetemporalAdd(datetime(btime),rand(18000,n)3600,s)配送时间:1小时5小时随机blng103。60972rand(1。0,n)0。5blat30。81841rand(1。0,n)0。5elng103。60972rand(1。0,n)0。5elat30。81841rand(1。0,n)0。5ttable(orderid,ts,btime,etime,code,blng,blat,elng,elat)torderloadTable(dfs:torder,order)torder。append!(t)selectcount()fromtorder数据检查selecttop10fromtorder写入车辆轨迹数据,8。64亿天defwritedata(){for(tsin2023。01。01。。2023。01。01){将10w车牌拆分成50份,写入50次(可通过降低拆分数量,进一步提高速度。如内存不支持,可能会OutOfMemory)for(iin1。。50){n8640j(i1)2000codesselectcodefromloadTable(dfs:tcar,car)limitj,2000itimedatetime(ts)10(0。。(n1))lng103。60972rand(1。0,n)0。5lat30。81841rand(1。0,n)0。5velocityrand(100,n)altituderand(300,n)directionrand(360,n)ttable(timeasts,lng,lat,velocity,altitude,direction)ttcj(t,codes)关联车牌和数据,每次写入量:20008640reorderColumns!(tt,loadTable(dfs:dfsdrive,drive)。schema()。colDefs。name)loadTable(dfs:dfsdrive,drive)。append!(tt)ttNULL}}}submitJob(writedata,writedata,writedata)后台执行写入操作drivesloadTable(dfs:dfsdrive,drive)数据检查selectcount()fromdrives《query。tx》:性能测试 步骤四:数据准备工作检查作业状态(预计执行8分钟)selectjobId,startTimeas开始时间,endTimeas结束时间,(endTimestartTime)1000as执行秒数fromgetRecentJobs(1)确定作业完成后,执行刷盘,LevelFile合并,清除缓存,确保性能测试的准确。因为短时间导入了大量数据,部分数据还在内存(CacheEngine)中,并逐步写入磁盘。为确保性能测试时,数据是从磁盘中读取,需要进行刷盘操作。flushTSDBCache()LevelFile合并:优化历史数据的查询性能chunkIdsexecchunkIdfromgetChunksMeta()wheretype1for(xinchunkIds){triggerTSDBCompaction(x)}清除缓存,确保测试性能准确clearAllCache()步骤五:查询统计全量数据检查:1。统计车辆经纬数据总数drivesloadTable(dfs:dfsdrive,drive)timertselectcount()fromdrivestselecttop10fromdrives2。按车牌时间,查询车辆经纬数据timertselectfromdriveswherets2023。01。0122:10:10。000,code浙A100207t3按车牌,统计数据总数timertselectcount()fromdriveswherecode浙A100207t4按车牌,查看车辆与总部距离poipoint(104。102683,30。482596)总部经纬度timertselectts,code,string(long(distance(poi,point(lng,lat)))1000)kmasdistancefromdriveswherets2023。01。0122:10:10。000,code浙A105207t5按车牌,查询一天的所有数据timertselectfromdriveswherecode浙A165207andtsbetween2023。01。0100:00:00。000:2023。01。0123:59:59。999t6按车牌查询每小时的平均车速timertselectavg(velocity)fromdriveswherecode浙A165207groupbybar(ts,1H)t7按订单ID,查询某订单所有路径新建自定义函数,用来查询订单(100w)的轨迹(8。6亿)deforderQuery(oid){tselectcode,btime,etimefromloadTable(dfs:torder,order)whereorderidoidcarcodet。code〔0〕ttselectfromloadTable(dfs:dfsdrive,drive)wherecodecarcode,tsbetweent。btime〔0〕:t。etime〔0〕returntt}执行订单查询timertorderQuery(1000006)t添加存储过程(函数视图):执行后,可通过api调用此函数try{dropFunctionView(orderQuery)}catch(x){}addFunctionView(orderQuery)8以60倍速(每秒钟播放真实时间1分钟的轨迹数据)的速率,播放某订单的车辆行驶轨迹rate60回放倍速torderQuery(1000006)需要回放的数据showtable(1:0,t。schema()。colDefs。name,t。schema()。colDefs。typeInt)submitJob(replaydrive,回放订单轨迹,replay,t,show,ts,ts,rate,false)持续执行(可通过share函数将表共享,以输出到GIS系统的可视化地图)selectfromshoworderbytsdesc