Uber開源H3算法(地理索引)的工程化實現(xiàn)

何為地理索引:

? ? 在工程領(lǐng)域,尤其是電商平臺灯萍,外賣平臺轧铁,打車平臺頻繁使用的比如某一范圍內(nèi)的商品,商家功能等旦棉。會使用到某一范圍比如10Km范圍內(nèi)的所有商家場景齿风。那么如何更加方便,簡單的實現(xiàn)這樣的場景呢绑洛?

? ?常用的有:基于GeoHash原理的實現(xiàn)救斑,Google-S2 空間索引的實現(xiàn),Geomesa Z3的實現(xiàn)真屯,Uber H3索引的實現(xiàn)等脸候;

? ?但是不同的使用場景,每個不同公司可以按照需求的不同選擇自己所需的實現(xiàn)技術(shù)棧绑蔫。本文將會結(jié)合我們已經(jīng)在工程領(lǐng)域中實現(xiàn)的Uber H3索引進行詳細講解运沦。

1.H3索引介紹

H3索引,由Uber公司開源配深⌒恚基礎(chǔ)為C語言編寫的算法;h3-java為包裝JNI的通用接口抽象篓叶;(由于我們的主要技術(shù)語言為java烈掠,本文將著重介紹我們關(guān)于java方面的使用場景)

官方介紹文檔手冊:https://uber.github.io/h3/#/documentation/overview/introduction

開源代碼地址:https://github.com/uber/h3

java版本開源代碼地址:https://github.com/uber/h3-java

? ? ? ? ??H3地理空間索引系統(tǒng)是具有分級線性索引索引的球體的多精度六角形平鋪。

? ? ? ? ? H3核心庫對緯度/經(jīng)度坐標和之間的轉(zhuǎn)換提供了函數(shù)H3的地理空間索引澜共。

2.當前階段Uber開源的H3工具包能夠?qū)ν馓峁┑姆眨?br>

? ? ? ? ? 給定緯度/經(jīng)度點向叉,找到特定分辨率下包含H3單元的索引

? ? ? ? ? 給定H3索引,找到緯度/經(jīng)度單元中心

? ? ? ? ? 給定H3索引嗦董,確定緯度/經(jīng)度坐標中的單元邊界

? ? ? ? ?其他等

3.重要的參考指標:

? ? ? ? 指標如下:

? ? 核心指標介紹: Resolution (精度)母谎,正六邊形覆蓋面積,正六邊形變長京革,每個精度對應的索引個數(shù)奇唤;

4. 轉(zhuǎn)換下思維方式:

? ? ?也就是從單純的點到點覆蓋范圍計算幸斥,查詢效率低下,而Uber H3通過為全球地理位置定制了一套咬扇,正六邊形構(gòu)成的覆蓋圖甲葬,每個覆蓋圖有一個唯一Id,通過空間換時間的思想懈贺,讓點對點的查詢變成了索引結(jié)構(gòu)的匹配查詢经窖。實現(xiàn)了在沒有巨大誤差前提下的高效查詢。

5.工程化實踐介紹:

使用依賴如下:

<dependency>? ? ?

? ? <groupId>com.uber</groupId>? ?

? ? <artifactId>h3</artifactId>? ?

? ? <version>3.4.0</version>

</dependency>

初始化H3的計算對象和通過經(jīng)緯度獲得H3索引:

private static void init() {

? ? try {

? ? ? ? h3 = H3Core.newInstance();

? ? }catch (IOException e) {?

? ? ? ?logger.error("H3Instance init failed", e);

? ? }

}

public static String getH3IndexByCoordinate(double latitude, double longitude, H3ResolutionEnum resolution) {

//param validate 經(jīng)緯度參數(shù)的合法校驗

? if (!isValidCoordinate(latitude, longitude)) {

? ? ? logger.warn("getH3IndexByCoordinate param is invalid,coordinate:{},{}", longitude, latitude);

? ? ? throw new IllegalArgumentException();

? }

//execute h3 index calculate 執(zhí)行通過經(jīng)緯度 選擇的精度画侣,計算H3索引邏輯

? ? try {

? ? ? ? if (h3 == null) {

? ? ? ? ? ? init();

? ? }

? ? ? ? // 得到對應精度的H3索引

? ? ? ? return h3.geoToH3Address(latitude, longitude, resolution.precision);

? ? } catch (Exception e) {

? ? ? ? logger.error("geoToH3Address-error", e);

? ? ? ? throw e;

? ? }

}

通過H3索引找到對應的正六邊形中心點坐標經(jīng)緯度:

public static Optional<GeoCoord> getCoordinateByH3Index(String h3Index) {

? ? try {

? ? ? ? //param validate 校驗H3索引字符串是否合法

? ? ? ? if (h3PreCheckInvalid(h3Index)) {

? ? ? ? logger.warn("getCoordinateByH3Index,param is invalid!");

? ? ? ? return Optional.empty();

? ? ? ? }

? ? ? ? //execute 獲取正六邊形中心坐標

? ? ? ? GeoCoord geoCoord = h3.h3ToGeo(h3Index);

? ? ? ? return Optional.of(geoCoord);

? ? } catch (Exception e) {

? ? ? ? logger.error("getCoordinateByH3Index error,h3Index:" + h3Index, e);

? ? ? ? return Optional.empty();

? ? }

}

有了上述的兩種方式,其實我們已經(jīng)可以通過Uber H3索引的屬性做自己需要的業(yè)務拓展了堡妒。

