[譯]解密 Uber 數據科學團隊路徑選擇算法的優化之路

概述

一鍵用車如今已經爛大街,可是 Uber 簡單的界面下又隱藏着怎樣複雜的後端架構和服務呢?這些複雜的路徑規劃和訂單匹配算法又是如何讓車找到人,將人送到目的地的呢?如今讓咱們揭開Uber App這神祕的面紗。git

下面是Uber以前解決路徑規劃問題的方法而且講解了咱們是如何從五年之前 三藩市單一的 UberBLACK 服務成長的到如今天天百萬以上用車量的。github

初出茅廬:2001-2014

當五年之前Uber平臺剛剛開始運營的時候,到達時間估算(ETA)是咱們推出的第一個特性。這是乘客對咱們的第一印象。web

2012年早些時候,應用內顯示的 ETA算法

在Uber早期,咱們用了一系列路徑引擎的組合(包括OSRM)來作ETA。(咱們剛開始並無應用內的導航功能,所以咱們只能用它來作ETA而且匹配所顯示的車輛位置。segmentfault

咱們稱這種服務爲」黃金ETA」,而它是須要在一個路徑引擎上創建模型而且用Uber 數據在同時同地的相似數據中調整初始的估計值。這種解決方案一般要同時觀察成千上萬的Uber行程,用初始路徑引擎對比它們的ETA。黃金ETA比以前沒有數據對比的ETA顯然來得更好。可是,這裏又產生了一個冷啓動的問題:當咱們進軍一個新的城市拓展業務的時候,咱們是沒有足夠的數據來打造」黃金ETA」的。也就是說,隨着咱們不斷擴張,咱們按期須要一些新特性來知足咱們快速增加的須要,這時候用以前的開源解決方案(OSRM)已經知足不了咱們高度定製化的需求了。後端

尋求突破:如何構建你本身的路徑優化引擎

咱們已經用黃金ETA好久了,可是隨着咱們在更多城市和服務上的擴展(好比在2014年3月開啓的 UberRUSH 服務以及 咱們在2014年春天開啓的 UberPOOL 服務),咱們須要爲Uber打造一個本身的路徑引擎的需求已經變得很是迫切了。所以,在2014年,咱們開始着手打造咱們本身的全套路徑引擎,咱們稱之爲 Gurafu。Gurafu的目標是爲Uber量身定製一個高性能、高精度的ETA計算工具。服務器

在咱們具體實施以前,讓我討論一下咱們須要一個路徑引擎的必要性。這整個的路網就像一個圖結構(運籌學中圖論的概念)。節點表示十字路口,邊表示道路。這個邊的權重表示一個有趣的度量:這段距離或時間路線常常被人通過。其餘一些像單行道,轉彎限制、轉彎成本以及速度限制等概念都在這個圖結構模型被考慮到了。微信

固然,這不是通往真實世界的惟一模型。有些人也把道路做爲節點,而兩個路段的轉換做爲邊。相對於以前提到的基於點的表達式這就是所謂的基於邊的表達式。每種表達式都有本身的權衡,所以在肯定使用哪一種模型以前明白咱們須要什麼就變得很是重要了。數據結構

一旦你的數據結構肯定了,你就可使用不一樣的路徑規劃算法來尋優。舉一個簡單的例子,你能夠嘗試的最基礎的Dijkstra搜索算法,這種方法是今天大多數搜索算法的基石。可是在生產環境下,Dijkstra或者其餘一些算法經常無法處理太大規模的圖結構,它老是顯得速度太慢了。架構

OSRM 是基於收縮的層次結構的。系統基於收縮層次結構來提高性能,經過預處理路線的圖結構只用毫秒級的時間就完成整個路徑的計算。下面99%的響應都是在100毫秒內完成的。由於在每次車輛收到用車請求的時候咱們都須要計算因此咱們很是須要這個功能。可是,由於這個預處理步驟是十分緩慢的,想要作實時的交通處理是很是困難的。而我咱們的數據會用全世界的道路花12個小時來構建這個收縮圖結構。這意味着咱們很難去更新這個交通流量的信息。

這是就是爲何一些預處理和變換經常須要加速查詢。(這類算法的最近例子包括了高速公路層次算法ALT算法以及自定義路徑規劃算法

這裏是從2014年開始嘗試構建本身的路徑引擎所作的工做:

1. 採用動態的收縮層次算法

在咱們的路徑圖結構中,隨着新交通訊息涌入,咱們須要可以動態更新這些圖結構的邊權重。就像咱們提到的,咱們所用的 OSRM 是用 收縮層次來作路徑尋優算法的。收縮層次的一個缺點就在與當邊權重更新,預處理過程須要用整個圖結構從新再跑一邊,當咱們跑稍微大一點的圖結構就須要好幾個小時,更不要說全世界了。因此這個收縮層次算法對於實時的交通變化並不適合,咱們須要一個增量算法。

收縮層次的預處理步驟能夠經過動態更新來快速實現,這種狀況下大多數節點的排序將保留,而只是更新須要更新的節點,這樣咱們就能夠大大減小預處理的計算量了。(這不是Virtual Dom嗎?)用這種方法,咱們以每次更新整個世界的圖結構中10%的路段,僅僅用10分鐘就能夠實現動態更新。可是,要估算ETA的話,10分鐘看起來對交通流的變化仍是有點延遲。所以,這條路最後也是一條死衚衕。

2. 分片

咱們也用一種叫做分片的方式,將整個圖結構分解成幾個小的地理區域,分而治之。分片加速了咱們構建圖結構的時間。可是,這裏須要在咱們的基礎設施上爲此作一些工做,而且在每一個地區的服務器集羣大小上老是會遇到瓶頸。若是一個地區在高峯期一會兒有太多的請求,那麼其餘服務就不能共享加載這種分片的資源了。咱們想要利用咱們有限的服務器資源,所以咱們也並無採用這種解決方案。

3. A星算法

對於小範圍的實時更新,咱們嘗試使用A星搜索算法。在更高的層面上,A星是Dijkstra搜索算法的啓發式實現,所以A星優先找到從A到B之間的一條可能的最優路徑。這意味着咱們能夠實時更新圖結構的邊權重,並且在不須要作任何預處理的條件下計算交通流量的狀況。既然大多數航線咱們須要計算是短途旅行(從司機乘客途中時間),那麼A *在這種狀況下其實很是有效的。

不過咱們知道A星算法是一個權宜之計,由於它對於比較長的路線規劃顯得很是的慢:A星的響應速度與深度遍歷的節點是相關的,以幾何增加。(例如,從普雷西迪奧到舊金山地區教會區的路線計算時間是120毫秒,這相比收縮層次算法花費了數倍的時間)。

即便A星算法利用地標、三角不等式和幾個預先估計技巧,不會增長A星遍歷的時間,足以使它成爲一個可行的解決方案。

可是對於長途旅行來講,A星仍是不可以快速響應,所以咱們又回到了使用靜態收縮圖結構的老路。

化蛹成蝶:2015以後

咱們既須要使用預處理來加速計算,又想要快速更新邊權重來支持實時交通。咱們的解決方案僅僅經過從新刷新整個圖結構的一部分就能夠完成預處理過程,有效解決了實時交通更新的問題。
由於咱們的解決方案將圖像劃分爲層相對獨立的小模塊,經過並行執行預處理,讓咱們可以在必要時讓這個過程加速計算。(瞭解更多,點擊這裏!)

在咱們的第一個Gurafu版本已經準備好測試以後,爲了知道咱們咱們以前推出的新路徑引擎的效果,咱們打算在2015年1月分別紀錄了Gurafu和黃金ETA的實時ETA準確度。

2015年1月份咱們製做了一個內部的儀表盤來顯示ETA準確性:Gurafu(紫色)相比黃金ETA(綠色和紅色)每次預測ETA都更加精準。注意到每每在交統統勤的高峯期(週三晚上和週四早上)Gurafu的表如今這時候一騎絕塵。這裏,咱們顯示的三藩市,可是這個模式在咱們全部的其餘城市也是如此。

2015年4月,咱們在全球範圍內推出了一個全新的更精確的ETA預測的路線引擎系統。新系統是基於咱們新的路線引擎Gurafu。另外,基於咱們從司機端收集的GPS數據,咱們還推出了 Uber的第一個歷史交通系統,咱們稱之爲 Flux。

咱們使用獨有的ETA系統主要是爲了獲取乘客,但咱們也在整個行程中記錄每次ETA預測的準確性。爲了衡量ETA的準確性,咱們用從Kafka日誌獲取的實時檢索實際到達時間(ATA)對比咱們的ETA並以此構建了一個工具。此外,咱們的團隊成員也可能直接從應用程序內報告ETA 的 bug。衡量線路質量有時須要在個案基礎上作可視化檢查,咱們還創建了一組豐富的web可視化工具,檢查和比較不一樣模型和路線從提供者的ETA預測狀況。

Goldeta 對比 Gurafu: 經過超過十萬次的行程採樣,系統計算預計到達時間(ETA)與實際到達時間(ATA)的差距。新的ETA系統Gurafu的偏差分佈更尖更高,這意味着新系統比舊系統在預測是更加穩定(方差更小)。縱軸是行程估計錯誤的數量。這意味着只有在不多機率會有小錯誤發生。

這些健康檢查顯示去年咱們已經走過了漫長的道路。

超高效路線規劃和高精度的ETA是相當重要的。咱們用現代的路線算法來創建一個精心優化系統來應對每秒成千上萬請求而且作出毫秒級的快速響應。咱們全部的新服務,如uberPOOL和UberEATS都開始部署這個系統。

這個優化之旅尚未結束。隨着咱們擴展和改進像UberPOOL這樣的產品,根據地點和時間的上下文肯定最優路線還將使得服務準確性和效率進一步提高。

咱們還想讓打電話保平安也變得更加可靠、智能。若是這聽起來像是一個你感興趣的挑戰,咱們但願你加入咱們的行列。


參考資料

原文做者: THI NGUYEN 譯者: Harry Zhu 英文原文地址:
https://eng.uber.com/engineering-an-efficient-route/

做爲分享主義者(sharism),本人全部互聯網發佈的圖文均聽從CC版權,轉載請保留做者信息並註明做者 Harry Zhu 的 FinanceR專欄:https://segmentfault.com/blog/harryprince,若是涉及源代碼請註明GitHub地址:https://github.com/harryprince。微信號: harryzhustudio商業使用請聯繫做者。

相關文章
相關標籤/搜索