1. 程式人生 > >基於 Google-S2 的地理相簿服務實現及應用

基於 Google-S2 的地理相簿服務實現及應用

馬蜂窩技術原創內容,更多幹貨請關注公眾號:mfwtech

隨著智慧手機儲存容量的增大,以及相簿備份技術的普及,我們可以隨時隨地用手機影像記錄生活,在手機中儲存幾千張甚至上萬張照片已經是很常見的事情。但另一方面,當我們想從這麼多張照片中去找到一張,也是一件麻煩事。

馬蜂窩作為旅行玩樂平臺,希望實現「會玩的人」與「好玩的事」之間的連線。眾多旅行愛好者在這裡記錄和分享他們的旅行記憶,使馬蜂窩在旅遊 UGC 領域累積了大量內容。因此,不斷優化使用者在釋出內容時的體驗是我們一直努力的主向。

用照片、視訊記錄旅行是最直接的方式。本文將介紹馬蜂窩如何通過 App 地理相簿空間索引的應用,為使用者提供直觀、好用的圖片分享服務。

Part.1 應用場景和需求

要想讓使用者快速地找到想要分享的照片/視訊,我們需要一個有效且合理的篩選手段,對使用者的相簿進行聚合、排序,提升使用者依託相簿去分享和記錄生活時易用性和便捷性。

首先要確定聚合排序的篩選維度。照片的地理位置就是最直觀的分類維度;同時,記錄最近發生的事情符合使用者的釋出行為習慣。因此我們方案要滿足的需求是:

  1. 根據目的地和時間,對使用者相簿進行聚合、排序;
  2. 基於某個地理位置資訊和給定範圍,在使用者相簿中搜索給定範圍的照片/視訊。

本文提及的地理相簿服務在馬蜂窩 App 內主要有兩個落地場景。

1.1 筆記

「筆記」是以圖片、視訊為主要呈現形式的旅行短內容分享。使用者釋出筆記的第一個環節就是從相簿中選擇需要釋出的照片/視訊,在新版 App 中,基於地理相簿服務結合馬蜂窩自有目的地資料,對使用者相簿進行按照地點維度的聚合分類,並且按照片/視訊的建立時間由近及遠的排序,提升使用者選擇釋出效率。

1.2 足跡

「足跡」這一產品的功能,旨在幫助馬蜂窩使用者以自動同步或手動點選去過的國家和地區這種更簡易的方式記錄旅行。在「我的足跡」中有一個場景,會鼓勵使用者對去過的但還沒有釋出筆記的地點發布筆記。此時地理相簿服務可以幫助使用者釋出相簿中以指定地點為圓心,給定半徑範圍內的所有照片。

Part.2 方案設計與演算法選型

2.1 初期方案

初期我們想到的方案比較直觀,也比較粗暴,就是對相簿進行遍歷後由服務端計算結果。具體來說,首先取出使用者所有攜帶地理資訊的照片/視訊,然後將地理資訊(經緯度)上傳服務端,由服務端進行聚合和篩選,返回給客戶端結果,但是這個方案有很多缺點。

文章開始我們已經描述了目前使用者手機裝置中的照片數量是成千上萬的,如果遍歷所有圖片,這上傳的資料體量是巨大的;同時,一般使用者照片的地理位置會有很多呈現出成簇聚集的狀態,因為一般我們會在一個地點範圍內拍攝許多照片,這就導致了大量的重複聚類的計算。

如果要優化這個方案,針對第一個需求我們可以採用快取+增量請求的方式,因為使用者分類資料是穩定的。但是針對給定範圍查詢的需求,我們無法做快取,這就需要每次都請求服務端做大量的計算,對於時間的消耗是不能容忍的。

可以看到,上述方案的挑戰主要在於使用者相簿中地理資訊的資料量和重複度、依賴服務端計算搜尋結果導致的效能問題和使用者體驗。經過調研我們發現,基於地理空間點(經緯度)索引演算法可以很好地解決這些問題。

2.2 基於地理空間點索引演算法的實踐

結合我們的實際需求來理解地理空間點索引演算法,即找到合適的方法來對地理空間中海量的座標點新增索引,從而對空間點進行快速查詢和排序的一種演算法。

我們對一些比較通用的地理空間點索引演算法進行了選型比較,下面主要介紹 GeoHash 演算法和 Google-S2 演算法。

2.2.1 演算法選型

(1)GeoHash

GeoHash 演算法即地理位置距離排序演算法。Geohash 是一種地理編碼,由 Gustavo Niemeyer 發明。它利用一種分級的資料結構,把空間劃分為網格。

GeoHash 屬於空間填充曲線中的 Z 階曲線的實際應用。GeoHash 有一個和 Z 階曲線相關的性質,那就是一個點附近的地方 Hash 字串總是有公共字首,並且公共字首的長度越長,這兩個點距離越近。由於這個特性,GeoHash 就常常被用來作為唯一識別符號,比如在資料庫裡面可用 GeoHash 來唯一表示一個點。

GeoHash 這個公共字首的特性就可以用來快速的進行鄰近點的搜尋。越接近的點通常和目標點的 GeoHash 字串公共字首越長。但是 Z 階曲線有一個比較嚴重的問題,就是它的突變性。在每個 Z 字母的拐角,都有可能出現順序的突變,導致搜尋臨近點的精確度較差,不能滿足我們的業務場景對精確度的要求。

(2)S2 演算法

S2 其實是來自幾何數學中的一個數學符號 S²,它表示的是單位球。

S2 演算法採用正方體投影的方式將地球展開,然後利用希爾伯特分形曲線將展開後的二維地球進行填充,完成了對三位地球的降維和分形,從而得到空間座標點與希爾伯特分形曲線的函式關係,即將球面經緯度座標轉換成球面 xyz 座標,再轉換成正方體投影面上的座標,最後變換成修正後的座標在座標系變換,對映到 [0,2^30^-1] 區間,最後一步就是把座標系上的點都對映到希爾伯特曲線上。最終,對映到希爾伯特曲線上的點成為 Cell ID,即是空間座標點的索引。

S2 的最大的優勢在於精度高。Geohash 有 12 級,從 5000km 到 3.7cm,中間每一級的變化比較大。有時候可能選擇上一級會大很多,選擇下一級又會小一些。而 S2 有 30 級,從 0.7cm² 到 85,000,000km²,中間每一級的變化都比較平緩,接近於 4 次方的曲線。所以選擇精度時不會出現 Geohash 選擇困難的問題。

綜上,S2 演算法能夠滿足我們對於功能和精度上的要求,因此最終選擇 S2 演算法作為空間點索引演算法的實現方案。

Part.3 功能實現與效能優化

3.1 模組設計

本文中的 App 地理相簿服務主要基於相簿索引資料操作、使用者相簿掃描、相簿索引服務和相簿地點分類計算四大模組實現:

以下分別介紹。

3.1.1 相簿索引資料操作模組

相簿位置資訊的索引採用資料庫作為儲存介質,將使用者照片資訊以及通過 S2 演算法計算出來的 Cell ID 儲存到資料庫當中。其中,考量儲存的數量和對搜尋和聚合經度的要求,儲存了從 Level4~Level16 經度級別的 Cell ID。

相簿索引資料操作模組,由資料庫(DB)和資料庫操作層(DAO)組成。資料表的設計見下圖:

資料庫操作層(DAO)封裝了資料插入、刪除、查詢等基本操作的 API。

3.1.2 使用者相簿掃描模組

使用者相簿掃描模組基於 iOS 原生提供的相簿查詢的 API,將使用者相簿的資料與本地資料庫中儲存的照片資料進行對比,提取出新增照片資料和使用者已經刪除的照片。

3.1.3 相簿索引服務模組

相簿索引服務模組,是基於 S2 演算法的相簿服務的核心模組。模組功能如下:

  • 直接與資料模組互動,向使用者遮蔽資料層的資料操作細節,提供滿足查詢、搜尋等需求的 API
  • 查詢指定 Cell ID 下的照片資源
  • 查詢指定 Level 下,相簿照片索引後的 Cell ID
  • 查詢以指定座標點為圓心、指定半徑範圍內的照片
  • 與使用者相簿掃描模組互動,獲取新增照片和已經刪除照片的資料,更新資料庫內容,同時支援查詢和通知更新狀態

3.1.4 相簿地點分類計算模組

