十分钟验证一个轻量化车联网解决方案

智能网联汽车在车联网的应用上,通常是以智能传感器、物联网、GIS技术为基础,结合大数据、人工智能技术,通过OT(Operation tecnology)和IT(information tecnology)融合的方式,实现智能车辆的辅助驾驶、状态监控、远程管理、数据分析及决策等功能。同时,通过对云端大数据的实时分析,还可以对运营车辆实现行程报警、路径规划、电子围栏、订单跟踪等企业级功能。

车联网云端大数据最重要的工作之一,是处理海量的GPS轨迹数据。GPS轨迹数据本质上是带时间标签的时序数据(time series data),市面上很多时序数据库都能够满足时序数据的简单存储和简单查询需求。

但在完整的车联网应用场景中,绝大部分时序数据库是无法直接输出最终业务所需结果的,也无法将时序数据与业务数据进行关联查询。

因此通常做法是在时序数据库的基础上,配合复杂的系统架构来支撑业务需求。例如,当我们想要将GPS轨迹跟车辆识别码、订单关联时,需要将GPS轨迹数据提取到应用端,使用关系数据库和编程工具进行二次处理。

这种方式虽然能解决业务查询问题,但是在一定程度上增加了系统的复杂性,并且在性能、开发难度、数据挖掘等方面受到架构限制

有没有更简单、更轻量化的架构呢?

作为一个基于时序数据库管理系统,支持数据分析、流计算的低延时平台,DolphinDB 具有轻量化、一站式的特点,不仅可以高速存储海量结构化数据,还能在库内直接进行复杂计算,内置的高性能流数据处理框架满足了实时流计算的需求,且脚本语言对标准 SQL 高度兼容,简单易上手。

这里我们给大家介绍一个基于 DolphinDB 的车联网大数据处理架构

在这一架构中,时间信息、车牌、经纬度、速度等多数据源的海量数据从采集层进入 DolphinDB 大数据平台,注入流数据表中。DolphinDB 通过订阅流数据表,并与订单业务、车辆配置等数据进行关联查询,实现分析与监测预警。输出的结果进入应用层,对接业务系统、消息中间件,或通过多种接口进行可视化展示。架构图如下所示:

file

基于 DolphinDB 的车联网大数据处理架构图

使用这一架构可以实现海量轨迹数据的存储,车辆、订单的关联聚合查询,以及结果直接输出的完整流程。

下面我们给出一段查询案例,完整的脚本代码在附件中,任何开发人员都可以花10分钟左右的时间进行复现。

数据集

表描述表名数据量
车辆信息表t_car10万
订单信息表t_order100万
订单信息表t_drive8.64亿

环境配置

项目参数
操作系统DELL Latitude 5420 笔记本电脑 windows 11 (22621.521)
CPU11th Gen Intel® Core™ i5-1145G7 @ 2.60GHz 1.50 GHz
内存16G
磁盘SSD 512G
服务端DolphinDB 2.00.9

SQL语句及参考耗时

序号场景耗时SQL 语句
1统计车辆经纬数据总数1msselect count(*) from drives
2按车牌+时间,查询车辆经纬数据4msselect * from drives where ts=2022.07.01 22:10:10.000 , code=”浙A100207”
3按车牌,统计数据总数5msselect count(*) from drives where code=”浙A100207”
4按车牌,查看车辆与总部距离3msselect ts,code,string(long(distance(poi,point(lng, lat)))/1000)+“km” as distance from drives where ts=2022.07.01 22:10:10.000 , code=“浙A105207”
5按车牌,查询一天的所有数据3msselect * from drives where code=“浙A165207” and ts between 2023.01.01 00:00:00.000:2023.01.01 23:59:59.999
6按车牌按每小时统计平均车速12msselect avg(velocity) from drives where code=“浙A165207” group by bar(ts,1H)
7按订单ID,查询该订单所有路径112ms//定义存储过程orderQuery orderQuery(1000006)
8以60倍速回放某订单的车辆行驶轨迹-replay函数

以场景7为例,将轨迹表(8.6亿)和订单表(100w)进行关联,返回某个配送订单的全部车辆运行轨迹,耗时在112毫秒左右:

file
场景8中,将某个订单的数据,按60倍速持续写入一个新表中,读取新表数据并输出到GIS系统的地图中,就可以非常方便的实现某个订单车辆配送轨迹的实时播放,轻松回放行驶路径,用于异常排查。

10 分钟轻松验证(Windows 版)

