A high-performance Go library to find the nearest city based on geographical coordinates using the S2 Geometry Library.
- Efficient Nearest City Search: Uses the S2 Geometry Library to provide fast and accurate nearest city searches.
- Low Memory Consumption: Optimized for low memory usage compared to other data structures.
- Easy Integration: Simple API for integrating into your Go projects.
- Support for Postal Codes: Find cities based on postal codes.
The S2 Geometry Library is chosen for its superior performance and efficiency in handling geographical data. It provides:
- Hierarchical Spatial Indexing: Efficiently manages and queries large sets of geographical points.
- High Precision: Ensures accurate results even with large datasets.
- Low Memory Footprint: Uses memory efficiently, making it suitable for applications with limited resources.
In benchmark tests, the S2 Geometry Library outperformed other methods such as R-tree, k-d Tree, and Geohash in both speed and memory consumption. Below is a summary of the performance comparison based on a sample dataset of approximately 12.8 million cities.
- All Countries Dataset: 12,759,551 entries
- Postal Code Dataset: 100,000+ entries (example size)
City | Finder | Time (ms) | Memory (KB) | Nearest City | Latitude | Longitude |
---|---|---|---|---|---|---|
London | k-d Tree | 1 <- Fastest | 648 | Nelson's Column | 51.507770 | -0.127920 |
London | R-tree | 89 | 624 | St Martin-in-the-Fields | 51.508860 | -0.126900 |
London | S2 | 0 <- Lowest | 6 <- Lowest | Edith Cavell Memorial | 51.509390 | -0.127160 |
London | Geohash | 3319 | 238 | Nelson's Column | 51.507770 | -0.127920 |
Tokyo | k-d Tree | 7 | 649 | Tokyo Prefecture | 35.689500 | 139.691710 |
Tokyo | R-tree | 26 | 606 | Tokyo | 35.689500 | 139.691710 |
Tokyo | S2 | 4 <- Lowest | 362 | Tōkyō Tochōsha | 35.689440 | 139.691780 |
Tokyo | Geohash | 2987 | 238 | Tokyo Prefecture | 35.689500 | 139.691710 |
Sydney | k-d Tree | 2 | 454 | Royal Theatre | -33.868000 | 151.209000 |
Sydney | R-tree | 20 | 409 | Medina Grand Harbourside | -33.867600 | 151.209600 |
Sydney | S2 | 0 <- Lowest | 8 <- Lowest | Westin Sydney Heritage Superior | -33.867790 | 151.207750 |
Sydney | Geohash | 3114 | 65 | Royal Theatre | -33.868000 | 151.209000 |
Moscow | k-d Tree | 4 | 682 | Budappest | 55.755790 | 37.617630 |
Moscow | R-tree | 36 | 537 | Bolschoi-Theater | 55.760300 | 37.618600 |
Moscow | S2 | 1 <- Lowest | 5 <- Lowest | Budappest | 55.755790 | 37.617630 |
Moscow | Geohash | 3325 | 238 | Budappest | 55.755790 | 37.617630 |
Chicago | k-d Tree | 2 | 453 | Kluczynski Federal Building | 41.878370 | -87.630050 |
Chicago | S2 | 0 <- Lowest | 10 <- Lowest | HHS Region 5 | 41.877860 | -87.629520 |
Chicago | R-tree | 222 | 629 | Federal Center | 41.878920 | -87.629770 |
Chicago | Geohash | 3167 | 238 | Kluczynski Federal Building | 41.878370 | -87.630050 |
New York | k-d Tree | 2 | 451 | New York City Hall | 40.712600 | -74.005970 |
New York | S2 | 0 <- Lowest | 11 <- Lowest | Vanderlyn's Rotunda (historical) | 40.713160 | -74.004310 |
New York | R-tree | 218 | 651 | Old New York County Courthouse | 40.713440 | -74.005420 |
New York | Geohash | 3326 | 239 | New York City Hall | 40.712600 | -74.005970 |
Paris | k-d Tree | 0 <- Lowest | 644 | Hôtel de Ville de Paris | 48.856440 | 2.352440 |
Paris | S2 | 5 | 8 <- Lowest | Rue de la Coutellerie | 48.857350 | 2.350270 |
Paris | R-tree | 201 | 611 | Rue de la Verrerie | 48.857830 | 2.353350 |
Paris | Geohash | 3176 | 61 | Hôtel de Ville de Paris | 48.856440 | 2.352440 |
Finder | Memory (KB) |
---|---|
S2 | 8,369,107 <- Lowest |
Geohash | 9,130,174 |
k-d Tree | 13,826,040 |
R-tree | 20,418,544 |
The S2 Geometry Library offers the best performance in terms of both speed and memory consumption for finding the nearest city based on geographical coordinates. This makes it the ideal choice for applications that require efficient and accurate spatial queries.
To install the library, use go get
:
go get github.com/SamyRai/nearestcity
To find the nearest city based on latitude and longitude:
package main
import (
"fmt"
"log"
"github.com/SamyRai/cityFinder"
)
func main() {
// Find the nearest city
nearestCity := cityFinder.FindNearestCity(40.7128, -74.0060) // New York coordinates
if nearestCity != nil {
fmt.Printf("Nearest city: %s, %s\n", nearestCity.Name, nearestCity.Country)
} else {
log.Println("No city found")
}
}
To find a city based on postal code:
nearestCity := cityFinder.FindCityByPostalCode("10001") // New York postal code
if nearestCity != nil {
fmt.Printf("Nearest city: %s, %s\n", nearestCity.Name, nearestCity.Country)
} else {
log.Println("No city found")
}
The package also includes a server that provides an API for finding the nearest city and querying cities by name or postal code.
To build the server, use the following command:
go build -o nearestcityserver cmd/server/main.go
To run the server, execute the built binary:
./nearestcityserver
By default, the server will listen on port 3000.
- Find Nearest City:
/nearest?lat=<latitude>&lon=<longitude>
- Find City by Name:
/coordinates?name=<city_name>
- Find City by Postal Code:
/postalcode?postalcode=<postal_code>
Unit tests are included for the library. To run the tests, use the following command:
go test ./cmd/server
This project requires datasets from the GeoNames database. Specifically, you need the allCountries.txt
for city data and zipCodes.txt
for postal code data. These files should be placed in the datasets
folder.
During initialization, the application checks if these datasets and the S2 index are available. If they are not, it downloads and extracts the required datasets and builds the S2 index. This ensures that the necessary data is always available regardless of how the library is used.
The server can be started using the following command:
go run cmd/server/main.go
Contributions are welcome! Please fork the repository and submit pull requests for any improvements or bug fixes.
This project is licensed under the MIT License. See the LICENSE file for details.
- S2 Geometry Library for providing the efficient spatial indexing and search capabilities.
- All contributors and community members for their support and contributions.
- GeoNames for providing the geographical data used in this project.