1
0
Fork 0
arangodb/Documentation/Books/Users/IndexHandling/Geo.mdpp

269 lines
11 KiB
Plaintext

!CHAPTER Geo Indexes
!SUBSECTION Introduction to Geo Indexes
This is an introduction to ArangoDB's geo indexes.
ArangoDB uses Hilbert curves to implement geo-spatial indexes.
See this [blog](https://www.arangodb.com/2012/03/31/using-hilbert-curves-and-polyhedrons-for-geo-indexing)
for details.
A geo-spatial index assumes that the latitude is between -90 and 90 degree and
the longitude is between -180 and 180 degree. A geo index will ignore all
documents which do not fulfill these requirements.
!SECTION Accessing Geo Indexes from the Shell
`collection.ensureGeoIndex(location)`
Creates a geo-spatial index on all documents using *location* as path
to the coordinates. The value of the attribute must be an array with at
least two numeric values. The array must contain the latitude (first value)
and the longitude (second value).
All documents, which do not have the attribute path or have a non-conforming
value in it are excluded from the index.
A geo index is implicitly sparse, and there is no way to control its sparsity.
In case that the index was successfully created, the index identifier is returned.
`collection.ensureGeoIndex(location, true)`
As above which the exception, that the order within the array is longitude followed
by latitude. This corresponds to the format described in
http://geojson.org/geojson-spec.html
`collection.ensureGeoIndex(latitude, longitude)`
Creates a geo-spatial index on all documents using *latitude* and *longitude* as paths
to the latitude and the longitude. The values of the attributes *latitude* and
*longitude* must be numeric. All documents, which do not have the attribute paths or
have non-conforming values in the index attributes are excluded from the index.
In case that the index was successfully created, the index identifier is returned.
*Examples*
Create an geo index for an array attribute:
```
arangosh> db.geo.ensureGeoIndex("loc");
{ "id" : "geo/47772301", "type" : "geo1", "geoJson" : false, "fields" : ["loc"], "isNewlyCreated" : true }
arangosh> for (i = -90; i <= 90; i += 10) {
for (j = -180; j <= 180; j += 10) {
db.geo.save({ name : "Name/" + i + "/" + j, loc: [ i, j ] });
}
}
arangosh> db.geo.count();
703
arangosh> db.geo.near(0, 0).limit(3).toArray();
[
{ "_id" : "geo/24861164", "_key" : "24861164", "_rev" : "24861164", "name" : "Name/0/0", "loc" : [ 0, 0 ] },
{ "_id" : "geo/24926700", "_key" : "24926700", "_rev" : "24926700", "name" : "Name/0/10", "loc" : [ 0, 10 ] },
{ "_id" : "geo/22436332", "_key" : "22436332", "_rev" : "22436332", "name" : "Name/-10/0", "loc" : [ -10, 0 ] }
]
arangosh> db.geo.near(0, 0).count();
100
```
Create a geo index for a hash array attribute:
```
arangosh> db.geo2.ensureGeoIndex("location.latitude", "location.longitude");
{ "id" : "geo2/1070652", "type" : "geo2", "fields" : ["location.latitude", "location.longitude"], "isNewlyCreated" : true }
arangosh> for (i = -90; i <= 90; i += 10) {
for (j = -180; j <= 180; j += 10) {
db.geo2.save({ name : "Name/" + i + "/" + j, location: { latitude : i, longitude : j } });
}
}
arangosh> db.geo2.near(0, 0).limit(3).toArray();
[
{
"_id" : "geo2/72964588",
"_key" : "72964588",
"_rev" : "72964588",
"location" : { "latitude" : 0, "longitude" : 0 },
"name" : "Name/0/0"
},
{
"_id" : "geo2/73030124",
"_key" : "73030124",
"_rev" : "73030124",
"location" : { "latitude" : 0, "longitude" : 10 },
"name" : "Name/0/10"
},
{
"_id" : "geo2/70539756",
"_key" : "70539756",
"_rev" : "70539756",
"location" : { "latitude" : -10, "longitude" : 0 },
"name" : "Name/-10/0"
}
]
```
`collection.geo(location-attribute)`
Looks up a geo index defined on attribute *location-attribute*.
Returns a geo index object if an index was found. The `near` or `within` operators
can then be used to execute a geo-spatial query on this particular index.
This is useful for collections with multiple defined geo indexes.
`collection.geo(location-attribute, true)`
Looks up a geo index on a compound attribute *location-attribute*.
Returns a geo index object if an index was found. The `near` or `within` operators
can then be used to execute a geo-spatial query on this particular index.
`collection.geo(latitude-attribute, longitude-attribute)`
Looks up a geo index defined on the two attributes *latitude-attribute*
and *longitude-attribute*.
Returns a geo index object if an index was found. The `near` or `within` operators
can then be used to execute a geo-spatial query on this particular index.
*Examples*
Assume you have a location stored as array in the attribute *home* and a destination
stored in the attribute *work*. Then you can use the `geo` operator to select which
geo-spatial attributes (and thus which index) to use in a `near` query.
```
arangosh> for (i = -90; i <= 90; i += 10) {
for (j = -180; j <= 180; j += 10) {
db.complex.save({ name : "Name/" + i + "/" + j, home : [ i, j ], work : [ -i, -j ] });
}
}
arangosh> db.complex.near(0, 170).limit(5);
exception in file '/simple-query' at 1018,5: a geo-index must be known
arangosh> db.complex.ensureGeoIndex(""home"");
arangosh> db.complex.near(0, 170).limit(5).toArray();
[
{ "_id" : "complex/74655276", "_key" : "74655276", "_rev" : "74655276", "name" : "Name/0/170", "home" : [ 0, 170 ], "work" : [ 0, -170 ] },
{ "_id" : "complex/74720812", "_key" : "74720812", "_rev" : "74720812", "name" : "Name/0/180", "home" : [ 0, 180 ], "work" : [ 0, -180 ] },
{ "_id" : "complex/77080108", "_key" : "77080108", "_rev" : "77080108", "name" : "Name/10/170", "home" : [ 10, 170 ], "work" : [ -10, -170 ] },
{ "_id" : "complex/72230444", "_key" : "72230444", "_rev" : "72230444", "name" : "Name/-10/170", "home" : [ -10, 170 ], "work" : [ 10, -170 ] },
{ "_id" : "complex/72361516", "_key" : "72361516", "_rev" : "72361516", "name" : "Name/0/-180", "home" : [ 0, -180 ], "work" : [ 0, 180 ] }
]
arangosh> db.complex.geo("work").near(0, 170).limit(5);
exception in file '/simple-query' at 1018,5: a geo-index must be known
arangosh> db.complex.ensureGeoIndex("work");
arangosh> db.complex.geo("work").near(0, 170).limit(5).toArray();
[
{ "_id" : "complex/72427052", "_key" : "72427052", "_rev" : "72427052", "name" : "Name/0/-170", "home" : [ 0, -170 ], "work" : [ 0, 170 ] },
{ "_id" : "complex/72361516", "_key" : "72361516", "_rev" : "72361516", "name" : "Name/0/-180", "home" : [ 0, -180 ], "work" : [ 0, 180 ] },
{ "_id" : "complex/70002220", "_key" : "70002220", "_rev" : "70002220", "name" : "Name/-10/-170", "home" : [ -10, -170 ], "work" : [ 10, 170 ] },
{ "_id" : "complex/74851884", "_key" : "74851884", "_rev" : "74851884", "name" : "Name/10/-170", "home" : [ 10, -170 ], "work" : [ -10, 170 ] },
{ "_id" : "complex/74720812", "_key" : "74720812", "_rev" : "74720812", "name" : "Name/0/180", "home" : [ 0, 180 ], "work" : [ 0, -180 ] }
]
```
`collection.near(latitude, longitude)`
The returned array is sorted according to the distance, with the nearest
document to the coordinate *(latitude, longitude)* coming first. If there
are near documents of equal distance, documents are chosen randomly from
this set until the limit is reached. It is possible to change the limit
using the `limit` operator.
In order to use the `near` operator, a geo index must be defined for the collection.
This index also defines which attribute holds the coordinates for the document.
If you have more then one geo-spatial index, you can use the `geo` operator to select
a particular index.
*Note*: `near` does not support negative skips. However, you can still use
`limit` followed to skip.
`collection.near(latitude, longitude).limit(limit)`
Limits the result to `limit` documents instead of the default 100.
*Note*: unlike with multiple explicit limits, `limit` will raise the implicit default
limit imposed by within.
`collection.near(latitude, longitude).distance()`
This will add an attribute named `distance` to all documents returned, which contains
the distance between the given point and the document in meters.
`collection.near(latitude, longitude).distance(name)`
This will add an attribute named `name` to all documents returned, which contains the
distance between the given point and the document in meters.
*Examples*
To get the nearest two locations:
```
arangosh> db.geo.near(0, 0).limit(2).toArray();
[
{ "_id" : "geo/24773376", "_key" : "24773376", "_rev" : "24773376", "name" : "Name/0/0", "loc" : [ 0, 0 ] },
{ "_id" : "geo/22348544", "_key" : "22348544", "_rev" : "22348544", "name" : "Name/-10/0", "loc" : [ -10, 0 ] }
]
```
If you need the distance as well, then you can use the `distance` operator:
```
arangosh> db.geo.near(0, 0).distance().limit(2).toArray();
[
{ "_id" : geo/24773376", "_key" : "24773376", "_rev" : "24773376", "distance" : 0, "name" : "Name/0/0", "loc" : [ 0, 0 ] },
{ "_id" : geo/22348544", "_key" : "22348544", "_rev" : "22348544", "distance" : 1111949.3, "name" : "Name/-10/0", "loc" : [ -10, 0 ] }
]
```
`collection.within(latitude, longitude, radius)`
This will find all documents within a given radius around the coordinate *(latitude, longitude)*.
The returned array is sorted by distance, beginning with the nearest document.
In order to use the `within` operator, a geo index must be defined for the collection.
This index also defines which attribute holds the coordinates for the document.
If you have more then one geo-spatial index, you can use the `geo` operator to select a particular index.
`collection.within(latitude, longitude, radius).distance()`
This will add an attribute named `distance` to all documents returned, which contains the
distance between the given point and the document in meters.
`collection.within(latitude, longitude, radius).distance(name)`
This will add an attribute named `name` to all documents returned, which contains the
distance between the given point and the document in meters.
*Examples*
To find all documents within a radius of 2000 km use:
```
arangosh> db.geo.within(0, 0, 2000 * 1000).distance().toArray();
[
{ "_id" : "geo/24773376", "_key" : "24773376", "_rev" : "24773376", "distance" : 0, "name" : "Name/0/0", "loc" : [ 0, 0 ] },
{ "_id" : "geo/24707840", "_key" : "24707840", "_rev" : "24707840", "distance" : 1111949.3, "name" : "Name/0/-10", "loc" : [ 0, -10 ] },
{ "_id" : "geo/24838912", "_key" : "24838912", "_rev" : "24838912", "distance" : 1111949.3, "name" : "Name/0/10", "loc" : [ 0, 10 ] },
{ "_id" : "geo/22348544", "_key" : "22348544", "_rev" : "22348544", "distance" : 1111949.3, "name" : "Name/-10/0", "loc" : [ -10, 0 ] },
{ "_id" : "geo/27198208", "_key" : "27198208", "_rev" : "27198208", "distance" : 1111949.3, "name" : "Name/10/0", "loc" : [ 10, 0 ] },
{ "_id" : "geo/22414080", "_key" : "22414080", "_rev" : "22414080", "distance" : 1568520.6, "name" : "Name/-10/10", "loc" : [ -10, 10 ] },
{ "_id" : "geo/27263744", "_key" : "27263744", "_rev" : "27263744", "distance" : 1568520.6, "name" : "Name/10/10", "loc" : [ 10, 10 ] },
{ "_id" : "geo/22283008", "_key" : "22283008", "_rev" : "22283008", "distance" : 1568520.6, "name" : "Name/-10/-10", "loc" : [ -10, -10 ] },
{ "_id" : "geo/27132672", "_key" : "27132672", "_rev" : "27132672", "distance" : 1568520.6, "name" : "Name/10/-10", "loc" : [ 10, -10 ] }
]
```