相簿地點分類計算模組是計算使用者相簿的地點分類結果的核心模組。該模組的主體功能如下:

  • 獲取 S2 相簿索引服務中的照片 Cell ID,作為引數上傳至服務端,服務端根據地圖服務提供的聚合介面,將 Cell ID 的聚合結果返回給服務端
  • 綜合考量精確度和 Cell ID 的資料量,選取 Level12 的 Cell ID 作為請求服務端的 Cell ID 等級
  • 呼叫相簿索引服務模組根據指定 Level 獲取 Cell ID 的方法得到去重後的 Cell ID
  • 服務端返回的資料結構是 mdd_id(目的地 ID) 與 Cell ID 的一對多的對映關係
  • 利用本地 S2 相簿索引服務中的照片 Cell ID,根據上一步服務端返回的分類資料進行分類
  • 快取每次地點分類的計算結果

3.2 整體流程

相簿索引服務模組會在 App 啟動時更新服務,將本地資料與相簿資料同步。當用戶觸發地點相簿功能時,相簿地點分類計算模組會先取出快取在本地相簿地點分類計算結果展現給使用者,同時驅動相簿索引服務更新。

在收到更新服務更新完畢的通知後,首先向相簿請求 12Level 的全量去重的 Cell ID,然後將 Cell ID 上傳服務端由服務端計算分類,最後結合相簿索引服務的全量照片資料,計算照片的地點分類結果,快取結果並渲染展現給使用者。

3.3 效能優化

3.3.1 獲取相簿增量照片

相簿索引服務模組需要同步服務和使用者相簿的照片資源資料,找到新增資料,加入到服務資料庫中。最初設計的獲取新增資料方案如下:

Step.1 獲取全量的使用者相簿的資料

Step.2 遍歷使用者照片,查詢是否存在本地服務資料庫中

但是這個方案應用到照片量較大的手機上時,獲取新增照片的時延很高。排查後我們發現原因在於全量遍歷使用者相簿時延很高,同時在遍歷中頻繁查詢資料庫也比較耗時。經過調研發現,iOS 的使用者相簿有「最近專案」的相簿分類,該相簿分類下的資源只按照新增順序的倒序排列,即越新的照片越靠前。故將方案優化如下:

Step.1:從列表頭部擷取 100 條

Step.2:將該 100 條追加為新增照片

Step.3:判斷該 100 條中的最後一條,即新增時間最晚的一條,查詢是否存在於服務資料庫中

  • 若不存在,繼續 Step.1
  • 若存在,停止擷取,從而得到新增照片

3.3.2 漸進計算相簿照片的地點分類

相簿地點分類計算模組在獲得服務端返回的分類結果(mdd_id 與 Cell ID 列表的對映關係)後,根據結果對本地服務資料庫中的照片進行分類。最初的方案如下:

Step.1:遍歷結果列表,獲得每個 mdd_id 對映的 Cell ID 列表

  • A. 遍歷 Cell ID 列表,通過 Cell ID 向相簿索引服務模組查詢屬於該 Cell ID 索引下的照片資源,從而獲得該 mdd_id 對應的照片資源
  • B. 對該目的地下的照片按照建立時間倒序排序

Step.2:將所有目的地維度照片分類結果,按照每個結果集中照片最晚建立時間,即第一個照片的建立時間,進行倒序排序,獲得按照地點維度和建立時間維度排序的地點相簿的最終計算結果。

這樣的方案導致在地點相簿首次計算的時候,使用者需要等待所有目的地下的結果計算完畢後才能展現給使用者,同時需要多次按照建立時間排序,導致時延很高,冷啟動下使用者體驗很差。

為此,我們做出了方案優化,減少排序次數,同時通過漸進載入的方式優化使用者體驗。主要思路是相簿索引服務模組的資料庫中,儲存照片的建立時間可以通過 SQL 查詢,按照建立時間倒序排列的所有照片資源,獲取倒序排列的照片資源集合:

Step.1:每次從照片資源集合頭部取 1000 條照片

  • 遍歷每一張照片,根據照片的 Cell ID,從 mdd_id-Cell ID 對映表中查詢所屬的目的地, 判斷照片目的地分類結果集中是否存在該目的地的照片資源分類集合
  • 存在,追加該照片
  • 建立該目的地的結果集,追加到照片目的地分類結果集中,並追加該照片

Step.2:將該 1000 張照片的分類結果渲染展現給使用者

Step.3:計算完所有照片的分類,通知結束渲染,計算完畢。

以上方案,將全量的本地照片資源以 1000 張為一批次,進行漸進計算,同時漸進渲染,縮短了使用者的等待時間;同時,依託關係型資料庫的排序能力,減少排序次數,優化了效能。

Part.4 未來規劃和總結

目前,本文介紹的基於 Google-S2 演算法實現的地點相簿在馬蜂窩 APP iOS 客戶端已經上線一段時間,並且為筆記釋出量帶來了正向增長。但是這套方案在資料庫資料處理中已經對於 Google-S2 演算法的使用上仍然有很大的優化和探索空間,後續我們團隊也會對其不斷優化和深挖。

Google-S2 演算法服務在馬蜂窩 App iOS 客戶端中的實現和落地,成果不僅僅是滿足了筆記釋出場景的探索,更使得客戶端具備了對於使用者相簿照片百米級精確度的索引和搜尋的能力,可以為後續更多、更復雜的業務場景服務,相信在不遠的未來能為使用者提供更便捷、更有趣的旅行記錄產品。

本文作者:王巖、王明友,馬蜂窩內容業務研發工程師。

相關推薦

基於 Google-S2地理相簿服務實現應用

馬蜂窩技術原創內容,更多幹貨請關注公眾號:mfwtech 隨著智慧手機儲存容量的增大,以及相簿備份技術的普及,我們可以隨時隨地用手機影像記錄生活,在手機中儲存幾千張甚至上萬張照片已經是很常見的事情。但另一方面,當我們想從這麼多張照片中去找到一張,也是一件麻煩事。 馬蜂窩作為旅行玩樂平臺,希望實現「會玩的人

服務穩定性應用防護方案

網站 iba html 域名 htm 穩定性 自動添加 策略 兩種 服務穩定性及應用防護方案 一、 服務穩定性 1. 基本監控 基本監控推薦使用Zabbix,開源分布式企業級監控系統,能滿足目前我們監控的需求 a. 系統監控,包括CPU、內存、磁盤、網絡等,能夠對系統級

行人重識別(ReID) ——技術實現應用場景

導讀 跨鏡追蹤(Person Re-Identification,簡稱 ReID)技術是現在計算機視覺研究的熱門方向,主要解決跨攝像頭跨場景下行人的識別與檢索。該技術能夠根據行人的穿著、體態、髮型等資訊認知行人,與人臉識別結合能夠適用於更多新的應用場景,將人工智慧的認知水平提高到一個新階段。

PHP訊息佇列實現應用:訊息佇列概念介紹

  在網際網路專案開發者經常會遇到『給使用者群發簡訊』、『訂單系統有大量的日誌需要記錄』或者在秒殺業務的時候伺服器無法承受瞬間併發的壓力。  這種情況下,我們怎麼保證系統正常有效的執行呢? 這個時候,我們可以引入一個叫『訊息佇列』的概念來解決上面的需求。 訊息佇列的概

ssh服務簡介應用服務的進程的類型

加密 兩個 net 共享 案例 命名 權限 ike strong SSH ,由 IETF 的網絡小組(Network Working Group)所制定;SSH 為建立在應用層基礎上的安全協議。SSH 是目前較可靠,專為遠程登錄會話和其他網絡服務提供安全性的協議。利用 SS

