すべてのプロダクト
Search
ドキュメントセンター

PolarDB:, ,

最終更新日:Dec 23, 2024

このトピックでは、PolarDB for PostgreSQL に基づくGanosBaseが提供するリアルタイムヒートマップ集約クエリと動的ヒートマップタイル出力機能を紹介します。 この機能により、クエリ結果をデータ交換構造にリアルタイムで配信できます

heatmapタイルについて

ヒートマップタイルとは何ですか?

ヒートマップタイル (HMT) はGanosBaseの大規模なベクトル /軌道データのための先駆的なリアルタイムヒートマップ集約クエリ技術に基づいています。 これらは、クエリ結果をリアルタイムでクライアントに返すために使用され、集計のための事前コーディングと表示のための事前タイリングを必要とするヒートマップ統計分析の従来の方法を変更します。 HMTは、数百万、数千万、さらには数億の規模のデータを数秒で集計およびレンダリングできます。 HMTは、一般的に使用されるさまざまな集計関数と代数式をサポートしているため、顧客はビジネスに関心のある指標を選択し、マップのズームインとズームアウトに応じてさまざまなレベルで動的に計算およびレンダリングできます。 これはビジネス効率を非常に高め、顧客プロダクトのためのより多くの可能性を提供する。 アプサラ会議2022では、GanosBaseはこの機能をリリースし、HMTを使用した大規模な輸送軌道のリアルタイムクエリ集約のケースを実証しました。これにより、以前はオフラインでの前処理が必要だったデータ製品を完全にオンライン化できます。 この機能は、業界で大きな認識と承認を受けています。

シナリオ

HMTの主な機能は、空間データのリアルタイム集計とレンダリングです。これは、主に、次のようなリアルタイムの統計分析を必要とする大量のベクトルデータを含むビジネスシナリオに適用されます。

  • 輸送: 輸送ツール (車、船など) の履歴軌道線に基づいて、地域全体のリアルタイムのヒートマップデータを集約し、時間 (冬、夏) 、開始 /終了ポイント、タイプ (貨物、乗客) などの条件でフィルタリングして、対応するヒートマップをリアルタイムで生成します。

  • 都市管理: 建物のフットプリントデータに基づいて、地域全体の建物密度、平均建物の高さ、総建物面積などの単一の指標を集約し、それらを土地区画情報と組み合わせて、床面積比などの複合指標を計算します。

  • 共有モビリティ: 共有モビリティデバイスの軌道ポイントに基づいて、地域全体にわたる機器ドッキングエリアのヒートマップを集約し、イベント (ロック解除 /ロック、搭乗 /降車、事故、損傷) 、流れの方向などに基づいて、共有モビリティ機器のディスパッチおよび運用戦略を分析します。

技術的な利点

H3またはS2グリッドに基づくプリコーディングおよびアグリゲーション方法と比較して、HMTには次の利点があります。

  1. 非常に効率的で、プリコーディングは不要で、追加のストレージコストもありません。 HMTのアグリゲーション技術は、H3/S2のようなグリッドアグリゲーション方法とは、技術的特性とアプリケーションシナリオが異なります。 グリッド集約方法は、所定の精度レベルを必要とするため、グリッドコーディングが検索条件として必要とされるシナリオでよく使用されます。 次いで、ベクトルデータは、その精度レベルで符号化され、符号化に基づいて集約される。 しかしながら、HMTは、データのプリコーディングを必要とせず、現在のビューポート範囲に基づいて集約することができる。 ビューポートがズームインおよびズームアウトすると、集計がリアルタイムで実行されます。 プロセス全体は、さまざまなタイプのジオメトリに対して同様に効率的であり、数億秒の規模でデータを集約およびレンダリングできます。

  2. 便利で使いやすい、集計結果を直接視覚化できます。 HMTは、集計結果をすばやくタイル化する機能を提供し、フロントエンドのレンダリングエンジンとの直接的な視覚化統合を可能にして、表示されるものが確実に得られるようにします。 HMTはまた、ユーザーが最適なレンダリングカラーテーブルを迅速かつ自動的に生成し、最適なフロントエンドパフォーマンスを保証するのに役立つ一連の統計関数を提供します。