步骤任务预计耗时操作描述
1部署DolphinDB大数据环境1分钟下载 DolphinDB,并解压(免安装)
2运行1秒双击 dolphindb.exe 文件,开启实例
3运行开发环境10秒打开 http://localhost:8848, 网页上可执行 SQL 等脚本
4模拟生成8.64亿数据8分钟复制《data.txt》脚本,执行(注意,此处模拟的是仿真数据,即每一条数据都是单独生成的,而不是简单的把一份数据重复复制。)
5验证查询性能3分钟复制《query.txt》脚本,依次执行,观察耗时

安装部署

1.下载官网社区最新版,建议2.00.9及以上版本。

传送门:https://www.dolphindb.cn/downloads/DolphinDB_Win64_V2.00.9.3.zip

2.windows解压路径,不能有空格,避免安装到Program Files路径下。

官网教程:standalone_server.md · dolphindb/Tutorials_CN - Gitee.com

3.本次测试使用免费的社区版,企业版license可申请免费试用。

联系方式:DolphinDB丨高性能分布式时序数据库

4.安装及测试过程中,有任何问题,可添加小助手微信(dolphindb1)咨询。

验证说明

1.统计耗时使用 timer 函数,即排除网络传输和序列化影响,仅统计服务端全部数据处理完成的时间。

2.性能受磁盘 IO、CPU、网络等系统资源的影响,如测试环境不同,表格中的性能实测数据可能会有差异。

3.web 端的交互编程执行方式,可以框选单条脚本,按 Ctrl-E 执行。也可以全选,按 Ctrl-E 执行。

4.模拟车辆轨迹写入的性能接近200万条/秒(1000万点/秒),可以作为真实数据写入性能的参考(排除协议连接、网络传输、序列化等耗时)。

5.性能测试优先保障性能,配置文件 dolphindb.cfg 中可以限制资源(核数、内存等)。

欢迎大家动手尝试,一起来验证一下吧!

附录

《data.txt》:建库建表,模拟数据生成

//步骤一:登录
login(`admin,`123456)

//步骤二:建库、建表
//1.车辆信息表:t_car
if(existsDatabase("dfs://t_car")){dropDatabase("dfs://t_car")}
create database "dfs://t_car" partitioned by VALUE([`code])
create table "dfs://t_car"."car" (
    code SYMBOL,    //车牌
    model SYMBOL,   //型号
    emissions SYMBOL,   //排量
    brand SYMBOL    //品牌
)
//2.配送订单表:t_order
if(existsDatabase("dfs://t_order")){dropDatabase("dfs://t_order")}
create database "dfs://t_order" partitioned by VALUE([date(now())]), engine="TSDB"
create table "dfs://t_order"."order" (
    orderid LONG,   //订单号
    ts TIMESTAMP,   //下单时间
    btime TIMESTAMP,    //配送起始时间
    etime TIMESTAMP,    //配送截止时间
    code SYMBOL,    //车牌
    blng DOUBLE,    //起始经度
    blat DOUBLE,    //起始纬度
    elng DOUBLE,    //目的地经度
    elat DOUBLE     //目的地纬度
)
partitioned by ts
sortColumns=[`orderid,`ts],
sortKeyMappingFunction=[hashBucket{,9}]

//3.车辆行驶路径表:dfs_drive
if(existsDatabase("dfs://dfs_drive")){dropDatabase("dfs://dfs_drive")}
create database "dfs://dfs_drive" partitioned by VALUE([date(now())]),HASH([SYMBOL,30]),engine="TSDB"
create table "dfs://dfs_drive"."drive" (
    ts TIMESTAMP,     //时间戳
    code SYMBOL,      //车牌
    lng DOUBLE,       //经度
    lat DOUBLE,       //纬度
    velocity INT,     //速度
    altitude INT,     //海拔
    direction INT     //方向
)
partitioned by ts,code
sortColumns=[`code,`ts],
sortKeyMappingFunction=[hashBucket{,99}]

//步骤三:模拟写入仿真数据
//写入车辆信息表:t_car(1万条)
n=100000
code=100001..200000     //产生序列数据
code="浙A"+string(code)
model=rand(`搅拌车`泵车`砂石车,n)		//rand随机函数,用于产生数量为 n 的向量值
emissions=string(rand(5..10,n))+`升
brand=rand(`SANY`ZOOMLION`XCMG`LOXA`FANGYUAN`RJST,n)
t=table(code,model,emissions,brand)
t_car=loadTable("dfs://t_car",`car)
t_car.append!(t)

select count(*) from t_car		//数据检查
select top 10 * from t_car