Linux下批量部署(Pxe、Kickstart實現應用

導讀: 作為運維經常會遇到一些重複的工作,例如:有時公司同時上線幾十甚至上百臺伺服器,而且需要我們在 短時間內完成系統安裝。本文主要講述了Linux下批量部署 Pxe、Kickstart實現及應用. 一、相關知識提要 1.理論知識 PXE : PXE(pre

Javascript (1) Javascript類的實現應用

    本篇簡單介紹javascrpt類的相關內容,具體內容如程式碼所示,對有面向物件程式設計經驗的同學提供一個簡易的參考。 class SimpleData{ constructor(year, month, day){ this._year = year;

跨叢集服務 實現Kubernetes應用的高可用_Kubernetes中文社群

我們在進行生產環境部署時得到的一個明確的需求,是Kubernetes使用者希望服務部署能夠zone、跨區域、跨叢集甚至跨雲邊界(譯者:如跨雲供應商)。相比單叢集多zone部署,跨叢集服務提供按地域分佈,支援混合雲、多雲場景,提升高可用等級。客戶希望服務能夠跨一到多個叢集(可能是本地或者遠端叢集

濾波反投影重建演算法(FBP)實現應用(matlab)

濾波反投影重建演算法實現及應用(matlab) 1. 濾波反投影重建演算法原理 濾波反投影重建演算法常用在CT成像重建中,背後的數學原理是傅立葉變換:對投影的一維傅立葉變換等效於對原影象進行二維的傅立葉變換。(傅立葉中心切片定理) CT重建演算法大致分為解析重建

java 代理模式的實現應用

java 代理模式代理(Proxy)是一種設計模式,提供了對目標物件另外的訪問方式;即通過代理物件訪問目標物件.這樣做的好處是:可以在目標物件實現的基礎上,增強額外的功能操作,即擴充套件目標物件的功能1.靜態代理靜態代理在使用時,需要定義介面或者父類,被代理物件與代理物件一起

Javascript (1) Javascript類的實現應用

    本篇簡單介紹javascrpt類的相關內容,具體內容如程式碼所示,對有面向物件程式設計經驗的同學提供一個簡易的參考。      class SimpleData{ constructor(year, month, day){ t

第九周專案三:稀疏矩陣的三元組表示的實現應用(2)

/* Copyright (c)2015,煙臺大學計算機與控制工程學院 All rights reserved. 檔名稱:專案3-2.cbp 作 者:孫立立 完成日期:2015年12月4日 版 本 號:v1.0 問題描述:(2)採用三元組儲存稀疏矩陣,設計兩個稀疏

android進階4step2:Android音視訊處理——拍照功能實現應用

Camera有哪幾種使用場景? 呼叫系統相機 使用Camera API 使用Camera大致的流程 1、呼叫系統的相機實現拍照/儲存/顯示 AndroidManifest.xml中寫上需要的許可權 注意:android6.0之後需要動態申請許可權 &

稀疏矩陣的三元組表示的實現應用(2)——採用三元組儲存稀疏矩陣,設計兩個稀疏矩陣相加的運算演算法

/* *Copyright (c) 2015 , 煙臺大學計算機學院 *All right resvered . *檔名稱: 稀疏矩陣.cpp *作 者: 鄭兆涵 *稀疏矩陣的三元組表示的實現及應用(2) */ 問題:稀疏矩

系統學習深度學習(五) --遞迴神經網路原理,實現應用

      但是大神們說,標準的RNN在實際使用中效果不是很好,真正起到作用的是LSTM,因此RNN只做簡單學習,不上原始碼(轉載了兩篇,第一個是簡單推導,第二個是應用介紹)。 下面是簡單推導,轉自:http://blog.csdn.net/aws3217150/article/details/5076

雲從科技資深演算法研究員詳解跨境追蹤(ReID)技術實現應用場景

跨鏡追蹤(Person Re-Identification,簡稱 ReID)技術是當前計算機視覺研究的熱門方向,主要解決跨攝像頭跨場景下行人的識別與檢索。跨鏡追蹤(ReID)技術能夠根據行人的穿著、體態、髮型等資訊認知行人,與人臉識別技術結合能夠適用於更多新的應用場景,提供更

PHP訊息佇列實現應用_慕課網學習

https://blog.csdn.net/d_g_h/article/details/79643714 https://blog.csdn.net/tTU1EvLDeLFq5btqiK/article/details/80971792   目前對訊息佇列並不瞭解其原理,本篇文章主要是通過慕課

堆的實現應用(優先順序佇列,堆排,TopK問題)

堆資料結構是一種陣列物件,它可以被看做是一棵完全二叉樹。 堆的二叉樹儲存有兩種方式: 1.最大堆:每個父節點的值都大於孩子節點 2.最小堆:每個父節點的值都小於小子節點 如上圖所示就是一個最小堆。 關於堆,其實說到底就是兩種演算法,一種是向下調整演

PHP訊息佇列實現應用:佇列處理訂單系統和配送系統

解耦案列:佇列處理 訂單系統和配送系統 這裡,我們要來處理其中一個場景:系統的解耦。 在電商專案中,當客戶提交了一個訂單之後,客戶在個人中心可以看到訂單處於配送中。 這個時候就要參與進來一個系統,叫做『配送系統』。如果我們在做架構的時候,把訂單系統和配

稀疏矩陣的三元組表示的實現應用(1)——建立稀疏矩陣三元組表示的演算法庫

/* *Copyright (c) 2015 , 煙臺大學計算機學院 *All right resvered . *檔名稱: 稀疏矩陣.cpp *作 者: 鄭兆涵 *稀疏矩陣的三元組表示的實現及應用(1) */ 問題:稀疏