Top Related Projects
Expression language and expression evaluation for Go
The high-performance database for modern applications
CockroachDB — the cloud native, distributed SQL database designed for high availability, effortless scale, and control over data placement.
Distributed reliable key-value store for the most critical data of a distributed system
Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps.
Distributed PostgreSQL as an extension
Quick Overview
Tile38 is a geospatial database and real-time geofencing server. It provides a powerful spatial index for fast searches and real-time location-based notifications. Tile38 supports various object types, including lat/lon points, bounding boxes, XYZ tiles, Geohashes, and GeoJSON.
Pros
- High performance and low latency for geospatial queries
- Supports real-time geofencing and notifications
- Provides a simple HTTP API and several client libraries
- Can be used as a standalone server or embedded into existing applications
Cons
- Limited documentation for advanced use cases
- Smaller community compared to more established databases
- Lacks some features found in full-fledged relational databases
- May require additional infrastructure for high availability setups
Code Examples
- Setting a point:
client.Set("fleet", "truck1", tile38.Point{X: -112.2693, Y: 33.5123})
- Searching within a radius:
results, err := client.Nearby("fleet", tile38.Circle{
Lat: 33.5123,
Lon: -112.2693,
Meters: 5000,
})
- Creating a geofence:
fence, err := client.Fence("fleet", tile38.Within(tile38.Circle{
Lat: 33.5123,
Lon: -112.2693,
Meters: 5000,
}))
for event := range fence {
fmt.Printf("Object %s entered the geofence\n", event.ID)
}
Getting Started
-
Install Tile38:
docker run -p 9851:9851 tile38/tile38
-
Connect to Tile38 using a client library (Go example):
import "github.com/tidwall/tile38/client" tile38Client := client.New("localhost:9851")
-
Set a point and perform a search:
tile38Client.Set("fleet", "truck1", tile38.Point{X: -112.2693, Y: 33.5123}) results, err := tile38Client.Nearby("fleet", tile38.Circle{ Lat: 33.5123, Lon: -112.2693, Meters: 5000, })
Competitor Comparisons
Expression language and expression evaluation for Go
Pros of expr
- Lightweight and focused on expression evaluation
- Easily embeddable in Go applications
- Supports a wide range of operators and functions
Cons of expr
- Limited to expression evaluation, not a full-featured database
- Lacks geospatial indexing and querying capabilities
- No built-in persistence or data storage mechanisms
Code Comparison
expr:
env := map[string]interface{}{
"foo": 1,
"bar": 2,
}
program, err := expr.Compile("foo + bar", expr.Env(env))
output, err := expr.Run(program, env)
Tile38:
conn, err := redis.Dial("tcp", "localhost:9851")
defer conn.Close()
conn.Do("SET", "fleet", "truck1", "POINT", 33.5123, -112.2693)
conn.Do("NEARBY", "fleet", "POINT", 33.5124, -112.2694, 100)
Key Differences
- expr is focused on expression evaluation within Go applications
- Tile38 is a geospatial database and real-time geofencing server
- expr is more suitable for in-memory calculations and logic
- Tile38 excels in location-based queries and spatial data management
Use Cases
expr:
- Evaluating dynamic expressions in Go applications
- Implementing rule engines or decision-making systems
Tile38:
- Real-time vehicle tracking and geofencing
- Location-based searches and proximity alerts
- Spatial data analysis and visualization
The high-performance database for modern applications
Pros of Dgraph
- Supports GraphQL natively, offering a more intuitive query language for complex relationships
- Designed for horizontal scalability, making it suitable for large-scale distributed systems
- Provides ACID transactions, ensuring data consistency in multi-node setups
Cons of Dgraph
- Higher learning curve due to its GraphQL-based query language and distributed architecture
- More resource-intensive, requiring more computational power and memory for optimal performance
- Less specialized for geospatial operations compared to Tile38's focused approach
Code Comparison
Dgraph query example:
{
user(func: eq(name, "Alice")) {
name
age
friends {
name
}
}
}
Tile38 query example:
NEARBY fleet POINT 33.462 -112.268 6000
Summary
Dgraph is a distributed graph database with native GraphQL support, offering powerful querying capabilities for complex relationships and scalability for large datasets. It provides ACID transactions but has a steeper learning curve.
Tile38 is a geospatial database and real-time geofencing server, specialized in location-based queries and operations. It's lighter and easier to set up but lacks the advanced relationship modeling of Dgraph.
Choose Dgraph for complex data relationships and large-scale distributed systems, or Tile38 for focused geospatial applications with simpler data models.
CockroachDB — the cloud native, distributed SQL database designed for high availability, effortless scale, and control over data placement.
Pros of CockroachDB
- Highly scalable distributed SQL database with strong consistency
- Built-in support for multi-region deployments and geo-partitioning
- ACID-compliant transactions with serializable isolation
Cons of CockroachDB
- Higher resource requirements and complexity compared to Tile38
- Steeper learning curve for setup and management
- May be overkill for simpler geospatial use cases
Code Comparison
CockroachDB (SQL-based):
CREATE TABLE locations (
id UUID PRIMARY KEY,
name STRING,
position GEOGRAPHY
);
INSERT INTO locations VALUES (
gen_random_uuid(), 'Point A', ST_GeogFromText('POINT(-122.4194 37.7749)')
);
Tile38 (Redis-like commands):
SET fleet truck1 POINT 33.5123 -112.2693
NEARBY fleet POINT 33.5124 -112.2694 100
Summary
CockroachDB is a full-featured distributed SQL database with strong consistency and geo-distribution capabilities, while Tile38 is a lightweight geospatial database and real-time geofencing server. CockroachDB offers more comprehensive features but requires more resources and setup complexity. Tile38 provides simpler, focused geospatial functionality with lower overhead, making it suitable for specific location-based applications.
Distributed reliable key-value store for the most critical data of a distributed system
Pros of etcd
- Mature and widely adopted distributed key-value store
- Strong consistency and high availability through Raft consensus algorithm
- Extensive documentation and community support
Cons of etcd
- Limited geospatial functionality compared to Tile38
- Higher resource consumption for small-scale deployments
- Steeper learning curve for newcomers
Code Comparison
etcd (Go):
cli, _ := clientv3.New(clientv3.Config{Endpoints: []string{"localhost:2379"}})
defer cli.Close()
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
_, err := cli.Put(ctx, "key", "value")
cancel()
Tile38 (Go):
conn, _ := redis.Dial("tcp", "localhost:9851")
defer conn.Close()
_, err := conn.Do("SET", "fleet", "truck1", "POINT", 33.5123, -112.2693)
Summary
etcd is a robust distributed key-value store with strong consistency guarantees, while Tile38 specializes in geospatial and real-time location tracking. etcd offers broader application in distributed systems, whereas Tile38 excels in location-based services. The choice between them depends on specific project requirements, with etcd being more suitable for general-purpose distributed storage and Tile38 for geospatial-focused applications.
Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps.
Pros of Redis
- Mature and widely adopted in-memory data store with extensive ecosystem
- Supports a broader range of data structures and operations
- Highly optimized for performance and scalability
Cons of Redis
- Lacks built-in geospatial indexing and querying capabilities
- More complex setup and configuration for specialized use cases
- Larger memory footprint for certain operations
Code Comparison
Redis:
GEOADD cities 13.361389 38.115556 "Palermo"
GEORADIUS cities 15 37 100 km
Tile38:
SET fleet truck1 POINT 33.5123 -112.2693
NEARBY fleet POINT 33.5124 -112.2694 100
Summary
Redis is a versatile in-memory data store with broad functionality, while Tile38 specializes in geospatial data and real-time location tracking. Redis offers more general-purpose features, but Tile38 excels in geospatial operations with simpler syntax. Redis has a larger community and ecosystem, whereas Tile38 provides more focused and efficient geospatial capabilities out of the box. The choice between them depends on specific project requirements and the importance of geospatial functionality.
Distributed PostgreSQL as an extension
Pros of Citus
- Built on PostgreSQL, offering full SQL support and compatibility with existing PostgreSQL tools and extensions
- Designed for horizontal scalability, allowing distribution of data and queries across multiple nodes
- Supports real-time analytics on large datasets with parallel query execution
Cons of Citus
- Requires more complex setup and configuration compared to Tile38's simpler architecture
- May have higher resource requirements for smaller datasets or simpler geospatial operations
- Learning curve for optimizing distributed queries and data sharding strategies
Code Comparison
Tile38 (Geofencing example):
NEARBY fleet FENCE POINT 33.462 -112.268 6000
Citus (Distributed table creation):
SELECT create_distributed_table('users', 'id');
Key Differences
Tile38 is a specialized geospatial database with built-in real-time geofencing capabilities, while Citus is an extension that transforms PostgreSQL into a distributed database system. Tile38 excels in location-based operations and real-time tracking, whereas Citus focuses on horizontal scalability for large-scale data processing and analytics across various domains.
Tile38 offers simpler setup and usage for geospatial applications, while Citus provides more flexibility and SQL capabilities for complex data operations beyond just geospatial use cases.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
Tile38 is an open source (MIT licensed), in-memory geolocation data store, spatial index, and realtime geofencing server. It supports a variety of object types including lat/lon points, bounding boxes, XYZ tiles, Geohashes, and GeoJSON.
This README is quick start document. You can find detailed documentation at https://tile38.com.
Features
- Spatial index with search methods such as Nearby, Within, and Intersects.
- Realtime geofencing through webhooks or pub/sub channels.
- Object types of lat/lon, bbox, Geohash, GeoJSON, QuadKey, and XYZ tile.
- Support for lots of Clients Libraries written in many different languages.
- Variety of protocols, including http (curl), websockets, telnet, and the Redis RESP.
- Server responses are RESP or JSON.
- Full command line interface.
- Leader / follower replication.
- In-memory database that persists on disk.
Components
- tile38-server: The server
- tile38-cli: Command line interface tool
- tile38-benchmark: Server benchmark tool
Getting Started
Getting Tile38
Perhaps 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.
Docker
To run the latest stable version of Tile38:
docker pull tile38/tile38
docker run -p 9851:9851 tile38/tile38
Visit the Tile38 hub page for more information.
Homebrew (macOS)
Install Tile38 using Homebrew
brew install tile38
tile38-server
Building Tile38
Tile38 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 must be installed on the build machine.
To build everything simply:
$ make
To test:
$ make test
Running
For command line options invoke:
$ ./tile38-server -h
To run a single server:
$ ./tile38-server
# The tile38 shell connects to localhost:9851
$ ./tile38-cli
> help
Prometheus Metrics
Tile38 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:
# start server and enable Prometheus metrics, listen on local interface only
./tile38-server --metrics-addr=127.0.0.1:4321
# access metrics
curl http://127.0.0.1:4321/metrics
If 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:<<port>>
to listen on all interfaces.
Use the redis_exporter for more advanced use cases like extracting key values or running a lua script.
Playing with Tile38
Basic operations:
$ ./tile38-cli
# add a couple of points named 'truck1' and 'truck2' to a collection named 'fleet'.
> set fleet truck1 point 33.5123 -112.2693 # on the Loop 101 in Phoenix
> set fleet truck2 point 33.4626 -112.1695 # on the I-10 in Phoenix
# search the 'fleet' collection.
> scan fleet # returns both trucks in 'fleet'
> nearby fleet point 33.462 -112.268 6000 # search 6 kilometers around a point. returns one truck.
# key value operations
> get fleet truck1 # returns 'truck1'
> del fleet truck2 # deletes 'truck2'
> drop fleet # removes all
Tile38 has a ton of great commands.
Fields
Fields 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.
To set a field when setting an object:
> set fleet truck1 field speed 90 point 33.5123 -112.2693
> set fleet truck1 field speed 90 field age 21 point 33.5123 -112.2693
To set a field when an object already exists:
> fset fleet truck1 speed 90
To get a field when an object already exists:
> fget fleet truck1 speed
Searching
Tile38 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.
Within
WITHIN searches a collection for objects that are fully contained inside a specified bounding area.
Intersects
INTERSECTS searches a collection for objects that intersect a specified bounding area.
Nearby
NEARBY searches a collection for objects that intersect a specified radius.
Search options
WHERE - This option allows for filtering out results based on field values. For examplenearby 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
.
Multiple WHEREs are concatenated as and clauses. WHERE speed 70 +inf WHERE age -inf 24
would be interpreted as speed is over 70 and age is less than 24.
The 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.
MATCH - MATCH is similar to WHERE except that it works on the object id instead of fields.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.
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.
NOFIELDS - NOFIELDS tells the server that you do not want field values returned with the search results.
LIMIT - LIMIT can be used to limit the number of objects returned for a single search request.
Geofencing
A geofence 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.Tile38 also allows for Webhooks to be assigned to Geofences.
A simple example:
> nearby fleet fence point 33.462 -112.268 6000
This command opens a geofence that monitors the 'fleet' collection. The server will respond with:
{"ok":true,"live":true}
And 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:
{"command":"set","detect":"enter","id":"truck02","object":{"type":"Point","coordinates":[-112.2695,33.4626]}}
The server will notify the client if the command
is del | set | drop
.
del
notifies the client that an object has been deleted from the collection that is being fenced.drop
notifies the client that the entire collection is dropped.set
notifies the client that an object has been added or updated, and when it's position is detected by the fence.
The detect
may be one of the following values.
inside
is when an object is inside the specified area.outside
is when an object is outside the specified area.enter
is when an object that was not previously in the fence has entered the area.exit
is when an object that was previously in the fence has exited the area.cross
is when an object that was not previously in the fence has entered and exited the area.
These can be used when establishing a geofence, to pre-filter responses. For instance, to limit responses to enter
and exit
detections:
> nearby fleet fence detect enter,exit point 33.462 -112.268 6000
Pub/sub channels
Tile38 supports delivering geofence notifications over pub/sub channels.
To create a static geofence that sends notifications when a bus is within 200 meters of a point and sends to the busstop
channel:
> setchan busstop nearby buses fence point 33.5123 -112.2693 200
Subscribe on the busstop
channel:
> subscribe busstop
Object types
All 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.
Lat/lon point
The 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.
set fleet truck1 point 33.5123 -112.2693 # plain lat/lon
set fleet truck1 point 33.5123 -112.2693 225 # lat/lon with z member
Bounding box
A bounding box consists of two points. The first being the southwestern most point and the second is the northeastern most point.
set fleet truck1 bounds 30 -110 40 -100
Geohash
A geohash is a string representation of a point. With the length of the string indicating the precision of the point.
set fleet truck1 hash 9tbnthxzr # this would be equivalent to 'point 33.5123 -112.2693'
GeoJSON
GeoJSON is an industry standard format for representing a variety of object types including a point, multipoint, linestring, multilinestring, polygon, multipolygon, geometrycollection, feature, and featurecollection.
* All ignored members will not persist.
Important to note that all coordinates are in Longitude, Latitude order.
set city tempe object {"type":"Polygon","coordinates":[[[0,0],[10,10],[10,0],[0,0]]]}
XYZ Tile
An XYZ tile is rectangle bounding area on earth that is represented by an X, Y coordinate and a Z (zoom) level. Check out maptiler.org for an interactive example.
QuadKey
A 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.
Network protocols
It's recommended to use a client library or the Tile38 CLI, 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.
HTTP
One of the simplest ways to call a tile38 command is to use HTTP. From the command line you can use curl. For example:
# call with request in the body
curl --data "set fleet truck3 point 33.4762 -112.10923" localhost:9851
# call with request in the url path
curl localhost:9851/set+fleet+truck3+point+33.4762+-112.10923
Websockets
Websockets 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.
Telnet
There is the option to use a plain telnet connection. The default output through telnet is RESP.
telnet localhost 9851
set fleet truck3 point 33.4762 -112.10923
+OK
The server will respond in JSON or RESP depending on which protocol is used when initiating the first command.
- HTTP and Websockets use JSON.
- Telnet and RESP clients use RESP.
Tile38 Client Libraries
The following clients are built specifically for Tile38.
Clients that support most Tile38 features are marked with a âï¸.
- âï¸ Go: xjem/t38c
- âï¸ Node.js: node-tile38 (example code)
- âï¸ Python: pyle38
- âï¸ TypeScript: tile38-ts
- Go: cjkreklow/t38c
- Python: pytile38
- Rust: nazar
- Swift: Talon
- Java: tile38-client-java
- Java: tile38-client
Redis Client Libraries
Tile38 uses the Redis RESP protocol natively. Therefore most clients that support basic Redis commands will also support Tile38.
- C: hiredis
- C#: StackExchange.Redis
- C++: redox
- Clojure: carmine
- Common Lisp: CL-Redis
- Erlang: Eredis
- Go: go-redis (example code)
- Go: redigo (example code)
- Haskell: hedis
- Java: lettuce (example code)
- Node.js: node_redis (example code)
- Perl: perl-redis
- PHP: tinyredisclient (example code)
- PHP: phpredis
- Python: redis-py (example code)
- Ruby: redic (example code)
- Ruby: redis-rb (example code)
- Rust: redis-rs
- Scala: scala-redis
- Swift: Redbird
Contact
Josh Baker @tidwall
License
Tile38 source code is available under the MIT License.
Top Related Projects
Expression language and expression evaluation for Go
The high-performance database for modern applications
CockroachDB — the cloud native, distributed SQL database designed for high availability, effortless scale, and control over data placement.
Distributed reliable key-value store for the most critical data of a distributed system
Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, Streams, HyperLogLogs, Bitmaps.
Distributed PostgreSQL as an extension
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot