blog

redisは、緯度と経度に基づいて近くの要素を照会したり、2つの緯度と経度間の距離を計算したりすることもできるのか?

前書き\n"\nシナリオ\n概要\n長い追加。\n要素の追加\nリストのハッシュ。\n地理的位置のハッシュを取得します。...

Aug 27, 2020 · 7 min. read
シェア

はじめに

"

時計のようにクリック、習慣に。

コレクションのポイント、人生は素晴らしい。

シナリオ

コンテンツ概要

RedisにおけるGeoディレクティブの基本的な使い方

緯度経度要素の追加コマンド

.1:6379> geoadd location 9 9 
(integer) 1

ハッシュコマンド

.1:6379> geohash location 
1) "wx4eysksu50"

緯度経度取得コマンド

.1:6379> geopos location 
1) 1) "3"
 2) "02"

2つの要素間の距離を計算 コマンド

.1:6379> GEODIST location meituan km
""

指定した要素の近くにある他の要素を照会る コマンド

# withdist 距離を示すのに使える
# asc  
# count 3 データを印刷する
.1:6379> GEORADIUSBYMEMBER location 20 km withcoord withdist withhash count 3 asc
1) 1) ""
 2) "0.) (integer) ) 1) "3"
 2) ") "xiaomi"
 2) "4.) (integer) ) 1) "03"
 2) ") ""
 2) ""
 3) (integer) ) 1) "83"
 2) "86"

RedisのGeoをコードで使う

Reidsに緯度と経度のデータをいくつか追加します。

ソースコードの解釈

// 指定されたキーに基づいて、指定された要素をredisに追加する。 キー:rediskey,point:緯度と経度をカプセル化したオブジェクト、member:要素
@Nullable
Long add(K key, Point point, M member);

ケースデモ

/**
 * ジオロケーションの初期化データ
 */
@Test
public void test_user_simple_geohash_init(){
 String key = "location";
 stringRedisTemplate.opsForGeo().add(key, new Point(,4), "");
 stringRedisTemplate.opsForGeo().add(key, new Point(3, 9), "ireader");
 stringRedisTemplate.opsForGeo().add(key, new Point(3, 9), "meituan");
 stringRedisTemplate.opsForGeo().add(key, new Point(8, 2), "jd");
 stringRedisTemplate.opsForGeo().add(key, new Point(5, 0), "xiaomi");
}

ジオロケーションのハッシュを取得

ソースコードの解釈

// 指定したキーに含まれる要素のハッシュ値を取得する。 key: 指定したキー, members: ハッシュ値を取得する要素
@Nullable
List<String> hash(K key, M... members);

ケースデモ

/**
 * ジオロケーションのハッシュ値を取得する
 */
@Test
public void test_user_simple_geohash_hash(){
 String key = "location";
 List<String> position = stringRedisTemplate.opsForGeo().hash(key, "", "ireader", "meituan", "jd", "xiaomi");
 assert position != null;
 position.forEach(System.out::println);
}

印刷結果

wx4gd94yjn0
wx4g52e1ce0
wx4gdg0tx40
wx4fk7jgtf0
wx4exqb0880

キーとエレメントに基づくジオロケーション・データの取得

ソースコードの解釈

// キーとエレメントに基づいてジオロケーション・データを取得する。 キー:指定キー、メンバー:指定エレメント
@Nullable
List<Point> position(K key, M... members);

ケースデモ

/**
 * ジオロケーションデータを入手する
 */
@Test
public void test_user_simple_geohash_get(){
 String key = "location";
 // 一度に複数を手に入れるか、1つを手に入れるか
 List<Point> position = stringRedisTemplate.opsForGeo().position(key, "", "ireader", "meituan", "jd", "xiaomi");
 assert position != null;
 position.forEach(System.out::println);
}

印刷結果

Point [x=0, y=3]
Point [x=2, y=9]
Point [x=2, y=0]
Point [x=6, y=3]
Point [x=3, y=0]

2つの要素間の距離の計算

ソースコードの解釈

// 2つの要素間の距離を計算する key: 指定されたキー,member1|member1:つの要素、メートル法:測定の単位、メートル、キロメートル......。
@Nullable
Distance distance(K key, M member1, M member1, Metric metric);

ケースデモ

/**
 * 2つの要素間の距離を計算する
 */
@Test
public void test_user_simple_geohash_distance(){
 String key = "location";
 Distance distance = stringRedisTemplate.opsForGeo().distance(key, "", "ireader", RedisGeoCommands.DistanceUnit.KILOMETERS);
 assert distance != null;
 System.out.println(distance.getValue() + " KM");
}

印刷結果

10.5501 KM

指定した要素に近い他の要素を照会

ソースコードの解釈

