golang地理定位数据库与实时地理围栏插件库Tile38的使用

Golang地理定位数据库与实时地理围栏插件库Tile38的使用

Tile38是一个开源(MIT许可)的内存地理定位数据存储、空间索引和实时地理围栏服务器。它支持多种对象类型,包括经纬度点、边界框、XYZ瓦片、Geohash和GeoJSON。

主要特性

  • 支持Nearby、Within和Intersects等搜索方法的空间索引
  • 通过webhooks或pub/sub通道实现实时地理围栏
  • 支持多种对象类型:经纬度点、边界框、Geohash、GeoJSON、QuadKey和XYZ瓦片
  • 支持多种协议:HTTP(使用curl)、WebSockets、Telnet和Redis RESP协议
  • 服务器响应格式为RESP或JSON
  • 完整的命令行界面
  • 主从复制
  • 内存数据库支持持久化到磁盘

安装Tile38

Docker方式

docker pull tile38/tile38
docker run -p 9851:9851 tile38/tile38

Homebrew(macOS)

brew install tile38
tile38-server

Golang客户端示例

以下是使用Go语言操作Tile38的完整示例代码:

package main

import (
	"context"
	"fmt"
	"log"
	"time"

	"github.com/xjem/t38c"
)

func main() {
	// 创建Tile38客户端
	client, err := t38c.New("localhost:9851", t38c.Debug)
	if err != nil {
		log.Fatal(err)
	}
	defer client.Close()

	// 设置一个点对象
	err = client.Keys.Set("fleet", "truck1").Point(33.5123, -112.2693).Do()
	if err != nil {
		log.Fatal(err)
	}

	// 设置带有字段的点对象
	err = client.Keys.Set("fleet", "truck2").
		Point(33.4626, -112.1695).
		Field("speed", 90).
		Field("age", 21).
		Do()
	if err != nil {
		log.Fatal(err)
	}

	// 搜索附近的对象
	searchRes, err := client.Search.Nearby("fleet", 33.462, -112.268, 6000).Do()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("附近6公里内的对象: %+v\n", searchRes)

	// 创建地理围栏
	fenceChan := make(chan t38c.GeofenceEvent)
	go func() {
		err := client.Geofence.Nearby("fleet", 33.462, -112.268, 6000).
			Actions(t38c.Enter, t38c.Exit).
			Do(fenceChan)
		if err != nil {
			log.Fatal(err)
		}
	}()

	// 监听地理围栏事件
	go func() {
		for event := range fenceChan {
			fmt.Printf("地理围栏事件: %+v\n", event)
		}
	}()

	// 更新对象位置以触发地理围栏
	time.Sleep(1 * time.Second)
	err = client.Keys.Set("fleet", "truck1").Point(33.462, -112.268).Do()
	if err != nil {
		log.Fatal(err)
	}

	// 等待一段时间查看结果
	time.Sleep(5 * time.Second)
}

基本操作示例

添加和查询对象

// 添加点对象
err := client.Keys.Set("fleet", "truck1").Point(33.5123, -112.2693).Do()

// 查询对象
getRes, err := client.Keys.Get("fleet", "truck1").Do()

// 扫描集合中的所有对象
scanRes, err := client.Search.Scan("fleet").Do()

地理围栏

// 创建地理围栏通道
fenceChan := make(chan t38c.GeofenceEvent)

// 设置地理围栏
err := client.Geofence.Within("fleet").
    Polygon([][2]float64{{0, 0}, {10, 10}, {10, 0}, {0, 0}}).
    Actions(t38c.Enter, t38c.Exit, t38c.Cross).
    Do(fenceChan)

// 监听围栏事件
go func() {
    for event := range fenceChan {
        switch event.Detect {
        case "enter":
            fmt.Printf("对象 %s 进入区域\n", event.ID)
        case "exit":
            fmt.Printf("对象 %s 离开区域\n", event.ID)
        case "cross":
            fmt.Printf("对象 %s 穿过区域\n", event.ID)
        }
    }
}()