複数の顧客によって実際のシナリオでテストされたHMTの集計効率は非常に高く、通常、数億のデータポイントの完全なマップ集計を数秒で実現します。

シナリオ

データ量

タイルスコープ

集計時間

軌道集約

  • 軌道線: 450,000

  • 軌道ポイント: 31,000,000

  • グローバル規模

  • 512 × 512タイル

372ミリ秒

建物のフットプリント集約

建物のフットプリント: 308万

  • グローバル規模

  • 512 × 512タイル

17秒

説明

データは、グローバル表示スケールでの完全な集約効率を表します。 マップがズームインすると効率が向上します。

機能

HMTには、ヒートマップタイルを生成および計算するための一連のSQL関数が含まれています。

  • ST_AsHMT : 指定された範囲と解像度に従って、幾何学的または軌道オブジェクトのセットをヒートマップ行列タイルに変換します。

  • ST_HMTAsArray : ヒートマップタイルを見やすいように配列行列表現に変換します。

  • ST_HMTStats : レンダリング用のヒートマップタイルの統計情報を計算します。

  • ST_HMTASRaster : 表示と計算のためにヒートマップタイルをラスタオブジェクトに変換します。

使用のヒント

パフォーマンスの向上と並列処理

大きなデータセットを扱う場合、並列処理でパフォーマンスを向上させます。 実際には、ビューポートの範囲に基づいて設定を調整できます。たとえば、上位レベルでは16の並列プロセスを使用し、下位レベルでは並列処理を使用しないなどです。 十分なCPUリソースがある場合、各クエリが並列処理を利用できるようにするには、max_worker_processesmax_parallel_workersを並列処理と同時実行の積に設定します。 詳細については、PostgreSQLの公式ドキュメントをご参照ください。 次の例では、並列度は16に設定されています。

SET max_worker_processes = 300;
SET max_parallel_workers = 260;
SET max_parallel_workers_per_gather = 16;
ALTER TABLE table_name SET (parallel_workers=16);
SET force_parallel_mode = on;

タイルサイズ

ほとんどの場合、エイリアシングの問題を回避するために、512 × 512タイルを256 × 256タイルに再サンプリングします。 データ量が非常に大きく、各タイルの計算に時間がかかる場合などの特別な場合には、より大きなタイル (1024 × 1024) を使用すると、タイルのフェッチ数を減らし、パフォーマンスを向上させることができます。

空間フィルタリングに && 演算子を使用

ST_AsHMT計算はST_Intersects計算よりもはるかに高速です。インデックスフィルタリングにST_Intersectsの代わりに && を使用します。

SELECT ST_AsHMT(column_name, -- Column of the geometry type
    ST_MakeEnvelope(0, 0, 10, 10, 4326), -- Define spatial range
    512,
    512,
    value       -- The value used to generate the reference column for output
)
FROM table_name
WHERE column_name && ST_MakeEnvelope(0, 0, 10, 10, 4326);

クエリ範囲の空間参照の変換

クエリ範囲とジオメトリオブジェクトの空間範囲に矛盾がある場合は、クエリの前にクエリ範囲で空間参照変換を実行します。 そうしないと、自動変換のパフォーマンスが低下する可能性があります。 タイルを取得したら、画像を指定した空間参照に変換して表示します。

SELECT ST_AsHMT(column_name, -- Spatial reference system is WGS 84 coordinate system
    ST_Transform(ST_TileEnvelope(6, 48, 32), 4326), -- Define the range of the tile
    512,
    512,
    value       -- The value used to render the tile image
)
FROM table_name
WHERE column_name && ST_Transform(ST_TileEnvelope(6, 48, 32), 4326));