比如通過某一個點,獲取到符合精度的正六邊形中心坐標皮迟,以這個正六邊形中心坐標伏尼,計算直線距離N公里內(nèi)有多少個索引休溶,得到索引集合扰她。

那么則可以通過索引集合來查詢貨物或者商家是否有符合集合內(nèi)索引的屬性,如果有則證明在N公里范圍內(nèi),如果沒有則證明不在N公里范圍內(nèi)窖壕。

H3核心API方法列舉:

final class NativeMethods {

? ? NativeMethods() {

? ? }

? ??native int maxH3ToChildrenSize(long var1, int var3);

? ??native void h3ToChildren(long var1, int var3, long[] var4);

? ??native boolean h3IsValid(long var1);

? ??native int h3GetBaseCell(long var1);

? ? native boolean h3IsPentagon(long var1);

? ? native long geoToH3(double var1, double var3, int var5);

? ? native void h3ToGeo(long var1, double[] var3);

? ? native int h3ToGeoBoundary(long var1, double[] var3);

? ? native int maxKringSize(int var1);

? ? native void kRing(long var1, int var3, long[] var4);

? ? native void kRingDistances(long var1, int var3, long[] var4, int[] var5);

? ? native int hexRange(long var1, int var3, long[] var4);

? ? native int hexRing(long var1, int var3, long[] var4); native int h3Distance(long var1, long var3);

? ? native int experimentalH3ToLocalIj(long var1, long var3, int[] var5);

? ? native long experimentalLocalIjToH3(long var1, int var3, int var4);

? ? native int h3LineSize(long var1, long var3);

? ? native int h3Line(long var1, long var3, long[] var5);

? ? native int maxPolyfillSize(double[] var1, int[] var2, double[] var3, int var4);

? ? native void polyfill(double[] var1, int[] var2, double[] var3, int var4, long[] var5);

? ? native void h3SetToLinkedGeo(long[] var1, ArrayList<List<List<GeoCoord>>> var2);

? ? native int compact(long[] var1, long[] var2);

? ? native int maxUncompactSize(long[] var1, int var2);

? ? native int uncompact(long[] var1, int var2, long[] var3);

? ? native double hexAreaKm2(int var1); native double hexAreaM2(int var1);

? ? native double edgeLengthKm(int var1);

? ? native double edgeLengthM(int var1);

? ? native long numHexagons(int var1);

? ? native void getRes0Indexes(long[] var1);

? ? native boolean h3IndexesAreNeighbors(long var1, long var3);

? ? native long getH3UnidirectionalEdge(long var1, long var3);

? ? native boolean h3UnidirectionalEdgeIsValid(long var1);

? ? native long getOriginH3IndexFromUnidirectionalEdge(long var1);

? ? native long getDestinationH3IndexFromUnidirectionalEdge(long var1);

? ? native void getH3IndexesFromUnidirectionalEdge(long var1, long[] var3);

? ? native void getH3UnidirectionalEdgesFromHexagon(long var1, long[] var3);

? ? native int getH3UnidirectionalEdgeBoundary(long var1, double[] var3);

}

那么如何正確的入手Uber H3呢忧勿?

我建議:1.了解自己的需求場景是否符合范圍查找的場景。

? ? ? ? ? ? ? 2.判斷是否對范圍查找的誤差要求沒有特別的高瞻讽。

? ? ? ? ? ? ? 3.下載Uber H3源碼包:源碼包中提供了鸳吸,基礎(chǔ)的場景測試用例,基準測試用例速勇。下載代碼后本地debug就可以進行調(diào)試晌砾。

? ? ? ? ? ? ? https://github.com/uber/h3-java/tree/master/src/test/java/com/uber/h3core??

? ? ? ? ? ? ? 4.調(diào)試完畢后,根據(jù)自己的場景模型烦磁,構(gòu)造符合自己使用的API或者工具類养匈,提供給使用方哼勇。

歡迎大家多提寶貴意見。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末呕乎,一起剝皮案震驚了整個濱河市积担,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌猬仁,老刑警劉巖帝璧,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異湿刽,居然都是意外死亡聋溜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門叭爱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來撮躁,“玉大人,你說我怎么就攤上這事买雾“崖” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵漓穿,是天一觀的道長嗤军。 經(jīng)常有香客問我,道長晃危,這世上最難降的妖魔是什么叙赚? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮僚饭,結(jié)果婚禮上震叮,老公的妹妹穿的比我還像新娘。我一直安慰自己鳍鸵,他們只是感情好苇瓣,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著偿乖,像睡著了一般击罪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贪薪,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天媳禁,我揣著相機與錄音,去河邊找鬼画切。 笑死竣稽,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播丧枪,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼光涂,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拧烦?” 一聲冷哼從身側(cè)響起忘闻,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎恋博,沒想到半個月后齐佳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡债沮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年炼吴,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疫衩。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡硅蹦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出闷煤,到底是詐尸還是另有隱情童芹,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布鲤拿,位于F島的核電站假褪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏近顷。R本人自食惡果不足惜生音,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望窒升。 院中可真熱鬧缀遍,春花似錦、人聲如沸异剥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽冤寿。三九已至,卻和暖如春青伤,著一層夾襖步出監(jiān)牢的瞬間督怜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工狠角, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留号杠,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像姨蟋,于是被迫代替她去往敵國和親屉凯。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容