使用字段

// 设置带有字段的对象
err := client.Keys.Set("fleet", "truck1").
    Point(33.5123, -112.2693).
    Field("speed", 90).
    Field("age", 21).
    Do()

// 获取字段值
fgetRes, err := client.Keys.FGet("fleet", "truck1", "speed").Do()

// 使用WHERE条件搜索
searchRes, err := client.Search.Nearby("fleet", 33.462, -112.268, 6000).
    Where("speed", 70, "+inf").
    Do()

对象类型支持

Tile38支持多种地理对象类型:

经纬度点

// 基本点
client.Keys.Set("fleet", "truck1").Point(33.5123, -112.2693).Do()

// 带高程的点
client.Keys.Set("fleet", "truck1").PointZ(33.5123, -112.2693, 225).Do()

边界框

client.Keys.Set("fleet", "truck1").Bounds(30, -110, 40, -100).Do()

GeoJSON

geojson := `{
    "type": "Polygon",
    "coordinates": [[[0,0],[10,10],[10,0],[0,0]]]
}`
client.Keys.Set("city", "tempe").Object(geojson).Do()

高级功能

搜索选项

// 使用WHERE和LIMIT
searchRes, err := client.Search.Within("fleet").
    Circle(33.462, -112.268, 6000).
    Where("speed", 70, "+inf").
    Where("age", "-inf", 24).
    Match("truck*").
    NoFields().
    Limit(10).
    Do()

发布/订阅通道

// 创建通道
err := client.Channels.Set("busstop").
    Nearby("buses").
    Point(33.5123, -112.2693, 200).
    Do()

// 订阅通道
subChan := make(chan t38c.PubSubMessage)
err := client.PubSub.Subscribe("busstop", subChan)

// 监听消息
go func() {
    for msg := range subChan {
        fmt.Printf("收到消息: %+v\n", msg)
    }
}()

性能监控

Tile38支持Prometheus指标:

# 启动服务器并启用Prometheus指标
./tile38-server --metrics-addr=127.0.0.1:4321

# 访问指标
curl http://127.0.0.1:4321/metrics

以上示例展示了如何在Golang中使用Tile38进行地理定位数据存储和实时地理围栏监控。Tile38提供了丰富的功能和灵活的API,非常适合构建需要实时地理位置服务的应用程序。


更多关于golang地理定位数据库与实时地理围栏插件库Tile38的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang地理定位数据库与实时地理围栏插件库Tile38的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang地理定位数据库与Tile38实时地理围栏使用指南

Tile38是一个高性能的地理定位数据库和实时地理围栏引擎,支持多种地理空间数据类型和查询操作。下面我将介绍如何在Golang中使用Tile38。

Tile38简介

Tile38主要特性:

  • 支持点、线、多边形、边界框等地理空间数据类型
  • 提供实时地理围栏功能
  • 支持多种查询:附近搜索、范围内搜索、交叉搜索等
  • 提供HTTP、WebSocket和RESP(Redis协议)接口

安装Tile38客户端库

go get github.com/tidwall/tile38-client

基本使用示例

1. 连接Tile38服务器

package main

import (
	"fmt"
	"github.com/tidwall/tile38-client"
)

func main() {
	// 连接Tile38服务器,默认端口9851
	client, err := tile38.New("localhost:9851")
	if err != nil {
		panic(err)
	}
	defer client.Close()
	
	// 测试连接
	pong, err := client.Ping()
	if err != nil {
		panic(err)
	}
	fmt.Println("Ping response:", pong)
}

2. 存储和查询位置数据

// 存储一个点
func setLocation(client *tile38.Client) error {
	// 设置一个名为"fleet"的集合中的对象"truck1"的位置
	err := client.Set("fleet", "truck1").Point(33.5123, -112.2693).Do()
	if err != nil {
		return err
	}
	fmt.Println("Location set successfully")
	return nil
}

