Redis 地理空间
提示
来自deepseek解释
原文链接:https://redis.io/docs/latest/develop/data-types/geospatial/
代码示例图例
下面的代码示例展示了如何在不同编程语言和客户端库中执行相同的操作:
- Redis CLI:Redis 命令行界面
- C#(同步):StackExchange.Redis 同步客户端
- C#(异步):StackExchange.Redis 异步客户端
- Go:go-redis 客户端
- Java(同步 - Jedis):Jedis 同步客户端
- Java(异步 - Lettuce):Lettuce 异步客户端
- Java(响应式 - Lettuce):Lettuce 响应式/流式客户端
- JavaScript(Node.js):node-redis 客户端
- PHP:Predis 客户端
- Python:redis-py 客户端
- Rust(同步):redis-rs 同步客户端
- Rust(异步):redis-rs 异步客户端
每个代码示例都演示了不同语言中相同的基本操作。具体语法和模式因语言和客户端库而异,但底层的 Redis 命令和行为保持一致。
地理空间命令摘要
本组共 10 条命令:
| 命令 | 摘要 | 复杂度 | 起始版本 |
|---|---|---|---|
| GEOADD | 向地理空间索引中添加一个或多个成员。如果键不存在则创建它。 | 每添加一个元素为 O(log(N)),其中 N 是索引中的元素数量... | 3.2.0 |
| GEODIST | 返回地理空间索引中两个成员之间的距离。 | O(1) | 3.2.0 |
| GEOHASH | 以 geohash 字符串形式返回地理空间索引中的成员。 | 每个请求的成员为 O(1)。 | 3.2.0 |
| GEOPOS | 返回地理空间索引中成员的经度和纬度。 | 每个请求的成员为 O(1)。 | 3.2.0 |
| GEORADIUS | 查询地理空间索引中距离坐标一定范围内的成员,并可选择存储结果。 | O(N+log(M)),其中 N 是边界框/半径区域内元素的数量... | 3.2.0 |
| GEORADIUS_RO | 返回地理空间索引中距离坐标一定范围内的成员。 | O(N+log(M)),其中 N 是边界框/半径区域内元素的数量... | 3.2.10 |
| GEORADIUSBYMEMBER | 查询地理空间索引中距离成员一定范围内的成员,并可选择存储结果。 | O(N+log(M)),其中 N 是边界框/半径区域内元素的数量... | 3.2.0 |
| GEORADIUSBYMEMBER_RO | 返回地理空间索引中距离成员一定范围内的成员。 | O(N+log(M)),其中 N 是边界框/半径区域内元素的数量... | 3.2.10 |
| GEOSEARCH | 查询地理空间索引中位于盒子或圆形区域内的成员。 | O(N+log(M)),其中 N 是边界框/半径区域内元素的数量... | 6.2.0 |
| GEOSEARCHSTORE | 查询地理空间索引中位于盒子或圆形区域内的成员,并可选择存储结果。 | O(N+log(M)),其中 N 是边界框/半径区域内元素的数量... | 6.2.0 |
Redis 地理空间索引允许您存储坐标并进行搜索。此数据结构对于在给定半径或边界框内查找附近点非常有用。
注意不要将地理空间数据类型与 Redis Search 中的地理空间功能混淆。尽管这两个功能有一些相似之处,但数据类型用于更简单的用例,并且没有 Redis Search 中可用的格式选项和查询范围。
示例
假设您正在构建一个移动应用程序,让您找到离当前位置最近的自行车租赁站。
将几个位置添加到地理空间索引中:
基础:使用 GEOADD 将地理坐标添加到地理空间索引中以存储位置数据
命令: GEOADD
复杂度:
- GEOADD: O(log(N))
可用客户端: Redis CLI, C#, Go, Java (同步 - Jedis), JavaScript (Node.js), Python
Redis CLI
> GEOADD bikes:rentable -122.27652 37.805186 station:1
(integer) 1
> GEOADD bikes:rentable -122.2674626 37.8062344 station:2
(integer) 1
> GEOADD bikes:rentable -122.2469854 37.8104049 station:3
(integer) 1C#
csharp
bool res1 = db.GeoAdd("bikes:rentable", -122.27652, 37.805186, "station:1");
Console.WriteLine(res1); // >>> True
bool res2 = db.GeoAdd("bikes:rentable", -122.2674626, 37.8062344, "station:2");
Console.WriteLine(res2); // >>> True
bool res3 = db.GeoAdd("bikes:rentable", -122.2469854, 37.8104049, "station:3");
Console.WriteLine(res3); // >>> TrueGo
go
res1, err := rdb.GeoAdd(ctx, "bikes:rentable",
&redis.GeoLocation{
Longitude: -122.27652,
Latitude: 37.805186,
Name: "station:1",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res1) // >>> 1
res2, err := rdb.GeoAdd(ctx, "bikes:rentable",
&redis.GeoLocation{
Longitude: -122.2674626,
Latitude: 37.8062344,
Name: "station:2",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res2) // >>> 1
res3, err := rdb.GeoAdd(ctx, "bikes:rentable",
&redis.GeoLocation{
Longitude: -122.2469854,
Latitude: 37.8104049,
Name: "station:3",
}).Result()
if err != nil {
panic(err)
}
fmt.Println(res3) // >>> 1Java(同步 - Jedis)
java
long res1 = jedis.geoadd("bikes:rentable", -122.27652, 37.805186, "station:1");
System.out.println(res1); // 1
long res2 = jedis.geoadd("bikes:rentable", -122.2674626, 37.8062344, "station:2");
System.out.println(res2); // 1
long res3 = jedis.geoadd("bikes:rentable", -122.2469854, 37.8104049, "station:3");
System.out.println(res2); // 1JavaScript(Node.js)
javascript
const res1 = await client.geoAdd('bikes:rentable', {
longitude: -122.27652,
latitude: 37.805186,
member: 'station:1'
});
console.log(res1) // 1
const res2 = await client.geoAdd('bikes:rentable', {
longitude: -122.2674626,
latitude: 37.8062344,
member: 'station:2'
});
console.log(res2) // 1
const res3 = await client.geoAdd('bikes:rentable', {
longitude: -122.2469854,
latitude: 37.8104049,
member: 'station:3'
})
console.log(res3) // 1Python
python
res1 = r.geoadd("bikes:rentable", [-122.27652, 37.805186, "station:1"])
print(res1) # >>> 1
res2 = r.geoadd("bikes:rentable", [-122.2674626, 37.8062344, "station:2"])
print(res2) # >>> 1
res3 = r.geoadd("bikes:rentable", [-122.2469854, 37.8104049, "station:3"])
print(res3) # >>> 1查找给定位置 5 公里半径内的所有位置,并返回到每个位置的距离:
邻近搜索:当需要发现附近点时,使用 GEOSEARCH 在半径或边界框内查找位置
难度: 中级
构建基础: geoadd
命令: GEOSEARCH
复杂度:
- GEOSEARCH: O(N+log(M))
可用客户端: Redis CLI, C#, Go, Java (同步 - Jedis), JavaScript (Node.js), Python
Redis CLI
> GEOSEARCH bikes:rentable FROMLONLAT -122.2612767 37.7936847 BYRADIUS 5 km WITHDIST
1) 1) "station:1"
2) "1.8523"
2) 1) "station:2"
2) "1.4979"
3) 1) "station:3"
2) "2.2441"C#
csharp
GeoRadiusResult[] res4 = db.GeoSearch("bikes:rentable",
-122.27652,
37.805186,
new GeoSearchCircle(5, GeoUnit.Kilometers)
);
foreach (GeoRadiusResult member in res4)
{
Console.WriteLine($"Member: '{member.Member}', distance: {member.Distance}, position: {member.Position}");
}
// >>> Member: 'station:1', distance: 0.0001, position: -122.27652043104172 37.80518485897756
// >>> Member: 'station:2', distance: 0.8047, position: -122.26745992898941 37.80623423353753
// >>> Member: 'station:3', distance: 2.6596, position: -122.24698394536972 37.81040384984464Go
go
res4, err := rdb.GeoSearch(ctx, "bikes:rentable",
&redis.GeoSearchQuery{
Longitude: -122.27652,
Latitude: 37.805186,
Radius: 5,
RadiusUnit: "km",
},
).Result()
if err != nil {
panic(err)
}
fmt.Println(res4) // >>> [station:1 station:2 station:3]Java(同步 - Jedis)
java
List<GeoRadiusResponse> res4 = jedis.geosearch(
"bikes:rentable",
new GeoCoordinate(-122.27652, 37.805186),
5,
GeoUnit.KM
);
List<String> members = res4.stream() //
.map(GeoRadiusResponse::getMemberByString) //
.collect(Collectors.toList());
System.out.println(members); // [station:1, station:2, station:3]JavaScript(Node.js)
javascript
const res4 = await client.geoSearch(
'bikes:rentable', {
longitude: -122.27652,
latitude: 37.805186,
},
{ radius: 5,
unit: 'km'
}
);
console.log(res4) // ['station:1', 'station:2', 'station:3']Python
python
res4 = r.geosearch(
"bikes:rentable",
longitude=-122.27652,
latitude=37.805186,
radius=5,
unit="km",
)
print(res4) # >>> ['station:1', 'station:2', 'station:3']了解更多
- Redis Geospatial Explained 通过展示如何构建本地公园景点地图来介绍地理空间索引。
- Redis University 的 RU101 详细介绍了 Redis 地理空间索引。