//写入订单信息表:t_order(100万条)
n=1000000
orderid=1000001..2000000            //产生序列数据
ts=take(2023.01.01..2023.01.10,n)   //产生10天的订单
ts=sort(ts)	                        //向量结构排序:10w条1月1日+10w条1月2日...+10w条1月10日
codes=select code from loadTable("dfs://t_car",`car)        //获取1万车牌号码
code=take(codes.code,n)										//向量结构:10w条车牌序列 x 10天=100w
btime=temporalAdd(datetime(ts),rand(14400,n)+32400,"s")		//开始配送时间:9点~13点随机
etime=temporalAdd(datetime(btime),rand(18000,n)+3600,"s")	//配送时间:1小时~5小时随机
blng=103.60972+rand(1.0,n)-0.5
blat=30.81841+rand(1.0,n)-0.5
elng=103.60972+rand(1.0,n)-0.5
elat=30.81841+rand(1.0,n)-0.5
t=table(orderid,ts,btime,etime,code,blng,blat,elng,elat)
t_order=loadTable("dfs://t_order",`order)
t_order.append!(t)

select count(*) from t_order		//数据检查
select top 10 * from t_order

//写入车辆轨迹数据,8.64亿/天
def write_data(){
	for(ts in 2023.01.01..2023.01.01){
		//将10w车牌拆分成50份,写入50次(可通过降低拆分数量,进一步提高速度。如内存不支持,可能会Out Of Memory)
	 	for(i in 1..50){
            n=8640
	 		j=(i-1)*2000
			codes=select code from loadTable("dfs://t_car",`car) limit j , 2000*i
            time = datetime(ts)+ 10*(0..(n-1))
            lng=103.60972+rand(1.0,n)-0.5
            lat=30.81841+rand(1.0,n)-0.5
            velocity=rand(100,n)
            altitude=rand(300,n)
            direction=rand(360,n)
			t=table(time as ts,lng,lat,velocity,altitude,direction)
			tt = cj(t,codes)	//关联车牌和数据,每次写入量:2000*8640
			reorderColumns!(tt,loadTable("dfs://dfs_drive",`drive).schema().colDefs.name)
			loadTable("dfs://dfs_drive",`drive).append!(tt)
			tt=NULL
	 	}
	}
}
submitJob(`write_data,`write_data,write_data)   //后台执行写入操作

drives=loadTable("dfs://dfs_drive",`drive)	//数据检查
select count(*) from drives

《query.tx》:性能测试

// 步骤四:数据准备工作
//检查作业状态(预计执行8分钟)
select jobId,startTime as 开始时间,endTime as 结束时间,(endTime-startTime)/1000 as 执行秒数 from getRecentJobs(1)

//确定作业完成后,执行刷盘,LevelFile合并,清除缓存,确保性能测试的准确。
//因为短时间导入了大量数据,部分数据还在内存(CacheEngine)中,并逐步写入磁盘。为确保性能测试时,数据是从磁盘中读取,需要进行刷盘操作。
flushTSDBCache()

//LevelFile合并:优化历史数据的查询性能
chunkIds = exec chunkId from getChunksMeta() where type=1 
for (x in chunkIds) {
triggerTSDBCompaction(x)
}
//清除缓存,确保测试性能准确
clearAllCache()

// 步骤五:查询统计
//全量数据检查:
/*1. 统计车辆经纬数据总数*/
drives=loadTable("dfs://dfs_drive",`drive)
timer t=select count(*) from drives
t
select top 10 * from drives
/*2. 按车牌+时间,查询车辆经纬数据*/
timer t=select * from drives where ts=2023.01.01 22:10:10.000 , code="浙A100207"
t
/*3 按车牌,统计数据总数*/
timer t=select count(*) from drives where code="浙A100207"
t
/*4 按车牌,查看车辆与总部距离*/
poi=point(104.102683,30.482596)	//总部经纬度
timer t=select ts,code,string(long(distance(poi,point(lng, lat)))/1000)+`km as distance from drives where ts=2023.01.01 22:10:10.000 , code="浙A105207"
t
/*5 按车牌,查询一天的所有数据*/
timer t=select * from drives where code="浙A165207" and ts between 2023.01.01 00:00:00.000:2023.01.01 23:59:59.999
t
/*6 按车牌查询每小时的平均车速  */
timer t=select avg(velocity) from drives where code="浙A165207" group by bar(ts,1H)
t
/*7 按订单ID,查询某订单所有路径*/
//新建自定义函数,用来查询订单(100w)的轨迹(8.6亿)
def orderQuery(oid){
	t=select code,btime,etime from loadTable("dfs://t_order",`order) where orderid=oid
	carcode = t.code[0]
	tt=select * from loadTable("dfs://dfs_drive",`drive) where code=carcode,ts between t.btime[0]:t.etime[0]
	return tt
}
//执行订单查询
timer t=orderQuery(1000006)
t
//添加存储过程(函数视图):执行后,可通过api调用此函数
try{dropFunctionView(`orderQuery)}catch(x){}
addFunctionView(orderQuery)

/*8 以60倍速(每秒钟播放真实时间1分钟的轨迹数据)的速率,播放某订单的车辆行驶轨迹*/
rate=60                 //回放倍速
t=orderQuery(1000006)   //需要回放的数据
show=table(1:0,t.schema().colDefs.name,t.schema().colDefs.typeInt)
submitJob("replay_drive","回放订单轨迹", replay, t,show, `ts, `ts, rate,false)
//持续执行(可通过share函数将表共享,以输出到GIS系统的可视化地图)
select * from show order by ts desc

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/10659.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2.3 连续性随机变量

思维导图: 学习目标: 我会按照以下步骤学习连续型随机变量: 复习概率论的基础知识,包括概率、期望、方差等概念和公式,以及离散型随机变量的概率分布函数和概率质量函数的概念和性质。 学习连续型随机变量的概念和性…

学生信息管理系统(student information manage system, SIMS)

一、前言 本项目为学生信息管理系统,使用C语言编写。 ★★★项目详见本人gitee仓库,地址 https://gitee.com/omnipotent-brother/student-information-manage-system.git ★★★ 二、项目介绍 开发环境: 基于windows 11系统下的Visual Studio…

YC-A11(原创)基于springboot,vue网上商城

绪论 课题的开发背景 随着计算机和网络的快速发展,并且越来越普及,互联网日益成为人们收集信息常用渠道,电子商务开始流行,一种全新的理念不断形成并且快速发展,像国内电商巨头淘宝、京东、苏宁易购、唯品会等电商平台…

【JavaScript】2.JavaScript函数

JavaScript 函数 1. 函数的概念 函数&#xff1a;就是封装了一段可被重复调用执行的代码块 通过此代码块可以实现大量代码的重复使用 2. 函数的使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta na…

前馈PID控制(热交换器/反应釜温度控制)

如何利用PID进行温度控制请参看下面博客文章: 博途PID 1200/1500PLC PID_Compact比例作用权重b微分作用权重c解读(PI-D控制器 I-PD控制器)_RXXW_Dor的博客-CSDN博客很多人会问PLC自带的PID指令和我们自己设计的PID有什么区别,这个问题要看你和什么PID控制器作对比,PID负反…

NDK RTMP直播客户端二

在之前完成的实战项目【FFmpeg音视频播放器】属于拉流范畴&#xff0c;接下来将完成推流工作&#xff0c;通过RTMP实现推流&#xff0c;即直播客户端。简单的说&#xff0c;就是将手机采集的音频数据和视频数据&#xff0c;推到服务器端。 接下来的RTMP直播客户端系列&#xff…

Redis用于全局ID生成器、分布式锁的解决方案

全局ID生成器 每个店铺都可以发布优惠卷 当用户抢购时&#xff0c;就会生成订单并保存到tb_voucher_order这张表中&#xff0c;而订单表如果使用数据库自增id就存在一些问题&#xff1a; 1.id的规律性太明显 2.受单表数据量的限制 全局ID生成器&#xff0c;是一种在分布式系…

Atlassian后Server时代 | Server版vs.数据中心版,二者的区别在哪里?

2024年2月&#xff0c;也就是一年不到&#xff0c;Atlassian将终止对Server产品及插件的所有支持。 此公告发布后&#xff0c;许多用户需要了解怎样的前进方向才是最适合企业的。为此&#xff0c;Atlassian提供了本地部署的数据中心&#xff08;Data Center&#xff09;版以及云…

线段树笔记草稿

一个左节点u << 1和右节点u << 1 | 1 的证明 区间修改部分 1.批量等值修改 前提条件 是要区间修改&#xff0c;区间查询&#xff0c;且修改操作修改的值是相同的 情景 一般是要对一个数组执行k次操作&#xff0c;每次改变其中一个区间内所有元素的值&#x…

ChatGPT文本框再次升级,打造出新型操作系统

在ChatGPT到来之前&#xff0c;没有谁能够预见。但是&#xff0c;它最终还是来了&#xff0c;并引起了不小的轰动&#xff0c;甚至有可能颠覆整个行业。 从某种程度上说&#xff0c;ChatGPT可能是历史上增长最快的应用程序&#xff0c;仅在两个多月就拥有了1亿多活跃用户&…

Adaptive Weight Assignment Scheme For Multi-task Learning

Adaptive Weight Assignment Scheme For Multi-task Learning 题目Adaptive Weight Assignment Scheme For Multi-task Learning译题用于多任务学习的自适应权重分配方案时间2022年期刊/会议IAES International Journal of Artificial Intelligence (IJ-AI) 摘要&#xff1a;如…

【AutoGPT】你自己运行,我先睡了—— ChatGPT过时了吗?

系列文章目录 【AI绘画】Midjourney和Stable Diffusion教程_山楂山楂丸的博客-CSDN博客 目录 系列文章目录 前言 一、AutoGPT是什么&#xff1f; 二、AutoGPT带来的利弊 三、AutoGPT和ChatGPT区别 四、未来 总结 前言 ChatGPT是否过时&#xff1f;AutoGPT的兴起&#…

MappingGenerator PRO 2023.3 Visual Studio 2019-2022

您的私人编码助手 MappingGenerator 最初是作为 AutoMapper 的设计时替代品创建的。现在它正在演变为编码助手&#xff0c;您可以将最平凡的编码任务委派给它&#xff1a; 生成映射生成显式转换实施克隆生成投影表达式脚手架方法调用脚手架对象创建清理方法调用方便ILogger的使…

ChatGPT风口下的中外“狂飙”,一文看懂微软、谷歌、百度、腾讯、华为、字节跳动们在做什么?

毫无疑问&#xff0c;ChatGPT正成为搅动市场情绪的buzzword。 历史经历过无线电&#xff0c;半导体&#xff0c;计算机&#xff0c;移动通讯&#xff0c;互联网&#xff0c;移动互联网&#xff0c;社交媒体&#xff0c;云计算等多个时代&#xff0c;产业界也一直在寻找Next Bi…

Golang每日一练(leetDay0031)

目录 91. 解码方法 Decode Ways &#x1f31f;&#x1f31f; 92. 反转链表 II Reverse Linked List II &#x1f31f;&#x1f31f; 93. 复原 IP 地址 Restore IP Addresses &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练…

【JVM】JVM之执行引擎

文章目录一、前言二、名词解释机器码指令指令集汇编语言高级语言字节码虚拟机&物理机前端编译器&后端编译器三、JVM之执行引擎执行引擎是如何工作的&#xff1f;解释器即时编译器&#xff08;JIT&#xff09;分层编译策略虚拟机执行模式热点代码&探测方式1&#xf…

如何在 Linux 中使用 Chage 命令,修改Linux系统用户密码更改策略

Chage是一个用于修改Linux系统用户密码更改策略的命令行工具。在本文中&#xff0c;我们将介绍如何在Linux系统中使用Chage命令。 检查用户密码过期信息 使用Chage命令可以检查用户密码更改策略和过期信息。要检查特定用户的密码过期信息&#xff0c;可以使用以下命令&#x…

PPT NO.1【用ppt如何做一张海报+字体】

PPT做得好的人&#xff0c;一定是站在观众的角度思考的人。 1、设置幻灯片尺寸大小&#xff1a; 设置完成后如下&#xff1a; 2、加载一张自己喜欢的图片进来&#xff1a;【图片越高清越好】 将图片铺满空白的地方&#xff0c;调整好自己喜欢的区域&#xff1a; 做裁剪&#xf…

数据结构---递归转化为非递归

递归转化为非递归前言快速排序非递归归并排序的非递归前言 为什么要学习非递归写法呢&#xff1f; 当我们在用递归实现一个程序的时候&#xff0c;要考虑一个问题&#xff0c;这个程序用递归去实现&#xff0c;当数据量庞大的时候&#xff0c;会不会造成栈溢出(STACK OVERFLOW…

代码随想录_226翻转二叉树、101对称二叉树

leetcode 226. 翻转二叉树 ​​​226. 翻转二叉树 给你一棵二叉树的根节点 root &#xff0c;翻转这棵二叉树&#xff0c;并返回其根节点。 示例 1&#xff1a; 输入&#xff1a;root [4,2,7,1,3,6,9] 输出&#xff1a;[4,7,2,9,6,3,1]示例 2&#xff1a; 输入&#xff1a;r…