VACUUM FULLおよびCLUSTERステートメントを空間テーブルで実行

  • VACUUM FULL操作は、空き領域を再利用してディスクファイルサイズを縮小し、クエリ中のI/O操作を削減します。

    VACUUM full table_name;
    Cluster table_name using index_name;
  • CLUSTER操作では、データ編成をインデックスに合わせ、隣接する空間データを隣接するデータページに格納し、データベースによるディスクアクセスを減らします。 詳細な使用方法については、PostgreSQLの公式ドキュメントをご参照ください。

    CLUSTER table_name USING index_name;

ベストプラクティス

  1. データベースの設定。

    1. 好ましくはFDW法を使用して、幾何学的または軌道データをデータベースにインポートする。 詳細については、「ベクターグリッドデータのクイックインポート」「」をご参照ください。 すべてのオブジェクトが同じ空間参照システムを共有していることを確認します。 確認にはST_Srid関数を使用します。

    2. ジオメトリまたは軌道列の空間インデックスを作成します。

      CREATE INDEX index_name ON table_name USING GIST(column_name);
    3. 空間範囲に基づいてヒートマップタイルを照会します。

      説明

      次のステートメントでは、ST_MakeEnvelope関数はST_TileEnvelope関数を使用してタイル範囲を取得できます。

      • グリッド内のオブジェクトの数を集計する:

        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);
      • 値列の値を合計することで、グリッド内の値を集計できます。

        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, --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;
  2. この例では、Node.jsを使用して、ヒートマップタイルの実際のユースケースを示す簡単なアプリケーションを作成します。

    ファイル構造:

    └── hmt_server
        ├── app.js
        ├── hmt.proto
        ├── index.html
        └── package.json

    hmt.protoは、ST_AsHMT で導入されたprotoファイルです。 その他のファイルの内容は以下の通りです。

    次のバックエンドパッケージ. jsonおよびapp.jsファイルを参照してください。

    • package.json

      {
        "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"
        }
      }
    • app.js

      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');
      
      // Set up database connection
      const CONNECTION = {
        user: 'YOUR_USER',
        password: 'YOUR_PWD',
        host: 'YOUR_HOST',
        database: 'YOUR_DB',
        port: YOUR_PORT
      };
      
      // Target table name
      const TABLE_NAME = 'YOUR_TABLE';
      
      // Target geometry column name
      const GEOMETRY_COLUMN = 'YOUR_GEOM_COLUMN';
      
      // Set no data value
      const NO_DATA_VALUE = 0;
      
      // Spatial reference of the target geometry column
      const SRID = 4326
      
      // Set color map
      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]
      ];
      
      // Create a database connection pool, which contains 10 connections by default
      const pool = new Pool(CONNECTION);
      
      // Configure color conversion
      const [colors, domains] = COLOR_MAP.reduce(([c, d], [colors, domains]) =>
        [[...c, colors], [...d, domains]], [[], []]);
      const colorMap = chroma.scale(colors).domain(domains).mode('rgb')
      
      // Load protobuf
      const hmtDecoder = protobuf.loadSync('./hmt.proto').lookupType('HMT');
      
      // Create a 1×1 transparent png to return as an empty tile
      const emptyPng = Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAADUlEQVQImWP4//8/AwAI/AL+hc2rNAAAAABJRU5ErkJggg==', 'base64');
      
      // For small scale tiles (z<5), where updates are relatively minor, set a 24-hour cache expiration 
      const globalCache = new LRUCache({ max: 1000, ttl: 1000 * 3600 * 24 });
      
      // For larger scale tiles (z>=5), set a 12-hour cache expiration, which can be modified according to actual conditions
      const localCache = new LRUCache({ max: 2000, ttl: 1000 * 3600 * 12 });
      
      // Register Express routes
      express()
        // Serve the HTML page
        .get("/", (_, res) => res.sendFile('index.html', { root: __dirname }))
        // Serve the heatmap tile service
        .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)) {
            // Set parallelism and call ST_AsHMT function to request a 256x256 heatmap tile for the area
            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};`
            // Skip set statements and get the result of the ST_AsHMT function
            const { rows: [{ tile }] } = (await pool.query(sql))[2];
      
            // If there is no data in the area, return an empty tile
            if (!tile) cache.set(key, emptyPng);
            else {
              // Parse protobuf result
              const { type, doubleValues, intValues } = hmtDecoder.decode(tile);
              const { values } = type == 1 ? doubleValues : intValues;
      
              // Convert values to corresponding colors and remove no data values
              const pixels = values.reduce((_pixels, value) => {
                _pixels.push(...colorMap(value).rgb());
                _pixels.push(value <= NO_DATA_VALUE ? 0 : 255);
                return _pixels;
              }, [])
      
              // Render as a PNG tile
              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);
        })
        // Listen on port 5500
        .listen(5500, () => console.log('HMT server started.'));

      上記のサンプルコードでは、

      • カラーマップはシームレスなスペクトルを提供し、16進文字列やCSS3文字列などのさまざまな文字列形式をサポートします。 詳細については、「chroma.jsドキュメント」をご参照ください。

      • よりスムーズなレンダリングが必要な場合は、512 × 512の生データを要求し、256 × 256にダウンサンプリングできます。 しかし、このプロセスは応答時間を増加させる。

      • データボリューム、データベースクラスター設定、および必要な応答時間に基づいて、並列処理の程度を設定します。

        説明

        この例では、Z<=5のときに並列度が低下する。

    • index.htmlのフロントエンドコードは、MapboxをマップSDKとして使用します。 ここでトークンを申請できます。

      ヒートマップタイルは最終的にPNG形式でレンダリングされるため、他のほとんどのマップSDKと互換性があります。

      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="utf-8">
        <title>HMT Viewer</title>
        <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
        <link href="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.css" rel="stylesheet">
        <script src="https://api.mapbox.com/mapbox-gl-js/v2.14.1/mapbox-gl.js"></script>
      </head>
      <body>
        <div id="map" style="position: absolute;left:0; top: 0; bottom: 0; width: 100%;"></div>
        <script>
          let CENTER = [YOUR_LONGITUDE, YOUR_LATITUDE]
          mapboxgl.accessToken = YOUR_MAPBOX_TOKEN;
          const map = new mapboxgl.Map({
            container: 'map',
            style: "mapbox://styles/mapbox/navigation-night-v1",
            center: CENTER,
            zoom: 5
          })
          map.on("load", () => {
            map.addSource('hmt_source', {
              type: 'raster',
              minzoom: 3,
              tiles: [`${window.location.href}hmt/{z}/{x}/{y}`],
              tileSize: 256,
            });
            map.addLayer({
              id: 'hmt',
              type: 'raster',
              source: 'hmt_source',
            });
          });
        </script>
      </body>
      </html>
  3. 依存関係をインストールし、heatmapタイルサービスを実行します。

    ## Navigate to the hmt_server directory
    cd ./hmt_server
    ## Install dependency libraries
    npm i
    ## Run the heatmap tile service
    node .
    ## You can open the browser and log in to http://localhost:5500/ to view the effect
  4. 効果をプレビューします。

    • 船舶軌道データのリアルタイム集計。

      31,000,000軌道ポイントと450,000軌道ラインのリアルタイム集約。

      船舶轨迹线-1

      传播轨迹线-2

    • 建物の足跡のリアルタイム集約。

      308万の建物の足跡のリアルタイム集約。

      建筑底面

概要

現在、 GanosBaseは、数十の業界で数千のアプリケーションシナリオをサポートしています。 安定性、費用対効果、高性能、使いやすさは、常にGanosBase の長期的な目標でした。HMTは、大規模な空間データの効率的な集約と視覚化における GanosBaseのカーネルレベルのコア競争力を表します。 大規模なデータ分析とマイニングのための効率的で使いやすいソリューションをお客様に提供し、すべてのユーザーがそれを体験することを歓迎します。

無料トライアル

PolarDB無料トライアル

ページで、「PolarDB」を選択し、GanosBase のHMTリアルタイムヒートマップ集計クエリ機能を確認します。