// 指定された要素の近傍にある他の要素にクエリを実行し、範囲クエリを指定する。
@Nullable
GeoResults<GeoLocation<M>> radius(K key, M member, Distance distance, GeoRadiusCommandArgs args);

ケースデモ

/**
 * 指定した要素の近くにある他の要素に照会る
 */
@Test
public void test_user_simple_geohash_radius(){
 String key = "location";
 // 距離計で3km先までの企業を正攻法で捕まえろ
 RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
 .sortAscending()//  
 .limit(2)// アウトプット要素の数
 .includeCoordinates()// 緯度と経度を出力する
 .includeDistance();//  
 // カプセル化距離パラメータ
 Distance distance = new Distance(3d, RedisGeoCommands.DistanceUnit.KILOMETERS);
 //  
 GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringRedisTemplate.opsForGeo().radius(key, "", distance, geoRadiusCommandArgs);
 assert radius != null;
 radius.getContent().forEach(s -> System.out.println("名前:"+ s.getContent().getName() + "
 経度と緯度:"+ s.getContent().getPoint() + "
 距離:"+ s.getDistance()));
}

印刷結果

 
 緯度と経度:ポイント[x=0, y=3]
 距離:0.0 KILOMETERS
名前:メイチュアン
 経度と緯度:ポイント[x=2, y=0]
 距離:1.3878 KILOMETERS

指定された要素の近くにある他の要素に照会る - オーバーロードされたメソッド

ソースコードの解釈

// 上記の方法の過多
@Nullable
GeoResults<GeoLocation<M>> radius(K key, Circle within, GeoRadiusCommandArgs args);

ケースデモ

/**
 * todo 過負荷メソッド
 * 指定した要素の近くにある他の要素に照会る
 */
@Test
public void test_user_simple_geohash_radius_circle() {
 String key = "location";
 // 距離計で3km先までの企業を正攻法で捕まえろ
 RedisGeoCommands.GeoRadiusCommandArgs geoRadiusCommandArgs = RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
 .sortAscending()//  
 .limit(2)// アウトプット要素の数
 .includeCoordinates()// 緯度と経度を出力する
 .includeDistance();//  
 // カプセル化距離パラメータ
 Distance distance = new Distance(3d, RedisGeoCommands.DistanceUnit.KILOMETERS);
 // 緯度経度パラメータのカプセル化
 Point point = new Point(,4);
 // パッケージ範囲パラメータ
 Circle circle = new Circle(point, distance);
 GeoResults<RedisGeoCommands.GeoLocation<String>> radius = stringRedisTemplate.opsForGeo().radius(key, circle, geoRadiusCommandArgs);
 assert radius != null;
 // 得られた距離は、科学的な表記に戻すことができる。
 radius.getContent().forEach(s -> System.out.println("名前:"+ s.getContent().getName() + "
 経度と緯度:"+ s.getContent().getPoint() + "
 距離:"+ s.getDistance()));
}

印刷結果

 
 緯度と経度:ポイント[x=0, y=3]
 距離:1.0E-4 KILOMETERS
名前:メイチュアン
 緯度と経度:ポイント[x=2, y=0]
 距離:1.3878 KILOMETERS

注目

マッピング・アプリケーションでは、車、レストラン、人に関するデータが何百万、何千万と存在する可能性があり、RedisのGeoデータ構造を使うと、それらはすべてzzetコレクションになる。Redisクラスタ環境では、セットをあるノードから別のノードにマイグレーションすることがあるが、1つのキーのデータ量が大きすぎると、クラスタのマイグレーション作業に大きな影響を与える。クラスタ環境では、1つのキーに対応するデータ量は1Mを超えないようにしないと、クラスタのマイグレーションが遅延する現象につながり、オンラインサービスの正常な運営に影響を与える。
というわけで、Geoのデータはクラスタ化された環境ではなく、Redisの個別のインスタンスを使ってデプロイすることをここでは推奨する。
データ量が数億、あるいはそれ以上になる場合は、国ごと、県ごと、市ごと、あるいは巨大都市の場合は地区ごとに、Geoデータを分割する必要がある。こうすることで、1つのzsetコレクションのサイズを大幅に縮小することができる。

"
  • が私の最大の支えであり、励み
  • です!
Read next

ホウ・イー:矢を射るから、乗ってくれ - MotionLayoutで栄冠王グループバトルを実現する

序文\n昨夜は、いつものように、夕食後、栄光の王のゲームを開き、基本的な焦げの最初と中盤の段階では、勝つために決定の後半波に、私は決定的な矢を撃った、チームメイトの直接電気で、反対側を撃った、ベースを介してグループ戦の波プッシュを獲得。それは素晴らしいです、チームメイトは賞賛を発行され、私はクールポイント

Aug 26, 2020 · 35 min read