PostgreSQL 生成空間熱力圖
標籤
PostgreSQL , 熱力圖 , 空間切割 , 平行計算 , parallel safe
背景
結合空間資料,計算基於地理位置資訊的熱力圖,在空間資料視覺化場景中是一個非常常見的需求。
結合流計算,可以實現實時的熱力圖計算。
結合平行計算,可以高效率的對海量資料進行熱力圖計算。
計算熱力圖中bucket的方法
ofollow,noindex" target="_blank">https://www.postgresql.org/docs/devel/static/functions-math.html
width_bucket(operand dp, b1 dp, b2 dp, count int) int return the bucket number to which operand would be assigned in a histogram having count equal-width buckets spanning the range b1 to b2; returns 0 or count+1 for an input outside the range width_bucket(5.35, 0.024, 10.06, 5) 3 width_bucket(operand numeric, b1 numeric, b2 numeric, count int) int return the bucket number to which operand would be assigned in a histogram having count equal-width buckets spanning the range b1 to b2; returns 0 or count+1 for an input outside the range width_bucket(5.35, 0.024, 10.06, 5) 3
例如
postgres=# select width_bucket(1,1,10,10); width_bucket -------------- 1 (1 row) postgres=# select width_bucket(0,1,10,10); width_bucket -------------- 0 (1 row) postgres=# select width_bucket(10,1,10,10); width_bucket -------------- 11 (1 row) postgres=# select width_bucket(9.9,1,10,10); width_bucket -------------- 10 (1 row)
width_bucket( p1 -- 輸入值 p2 -- 邊界值(最小,包含) p3 -- 邊界值(最大,不包含) p4 -- 切割份數 ) 當小於最小邊界值時,返回0 當大於等於最大邊界值時,返回p4+1
例如x軸的邊界是1,10000,y軸的邊界是1,10000。
x,y兩個方向分別切割為50個bucket,一共2500個bucket,求一個點落在哪個bucket:
width_bucket(pos[0], 1, 10001, 50),-- x軸落在哪列bucket width_bucket(pos[1], 1, 10001, 50),-- y軸落在哪列bucket
例子
1、建表
create table tbl_pos( id int, info text,-- 資訊 val float8,-- 取值 pos point-- 位置 );
2、寫入1億個點
vi test.sql insert into tbl_pos values ( random()*100000, md5(random()::text), random()*1000, point((random()*10000::int), (random()*10000::int)) ); pgbench -M prepared -n -r -P 1 -f ./test.sql -c 50 -j 50 -t 2000000
3、熱力圖計算
強制平行計算
postgres=# set min_parallel_table_scan_size =0; SET postgres=# set min_parallel_index_scan_size =0; SET postgres=# set parallel_setup_cost =0; SET postgres=# set parallel_tuple_cost =0; SET postgres=# set max_parallel_workers_per_gather =28; SET postgres=# alter table tbl_pos set (parallel_workers =28); ALTER TABLE
熱力圖計算SQL,效率還不錯:
select width_bucket(pos[0], 0, 10001, 50),-- x軸落在哪列bucket width_bucket(pos[1], 0, 10001, 50),-- y軸落在哪列bucket avg(val), min(val), max(val), stddev(val), count(*) from tbl_pos group by 1,2; QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Finalize GroupAggregate(cost=1252812.00..1252928.00 rows=200 width=48) (actual time=2632.324..2672.909 rows=2500 loops=1) Group Key: (width_bucket(pos[0], '0'::double precision, '10001'::double precision, 50)), (width_bucket(pos[1], '0'::double precision, '10001'::double precision, 50)) ->Sort(cost=1252812.00..1252826.00 rows=5600 width=96) (actual time=2632.290..2648.544 rows=72500 loops=1) Sort Key: (width_bucket(pos[0], '0'::double precision, '10001'::double precision, 50)), (width_bucket(pos[1], '0'::double precision, '10001'::double precision, 50)) Sort Method: external mergeDisk: 9824kB ->Gather(cost=1252460.37..1252463.37 rows=5600 width=96) (actual time=2532.132..2564.905 rows=72500 loops=1) Workers Planned: 28 Workers Launched: 28 ->Partial HashAggregate(cost=1252460.37..1252463.37 rows=200 width=96) (actual time=2522.428..2523.559 rows=2500 loops=29) Group Key: width_bucket(pos[0], '0'::double precision, '10001'::double precision, 50), width_bucket(pos[1], '0'::double precision, '10001'::double precision, 50) ->Parallel Seq Scan on tbl_pos(cost=0.00..1189951.79 rows=3571919 width=16) (actual time=0.030..1302.462 rows=3448276 loops=29) Planning time: 0.154 ms Execution time: 2676.288 ms (13 rows)
樣本
postgres=# select width_bucket(pos[0], 0, 10001, 10),-- x軸落在哪列bucket width_bucket(pos[1], 0, 10001, 10),-- y軸落在哪列bucket avg(val), min(val), max(val), stddev(val), count(*) from tbl_pos group by 1,2; width_bucket | width_bucket |avg|min|max|stddev|count --------------+--------------+------------------+----------------------+------------------+------------------+--------- 1 |1 | 499.638668709335 | 0.000637955963611603 | 999.998900108039 | 288.562996477433 | 1002686 1 |2 | 499.772206697849 |0.00113388523459435 | 999.999452847987 | 288.505295714968 | 1000891 1 |3 |500.44455454312 |0.00135181471705437 | 999.997937120497 |288.45102360668 |999911 1 |4 | 500.234164866407 |0.00214902684092522 | 999.999100342393 | 288.707167816157 | 1000473 1 |5 | 499.793710464008 | 0.000125262886285782 | 999.999575316906 | 288.672382834812 |999036 1 |6 | 500.366854944369 |0.00212574377655983 | 999.999585561454 | 288.558891852102 |998866 1 |7 | 499.825623783545 | 0.000547617673873901 | 999.999700114131 | 288.582317248892 | 1000902 1 |8 | 499.393569281915 |0.00330200418829918 | 999.999083112925 | 288.561094278074 | 1000193 1 |9 | 499.713056248083 |0.00243959948420525 | 999.999618623406 | 288.709997455837 | 1000017 1 |10 | 500.312448499828 |0.00238511711359024 | 999.999850522727 | 288.865560266629 |998469 2 |1 | 499.848655048635 |0.00146497040987015 | 999.999508261681 | 288.639402346948 | 1000917 2 |2 | 500.084846394446 |0.0005294568836689 | 999.999178107828 | 288.704696698903 |997594 2 |3 |499.99258346144 |0.00163912773132324 |999.99839020893 | 288.507497234907 | 1001310 2 |4 | 499.817295558208 |0.00184541568160057 | 999.997940845788 | 288.767308817191 | 1000607 2 |5 |499.87314410326 |0.00135786831378937 | 999.999302905053 | 288.593077096809 |998588 2 |6 | 499.825467223571 | 0.000847037881612778 | 999.998526647687 | 288.789326889728 | 1000426 2 |7 |499.50907809986 |7.4971467256546e-05 |999.9989871867 | 288.535982009648 | 1001179 2 |8 | 499.850422744194 | 0.000966247171163559 | 999.999921303242 | 288.516738657089 | 1000745 2 |9 | 500.110417044655 | 0.000320374965667725 | 999.999660998583 |288.77420504779 |999978 2 |10 | 500.135548004555 | 0.000233296304941177 | 999.999852851033 | 288.520964728395 |998363 ........
取出資料,即可渲染。
結合流計算,可以在FEED資料寫入時,實時的進行計算。而不是QUERY發起時計算。參考本文末尾的文件。
小結
PostgreSQL非常適合於時空資料的分析,包括本文提到的熱力圖分析。
使用平行計算,即查即算,1億個點,差不多耗時2.7秒。
如果使用流式計算,寫入時即算,查詢時查的是結果,效率更高。
參考
1、求bucket值
https://www.postgresql.org/docs/devel/static/functions-math.html
width_bucket(operand dp, b1 dp, b2 dp, count int) int return the bucket number to which operand would be assigned in a histogram having count equal-width buckets spanning the range b1 to b2; returns 0 or count+1 for an input outside the range width_bucket(5.35, 0.024, 10.06, 5) 3 width_bucket(operand numeric, b1 numeric, b2 numeric, count int) int return the bucket number to which operand would be assigned in a histogram having count equal-width buckets spanning the range b1 to b2; returns 0 or count+1 for an input outside the range width_bucket(5.35, 0.024, 10.06, 5) 3
2、求geometry物件的x,y,z值
http://postgis.net/docs/manual-2.4/reference.html
ST_X — Return the X coordinate of the point, or NULL if not available. Input must be a point. ST_XMax — Returns X maxima of a bounding box 2d or 3d or a geometry. ST_XMin — Returns X minima of a bounding box 2d or 3d or a geometry. ST_Y — Return the Y coordinate of the point, or NULL if not available. Input must be a point. ST_YMax — Returns Y maxima of a bounding box 2d or 3d or a geometry. ST_YMin — Returns Y minima of a bounding box 2d or 3d or a geometry. ST_Z — Return the Z coordinate of the point, or NULL if not available. Input must be a point. ST_ZMax — Returns Z minima of a bounding box 2d or 3d or a geometry. ST_Zmflag — Returns ZM (dimension semantic) flag of the geometries as a small int. Values are: 0=2d, 1=3dm, 2=3dz, 3=4d. ST_ZMin — Returns Z minima of a bounding box 2d or 3d or a geometry.
3、求point物件的x,y值
point[0] point[1]
4、PostgreSQL 平行計算
《PostgreSQL 11 preview - 平行計算 增強 彙總》
《PostgreSQL 單表並行bulkload的extend file lock 衝突問題解決》
《阿里雲RDS PostgreSQL OSS 外部表實踐 - (dblink非同步呼叫封裝並行) 從OSS並行匯入資料》
《PostgreSQL 變態並行拉取單表的方法 - 按塊並行(按行號(ctid)並行) + dblink 非同步呼叫》
《PostgreSQL 11 preview - 多階段並行聚合array_agg, string_agg》
《PostgreSQL 11 preview - 分割槽表智慧並行聚合、分組計算(已類似MPP架構,效能暴增)》
《PostgreSQL Oracle 相容性之 - 自定義並行聚合函式 PARALLEL_ENABLE AGGREGATE》
《PostgreSQL VOPS 向量計算 + DBLINK非同步並行 - 單例項 10億 聚合計算跑進2秒》
《PostgreSQL 相似搜尋分散式架構設計與實踐 - dblink非同步呼叫與多機並行(遠端 遊標+記錄 UDF例項)》
《PostgreSQL 11 preview - Parallel Append(包括 union all\分割槽查詢) (多表平行計算) sharding架構平行計算核心功能之一》
《PostgreSQL 11 preview - 並行排序、並行索引 (效能線性暴增) 單例項100億TOP-K僅40秒》
《PostgreSQL 11 preview - 分割槽表智慧並行JOIN (已類似MPP架構,效能暴增)》
《PostgreSQL 10 自定義平行計算聚合函式的原理與實踐 - (含array_agg合併多個數組為單個一元陣列的例子)》
《驚天效能!單RDS PostgreSQL例項 支撐 2000億 - 實時標籤透視案例 (含dblink非同步並行呼叫)》
《HTAP資料庫 PostgreSQL 場景與效能測試之 23 - (OLAP) 平行計算》
《PostgreSQL 如何讓 列存(外部列存) 並行起來》
《阿里雲RDS PostgreSQL OSS 外部表實踐 - (dblink非同步呼叫封裝並行) 資料並行匯出到OSS》
《PostgreSQL 並行寫入堆表,如何保證時序線性儲存 - BRIN索引優化》
《PostgreSQL 10.0 preview 功能增強 - 邏輯複製支援並行COPY初始化資料》
《PostgreSQL 10.0 preview 多核並行增強 - 控制叢集並行度》
《PostgreSQL 10.0 preview 多核並行增強 - 索引掃描、子查詢、VACUUM、fdw/csp鉤子》
《PostgreSQL 10.0 preview sharding增強 - 支援Append節點並行》
《PostgreSQL 10.0 preview 多核並行增強 - 並行hash join支援shared hashdata, 節約雜湊表記憶體提高效率》
《PostgreSQL 10.0 preview sharding增強 - postgres_fdw 多節點非同步並行執行》
《PostgreSQL 10.0 preview 多核並行增強 - tuplesort 多核並行建立索引》
《PostGIS 地理資訊、柵格資料 多核並行處理(st_memunion, st_union)》
《分析加速引擎黑科技 - LLVM、列存、多核並行、運算元複用 大聯姻 - 一起來開啟PostgreSQL的百寶箱》
《PostgreSQL 9.6 平行計算 在 xfs, ext4 下的表現對比》
《PostgreSQL 9.6 平行計算 優化器演算法淺析 - 以及如何強制並行度》
《PostgreSQL 9.6 引領開源資料庫攻克多核平行計算難題》
《PostgreSQL 9.6 平行計算 優化器演算法淺析》
5、流計算
《PostgreSQL 流式處理應用實踐 - 二手商品實時歸類(非同步訊息notify/listen、閱後即焚)》
《PostgreSQL 流計算外掛pipelinedb sharding 叢集版原理介紹 - 一個全功能的分散式流計算引擎》
《[未完待續] PostgreSQL 流式fft傅立葉變換 (plpython + numpy + 資料庫流式計算)》
《PostgreSQL count-min sketch top-n 概率計算外掛 cms_topn (結合視窗實現同比、環比、滑窗分析等) - 流計算核心功能之一》
《阿里雲RDS PostgreSQL varbitx實踐 - 流式標籤 (閱後即焚流式批量計算) - 萬億級,任意標籤圈人,毫秒響應》
《HTAP資料庫 PostgreSQL 場景與效能測試之 32 - (OLTP) 高吞吐資料進出(堆存、行掃、無需索引) - 閱後即焚(JSON + 函式流式計算)》
《HTAP資料庫 PostgreSQL 場景與效能測試之 31 - (OLTP) 高吞吐資料進出(堆存、行掃、無需索引) - 閱後即焚(讀寫大吞吐並測)》
《HTAP資料庫 PostgreSQL 場景與效能測試之 27 - (OLTP) 物聯網 - FEED日誌, 流式處理 與 閱後即焚 (CTE)》
《[未完待續] 流式機器學習(online machine learning) - pipelineDB with plR and plPython》
《[未完待續] PostgreSQL 分散式流式計算 最佳實踐》
《打造雲端流計算、線上業務、資料分析的業務資料閉環 - 阿里雲RDS、HybridDB for PostgreSQL最佳實踐》
《PostgreSQL 10.0 preview 效能增強 - libpq支援pipeline batch模式減少網路互動提升效能》
《流計算風雲再起 - PostgreSQL攜PipelineDB力挺IoT》
《在PostgreSQL中實現update | delete limit - CTID掃描實踐 (高效閱後即焚)》