golang高效内存地理空间索引插件库go-geoindex的使用
Golang高效内存地理空间索引插件库go-geoindex的使用
概述
go-geoindex是一个将地球表面划分为网格的地理空间索引库。在每个单元格中可以存储数据,如点列表、点计数等。它支持K最近邻(KNearest)和范围(Range)查询。
示例Demo
下面是一个完整的go-geoindex使用示例:
package main
import (
"fmt"
"github.com/hailocab/go-geoindex"
)
// 定义Driver结构体
type Driver struct {
lat float64
lon float64
id string
canAcceptJobs bool
}
// 实现Point接口
func (d *Driver) Lat() float64 { return d.lat }
func (d *Driver) Lon() float64 { return d.lon }
func (d *Driver) Id() string { return d.id }
func main() {
// 创建点索引,分辨率为0.5公里
index := geoindex.NewPointsIndex(geoindex.Km(0.5))
// 添加点到索引中
index.Add(&Driver{lat: 51.51, lon: -0.08, id: "driver1", canAcceptJobs: true})
index.Add(&Driver{lat: 51.52, lon: -0.07, id: "driver2", canAcceptJobs: false})
index.Add(&Driver{lat: 51.53, lon: -0.09, id: "driver3", canAcceptJobs: true})
// 移除一个点
index.Remove("driver2")
// 查询5公里范围内最近的5个可接单司机
center := &geoindex.GeoPoint{Id: "center", Lat: 51.511, Lon: -0.081}
points := index.KNearest(
center,
5,
geoindex.Km(5),
func(p geoindex.Point) bool {
return p.(*Driver).canAcceptJobs
},
)
// 打印结果
for _, point := range points {
driver := point.(*Driver)
fmt.Printf("找到司机: ID=%s, 纬度=%.3f, 经度=%.3f\n", driver.id, driver.lat, driver.lon)
}
// 范围查询
topLeft := &geoindex.GeoPoint{Lat: 51.515, Lon: -0.085}
bottomRight := &geoindex.GeoPoint{Lat: 51.505, Lon: -0.075}
pointsInRange := index.Range(topLeft, bottomRight)
fmt.Printf("范围内找到%d个点\n", len(pointsInRange))
}
API说明
基本操作
// 创建点索引,分辨率为0.5公里
index := NewPointsIndex(Km(0.5))
// 添加点
index.Add(&Driver{"id1", lat, lng, true})
// 移除点
index.Remove("id1")
// K最近邻查询
points := index.KNearest(&GeoPoint{id, lat, lng}, 5, Km(5), func(p Point) bool {
return p.(*Driver).canAcceptJobs
})
// 范围查询
points := index.Range(topLeftPoint, bottomRightPoint)
索引类型
go-geoindex提供了多种索引类型:
NewPointsIndex(Km(0.5)) // 创建维护点的索引
NewExpiringPointsIndex(Km(0.5), Minutes(5)) // 创建会过期的点索引
NewCountIndex(Km(0.5)) // 创建维护点计数的索引
NewExpiringCountIndex(Km(0.5), Minutes(15)) // 创建会过期的计数索引
NewClusteringIndex() // 创建在不同缩放级别聚类点的索引,用于地图显示
NewExpiringClusteringIndex(Minutes(15)) // 创建会过期并在不同缩放级别聚类的索引
性能基准
以下是go-geoindex的性能基准测试结果:
BenchmarkClusterIndexAdd 500000 5395 ns/op
BenchmarkClusterIndexStreetRange 100000 22207 ns/op
BenchmarkClusterIndexCityRange 100000 16389 ns/op
BenchmarkClusterIndexEuropeRange 50000 36559 ns/op
BenchmarkExpiringClusterIndexAdd 300000 7124 ns/op
BenchmarkExpiringClusterIndexStreetRange 50000 27030 ns/op
BenchmarkExpiringClusterIndexCityRange 100000 22185 ns/op
BenchmarkExpiringClusterIndexEuropeRange 30000 52080 ns/op
BenchmarkCountIndexAdd 1000000 1670 ns/op
BenchmarkCountIndexCityRange 100000 20325 ns/op
BenchmarkExpiringCountIndexAdd 500000 2808 ns/op
BenchmarkExpiringCountIndexRange 50000 35791 ns/op
BenchmarkPointIndexRange 100000 15945 ns/op
BenchmarkPointIndexAdd 1000000 2416 ns/op
BenchmarkPointIndexKNearest 100000 13788 ns/op
BenchmarkExpiringPointIndexAdd 500000 4324 ns/op
BenchmarkExpiringPointIndexKNearest 100000 15638 ns/op
BenchmarkExpiringPointIndexRange 100000 20386 ns/op
这些基准测试展示了go-geoindex在各种操作上的性能表现,包括添加点、范围查询和K最近邻查询等。
更多关于golang高效内存地理空间索引插件库go-geoindex的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang高效内存地理空间索引插件库go-geoindex的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Go-GeoIndex 高效内存地理空间索引库使用指南
Go-GeoIndex 是一个高效的 Golang 内存地理空间索引库,用于快速查询附近的地理位置点。它基于四叉树(QuadTree)实现,适合需要快速地理位置查询的应用场景。
主要特性
- 高效的内存索引结构
- 支持点(point)和矩形(rectangle)索引
- 快速范围查询和最近邻查询
- 线程安全
- 简单易用的API
安装
go get github.com/hailocab/go-geoindex
基本使用示例
1. 创建索引并添加点
package main
import (
"fmt"
"github.com/hailocab/go-geoindex"
)
type Place struct {
id string
lat, lon float64
}
func (p *Place) Lat() float64 { return p.lat }
func (p *Place) Lon() float64 { return p.lon }
func (p *Place) Id() string { return p.id }
func main() {
// 创建索引,参数是每个节点的最大点数(当超过时会分裂)
index := geoindex.NewPointsIndex(geoindex.Km(0.5))
// 添加地点
index.Add(&Place{id: "Eiffel Tower", lat: 48.858370, lon: 2.294481})
index.Add(&Place{id: "Louvre", lat: 48.860611, lon: 2.337644})
index.Add(&Place{id: "Arc de Triomphe", lat: 48.873792, lon: 2.295028})
index.Add(&Place{id: "Notre Dame", lat: 48.852968, lon: 2.349902})
// 查询埃菲尔铁塔附近1公里内的地点
center := &geoindex.GeoPoint{Lon: 2.294481, Lat: 48.858370}
results := index.Range(center, geoindex.Km(1), func(p geoindex.Point) bool {
return p.Id() != "Eiffel Tower" // 排除自身
})
for _, p := range results {
fmt.Printf("附近地点: %s (距离 %.2fkm)\n",
p.Id(),
geoindex.Distance(center, p)/1000)
}
}
2. 查找最近的K个点
// 查找最近的2个地点
nearest := index.KNearest(
&geoindex.GeoPoint{Lon: 2.294481, Lat: 48.858370}, // 中心点
2, // 数量
geoindex.Km(10), // 搜索半径
func(p geoindex.Point) bool { return true }, // 过滤条件
)
for _, p := range nearest {
fmt.Printf("最近地点: %s (距离 %.2fkm)\n",
p.Id(),
geoindex.Distance(center, p)/1000)
}
3. 矩形范围查询
// 定义矩形范围 (minLat, minLon, maxLat, maxLon)
bounds := geoindex.NewBoundingBox(48.85, 2.29, 48.86, 2.34)
withinBounds := index.Inside(bounds)
for _, p := range withinBounds {
fmt.Printf("矩形范围内地点: %s\n", p.Id())
}
性能优化建议
-
节点大小选择:创建索引时选择合适的节点大小(NewPointsIndex参数)。较小的值会提高查询精度但增加内存使用,较大的值则相反。
-
批量添加:如果需要添加大量点,考虑使用批量添加而非单个添加。
-
合理使用过滤函数:Range和KNearest方法都接受过滤函数,可以用于进一步筛选结果。
-
避免频繁重建索引:索引一旦建立,重建成本较高。
实际应用场景
- 查找附近的服务点(餐厅、加油站等)
- 地理围栏(geofencing)应用
- 实时位置服务
- 地理数据分析
注意事项
- 这是一个内存索引库,不适合超大规模数据集(数百万以上)
- 不支持持久化,应用重启后需要重建索引
- 对于需要持久化的场景,可以考虑结合数据库使用
Go-GeoIndex 提供了简单高效的地理位置查询能力,适合需要快速响应的地理位置服务应用。根据你的具体需求,可以灵活运用其提供的各种查询方法。