// 查询附近的对象
func nearbySearch(client *tile38.Client) error {
	// 查询距离(33.462, -112.268) 5000米范围内的对象
	objects, err := client.Nearby("fleet").
		Distance().
		Point(33.462, -112.268, 5000).
		Do()
	if err != nil {
		return err
	}

	fmt.Println("Nearby objects:")
	for _, obj := range objects {
		fmt.Printf("ID: %s, Distance: %.2fm, Point: %v\n", 
			obj.ID, obj.Distance, obj.Point)
	}
	return nil
}

3. 实时地理围栏

// 设置地理围栏
func setupGeofence(client *tile38.Client) error {
	// 创建一个WebSocket连接来接收围栏通知
	ws, err := client.Geofence("fence1").
		Within("fleet").
		Circle(33.462, -112.268, 1000).
		Actions(tile38.Enter, tile38.Exit).
		Do()
	if err != nil {
		return err
	}

	// 处理围栏事件
	go func() {
		for {
			msg, err := ws.Receive()
			if err != nil {
				fmt.Println("Geofence error:", err)
				return
			}
			switch msg.Detect {
			case tile38.Enter:
				fmt.Printf("Object %s entered the area at %v\n", msg.ID, msg.Time)
			case tile38.Exit:
				fmt.Printf("Object %s exited the area at %v\n", msg.ID, msg.Time)
			}
		}
	}()

	return nil
}

4. 多边形围栏和复杂查询

// 使用多边形设置地理围栏
func polygonGeofence(client *tile38.Client) error {
	// 定义多边形顶点
	polygon := [][2]float64{
		{33.462, -112.268},
		{33.471, -112.269},
		{33.470, -112.259},
		{33.462, -112.258},
	}

	// 设置多边形围栏
	err := client.Set("areas", "warehouse").Polygon(polygon).Do()
	if err != nil {
		return err
	}

	// 查询在仓库多边形内的车辆
	objects, err := client.Intersects("fleet").
		Get("areas", "warehouse").
		Do()
	if err != nil {
		return err
	}

	fmt.Println("Vehicles in warehouse area:")
	for _, obj := range objects {
		fmt.Printf("ID: %s, Point: %v\n", obj.ID, obj.Point)
	}

	return nil
}

高级功能

1. 使用通道(CHAN)进行发布/订阅

func setupChannel(client *tile38.Client) error {
	// 订阅通道
	ws, err := client.Subscribe("alerts")
	if err != nil {
		return err
	}

	go func() {
		for {
			msg, err := ws.Receive()
			if err != nil {
				fmt.Println("Channel error:", err)
				return
			}
			fmt.Printf("Received alert: %s\n", msg.Message)
		}
	}()

	// 向通道发布消息
	err = client.Publish("alerts", "Truck1 speed exceeded limit")
	if err != nil {
		return err
	}

	return nil
}

2. 使用Hook实现事件触发

func setupHook(client *tile38.Client) error {
	// 设置一个HTTP Hook,当有车辆进入围栏时触发
	err := client.SetHook("speed-alert", "http://your-server/alerts").
		Nearby("fleet").
		Point(33.462, -112.268, 1000).
		Do()
	if err != nil {
		return err
	}

	fmt.Println("Hook set up successfully")
	return nil
}

性能优化建议

  1. 使用连接池管理Tile38连接
  2. 对于大量数据插入,考虑使用Pipeline
  3. 合理设置围栏检测精度(使用DETECT参数)
  4. 对频繁查询的数据建立索引

总结

Tile38为Golang开发者提供了强大的地理空间数据处理能力,特别适合需要实时地理围栏功能的应用程序。通过上述示例,您可以快速上手Tile38的基本功能,并根据项目需求扩展更复杂的地理空间应用。

要了解更多细节,可以参考Tile38官方文档:https://tile38.com/

回到顶部