在地圖上查詢結果一般以標記點的形式展示,可是若是標記點較多,不只會大大增長客戶端的渲染時間,讓客戶端變得很卡,並且會讓人產生密集恐懼症(圖1)。爲了解決這一問題,咱們須要一種手段能在用戶有限的可視區域範圍內,利用最小的區域展現出最全面的信息,而又不產生重疊覆蓋。html
圖1算法
直覺上用聚類算法能較好達成咱們目標,所以採用簡單的kmeans聚類。根據客戶端的請求,咱們知道了客戶端顯示的範圍,併到索引引擎裏取出在此範圍內的數據,並對這些數據進行kmeans聚類,最後將結果返回給客戶端。網絡
可是上線以後發現kmeans效果並不如意,主要有如下兩個缺點。app
a)性能問題性能
kmeans是計算密集型算法,須要迭代屢次才能完成,並且每次迭代過程當中都涉及到複雜的距離計算,比較消耗cpu。優化
咱們在上線後遇到load較高的問題。google
b)效果問題spa
kmeans未能完全解決重疊覆蓋問題!能夠看到有些聚合後的圖標會疊合在一塊兒。htm
再次回顧咱們的目的:咱們須要一種手段能在用戶有限的可視區域範圍內,利用最小的區域展現出最全面的信息,而又不產生重疊覆蓋。blog
解決地理空間相關問題時,對空間劃分網格這種方法每每屢試不爽。
原理:將地圖範圍劃分紅指定尺寸的正方形(每一個縮放級別不一樣尺寸),而後將落在對應格子中的點聚合到該正方形中(正方形的中心),最終一個正方形內只顯示一箇中心點,而且點上顯示該聚合點所包含的原始點的數量。
如何將點落到正方形內呢?咱們將空間人爲指定100*100大小,經過這個公式進行映射。
優勢:運算速度較快,每一個原始點只需計算一次,沒有複雜的距離計算。
缺點:有時明明很相近的點,卻僅僅由於網絡的分界線而被逼分開在不一樣的聚合點中,此外,聚合點的位置採用的是該網格的中心,而非該網格的質心,這樣聚合出來的點可能不能較精確反映原始點的信息。
原理:沿用方案一思想,1)將各個點落到相應正方形內;2)求解各個網格的質心;3)合併質心:判斷各個質心是否在某一範圍內,若是在某一範圍內則進行合併。
如何判斷各個質心點是否須要合併呢?以A點爲例,畫一個矩形或者圓範圍,落在此範圍內的合併,B、C均落在範圍內,所以A、B、C三點合併。
優勢:運算速度一樣較快,相對於方案一,多了求解質心以及質心合併兩個步驟,但這兩個步驟都較爲簡單,能很快完成。
原理:初始時沒有任何已知聚合點,而後對每一個點進行迭代,計算一個點的外包正方形,若此點的外包正方形與現有的聚合點的外包正方形不相交,則新建聚合點(這裏不是計算點與點間的距離,而是計算一個點的外包正方形,正方形的變長由用戶指定或程序設置一個默認值),若相交,則把該點聚合到該聚合點中,若點與多個已知的聚合點的外包正方形相交,則計算該點到到聚合點的距離,聚合到距離最近的聚合點中,如此循環,直到全部點都遍歷完畢。每一個縮放級別都從新遍歷全部原始點要素。
優勢:運算速度相對較快,每一個原始點只需計算一次,可能會有點與點距離計算,聚合點較精確的反映了所包含的原始點要素的位置信息。
缺點:速度不如徹底基於網格的速度快等,此法還有個缺點,就是各個點迭代順序不一樣致使最終結果不一樣。所以涉及到制定迭代順序的問題。
這種方法須要結合PCA(主成分分析)和K-D樹,在效果上比較好,可是性能較差,實現也較爲複雜。
(http://applidium.com/en/news/too_many_pins_on_your_map/)
https://developers.google.com/maps/articles/toomanymarkers
http://applidium.com/en/news/too_many_pins_on_your_map/
基於百度地圖的標記點聚合算法研究