How to store GPS coordinate and search places in a

2019-03-20 08:46发布

问题:

My team needs a DBMS like DynamoDB to store large amount of data, principally places and coordinates. I've considered to use some GIS-based DBMS (like PostGIS) with an index on the POINT, but DynamoDB seems great for our use.

What is the best method to store the coordinate and quickly retrieve all objects in a particular radius?

In PostGIS it's easy, something like this:

SELECT *
FROM places
WHERE ST_DWithin(coordinate, ST_GeomFromText('POINT(45.07085 7.68434)', 4326), 100.0);

How can I do something like that in a NoSQL DBMS?

回答1:

We had the same issue, we're using AWS and DynamoDB in particular. We solved that problem by using CloudSearch Service, every time we store some 'geo-searchable' data in our database we index the data in a CloudSearch instance with lat,lon as filters ( to do this you have to do a transformation on lat and lon to turn it into a uint ).

Then let's say you want to do a search on a particular lat/lon and radius you compute the corresponding geobox ( latmin, latmax , lonmin, lonmax ) and query your CloudSearch instance with the specific filters to retrieve the key schema of your data, you can then query DynamoDB to get the information.

Some code in Java to do just the above :

Using RectangularWindows from the com.javadocmd.simplelatlng.window package by Tyler Coles, computing the bounding box and doing the transformation for lat / lon .

RectangularWindow rectangularWindow = new RectangularWindow(newLatLng(location.getLat().doubleValue(), location.getLon().doubleValue()), radius.doubleValue(), radius.doubleValue(), LengthUnit.KILOMETER);
latMin = (long) ((180 + rectangularWindow.getMinLatitude()) * 100000);     
latMax = (long) ((180 + rectangularWindow.getMaxLatitude()) * 100000);
lonMin = (long) ((360 + rectangularWindow.getLeftLongitude()) * 100000);
lonMax = (long) ((360 + rectangularWindow.getRightLongitude()) * 100000);

Then an example of a query on the CloudSearch instance :

http://[SEARCHURL]/2011-02-01/search?bq=(and lat:22300347..22309340 (and lon:28379282..28391589))

I'm not sure it's the best solution but that's what we came up with



回答2:

You could use geohashing to do queries of nearby objects based on strings rather than calculations.

Geohash will allow you store the location of nodes into "buckets" which can then be queried by using strings as a range or hash key in dynamodb.

Here is a good example https://github.com/davetroy/geohash-js done in javascript which can easily be rewritten in other languages.



回答3:

I'm currently researching this subject myself. I'm using MongoDb (I know you asked for DynamoDb, but you also asked for general NoSql usage) and my code looks like this:

record structure:

public class FrameDocument
{
    [BsonId]
    public Guid Id { get; set; }

    [BsonElement("coordinates")]
    public Point[] Polygon { get; set; }
}

public class Point
{
    [BsonElement("name")]
    public string Orientation { get; set; }

    [BsonElement("loc")]
    public double[] Location { get; set; }
}

connecting and ensuring index:

MongoServer server = MongoServer.Create(connectionString);
MongoDatabase database = server.GetDatabase(databaseName);
database.GetCollection(collectionName).EnsureIndex(IndexKeys.GeoSpatial("coordinates.loc"));

writing:

var items = database.GetCollection(collectionName);
items.InsertBatch(itemsToInsert);

searching:

double[,] points; // define you search coordinates
var items = database.GetCollection<FrameDocument>(collectionName);
var query = Query.WithinPolygon("coordinates.loc", points);
var cursor = items.Find(query);