{"id":13393922,"url":"https://github.com/tidwall/tile38","last_synced_at":"2025-05-12T09:23:51.035Z","repository":{"id":37883631,"uuid":"53171300","full_name":"tidwall/tile38","owner":"tidwall","description":"Real-time Geospatial and Geofencing","archived":false,"fork":false,"pushed_at":"2025-05-08T15:17:30.000Z","size":50479,"stargazers_count":9321,"open_issues_count":151,"forks_count":578,"subscribers_count":207,"default_branch":"master","last_synced_at":"2025-05-12T02:51:54.905Z","etag":null,"topics":["database","geo","geofences","geospatial","index","location","spatial"],"latest_commit_sha":null,"homepage":"https://tile38.com","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tidwall.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-03-04T23:07:44.000Z","updated_at":"2025-05-11T14:35:33.000Z","dependencies_parsed_at":"2023-01-31T09:45:33.392Z","dependency_job_id":"7b75b551-7c4f-4f9a-8cf1-971197a47866","html_url":"https://github.com/tidwall/tile38","commit_stats":{"total_commits":1208,"total_committers":63,"mean_commits":"19.174603174603174","dds":"0.24006622516556286","last_synced_commit":"a3b5db776fdcdfa503cd2e22b4daa0f8a8e1440a"},"previous_names":[],"tags_count":106,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Ftile38","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Ftile38/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Ftile38/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tidwall%2Ftile38/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tidwall","download_url":"https://codeload.github.com/tidwall/tile38/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253708873,"owners_count":21951062,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","geo","geofences","geospatial","index","location","spatial"],"created_at":"2024-07-30T17:01:02.639Z","updated_at":"2025-05-12T09:23:50.974Z","avatar_url":"https://github.com/tidwall.png","language":"Go","readme":"\u003cp align=\"center\"\u003e\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"/.github/images/logo-dark.svg\"\u003e\n  \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"/.github/images/logo-light.svg\"\u003e\n  \u003cimg alt=\"Tile38\" src=\"/.github/images/logo-light.svg\" width=\"284\"\u003e\n\u003c/picture\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n\u003ca href=\"https://tile38.com/slack/\"\u003e\u003cimg src=\"https://img.shields.io/badge/Slack-4A154B?logo=slack\u0026logoColor=fff\" alt=\"Slack\"\u003e\u003c/a\u003e\n\u003ca href=\"https://discord.gg/esq8ESgzms\"\u003e\u003cimg src=\"https://img.shields.io/badge/Discord-%235865F2.svg?\u0026logo=discord\u0026logoColor=white\" alt=\"Discord\"\u003e\u003c/a\u003e\n\u003ca href=\"https://hub.docker.com/r/tile38/tile38\"\u003e\u003cimg src=\"https://img.shields.io/docker/pulls/tile38/tile38.svg\" alt=\"Docker Pulls\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\n\n\nTile38 is an open source (MIT licensed), in-memory geolocation data store, spatial index, and realtime geofencing server.\nIt supports a variety of object types including lat/lon points, bounding boxes, XYZ tiles, Geohashes, and GeoJSON. \n\n\u003cp align=\"center\"\u003e\n\u003ci\u003eThis README is quick start document. You can find detailed documentation at \u003ca href=\"https://tile38.com\"\u003ehttps://tile38.com\u003c/a\u003e.\u003c/i\u003e\u003cbr\u003e\u003cbr\u003e\n\u003ca href=\"#searching\"\u003e\u003cimg src=\"/.github/images/search-nearby.png\" alt=\"Nearby\" border=\"0\" width=\"120\" height=\"120\"\u003e\u003c/a\u003e\n\u003ca href=\"#searching\"\u003e\u003cimg src=\"/.github/images/search-within.png\" alt=\"Within\" border=\"0\" width=\"120\" height=\"120\"\u003e\u003c/a\u003e\n\u003ca href=\"#searching\"\u003e\u003cimg src=\"/.github/images/search-intersects.png\" alt=\"Intersects\" border=\"0\" width=\"120\" height=\"120\"\u003e\u003c/a\u003e\n\u003ca href=\"https://tile38.com/topics/geofencing\"\u003e\u003cimg src=\"/.github/images/geofence.gif\" alt=\"Geofencing\" border=\"0\" width=\"120\" height=\"120\"\u003e\u003c/a\u003e\n\u003ca href=\"https://tile38.com/topics/roaming-geofences\"\u003e\u003cimg src=\"/.github/images/roaming.gif\" alt=\"Roaming Geofences\" border=\"0\" width=\"120\" height=\"120\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n## Features\n\n- Spatial index with [search](#searching) methods such as Nearby, Within, and Intersects.\n- Realtime [geofencing](#geofencing) through [webhooks](https://tile38.com/commands/sethook) or [pub/sub channels](#pubsub-channels).\n- Object types of [lat/lon](#latlon-point), [bbox](#bounding-box), [Geohash](#geohash), [GeoJSON](#geojson), [QuadKey](#quadkey), and [XYZ tile](#xyz-tile).\n- Support for lots of [Clients Libraries](#tile38-client-libraries) written in many different languages.\n- Variety of protocols, including [http](#http) (curl), [websockets](#websockets), [telnet](#telnet), and the [Redis RESP](https://redis.io/topics/protocol).\n- Server responses are [RESP](https://redis.io/topics/protocol) or [JSON](https://www.json.org).\n- Full [command line interface](#cli).\n- Leader / follower [replication](#replication).\n- In-memory database that persists on disk.\n\n## Components\n- tile38-server: The server\n- tile38-cli: Command line interface tool\n- tile38-benchmark: Server benchmark tool\n\n## Getting Started\n\n### Getting Tile38\n\nPerhaps the easiest way to get the latest Tile38 is to use one of the pre-built release binaries which are available for OSX, Linux, FreeBSD, and Windows. Instructions for using these binaries are on the GitHub [releases page](https://github.com/tidwall/tile38/releases).\n\n### Docker \n\nTo run the latest stable version of Tile38:\n\n```\ndocker pull tile38/tile38\ndocker run -p 9851:9851 tile38/tile38\n```\n\nVisit the [Tile38 hub page](https://hub.docker.com/r/tile38/tile38/) for more information.\n\n### Homebrew (macOS)\n\nInstall Tile38 using [Homebrew](https://brew.sh/)\n\n```sh\nbrew install tile38\ntile38-server\n```\n\n### Building Tile38 \n\nTile38 can be compiled and used on Linux, OSX, Windows, FreeBSD, and probably others since the codebase is 100% Go. We support both 32 bit and 64 bit systems. [Go](https://golang.org/dl/) must be installed on the build machine.\n\nTo build everything simply:\n```\n$ make\n```\n\nTo test:\n```\n$ make test\n```\n\n### Running \nFor command line options invoke:\n```\n$ ./tile38-server -h\n```\n\nTo run a single server:\n\n```\n$ ./tile38-server\n\n# The tile38 shell connects to localhost:9851\n$ ./tile38-cli\n\u003e help\n```\n\n#### Prometheus Metrics\nTile38 can natively export Prometheus metrics by setting the `--metrics-addr` command line flag (disabled by default). This example exposes the HTTP metrics server on port 4321:\n```\n# start server and enable Prometheus metrics, listen on local interface only\n./tile38-server --metrics-addr=127.0.0.1:4321\n\n# access metrics\ncurl http://127.0.0.1:4321/metrics\n```\nIf you need to access the `/metrics` endpoint from a different host you'll have to set the flag accordingly, e.g. set it to `0.0.0.0:\u003c\u003cport\u003e\u003e` to listen on all interfaces.\n\nUse the [redis_exporter](https://github.com/oliver006/redis_exporter) for more advanced use cases like extracting key values or running a lua script.\n\n\n## \u003ca name=\"cli\"\u003e\u003c/a\u003ePlaying with Tile38\n\nBasic operations:\n```\n$ ./tile38-cli\n\n# add a couple of points named 'truck1' and 'truck2' to a collection named 'fleet'.\n\u003e set fleet truck1 point 33.5123 -112.2693   # on the Loop 101 in Phoenix\n\u003e set fleet truck2 point 33.4626 -112.1695   # on the I-10 in Phoenix\n\n# search the 'fleet' collection.\n\u003e scan fleet                                 # returns both trucks in 'fleet'\n\u003e nearby fleet point 33.462 -112.268 6000    # search 6 kilometers around a point. returns one truck.\n\n# key value operations\n\u003e get fleet truck1                           # returns 'truck1'\n\u003e del fleet truck2                           # deletes 'truck2'\n\u003e drop fleet                                 # removes all \n```\n\nTile38 has a ton of [great commands](https://tile38.com/commands).\n\n## Fields\nFields are extra data that belongs to an object. A field is always a double precision floating point. There is no limit to the number of fields that an object can have. \n\nTo set a field when setting an object:\n```\n\u003e set fleet truck1 field speed 90 point 33.5123 -112.2693             \n\u003e set fleet truck1 field speed 90 field age 21 point 33.5123 -112.2693\n```\n\nTo set a field when an object already exists:\n```\n\u003e fset fleet truck1 speed 90\n```\n\nTo get a field when an object already exists:\n```\n\u003e fget fleet truck1 speed\n```\n\n## Searching\n\nTile38 has support to search for objects and points that are within or intersects other objects. All object types can be searched including Polygons, MultiPolygons, GeometryCollections, etc.\n\n\u003cimg src=\"/.github/images/search-within.png\" width=\"200\" height=\"200\" border=\"0\" alt=\"Search Within\" align=\"left\"\u003e\n\n#### Within \nWITHIN searches a collection for objects that are fully contained inside a specified bounding area.\n\u003cBR CLEAR=\"ALL\"\u003e\n\n\u003cimg src=\"/.github/images/search-intersects.png\" width=\"200\" height=\"200\" border=\"0\" alt=\"Search Intersects\" align=\"left\"\u003e\n\n#### Intersects\nINTERSECTS searches a collection for objects that intersect a specified bounding area.\n\u003cBR CLEAR=\"ALL\"\u003e\n\n\u003cimg src=\"/.github/images/search-nearby.png\" width=\"200\" height=\"200\" border=\"0\" alt=\"Search Nearby\" align=\"left\"\u003e\n\n#### Nearby\nNEARBY searches a collection for objects that intersect a specified radius.\n\u003cBR CLEAR=\"ALL\"\u003e\n\n### Search options\n**WHERE** - This option allows for filtering out results based on [field](#fields) values. For example\u003cbr\u003e```nearby fleet where speed 70 +inf point 33.462 -112.268 6000``` will return only the objects in the 'fleet' collection that are within the 6 km radius **and** have a field named `speed` that is greater than `70`. \u003cbr\u003e\u003cbr\u003eMultiple WHEREs are concatenated as **and** clauses. ```WHERE speed 70 +inf WHERE age -inf 24``` would be interpreted as *speed is over 70 \u003cb\u003eand\u003c/b\u003e age is less than 24.*\u003cbr\u003e\u003cbr\u003eThe default value for a field is always `0`. Thus if you do a WHERE on the field `speed` and an object does not have that field set, the server will pretend that the object does and that the value is Zero.\n\n**MATCH** - MATCH is similar to WHERE except that it works on the object id instead of fields.\u003cbr\u003e```nearby fleet match truck* point 33.462 -112.268 6000``` will return only the objects in the 'fleet' collection that are within the 6 km radius **and** have an object id that starts with `truck`. There can be multiple MATCH options in a single search. The MATCH value is a simple [glob pattern](https://en.wikipedia.org/wiki/Glob_(programming)).\n\n**CURSOR** - CURSOR is used to iterate though many objects from the search results. An iteration begins when the CURSOR is set to Zero or not included with the request, and completes when the cursor returned by the server is Zero.\n\n**NOFIELDS** - NOFIELDS tells the server that you do not want field values returned with the search results.\n\n**LIMIT** - LIMIT can be used to limit the number of objects returned for a single search request.\n\n\n## Geofencing\n\n\u003cimg src=\"/.github/images/geofence.gif\" width=\"200\" height=\"200\" border=\"0\" alt=\"Geofence animation\" align=\"left\"\u003e\nA \u003ca href=\"https://en.wikipedia.org/wiki/Geo-fence\"\u003egeofence\u003c/a\u003e is a virtual boundary that can detect when an object enters or exits the area. This boundary can be a radius, bounding box, or a polygon. Tile38 can turn any standard search into a geofence monitor by adding the FENCE keyword to the search. \n\n*Tile38 also allows for [Webhooks](https://tile38.com/commands/sethook) to be assigned to Geofences.*\n\n\u003cbr clear=\"all\"\u003e\n\nA simple example:\n```\n\u003e nearby fleet fence point 33.462 -112.268 6000\n```\nThis command opens a geofence that monitors the 'fleet' collection. The server will respond with:\n```\n{\"ok\":true,\"live\":true}\n```\nAnd the connection will be kept open. If any object enters or exits the 6 km radius around `33.462,-112.268` the server will respond in realtime with a message such as:\n\n```\n{\"command\":\"set\",\"detect\":\"enter\",\"id\":\"truck02\",\"object\":{\"type\":\"Point\",\"coordinates\":[-112.2695,33.4626]}}\n```\n\nThe server will notify the client if the `command` is `del | set | drop`. \n\n- `del` notifies the client that an object has been deleted from the collection that is being fenced.\n- `drop` notifies the client that the entire collection is dropped.\n- `set` notifies the client that an object has been added or updated, and when it's position is detected by the fence.\n\nThe `detect` may be one of the following values.\n\n- `inside` is when an object is inside the specified area.\n- `outside` is when an object is outside the specified area.\n- `enter` is when an object that **was not** previously in the fence has entered the area.\n- `exit` is when an object that **was** previously in the fence has exited the area.\n- `cross` is when an object that **was not** previously in the fence has entered **and** exited the area.\n\nThese can be used when establishing a geofence, to pre-filter responses. For instance, to limit responses to `enter` and `exit` detections:\n\n```\n\u003e nearby fleet fence detect enter,exit point 33.462 -112.268 6000\n```\n\n### Pub/sub channels\n\nTile38 supports delivering geofence notifications over pub/sub channels. \n\nTo create a static geofence that sends notifications when a bus is within 200 meters of a point and sends to the `busstop` channel:\n\n```\n\u003e setchan busstop nearby buses fence point 33.5123 -112.2693 200\n```\n\nSubscribe on the `busstop` channel:\n\n```\n\u003e subscribe busstop\n```\n\n## Object types\n\nAll object types except for XYZ Tiles and QuadKeys can be stored in a collection. XYZ Tiles and QuadKeys are reserved for the SEARCH keyword only.\n\n#### Lat/lon point\nThe most basic object type is a point that is composed of a latitude and a longitude. There is an optional `z` member that may be used for auxiliary data such as elevation or a timestamp.\n```\nset fleet truck1 point 33.5123 -112.2693     # plain lat/lon\nset fleet truck1 point 33.5123 -112.2693 225 # lat/lon with z member\n```\n\n#### Bounding box\nA bounding box consists of two points. The first being the southwestern most point and the second is the northeastern most point.\n```\nset fleet truck1 bounds 30 -110 40 -100\n```\n#### Geohash\nA [geohash](https://en.wikipedia.org/wiki/Geohash) is a string representation of a point. With the length of the string indicating the precision of the point. \n```\nset fleet truck1 hash 9tbnthxzr # this would be equivalent to 'point 33.5123 -112.2693'\n```\n\n#### GeoJSON\n[GeoJSON](https://tools.ietf.org/html/rfc7946) is an industry standard format for representing a variety of object types including a point, multipoint, linestring, multilinestring, polygon, multipolygon, geometrycollection, feature, and featurecollection.\n\n\u003ci\u003e* All ignored members will not persist.\u003c/i\u003e\n\n**Important to note that all coordinates are in Longitude, Latitude order.**\n\n```\nset city tempe object {\"type\":\"Polygon\",\"coordinates\":[[[0,0],[10,10],[10,0],[0,0]]]}\n```\n\n#### XYZ Tile\nAn XYZ tile is rectangle bounding area on earth that is represented by an X, Y coordinate and a Z (zoom) level.\nCheck out [maptiler.org](http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/) for an interactive example.\n\n#### QuadKey\nA QuadKey used the same coordinate system as an XYZ tile except that the string representation is a string characters composed of 0, 1, 2, or 3. For a detailed explanation checkout [The Bing Maps Tile System](https://msdn.microsoft.com/en-us/library/bb259689.aspx).\n\n## Network protocols\n\nIt's recommended to use a [client library](#tile38-client-libraries) or the [Tile38 CLI](#running), but there are times when only HTTP is available or when you need to test from a remote terminal. In those cases we provide an HTTP and telnet options.\n\n#### HTTP\nOne of the simplest ways to call a tile38 command is to use HTTP. From the command line you can use [curl](https://curl.haxx.se/). For example:\n\n```\n# call with request in the body\ncurl --data \"set fleet truck3 point 33.4762 -112.10923\" localhost:9851\n\n# call with request in the url path\ncurl localhost:9851/set+fleet+truck3+point+33.4762+-112.10923\n```\n\n#### Websockets\nWebsockets can be used when you need to Geofence and keep the connection alive. It works just like the HTTP example above, with the exception that the connection stays alive and the data is sent from the server as text websocket messages.\n\n#### Telnet\nThere is the option to use a plain telnet connection. The default output through telnet is [RESP](https://redis.io/topics/protocol).\n\n```\ntelnet localhost 9851\nset fleet truck3 point 33.4762 -112.10923\n+OK\n\n```\n\nThe server will respond in [JSON](https://json.org) or [RESP](https://redis.io/topics/protocol) depending on which protocol is used when initiating the first command.\n\n- HTTP and Websockets use JSON. \n- Telnet and RESP clients use RESP.\n\n## Tile38 Client Libraries\n\nThe following clients are built specifically for Tile38.  \nClients that support most Tile38 features are marked with a ⭐️.\n\n- ⭐️ Go: [xjem/t38c](https://github.com/xjem/t38c)\n- ⭐️ Node.js: [node-tile38](https://github.com/phulst/node-tile38) ([example code](https://github.com/tidwall/tile38/wiki/Node.js-example-(node-tile38)))\n- ⭐️ Python: [pyle38](https://github.com/iwpnd/pyle38)\n- ⭐️ TypeScript: [tile38-ts](https://github.com/iwpnd/tile38-ts)\n- Go: [cjkreklow/t38c](https://github.com/cjkreklow/t38c)\n- Python: [pytile38](https://github.com/mitghi/pytile38)\n- Rust: [nazar](https://github.com/younisshah/nazar)\n- Swift: [Talon](https://github.com/mikekinney/Talon)\n- Java: [tile38-client-java](https://github.com/jamshidrostami/tile38-client-java)\n- Java: [tile38-client](https://github.com/HkMoyun/tile38-client)\n\n## Redis Client Libraries\n\nTile38 uses the [Redis RESP](https://redis.io/topics/protocol) protocol natively. \nTherefore most clients that support basic Redis commands will also support Tile38.\n\n- C: [hiredis](https://github.com/redis/hiredis)\n- C#: [StackExchange.Redis](https://github.com/StackExchange/StackExchange.Redis)\n- C++: [redox](https://github.com/hmartiro/redox)\n- Clojure: [carmine](https://github.com/ptaoussanis/carmine)\n- Common Lisp: [CL-Redis](https://github.com/vseloved/cl-redis)\n- Erlang: [Eredis](https://github.com/wooga/eredis)\n- Go: [go-redis](https://github.com/go-redis/redis) ([example code](https://github.com/tidwall/tile38/wiki/Go-example-(go-redis)))\n- Go: [redigo](https://github.com/gomodule/redigo) ([example code](https://github.com/tidwall/tile38/wiki/Go-example-(redigo)))\n- Haskell: [hedis](https://github.com/informatikr/hedis)\n- Java: [lettuce](https://github.com/mp911de/lettuce) ([example code](https://github.com/tidwall/tile38/wiki/Java-example-(lettuce)))\n- Node.js: [node_redis](https://github.com/NodeRedis/node_redis) ([example code](https://github.com/tidwall/tile38/wiki/Node.js-example-(node-redis)))\n- Perl: [perl-redis](https://github.com/PerlRedis/perl-redis)\n- PHP: [tinyredisclient](https://github.com/ptrofimov/tinyredisclient) ([example code](https://github.com/tidwall/tile38/wiki/PHP-example-(tinyredisclient)))\n- PHP: [phpredis](https://github.com/phpredis/phpredis)\n- Python: [redis-py](https://github.com/andymccurdy/redis-py) ([example code](https://github.com/tidwall/tile38/wiki/Python-example))\n- Ruby: [redic](https://github.com/amakawa/redic) ([example code](https://github.com/tidwall/tile38/wiki/Ruby-example-(redic)))\n- Ruby: [redis-rb](https://github.com/redis/redis-rb) ([example code](https://github.com/tidwall/tile38/wiki/Ruby-example-(redis-rb)))\n- Rust: [redis-rs](https://github.com/mitsuhiko/redis-rs)\n- Scala: [scala-redis](https://github.com/debasishg/scala-redis)\n- Swift: [Redbird](https://github.com/czechboy0/Redbird)\n\n## Contact\n\nJosh Baker [@tidwall](https://twitter.com/tidwall)\n\n## License\n\nTile38 source code is available under the MIT [License](/LICENSE).\n","funding_links":[],"categories":["Go","开源类库","Database","Geographic","database","Open source library","Key-value Data Model","Go 程序设计","Spatial Database","地理","位置信息与地理GEO处理库","數據庫","\u003cspan id=\"数据库-database\"\u003e数据库 Database\u003c/span\u003e","Relational Databases","数据库"],"sub_categories":["数据库","Advanced Console UIs","Search and Analytic Databases","Database","网络服务_其他","检索及分析资料库","SQL 查询语句构建库","高級控制台界面","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e","高级控制台界面"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftidwall%2Ftile38","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftidwall%2Ftile38","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftidwall%2Ftile38/lists"}