高度なアプリケーションの[10]のRedis Redisのシリーズ-GeoHash

オリジナル: 高度なアプリケーションの10 []のRedis Redisのシリーズ-GeoHash

Redisの3.2バージョンでは、ショッピングモールの近くにあなたがRedisのことで近くの人を作ることができる手段GEOテンプレート、店の近くでそのような機能を追加します。

近くに人を数えるためにデータベースを使用します

緯度と経度、経度範囲(-180、180]、緯度範囲(-90、90]で表される二次元マップ要素を使用して位置データ、プラスまたはマイナス赤道緯度境界、南北負、経度の負子午線そのような望京SOHO、その緯度及び経度座標(116.48105,39.996794)でデンバーオフィスとして(イギリスグリニッジ天文台)セクタの、負により東西、中国北東半球に位置するので、陽性です。

2つの要素間の距離が非常に遠く離れていない場合、あなたは直接要素間のピタゴラスの定理の距離を考慮することができる使用することができます。「周辺の人々は、」我々は通常、機能素子の距離が十分に大きく、距離計算ピタゴラス定理ではありません使用します。しかし、緯度と経度の座標の密度が同じではないことに注意してください(地球が楕円である)、およびではない正確なため、彼ができる場合二乗差演算のピタゴラスの総和は、加重和より特定の因子によって必要とされる時間の後にあなたは加重する必要はありません。

問題:1:なぜ2の密度から360度の経度、のみ180°の緯度合計の合計?

あなたは要素の座標指定され、「周囲の人々を」、計算し、その後、ソートされた距離によって座標の近くに他の要素を計算したい場合は今、どこから始めれば?

image.png

リレーショナルデータベース(要素ID、経度X、緯度y)を用いて、要素の現在の緯度と経度の座標が格納されている場合、どのように計算しますか?

まず第一に、あなたがして大きすぎる、パフォーマンスは確かに満たすことができない。この計算を横断することによってソートされているすべての要素とターゲット要素までの距離を計算することはできません。一般的な方法は、要素数が矩形領域によって定義される、次に距離算出並べ替えの合計量中の要素の面積。これは、大幅に計算量を減らすことができます。それの矩形領域を分割するには?あなたは、SQL缶サークルを使用して、半径rを指定することができます。ユーザーはふるいアウトの結果に満足されていない場合は、スクリーニングの半径を拡大していくでしょう。

select id from positions where x0-r < x < x0+r and y0-r < y < y0+r

高性能アルゴリズム矩形領域を満たすために、緯度と経度の座標に加え、双方向複合指数(x、y)は、クエリのパフォーマンスを最適化することができる最大の表のニーズのデータ​​。

「近隣の人々」のクエリは非常に高い同時実行の状況である場合は、データベースクエリのパフォーマンスが、限定されている、これは良いソリューションではないかもしれません。

ジオハッシュアルゴリズム

産業より一般的な地理的距離ソートアルゴリズムは、Redisのもジオハッシュアルゴリズムを使用して、ジオハッシュアルゴリズムです。一次元の整数に二次元マッピングアルゴリズムジオハッシュ緯度と経度のデータが、そうすべての要素が一次元距離後点に近い二次元座標との間の距離に、ラインに搭載されることが非常に近いであろう。「人々は近く、とき」我々は最初の目標位置を計算する場合は、この行にマップされている場合は、その行に、この1次元の線に近いポイントを得ます。

それが何であるか、具体的であるマッピングアルゴリズム?その二次元平面として地球全体、及びその後、分割は、碁のボードのような正方格子のシリーズとなっています。地図座標のすべての要素は、正方形に配置されます。正方形、より正確な座標より小さい。これらのボックスは、次に近い近い符号化正方形、コーディング整数です。どのようにそれはそれをコード化しますか?最も簡単な解決策の一つは、ケーキの方法をカットすることです。あなたの前にケーキの正方形を想像二ナイフはダウン4つの小さな正方形はそれぞれ4進整数00、としてマークすることができる4つの小さな正方形に等分します。次に、2本のナイフでどんな小さな広場に続けるには、あなたが発現されるように4ビットのバイナリ整数を使用することができ、各小さな広場を少しカット。その後、バイナリ整数が長くなってきます正方形はますます小さくなり、伐採し続け、精度が高くなります。

画像

使用される上記の例では、第二ナイフである、実際のアルゴリズムは、他のブレードの多くなり、最終的な符号化された整数のうち、同一ではありません。

符号化した後、各マップ要素の座標が整数になるように、要素の座標は、この整数、長い整数大きく、座標値のうち損失の低減の小さい程度によって復元することができます。この機能の「付近の人々」について、その損失の精度はごくわずかです。

GeoHash 算法会继续对这个整数做一次 base32 编码 (0-9,a-z 去掉 a,i,l,o 四个字母) 变成一个字符串。在 Redis 里面,经纬度使用 52 位的整数进行编码,放进了 zset 里面,zset 的 value 是元素的 key,score 是 GeoHash 的 52 位整数值。zset 的 score 虽然是浮点数,但是对于 52 位的整数值,它可以无损存储。

在使用 Redis 进行 Geo 查询时,我们要时刻想到它的内部结构实际上只是一个 zset(skiplist)。通过 zset 的 score 排序就可以得到坐标附近的其它元素 (实际情况要复杂一些,不过这样理解足够了),通过将 score 还原成坐标值就可以得到元素的原始坐标。

基本使用

Redis 提供的 Geo 指令只有 6 个,读者们瞬间就可以掌握。使用时,读者务必再次想起,它只是一个普通的 zset 结构。

增加

geoadd 指令携带集合名称以及多个经纬度名称三元组,注意这里可以加入多个三元组

127.0.0.1:6379> geoadd company 116.48105 39.996794 juejin
(integer) 1
127.0.0.1:6379> geoadd company 116.514203 39.905409 ireader
(integer) 1
127.0.0.1:6379> geoadd company 116.489033 40.007669 meituan
(integer) 1
127.0.0.1:6379> geoadd company 116.562108 39.787602 jd 116.334255 40.027400 xiaomi
(integer) 2

也许你会问为什么 Redis 没有提供 geo 删除指令?前面我们提到 geo 存储结构上使用的是 zset,意味着我们可以使用 zset 相关的指令来操作 geo 数据,所以删除指令可以直接使用 zrem 指令即可。

距离

geodist 指令可以用来计算两个元素之间的距离,携带集合名称、2 个名称和距离单位。

127.0.0.1:6379> geodist company juejin ireader km
"10.5501"
127.0.0.1:6379> geodist company juejin meituan km
"1.3878"
127.0.0.1:6379> geodist company juejin jd km
"24.2739"
127.0.0.1:6379> geodist company juejin xiaomi km
"12.9606"
127.0.0.1:6379> geodist company juejin juejin km
"0.0000"

我们可以看到掘金离美团最近,因为它们都在望京。距离单位可以是 m、km、ml、ft,分别代表米、千米、英里和尺。

获取元素位置

geopos 指令可以获取集合中任意元素的经纬度坐标,可以一次获取多个。

127.0.0.1:6379> geopos company juejin
1) 1) "116.48104995489120483"
   2) "39.99679348858259686"
127.0.0.1:6379> geopos company ireader
1) 1) "116.5142020583152771"
   2) "39.90540918662494363"
127.0.0.1:6379> geopos company juejin ireader
1) 1) "116.48104995489120483"
   2) "39.99679348858259686"
2) 1) "116.5142020583152771"
   2) "39.90540918662494363"

我们观察到获取的经纬度坐标和 geoadd 进去的坐标有轻微的误差,原因是 geohash 对二维坐标进行的一维映射是有损的,通过映射再还原回来的值会出现较小的差别。对于「附近的人」这种功能来说,这点误差根本不是事。

获取元素的 hash 值

ジオハッシュは、base32エンコードされ、既に上述したように、緯度と経度エンコードされた文字列の要素を取得することができます。あなたはこのエンコードされた値を使用することができます} geohash.org/${hashをまっすぐ...運ば値のジオハッシュの標準エンコーディングを。

127.0.0.1:6379> geohash company ireader
1) "wx4g52e1ce0"
127.0.0.1:6379> geohash company juejin
1) "wx4gd94yjn0"

さて、この位置は非常に正確です。

会社の近くで

georadiusbymember命令は指定された要素の近傍でのクエリ他の要素に使用することができる最も重要なコマンドです、そのパラメータは非常に複雑です。

距離に応じて3つの正変位素子までの約20kmの範囲内で、それ自体を排除するものではありません

127.0.0.1:6379> georadiusbymember company ireader 20 km count 3 asc
1) "ireader"
2) "juejin"
3) "meituan"
# 范围 20 公里以内最多 3 个元素按距离倒排
127.0.0.1:6379> georadiusbymember company ireader 20 km count 3 desc
1) "jd"
2) "meituan"
3) "juejin"
# 三个可选参数 withcoord withdist withhash 用来携带附加参数
# withdist 很有用,它可以用来显示距离
127.0.0.1:6379> georadiusbymember company ireader 20 km withcoord withdist withhash count 3 asc
1) 1) "ireader"
   2) "0.0000"
   3) (integer) 4069886008361398
   4) 1) "116.5142020583152771"
      2) "39.90540918662494363"
2) 1) "juejin"
   2) "10.5501"
   3) (integer) 4069887154388167
   4) 1) "116.48104995489120483"
      2) "39.99679348858259686"
3) 1) "meituan"
   2) "11.5748"
   3) (integer) 4069887179083478
   4) 1) "116.48903220891952515"
      2) "40.00766997707732031"

クエリの要素の近傍の要素に基づいてgeoradiusbymember命令に加えて、Redisのは、このコマンドの近傍の座標値に基づいて、クエリの要素を提供し、より便利であり、それは計算することができる「車両の近傍に、」ユーザの位置に応じて、「近くのレストラン」など。そのパラメータは、緯度および経度座標にターゲット要素ことを除いて、georadiusbymember基本的に同じです。

127.0.0.1:6379> georadius company 116.514202 39.905409 20 km withdist count 3 asc
1) 1) "ireader"
   2) "0.0000"
2) 1) "juejin"
   2) "10.5501"
3) 1) "meituan"
   2) "11.5748"

おすすめ

転載: www.cnblogs.com/lonelyxmas/p/12515052.html