ABAP实现Geohash
Posted hhelibeb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ABAP实现Geohash相关的知识,希望对你有一定的参考价值。
前几天群里有人问ABAP有没有Geohash函数,用来帮助SAP存储门店位置、实现查找附近门店的功能。因为没有查到,所以我动手写了一个。
Geohash是什么
Geohash是一种公共域地理编码系统,它将一个地理位置编码成一串字母和数字。字符串越长,表示的范围越精确。两个字符串的相同前缀越多,表示它们所代表的地点的距离越近,这样就可以利用字符串的前缀匹配来快速查询附近的地点信息。
关于Geohash的更多介绍,可以参考:
本文链接:https://www.cnblogs.com/hhelibeb/p/11426826.html
原创内容,转载请注明
实现
我在Github创建了一个repo,包含了自己写的编码、解码方法。地址是:https://github.com/hhelibeb/geohash-abap
代码如下,目前还有更多功能在实现中,有兴趣的朋友可以来一起写。
class zcl_geohash definition public final create public. public section. types: ty_tude type p length 16 decimals 12. constants c_max_hash_length type i value 12 ##NO_TEXT. class-methods class_constructor. class-methods encode importing !i_longitude type ty_tude !i_latitude type ty_tude !i_length type i default 8 returning value(r_geo_hash) type string . class-methods decode importing !i_geo_hash type string exporting !e_longitude type ty_tude !e_latitude type ty_tude . protected section. private section. types: begin of ty_base32, decimals type i, base32 type string, end of ty_base32 . types: ty_base32_t1 type hashed table of ty_base32 with unique key decimals . types: ty_base32_t2 type hashed table of ty_base32 with unique key base32 . types: begin of ty_code, code type string, end of ty_code. types: ty_code_t type standard table of ty_code with empty key. class-data mt_base32_code1 type ty_base32_t1 . class-data mt_base32_code2 type ty_base32_t2 . constants c_longitude_min type ty_tude value ‘-180.00‘ ##NO_TEXT. constants c_longitude_max type ty_tude value ‘180.00‘ ##NO_TEXT. constants c_latitude_min type ty_tude value ‘-90.00‘ ##NO_TEXT. constants c_latitude_max type ty_tude value ‘90.00‘ ##NO_TEXT. constants c_zero type c value ‘0‘ ##NO_TEXT. constants c_one type c value ‘1‘ ##NO_TEXT. class-methods bin_to_dec importing !i_bin type string default ‘0‘ returning value(r_dec) type int4. class-methods dec_to_bin importing !i_dec type int4 returning value(r_bin) type string. class-methods get_bin importing !i_left type ty_tude !i_right type ty_tude !i_tude type ty_tude exporting !e_left type ty_tude !e_right type ty_tude !e_bin type char1 . class-methods get_tude importing !i_left type ty_tude !i_right type ty_tude !i_bin type string exporting !e_left type ty_tude !e_right type ty_tude !e_tude type ty_tude . class-methods: get_code_neighbor importing i_table type standard table i_member type string returning value(r_table) type ty_code_t. ENDCLASS.
CLASS ZCL_GEOHASH IMPLEMENTATION. method bin_to_dec. if contains( val = i_bin regex = `[^01]` ). return. endif. data(length) = strlen( i_bin ). data(l_index) = 0. do length times. data(temp) = i_bin+l_index(1). if temp = 1. r_dec = r_dec + 2 ** ( length - l_index - 1 ). endif. l_index = l_index + 1. enddo. endmethod. method class_constructor. mt_base32_code1 = value #( ( decimals = 0 base32 = ‘0‘ ) ( decimals = 1 base32 = ‘1‘ ) ( decimals = 2 base32 = ‘2‘ ) ( decimals = 3 base32 = ‘3‘ ) ( decimals = 4 base32 = ‘4‘ ) ( decimals = 5 base32 = ‘5‘ ) ( decimals = 6 base32 = ‘6‘ ) ( decimals = 7 base32 = ‘7‘ ) ( decimals = 8 base32 = ‘8‘ ) ( decimals = 9 base32 = ‘9‘ ) ( decimals = 10 base32 = ‘b‘ ) ( decimals = 11 base32 = ‘c‘ ) ( decimals = 12 base32 = ‘d‘ ) ( decimals = 13 base32 = ‘e‘ ) ( decimals = 14 base32 = ‘f‘ ) ( decimals = 15 base32 = ‘g‘ ) ( decimals = 16 base32 = ‘h‘ ) ( decimals = 17 base32 = ‘j‘ ) ( decimals = 18 base32 = ‘k‘ ) ( decimals = 19 base32 = ‘m‘ ) ( decimals = 20 base32 = ‘n‘ ) ( decimals = 21 base32 = ‘p‘ ) ( decimals = 22 base32 = ‘q‘ ) ( decimals = 23 base32 = ‘r‘ ) ( decimals = 24 base32 = ‘s‘ ) ( decimals = 25 base32 = ‘t‘ ) ( decimals = 26 base32 = ‘u‘ ) ( decimals = 27 base32 = ‘v‘ ) ( decimals = 28 base32 = ‘w‘ ) ( decimals = 29 base32 = ‘x‘ ) ( decimals = 30 base32 = ‘y‘ ) ( decimals = 31 base32 = ‘z‘ ) ). mt_base32_code2 = mt_base32_code1. endmethod. method decode. types: numc5 type n length 5. data(length) = strlen( i_geo_hash ). if length <= 0. return. endif. if length > c_max_hash_length. length = c_max_hash_length. endif. data(geo_hash) = to_lower( i_geo_hash ). data(hash_index) = 0. do length times. data(base32) = geo_hash+hash_index(1). data(decimals) = value #( mt_base32_code2[ base32 = base32 ]-decimals optional ). data(bin5) = conv numc5( dec_to_bin( decimals ) ). data: mix_bin type string, longitude_bin type string, latitude_bin type string. mix_bin = mix_bin && bin5. hash_index = hash_index + 1. enddo. data(bin_index) = 0. do strlen( mix_bin ) times. data(bin) = mix_bin+bin_index(1). if bin_index mod 2 = 0. longitude_bin = longitude_bin && bin. else. latitude_bin = latitude_bin && bin. endif. bin_index = bin_index + 1. enddo. data(longitude_left) = c_longitude_min. data(longitude_right) = c_longitude_max. data(latitude_left) = c_latitude_min. data(latitude_right) = c_latitude_max. data(longitude_index) = 0. do strlen( longitude_bin ) times. data(bin_longitude) = longitude_bin+longitude_index(1). get_tude( exporting i_left = longitude_left i_right = longitude_right i_bin = bin_longitude importing e_left = longitude_left e_right = longitude_right e_tude = e_longitude ). longitude_index = longitude_index + 1. enddo. data(latitude_index) = 0. do strlen( latitude_bin ) times. data(bin_latitude) = latitude_bin+latitude_index(1). get_tude( exporting i_left = latitude_left i_right = latitude_right i_bin = bin_latitude importing e_left = latitude_left e_right = latitude_right e_tude = e_latitude ). latitude_index = latitude_index + 1. enddo. endmethod. method dec_to_bin. "ignore negative number data(temp) = 0. data(dec) = i_dec. while dec > 0. temp = dec mod 2. dec = dec / 2 - temp. r_bin = r_bin && conv char1( temp ). endwhile. r_bin = reverse( r_bin ). endmethod. method encode. if i_length < 1. return. endif. if i_length > c_max_hash_length. data(hash_length) = c_max_hash_length. else. hash_length = i_length. endif. data(loop_times) = hash_length * 5 / 2 + 1. data: longitude_bin type string, latitude_bin type string, mix_bin type string. data(longitude_left) = c_longitude_min. data(longitude_right) = c_longitude_max. data(latitude_left) = c_latitude_min. data(latitude_right) = c_latitude_max. do loop_times times. get_bin( exporting i_left = longitude_left i_right = longitude_right i_tude = i_longitude importing e_left = longitude_left e_right = longitude_right e_bin = data(longitude_bin_temp) ). get_bin( exporting i_left = latitude_left i_right = latitude_right i_tude = i_latitude importing e_left = latitude_left e_right = latitude_right e_bin = data(latitude_bin_temp) ). mix_bin = mix_bin && longitude_bin_temp && latitude_bin_temp. enddo. data(code_index) = 0. do hash_length times. data(offset) = code_index * 5 . data(bin) = mix_bin+offset(5). r_geo_hash = r_geo_hash && value #( mt_base32_code1[ decimals = bin_to_dec( i_bin = bin ) ]-base32 optional ). code_index = code_index + 1. enddo. endmethod. method get_bin. data(mid) = conv ty_tude( ( i_left + i_right ) / 2 ). if i_tude <= mid. e_bin = c_zero. e_left = i_left. e_right = mid. else. e_bin = c_one. e_left = mid. e_right = i_right. endif. endmethod. method get_code_neighbor. endmethod. method get_tude. data(mid) = conv ty_tude( ( i_left + i_right ) / 2 ). if i_bin = c_zero. e_left = i_left. e_right = mid. e_tude = ( i_left + mid ) / 2. else. e_left = mid. e_right = i_right. e_tude = ( mid + i_right ) / 2. endif. endmethod. ENDCLASS.
使用
本节包含一些使用示例。
编码
以浙江省丽水中学的经纬度坐标 (28.4751600000, 119.9314500000) 为例,
编码代码如下,
report ztest_qq1. data(hash) = zcl_geohash=>encode( i_latitude = ‘28.4751600000‘ i_longitude = ‘119.9314500000‘ ). cl_demo_output=>display( hash ).
可以得到结果wtj3cper。
默认的geohash长度是8位,也可以使用更长的编码提高精度,比如,
data(hash) = zcl_geohash=>encode( i_latitude = ‘28.4751600000‘ i_longitude = ‘119.9314500000‘ i_length = 12 ).
可以得到wtj3cperv6d9。12是geohash-abap支持的最大长度。
解码
对上面得到的geohash编码结果wtj3cperv6d9进行解码,
zcl_geohash=>decode( exporting i_geo_hash = hash importing e_latitude = data(latitude) e_longitude = data(longitude) ). cl_demo_output=>display( latitude && ‘,‘ && longitude ).
得到的结果是 (28.475159956144, 119.931449834260) 可以看到是一个近似结果,和原值有微小的差距。
查询
将地点的geohash存储在数据库中之后,可以方便地用SQL中的like关键字,查找到附近的地点。
比如select * from table where geohash like ‘wtj3cperv%‘等等...
以上是关于ABAP实现Geohash的主要内容,如果未能解决你的问题,请参考以下文章
Hbase geohash实现地理轨迹的空间搜索实现思路设计
Hbase geohash实现地理轨迹的空间搜索实现思路设计