咱們都知道手機定位服務,其本質是彙總各類信號得出一個經緯度座標(x,y)(具體定位原理能夠參考:LBS定位技術、基於樸素貝葉斯的定位算法),然而定位服務並未提供該座標對應的實體地理信息,好比街道、POI等,要知道這些信息就須要使用地址反解析服務,該服務就是由經緯度信息獲得結構化地址信息(圖1)。html
圖1 地址反解析算法
例如lat:30.252188, lng:120.120427,地址反解析獲得的結果如表1所示。數據庫
表1 地址反解析獲得的結果異步
{
data:
{
province: "杭州市",
city: "杭州",
district: "西湖區",
detail: "靈隱路-靈溪南路",
lat: 30.252188,
lng: 120.120427
}
}
通常現有的地圖服務公司如高德、google、百度等都會提供地址反解析服務,當你們業務規模較小時能夠選擇調用他們提供的接口,可是若是業務規模較大時,再去直接調用顯然不太合適。你們須要有本身的實現能力!post
實現地址反解析服務有矢量和柵格兩種思路。大數據
高德、google、百度等地圖服務公司有本身的地圖數據,包括矢量數據(好比點、線、面等幾何數據)以及矢量對應的屬性信息(好比某線對應的屬性是「北京朝陽望京東路」),所以他們的地址反解析思路很直接,直接根據經緯度查找附近的矢量數據(POI、道路等數據),好比查找到一條道路,而後返回道路對應的屬性信息便可(圖2)。具體實現思路與地理圍欄算法解析(Geo-fencing)一文類似。google
圖2 矢量思路示意圖編碼
這種方式的優勢是數據存儲量較小。缺點是要求有詳細的地圖矢量數據以及對應的屬性數據,而對通常公司來講很難得到。url
儘管咱們能夠經過開源的openstreetmap拿到中國的矢量地圖數據(如何獲取、存儲、管理、使用osm數據呢?能夠參考:利用OpenStreetMap(OSM)數據搭建一個地圖服務),可是openstreetmap中國地區的矢量地圖數據很不詳細,精度也較低,徹底依賴於openstreetmap的地圖數據來進行地址反解析還不太靠譜。spa
什麼是柵格思路?如圖3a所示,好比將北京劃分紅不少柵格(也稱之爲瓦片),當柵格比較精細時,好比爲10米*10米時,咱們能夠假設一個柵格內部的地址是相同的。這種假設是合理的,如圖3b虛線框柵格內的兩點所示,儘管該兩點經緯度座標不一樣,可是其地址均爲「中國北京市朝陽區北苑路」。基於上述假設,咱們能夠事先存儲各個柵格對應的地址信息。每當一個用戶請求過來,首先判斷該用戶經緯度所對應的柵格,而後將此柵格對應的地址信息返回便可。
柵格思路的優勢是很簡單很直觀,缺點是數據量大。以北京爲例,北京全市面積爲 16,410.54平方公里,若是柵格大小爲10米*10米,那麼須要存儲1.6億個柵格對應的地址信息,若是放大到全國(約960萬平方公里),數據量將更大。
圖3 柵格思路示意圖
在沒有矢量數據的狀況下通常應用能夠採用柵格思路,由於簡單直觀易於上手,後期若是找到完備的矢量數據則能夠借鑑矢量思路。
柵格方案最大的缺點是存儲量巨大,如何下降柵格方案的數據存儲量呢?咱們有兩種思路。
a)有效柵格方案。前面講到若是柵格爲10米*10米時,僅北京就會有1.6億個柵格。可是咱們知道通常應用的用戶基本是在城區進行訪問,鮮有用戶會在山溝溝裏使用你們的服務,所以這1.6億個柵格有大部分是不會有被訪問到的(某柵格被訪問到是指用戶請求的經緯度落在該柵格範圍內),咱們將被用戶訪問到的柵格稱之爲有效柵格。事實上咱們無需存儲全部柵格對應的地址信息,而僅需存儲有效柵格對應的地址信息便可實現咱們的地址反解析服務,從而大大下降數據存儲量。如圖4所示,黃色柵格表明是有用戶訪問到的柵格,即有效柵格,有效柵格數目<<所有柵格數目。
圖4 有效柵格方案(紅點表明用戶請求的經緯度,黃色柵格表明有效柵格)
b)自適應粒度柵格方案。以前柵格粒度是不變的,好比都是10米*10米,因爲大部分柵格用戶不會訪問到,這樣較爲浪費存儲空間。咱們能夠採用四叉樹對地理空間進行劃分(圖5),每次劃分都對空間進行四等分,直到劃分出的柵格內沒有用戶請求點或者柵格的粒度<=10米*10米爲止。在用戶訪問密集區域,柵格的粒度較爲精細,精度較高,在鮮有用戶訪問區域,柵格粒度較粗,地址反解析的結果也較粗,能夠發現:自適應粒度柵格數目<<均等粒度柵格數目。
圖5 自適應粒度柵格方案
從本質上講有效柵格方案是key-value的存儲結構,存儲簡單方便,而且更新也很簡便,很是適合大數據環境。而自適應粒度柵格方案本質上是樹存儲結構(四叉樹),涉及到樹結構的節點分裂等操做,在大數據環境下實現邏輯較爲複雜。簡便起見咱們採用有效柵格方案。
有效柵格方案本質是key-value的存儲方式。1)這裏的key指的是柵格的編號,一個用戶請求過來,首先根據用戶請求的經緯度判斷其所在的柵格編號(key),而後查找該編號(key)對應的地址信息。柵格的編號方式有不少,能夠採用geohash編碼來進行編號(關於geohash能夠查看GeoHash核心原理解析、Geohash距離估算),通常來說,geohash編碼長度爲8位時,其表明着20米*20米的柵格。2)value值指的是該柵格的中心點對應的地址信息。
此外還需存儲該記錄的時間戳,以便咱們知道數據的新舊,方便更新(表2)。
表2 數據存儲結構
地址反解析服務實現流程分爲預處理以及線上服務兩個步驟(參見圖6)。
a)預處理
1)利用已有用戶的定位/地址反解析請求日誌來肯定有效柵格
用戶定位/地址反解析請求會攜帶有經緯度信息,能夠計算該經緯度對應的geohash編碼(key),並查詢數據庫,若是沒有該key則進行插入,數據量較大時可使用mapreduce進行處理,最後將數據寫入Hbase以便線上實時查詢;
2)獲取各個有效柵格對應的地址信息
獲取每一個有效柵格對應的經緯度,去請求地圖服務商google、baidu、高德、搜狗等的地址反解析服務接口,得到相應結構化地址信息並進行插入。
上述兩個步驟也能夠合二爲一,肯定了有效柵格後便可請求地圖服務商接口,並將geohash編碼、結構化地址信息和時間戳信息插入到數據庫中。
b)線上服務
對一個用戶請求,首先獲得經緯度,經過geohash對該經緯度編碼,從而查找數據庫,若是找到便直接返回,若是沒找到或離上次更新時間與如今間隔超過一個月(具體時間能夠動態設置)以內,則請求第三方地址反解析接口,並將更新任務放在任務隊列裏實現異步更新。
圖6 柵格思路的地址反解析方案