Ganos实时热力聚合查询能力解析与最佳实践

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
简介: Ganos是由阿里云数据库产品事业部与飞天实验室共同研发的新一代云原生位置智能引擎,集成于PolarDB-PG、Lindorm、AnalyticDB-PG和RDS-PG等核心产品中。Ganos拥有十大核心引擎,涵盖几何、栅格、轨迹等多种数据处理能力,实现了多模多态数据的一体化存储、查询与分析。本文重点介绍了Ganos的热力瓦片(HMT)技术,通过实时热力聚合查询与动态输出热力瓦片,无需预处理即可实现大规模数据秒级聚合与渲染,适用于交通、城市管理、共享出行等多个领域。HMT相比传统网格聚合技术具有高效、易用的优势,并已在多个真实场景中验证其卓越性能。

关于Ganos
Ganos是阿里云数据库产品事业部联合飞天数据库与存储实验室共同研发的新一代云原生位置智能引擎,它将时空数据处理能力融入了云原生关系型数据库PolarDB-PG、云原生多模数据库Lindorm、云原生数据仓库AnalyticDB-PG和云数据库RDS-PG等核心产品中。Ganos目前拥有几何、栅格、轨迹、表面网格、体网格、3D实景、点云、路径、地理网格、快显十大核心引擎,为数据库构建了面向新型物理世界多模多态数据的存储、查询、分析、服务等一体化能力。
本文主要介绍Ganos实时热力聚合查询并动态输出热力瓦片能力,依托阿里云PolarDB PostgreSQL产品、ADB PostgreSQL和RDS PostgreSQL 三款数据库建设输出。

  1. 关于热力瓦片
    2.1 什么是热力瓦片
    热力瓦片(HeatMap Tile,简称HMT)底层基于Ganos首创的大规模矢量/轨迹数据实时热力聚合查询技术,用于将查询处理结果即时返回client的数据交换结构,它改变了热力统计分析中“聚合需要预打码、展示需要预切片”的传统方式,可针对百万级、千万级、亿级规模数据秒级聚合并渲染。HMT支持多种常用聚合函数与代数表达式,客户可选择统计业务关心的指标并随地图的放大缩小进行不同层级的动态计算和实时绘制,极大程度提升了业务效率,为客户产品带来的更多可能。在本年度的云栖大会上,Ganos发布了这项能力,并现场展示了基于HMT构建大规模运输轨迹实时查询聚合的案例,帮助客户把以往需要线下预处理才能发布的数据产品完全在线化,该功能得到了很大行业反响与认可。
    2.2 热力瓦片的使用场景
    热力瓦片的特点是空间数据的实时聚合与渲染,主要应用于拥有海量矢量数据并需要实时统计分析的业务场景,比如:
  2. 交通运输类:根据运输工具(车、船等)的历史轨迹线,聚合出全域范围内的实时热力,并可根据时间(冬季、夏季)、起点/终点、类型(货车、客车)等附带条件进行过滤后实时生成相应的热力;
  3. 城市管理类:根据房屋建筑底面数据聚合出全域范围内城市/农村的建筑密度、建筑平均高度、建筑总面积等单项指标,并可结合地块信息聚合出容积率等复合指标;
  4. 共享出行类:根据共享出行设备的轨迹点,聚合出全域范围内设备的停靠区域热力,并可根据设备事件(开锁/关锁、上车/下车、事故、损坏)、流向等条件分析共享出行设备的调度运维策略;
    2.3 热力瓦片的技术优势
    相较于基于H3或S2网格预打码聚合的方式,HMT热力瓦片拥有如下优势:
  5. 效率极高,无需要预打码,不增加存储成本。HMT的聚合技术与H3/S2等网格聚合方式在技术特点及应用场景方面都有不同,网格聚合方式往往面向需要以网格编码作为检索条件的应用场景,因为它需要预先设定某一精度层级,之后在该精度下针对矢量数据进行赋码,再根据编码进行相关统计;而HMT不需要提前针对数据预打码,完全可以根据当前视口范围进行聚合,随着视口的放大缩小,聚合会实时进行,整个过程针对各类几何对象效率一致,均可达到亿级规模秒级聚合渲染;
  6. 方便宜用,聚合结果直接可视化。HMT提供了聚合结果快速瓦片化的能力,可以将聚合结果直接与前端渲染引擎进行可视化对接,保证所见即所得。同时HMT还提供了一系列的统计函数,帮助用户快速自动化生成最佳的渲染色表,确保前端的最优表现;
    经多个客户真实场景测试,HMT的聚合有着极高的效率,基本可以实现亿级规模全图聚合秒级完成:
    应用场景
    数据量
    瓦片范围
    聚合效率
    轨迹聚合
    轨迹线:45万
    轨迹点:3100万
    全球级别
    512512瓦片
    372ms
    建筑底面聚合
    建筑底面:3.08亿
    全球级别,
    512
    512瓦片
    17s
    注:上述数据均为全球展示尺度下全量数据聚合效率,随着地图不断放大,效率不断提升;
    2.4 热力瓦片的功能介绍
    热力瓦片包含一系列的SQL函数,用于解决热力瓦片的生成与统计问题,具体包括:
    • ST_AsHMT:将一组几何对象或轨迹对象按照指定范围和指定分辨率转为热力矩阵瓦片;
    • ST_HMTAsArray:将热力图瓦片转为基于数组矩阵的表示方法,方便进行查看;
    • ST_HMTStats:计算热力图瓦片统计信息;
    • ST_HMTAsRaster:将热力瓦片转为Raster对象,方便进行查看以及计算操作;
  7. 热力瓦片最佳实践
    3.1 操作步骤
  8. 将几何或轨迹数据入库到数据库中,建议使用FDW的方式进行入库。确保所有的对象都具备相同的空间参考系统(可以通过ST_Srid函数进行确认)
  9. 对几何列或轨迹列创建空间索引
    CREATE INDEX index_name ON table_name USING GIST(column_name)
  10. 根据空间范围进行热力瓦片的查询
    可以针对网格内的对象数量的进行热力聚合
    SELECT ST_AsHMT(column_name, --geometry type
    ST_MakeEnvelope(0, 0, 10, 10, 4326), -- Extent
    512, -- Width
    512 -- height
    )
    FROM table_name
    WHERE column_name && ST_MakeEnvelope(0, 0, 10, 10, 4326);
    也可以对某个网格内的数值进行聚合,使用value字段中的数值进行求和操作
    SELECT ST_AsHMT(column_name, --geometry type
    ST_MakeEnvelope(0, 0, 10, 10, 4326), -- Extent
    512, -- Width
    512, -- height
    value -- value column
    )
    FROM table_name
    WHERE column_name && ST_MakeEnvelope(0, 0, 10, 10, 4326);
    其中ST_MakeEnvelope可以使用ST_TileEnvelope函数获取瓦片范围。
    同样可以增加其他过滤条件:
    SELECT ST_AsHMT(column_name, --geometry type
    ST_MakeEnvelope(0, 0, 10, 10, 4326), -- Extent
    512, -- Width
    512, -- height
    value -- value column
    )
    FROM table_name
    WHERE column_name && ST_MakeEnvelope(0, 0, 10, 10, 4326);
    AND name like 'xxxx%' AND value > 100;
    3.2 使用技巧
    • 在数据量较大时采用并行提升性能,以下以并行度为16为例:
    SET max_worker_processes = 300; -- Maximum number of background processes
    set max_parallel_workers = 260; -- maximum number of workers
    set max_parallel_workers_per_gather = 16; --maximum number of workers that can be started by a single Gather or Gather Merge node
    alter table table_name set (parallel_workers=16);
    set force_parallel_mode = on;
    在实际使用中可以根据视口范围进行设置,如较高层级下使用16并行,较低层级下不使用并行等。
    在CPU足够的情况下,为了确保每个查询都可以使用并行,需要将max_worker_processes 和 max_parallel_workers 设置为并行度和并发数的乘积。 参考 postgresql的官方文档
    https://www.postgresql.org/docs/current/runtime-config-resource.html
    • 瓦片大小
    通常情况下使用512512 的瓦片重采样到256256的瓦片来避免锯齿的问题。但在在特殊情况下,如数据量非常大时,每个瓦片计算非常耗时,可以使用大瓦片(10241024)来降低瓦片的获取数量提升性能。
    • 使用&& 操作符进行空间过滤
    由于ST_AsHMT的计算比ST_Intersects要快很多, 在索引过滤时使用 && 替代ST_Intersects 过滤对象
    SELECT ST_AsHMT(column_name, --geometry type
    ST_MakeEnvelope(0, 0, 10, 10, 4326), -- Extent
    512, -- Width
    512, -- height
    value -- value column
    )
    FROM table_name
    WHERE column_name && ST_MakeEnvelope(0, 0, 10, 10, 4326);
    • 查询范围进行空间参考转换
    当查询范围和几何对象空间范围不一致时,将查询范围进行空间参考转换后查询。否则自动转换可能会引起性能较低。获取瓦片后将图片转换为指定的空间参考进行展示
    SELECT ST_AsHMT(column_name, -- srid = 4326
    ST_Transform(ST_TileEnvelope(6, 48, 32), 4326), -- Extent
    512, -- Width
    512, -- height
    value -- value column
    )
    FROM table_name
    WHERE column_name && ST_Transform(ST_TileEnvelope(6, 48, 32), 4326));
    • 对空间表进行vaccum full和cluster操作
    Vaccum操作可以回收空闲空间,降低磁盘文件大小,在查询时能降低IO数量。
    Cluster操作可以将数据组织与索引保持一致,相邻的空间数据会保存在相邻的数据页面中,访问时可以降低数据库的磁盘访问。
    VACUUM full table_name;
    Cluster table_name using index_name;
    3.3 发布服务进行浏览
    我们使用Node.js编写一个简易的应用,演示热力瓦片的实际使用场景。
    3.3.1 文件结构
    └── hmt_server
    ├── app.js
    ├── hmt.proto
    ├── index.html
    └── package.json
    其中:hmt.proto为上文中ST_AsHMT一节中介绍的proto文件,其他文件内容将在下文给出。
    3.3.2 后端代码
    {
    "name": "hmt_server",
    "version": "1.0.0",
    "main": "app.js",
    "license": "ISC",
    "dependencies": {
    "chroma-js": "^2.4.2",
    "express": "^4.18.2",
    "lru-cache": "^10.1.0",
    "pg": "^8.11.3",
    "protobufjs": "^7.2.5",
    "sharp": "^0.32.6"
    }
    }
    const express = require('express');
    const { Pool } = require('pg');
    const chroma = require('chroma-js');
    const sharp = require("sharp");
    const protobuf = require('protobufjs');
    const { LRUCache } = require('lru-cache');
    // 设定数据库连接
    const CONNECTION = {
    user: 'YOUR_USER',
    password: 'YOUR_PWD',
    host: 'YOUR_HOST',
    database: 'YOUR_DB',
    port: YOUR_PORT
    };
    // 目标表名
    const TABLE_NAME = 'YOUR_TABLE';
    // 目标几何字段名
    const GEOMETRY_COLUMN = 'YOUR_GEOM_COLUMN';
    // 设定无数据值
    const NO_DATA_VALUE = 0;
    // 目标几何字段空间参考
    const SRID = 4326
    // 设定色带
    const COLOR_MAP = [
    ['#536edb', 1],
    ['#5d96a5', 3],
    ['#68be70', 5],
    ['#91d54d', 7],
    ['#cddf37', 9],
    ['#fede28', 11],
    ['#fda938', 13],
    ['#fb7447', 15],
    ['#f75a40', 17],
    ['#f24734', 19],
    ['#e9352a', 21],
    ['#da2723', 23],
    ['#cb181d', 25]
    ];
    // 创建数据库连接池,默认为10个连接
    const pool = new Pool(CONNECTION);
    // 配置颜色转换
    const [colors, domains] = COLOR_MAP.reduce(([c, d], [colors, domains]) =>
    [[...c, colors], [...d, domains]], [[], []]);
    const colorMap = chroma.scale(colors).domain(domains).mode('rgb')
    // 加载protobuf
    const hmtDecoder = protobuf.loadSync('./hmt.proto').lookupType('HMT');
    // 创建一个1x1的透明png,作为空瓦片返回
    const emptyPng = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAADUlEQVQImWP4//8/AwAI/AL+hc2rNAAAAABJRU5ErkJggg==', 'base64');
    // 对于小比例尺瓦片(z<5),因更新相对不明显,设定一个24小时过期的缓存
    const globalCache = new LRUCache({ max: 1000, ttl: 1000
    3600 24 });
    // 对于更大比例尺瓦片(z>=5),设定一个12小时过期的缓存,也可根据实际情况自行修改
    const localCache = new LRUCache({ max: 2000, ttl: 1000
    3600 * 12 });
    // 注册Express路由
    express()
    // 响应HTML页面
    .get("/", (_, res) => res.sendFile('index.html', { root: __dirname }))
    // 响应热力瓦片服务
    .get('/hmt/:z/:x/:y', async ({ params: { z, x, y } }, res) => {
    const cache = z < 5 ? globalCache : localCache;
    const key = ${z},${x},${y}
    if (!cache.has(key)) {
    // 设定并行度,并调用ST_AsHMT函数,请求该区域256x256的热力瓦片
    const parallel = z <= 5 ? 10 : 5;
    const sql = set max_parallel_workers = ${parallel}; set max_parallel_workers_per_gather = ${parallel}; WITH _PARAMS(_BORDER) as (VALUES(ST_Transform(ST_TileEnvelope(${key}),${SRID}))) SELECT ST_AsHMT(${GEOMETRY_COLUMN},_BORDER,256,256) tile FROM ${TABLE_NAME},_PARAMS WHERE _BORDER && ${GEOMETRY_COLUMN};
    // 跳过set语句,获取ST_AsHMT函数的结果
    const { rows: [{ tile }] } = (await pool.query(sql))[2];
    // 若该区域无数据则直接返回空瓦片
    if (!tile) cache.set(key, emptyPng);
    else {
     // 解析protobuf结果
     const { type, doubleValues, intValues } = hmtDecoder.decode(tile);
     const { values } = type == 1 ? doubleValues : intValues;
     // 将数值转换为对应的颜色,并剔除无数据值
     const pixels = values.reduce((_pixels, value) => {
       _pixels.push(...colorMap(value).rgb());
       _pixels.push(value <= NO_DATA_VALUE ? 0 : 255);
       return _pixels;
     }, [])
     // 渲染为png瓦片
     const rawConfig = { raw: { width: 256, height: 256, channels: 4 } };
     const renderedPng = await sharp(Uint8Array.from(pixels), rawConfig)
       .png().toBuffer();
     cache.set(key, renderedPng);
    
    }
    }
    const tile = cache.get(key)
    res.set("Content-Type", "image/png").send(tile);
    })
    // 监听5500端口
    .listen(5500, () => console.log('HMT server started.'));
    其中:
    • 色带为连续色带,支持十六进制字符串颜色、CSS3名称颜色等表达方式,可参见chroma.js文档。
    • 若想瓦片渲染效果更加平滑,可以以512x512请求数据,再降采样到256x256分辨率,只是会增加响应时间。
    • 并行度的设定需要根据数据量大小,数据库实例配置及对响应速度的需求来调整。
    • 本例在Z<=5时适当降低并行度。
    3.3.3 前端代码
    我们使用Mapbox作为前端地图SDK,其token可在此处申请查看。
    由于热力瓦片最终被渲染为PNG格式,因此兼容其他绝大多数地图SDK。
    <!DOCTYPE html>













