午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

ABAP實(shí)現(xiàn)Geohash

 Coder編程 2020-08-21

前幾天群里有人問(wèn)ABAP有沒(méi)有Geohash函數(shù),用來(lái)幫助SAP存儲(chǔ)門(mén)店位置、實(shí)現(xiàn)查找附近門(mén)店的功能。因?yàn)闆](méi)有查到,所以我動(dòng)手寫(xiě)了一個(gè)。

 

Geohash是什么

Geohash是一種公共域地理編碼系統(tǒng),它將一個(gè)地理位置編碼成一串字母和數(shù)字。字符串越長(zhǎng),表示的范圍越精確。兩個(gè)Geohash字符串的相同前綴越多,表示它們所代表的地點(diǎn)的距離越近,這樣就可以利用字符串的前綴匹配來(lái)快速查詢附近的地點(diǎn)信息。

關(guān)于Geohash的更多介紹,可以參考:

 

本文鏈接:https://www.cnblogs.com/hhelibeb/p/11426826.html 

原創(chuàng)內(nèi)容,轉(zhuǎn)載請(qǐng)注明

實(shí)現(xiàn)

我在Github創(chuàng)建了一個(gè)repo,包含了自己寫(xiě)的編碼、解碼方法。地址是:https://github.com/hhelibeb/geohash-abap

代碼如下,目前還有更多功能在實(shí)現(xiàn)中,有興趣的朋友可以來(lái)一起寫(xiě)。

(注:github上面的代碼會(huì)不定時(shí)更新,博客中貼的只是初始代碼,請(qǐng)前往github查看最新代碼

class zcl_geohash definition  public  final  create public .  public section.    types: begin of ty_hash,             hash type string,           end of ty_hash.    types: ty_hash_t type standard table of ty_hash with empty key.    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        !longitude        type ty_tude        !latitude         type ty_tude        !length           type i default 8      returning        value(r_geo_hash) type string .    class-methods decode      importing        !geohash   type string      exporting        !longitude type ty_tude        !latitude  type ty_tude .    class-methods neighbors importing geohash          type string                            returning value(neighbors) type ty_hash_t.    class-methods validate importing geohash      type string                           returning value(valid) type abap_bool.  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_neighbors_odd,             f1 type string,             f2 type string,             f3 type string,             f4 type string,             f5 type string,             f6 type string,             f7 type string,             f8 type string,           end of ty_neighbors_odd.    types: ty_neighbors_odd_t type standard table of ty_neighbors_odd with empty key.    types: begin of ty_neighbors_even,             f1 type string,             f2 type string,             f3 type string,             f4 type string,           end of ty_neighbors_even.    types: ty_neighbors_even_t type standard table of ty_neighbors_even with empty key.    class-data mt_base32_code1 type ty_base32_t1 .    class-data mt_base32_code2 type ty_base32_t2 .    class-data mt_neighbors_odd type ty_neighbors_odd_t.    class-data mt_neighbors_even type ty_neighbors_even_t.    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_index importing index          type i                                       offset         type i                                       max_index      type i                             returning value(r_index) type i.    class-methods: get_code_neighbor importing i_table        type standard table                                               i_member       type string                                     returning value(r_table) type ty_hash_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.    mt_neighbors_odd = value #(     (  f1 = 'b' f2 = 'c' f3 = 'f' f4 = 'g' f5 = 'u' f6 = 'v' f7 = 'y' f8 = 'z' )     (  f1 = '8' f2 = '9' f3 = 'd' f4 = 'e' f5 = 's' f6 = 't' f7 = 'w' f8 = 'x' )     (  f1 = '2' f2 = '3' f3 = '6' f4 = '7' f5 = 'k' f6 = 'm' f7 = 'q' f8 = 'r' )     (  f1 = '0' f2 = '1' f3 = '4' f4 = '5' f5 = 'h' f6 = 'j' f7 = 'n' f8 = 'p' )    ).    mt_neighbors_even = value #(     (  f1 = 'p' f2 = 'r' f3 = 'x' f4 = 'z' )     (  f1 = 'n' f2 = 'q' f3 = 'w' f4 = 'y' )     (  f1 = 'j' f2 = 'm' f3 = 't' f4 = 'v' )     (  f1 = 'h' f2 = 'k' f3 = 's' f4 = 'u' )     (  f1 = '5' f2 = '7' f3 = 'e' f4 = 'g' )     (  f1 = '4' f2 = '6' f3 = 'd' f4 = 'f' )     (  f1 = '1' f2 = '3' f3 = '9' f4 = 'c' )     (  f1 = '0' f2 = '2' f3 = '8' f4 = 'b' )    ).  endmethod.  method decode.    types: numc5 type n length 5.    data(length) = strlen( geohash ).    if length <= 0.      return.    endif.    if length > c_max_hash_length.      length = c_max_hash_length.    endif.    data(geo_hash_internal) = to_lower( geohash ).    data(hash_index) = 0.    do length times.      data(base32) = geo_hash_internal+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  = 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  = 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 length < 1.      return.    endif.    if length > c_max_hash_length.      data(hash_length) = c_max_hash_length.    else.      hash_length = 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  = 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  = 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.    data(table_descr) = cast cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data( i_table ) ).    data(column_count) = lines(      cast cl_abap_structdescr( table_descr->get_table_line_type( ) )->components ).    data(col_index) = 1.    loop at i_table assigning field-symbol(<line>).      data(row_index) = sy-tabix.      col_index = 1.      while col_index <= column_count.        assign component col_index of structure <line> to field-symbol(<field>).        if sy-subrc = 0.          if <field> = i_member.            data(found) = abap_true.            exit.          endif.        endif.        col_index = col_index + 1.      endwhile.      if found = abap_true.        exit.      endif.    endloop.    if found = abap_false.      return.    endif.    types: begin of ty_direction,             row type i,             col type i,           end of ty_direction.    data: direction_index_table type standard table of ty_direction.    direction_index_table = value #(      ( row = -1 col =  -1  )      ( row = -1 col =   0  )      ( row = -1 col =  +1  )      ( row =  0 col =  -1  )      ( row =  0 col =  +1  )      ( row =  1 col =  -1  )      ( row =  1 col =   0  )      ( row =  1 col =  +1  )    ).    data(row_count) = lines( i_table ).    loop at direction_index_table assigning field-symbol(<direction_index>).      data(row_result) = get_index( index = row_index offset = <direction_index>-row max_index = row_count ).      data(col_result) = get_index( index = col_index offset = <direction_index>-col max_index = column_count ).      read table i_table assigning <line> index row_result.      if sy-subrc = 0.        assign component col_result of structure <line> to <field>.        if sy-subrc = 0.          r_table = value #( base r_table ( hash = <field> ) ).        endif.      endif.    endloop.  endmethod.  method get_index.    if abs( offset ) >= max_index.      return.    endif.    r_index = index + offset.    if r_index > max_index .      r_index = offset.    endif.    if r_index <= 0.      r_index = max_index + r_index.    endif.  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.  method neighbors.    if geohash is initial.      return.    endif.    data(geohash_internal) = to_lower( geohash ).    data(length) = strlen( geohash_internal ).    data(offset) = length - 1.    data(suffix) = geohash_internal+offset(1).    if length mod 2 = 0.      data(code_table) = get_code_neighbor( i_table = mt_neighbors_even i_member = suffix ).    else.      code_table       = get_code_neighbor( i_table = mt_neighbors_odd  i_member = suffix ).    endif.    data(prefix) = geohash_internal(offset).    loop at code_table assigning field-symbol(<hash>).      neighbors = value #( base neighbors ( hash = prefix && <hash>-hash ) ).    endloop.  endmethod.  method validate.    valid = abap_false.    if geohash is initial .      return.    endif.    if strlen( geohash ) > c_max_hash_length.      return.    endif.    data(geohash_internal) = to_lower( geohash ).    data(geohash_index) = 0.    do strlen( geohash ) times.      data(hash) = geohash_internal+geohash_index(1).      if not line_exists( mt_base32_code2[ base32 = hash ] ).        return.      endif.      geohash_index = geohash_index + 1.    enddo.    valid = abap_true.  endmethod.endclass.

 

使用

本節(jié)包含一些使用示例。

編碼

以浙江省麗水中學(xué)的經(jīng)緯度坐標(biāo) (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 ).

 

可以得到結(jié)果wtj3cper。

 

 

 

默認(rèn)的geohash長(zhǎng)度是8位,也可以使用更長(zhǎng)的編碼提高精度,比如,

data(hash) = zcl_geohash=>encode(  i_latitude  = '28.4751600000'  i_longitude = '119.9314500000'  i_length    = 12).

 

可以得到wtj3cperv6d9。12是geohash-abap支持的最大長(zhǎng)度。

解碼

對(duì)上面得到的geohash編碼結(jié)果wtj3cperv6d9進(jìn)行解碼,

zcl_geohash=>decode(  exporting    i_geo_hash = hash  importing    e_latitude  = data(latitude)    e_longitude = data(longitude)  ).cl_demo_output=>display( latitude && ',' && longitude ).

 

得到的結(jié)果是 (28.475159956144, 119.931449834260) 可以看到是一個(gè)近似結(jié)果,和原值有微小的差距。

 

查詢

將地點(diǎn)的geohash存儲(chǔ)在數(shù)據(jù)庫(kù)中之后,可以方便地用SQL中的like關(guān)鍵字,查找到附近的地點(diǎn)。

比如select * from table where geohash like 'wtj3cperv%'等等...

相鄰區(qū)域編碼

為了準(zhǔn)群找到最近的地址,需要找到一個(gè)geohash所代表的區(qū)域的周?chē)?個(gè)區(qū)域。

為什么?

比如,下圖中邊緣附近的紅點(diǎn)。

黃色的點(diǎn)要比黑色的點(diǎn)更加靠近紅點(diǎn),但是由于黑點(diǎn)跟紅點(diǎn)的GeoHash前綴匹配數(shù)目更多,因此直接用like查詢,會(huì)得到黑點(diǎn)。

(參考文章:https://blog.csdn.net/youhongaa/article/details/78816700

獲取附近8個(gè)區(qū)域編碼的方法:

data(neighbors) = zcl_geohash=>neighbors( 'wtj3cper' ).

 

參考:用打表的方式解決求Geohash當(dāng)前區(qū)域周?chē)?個(gè)區(qū)域編碼

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多