3.3.4 安装与发布
https://www.bilibili.com/read/cv38852834
https://www.bilibili.com/read/cv38852896
https://www.bilibili.com/read/cv38852956

定位到hmt_server目录

cd ./hmt_server

安装依赖库

npm i

运行热力瓦片服务

node .

此时可以打开浏览器,登录地址 http://localhost:5500/ 查看效果

3.4 效果预览
3.4.1 船舶轨迹线实时聚合
• 3100万轨迹点,45万轨迹线实时聚合
3.4.2 建筑底面实时聚合
• 3.08亿建筑底面实时聚合
  • 总结
    目前,Ganos已经发展到了v6.0版本,支撑了数十个行业领域的数千个应用场景,稳定、成本、性能与易用性一直Ganos长期坚持的目标,HMT热力瓦片就是Ganos在大规模空间数据高效聚合与可视化领域的内核级核心竞争力,它为客户大规模数据分析挖掘提供了真正高效、易用的方案,欢迎各位用户体验。
  • 试用体验
    可以访问PolarDB免费试用页面,选择试用“云原生数据库PolarDB PostgreSQL版”,体验Ganos HMT实时热力统计查询能力。
  • 相关文章
    |
    18天前
    |
    存储 缓存 监控
    后端开发中的缓存机制:深度解析与最佳实践####
    本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
    |
    15天前
    |
    监控 数据管理 测试技术
    API接口自动化测试深度解析与最佳实践指南
    本文详细介绍了API接口自动化测试的重要性、核心概念及实施步骤,强调了从明确测试目标、选择合适工具、编写高质量测试用例到构建稳定测试环境、执行自动化测试、分析测试结果、回归测试及集成CI/CD流程的全过程,旨在为开发者提供一套全面的技术指南,确保API的高质量与稳定性。
    |
    13天前
    |
    PHP 开发者 容器
    PHP命名空间深度解析及其最佳实践####
    本文深入探讨了PHP中引入命名空间的重要性与实用性,通过实例讲解了如何定义、使用及别名化命名空间,旨在帮助开发者有效避免代码冲突,提升项目的模块化与可维护性。同时,文章还涉及了PHP-FIG标准,引导读者遵循最佳实践,优化代码结构,促进团队协作效率。 ####
    23 1
    |
    17天前
    |
    Java 数据库连接 开发者
    Java中的异常处理机制:深入解析与最佳实践####
    本文旨在为Java开发者提供一份关于异常处理机制的全面指南,从基础概念到高级技巧,涵盖try-catch结构、自定义异常、异常链分析以及最佳实践策略。不同于传统的摘要概述,本文将以一个实际项目案例为线索,逐步揭示如何高效地管理运行时错误,提升代码的健壮性和可维护性。通过对比常见误区与优化方案,读者将获得编写更加健壮Java应用程序的实用知识。 --- ####
    |
    28天前
    |
    Kubernetes 监控 API
    深入解析Kubernetes及其在生产环境中的最佳实践
    深入解析Kubernetes及其在生产环境中的最佳实践
    42 1
    |
    29天前
    |
    API PHP 数据库
    PHP中的异常处理机制深度解析与最佳实践####
    本文深入探讨了PHP中异常处理机制的核心概念、工作原理及其在现代Web开发中的应用。通过剖析try-catch结构、自定义异常类及异常的继承体系,揭示了如何高效地捕获、处理并管理运行时错误,以提升应用的稳定性和用户体验。文章还结合实例,分享了在实际项目中实施异常处理的最佳实践,帮助开发者构建更加健壮的PHP应用程序。 ####
    |
    25天前
    |
    网络协议 安全 网络安全
    OSPF的安全性考虑:全面解析与最佳实践
    OSPF的安全性考虑:全面解析与最佳实践
    35 0
    |
    29天前
    |
    监控 Java 应用服务中间件
    高级java面试---spring.factories文件的解析源码API机制
    【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
    67 2
    |
    2月前
    |
    缓存 Java 程序员
    Map - LinkedHashSet&Map源码解析
    Map - LinkedHashSet&Map源码解析
    75 0
    |
    2月前
    |
    算法 Java 容器
    Map - HashSet & HashMap 源码解析
    Map - HashSet & HashMap 源码解析
    57 0

    推荐镜像

    更多