Статьи

Написание геопространственных запросов для MongoDB на Java

MongoDB поддерживает двухмерные геопространственные индексы . Вы можете посмотреть  презентацию MongoSF (май 2011),  чтобы понять ее на базовом уровне.

В этой статье я помогу вам быстро написать геопространственные запросы, описанные в презентации выше, с использованием языка программирования Java. Я предполагаю, что у вас есть сервер MongoDB и работает на вашей машине. Исходный код этой статьи доступен в этом проекте Github .

Хранилище географических мест

Ниже класса Java хранятся крупные города в Калифорнии, США, в виде массива String. Мы будем использовать этот массив в следующей программе.

public class Places
{
 public static final String[] cities = new String[]

{ "Palos Verdes Estates", "Los Altos Hills", "Hillsborough", "Monte Sereno", "Villa Park", "Palo Alto",
 "Belvedere", "Los Altos", "Rolling Hills", "Montecito", "Piedmont", "Foster City", "Yorba Linda",
 "Mission Canyon", "Saratoga", "Orinda", "Manhattan Beach", "Pleasanton", "Imperial", "Goleta", "Tiburon",
 "Tustin Foothills", "Rancho Palos Verdes", "Mountain View", "La Habra Heights", "Newport Beach",
 "Toro Canyon", "Agoura Hills", "Redondo Beach", "Menlo Park", "Mill Valley", "Indian Wells", "Moraga",
 "Ross", "La Palma", "Kensington", "Hermosa Beach", "Thousand Oaks", "Belmont", "Rolling Hills Estates",
 "Loyola", "Summerland", "Santa Monica", "Rossmoor", "Irvine", "Lafayette", "Laguna Niguel", "Torrance",
 "Fairbanks Ranch", "Cupertino", "Santa Barbara", "Portola Valley", "Woodside", "San Ramon", "Santa Ynez",
 "Emerald Lake Hills", "Angwin", "El Segundo", "Orange", "West Menlo Park", "West Bishop", "Ladera Heights",
 "Huntington Beach", "Atherton", "Coronado", "Danville", "Diamond Bar", "Rancho Santa Fe", "Chino Hills",
 "Clayton", "Walnut", "San Anselmo", "Solvang", "Cerritos", "Blackhawk-Camino Tassajara",
 "Highlands-Baywood Park", "Fountain Valley", "Westlake Village", "Sunnyvale", "Poway", "Del Monte Forest",
 "Brea", "San Carlos", "Los Gatos", "Rancho Santa Margarita", "Camarillo", "Cypress", "Newport Coast",
 "San Joaquin Hills", "Folsom", "Arroyo Grande", "Malibu", "Sausalito", "Del Rio", "Green Valley",
 "Mission Viejo", "Aliso Viejo", "Stanford", "Encinitas", "Rancho Mirage" };
}

Программа геопространственных запросов

Эта программа запускает следующие методы в таком порядке:

1. addPlaces () — добавляет перечисленные выше 100 городов Калифорнии на плоскости 10X10. Данные хранятся в коллекции MongoDB под названием «места».

2. findWithinCircle () — Находит все города в круге, центр которого (5,5) и находится в радиусе 1 единицы (нашей воображаемой плоскости)

3. findWithinBox () — Находит все города в прямоугольнике, образованном между координатами (4,4) и (6,6)

4. FindWithinPolygon () — Находит все города в пределах многоугольника (в данном случае треугольника), образованного из 3 координат.

5. findCenterSphere () — То же, что 2, но запрос имеет сферическую природу.

6. findNear () — Находит все города рядом (4,4) с максимальным расстоянием 2 единицы.

7. findNearSphere () — То же, что и выше, но запрос имеет сферическую природу.

import java.net.UnknownHostException;

import java.util.ArrayList;
import java.util.List;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBAddress;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.MongoException;

/**
 * Example code for Geospatial queries in MongoDB
 * @author amresh.singh
 */
public class GeospatialExample
{
 public static final String dbName = "geospatial";
 public static final String host = "127.0.0.1";
 public static final int port = 27017;
 public static final String collectionName = "places";
 public static final String indexName = "geospatialIdx";

 Mongo mongo;
 DBCollection collection;

 private Mongo getMongo() {
 try
 {
 mongo = new Mongo(new DBAddress(host, port, dbName));
 }
 catch (MongoException e)
 {
 e.printStackTrace();
 }
 catch (UnknownHostException e)
 {
 e.printStackTrace();
 }
 return mongo;
 }

public static void main(String[] args)
{
 new GeospatialExample().runExample();
}

private void runExample()
{
 collection = getMongo().getDB(dbName).getCollection(collectionName);
 collection.ensureIndex(new BasicDBObject("loc", "2d"), indexName);

 addPlaces();
 findWithinCircle();
 findWithinBox();
 findWithinPolygon();
 findCenterSphere();
 findNear();
 findNearSphere();

}

private void findWithinCircle()
{

 System.out.println("findWithinCircle\n----------------------\n");
 List circle = new ArrayList();
 circle.add(new double[] { 5, 5 }); // Centre of circle
 circle.add(1); // Radius
 BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within",
 new BasicDBObject("$center", circle)));

 printOutputs(query);
}

private void findWithinBox()
{
 System.out.println("findWithinBox\n----------------------\n");
 List box = new ArrayList();
 box.add(new double[] { 4, 4 }); //Starting coordinate
 box.add(new double[]{6,6}); // Ending coordinate
 BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within",
 new BasicDBObject("$box", box)));

 printOutputs(query);

}

private void findWithinPolygon()
{
 System.out.println("findWithinPolygon\n----------------------\n");
 List polygon = new ArrayList();
 polygon.add(new double[] { 3, 3 }); //Starting coordinate
 polygon.add(new double[]{8,3}); // Ending coordinate
 polygon.add(new double[]{6,7}); // Ending coordinate
 BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within",
 new BasicDBObject("$polygon", polygon)));

 printOutputs(query);
}

private void findNear() {
 System.out.println("findNear\n----------------------\n");
 BasicDBObject filter = new BasicDBObject("$near", new double[] { 4, 4 });
 filter.put("$maxDistance", 2);

 BasicDBObject query = new BasicDBObject("loc", filter);

 printOutputs(query);
}

private void findNearSphere() {
 System.out.println("findNearSphere\n----------------------\n");
 BasicDBObject filter = new BasicDBObject("$nearSphere", new double[] { 5, 5 });
 filter.put("$maxDistance", 0.06);
 // Radius of the earth: 3959.8728

 BasicDBObject query = new BasicDBObject("loc", filter);
 printOutputs(query);
}

private void findCenterSphere() {
 System.out.println("findCenterSphere\n----------------------\n");
 List circle = new ArrayList();
 circle.add(new double[] { 5, 5 }); // Centre of circle
 circle.add(0.06); // Radius
 BasicDBObject query = new BasicDBObject("loc", new BasicDBObject("$within",
 new BasicDBObject("$centerSphere", circle)));

 printOutputs(query);
}

public void printOutputs(BasicDBObject query)
{
 DBCursor cursor = collection.find(query);
 List<BasicDBList> outputs = new ArrayList<BasicDBList>();
 while (cursor.hasNext())
 {
 DBObject result = cursor.next();
 System.out.println(result.get("name") + "--->" + result.get("loc"));
 outputs.add((BasicDBList) result.get("loc"));
 }

 for (int y = 9; y >= 0; y--)
 {
 String s = "";
 for (int x = 0; x < 10; x++)
 {
 boolean found = false;
 for (BasicDBList obj : outputs)
 {
 double xVal = (Double) obj.get(0);
 double yVal = (Double) obj.get(1);
 if (yVal == y && xVal == x)
 {
 found = true;
 }
 }
 if(found) {
 s = s + " @";
 } else {
 s = s + " +";
 }
 }
 System.out.println(s);
 }
}

private void addPlaces()
{
 System.out.println("Adding places...");
 for (int i = 0; i < 100; i++)
 {
 double x = i % 10;
 double y = Math.floor(i / 10);
 addPlace(collection, Places.cities[i], new double[] { x, y });
 }
 System.out.println("All places added");
 }

 private void addPlace(DBCollection collection, String name, final double[] location)
 {
 final BasicDBObject place = new BasicDBObject();
 place.put("name", name);
 place.put("loc", location);
 collection.insert(place);
}

}

Консоль MongoDB (после запуска программы)

amresh@ubuntu:/usr/local/mongodb-linux-i686-1.8.1/bin$ ./mongo
MongoDB shell version: 1.8.1
connecting to: test
> use geospatial;
switched to db geospatial
> db.places.find();
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb40a"), "name" : "Palos Verdes Estates", "loc" : [ 0, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb40b"), "name" : "Los Altos Hills", "loc" : [ 1, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb40c"), "name" : "Hillsborough", "loc" : [ 2, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb40d"), "name" : "Monte Sereno", "loc" : [ 3, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb40e"), "name" : "Villa Park", "loc" : [ 4, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb40f"), "name" : "Palo Alto", "loc" : [ 5, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb410"), "name" : "Belvedere", "loc" : [ 6, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb411"), "name" : "Los Altos", "loc" : [ 7, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb412"), "name" : "Rolling Hills", "loc" : [ 8, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb413"), "name" : "Montecito", "loc" : [ 9, 0 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb414"), "name" : "Piedmont", "loc" : [ 0, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb415"), "name" : "Foster City", "loc" : [ 1, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb416"), "name" : "Yorba Linda", "loc" : [ 2, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb417"), "name" : "Mission Canyon", "loc" : [ 3, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb418"), "name" : "Saratoga", "loc" : [ 4, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb419"), "name" : "Orinda", "loc" : [ 5, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb41a"), "name" : "Manhattan Beach", "loc" : [ 6, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb41b"), "name" : "Pleasanton", "loc" : [ 7, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb41c"), "name" : "Imperial", "loc" : [ 8, 1 ] }
{ "_id" : ObjectId("50747ebf44ae3dfd6b8eb41d"), "name" : "Goleta", "loc" : [ 9, 1 ] }
has more

Выход программы

Adding places...
All places added
findWithinCircle
----------------------

Emerald Lake Hills--->[ 5.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Emerald Lake Hills--->[ 5.0 , 5.0]
Santa Ynez--->[ 4.0 , 5.0]
Santa Ynez--->[ 4.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Danville--->[ 5.0 , 6.0]
Danville--->[ 5.0 , 6.0]
Angwin--->[ 6.0 , 5.0]
Angwin--->[ 6.0 , 5.0]
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + @ + + + +
 + + + + @ @ @ + + +
 + + + + + @ + + + +
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
findWithinBox
----------------------

Emerald Lake Hills--->[ 5.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Emerald Lake Hills--->[ 5.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Santa Ynez--->[ 4.0 , 5.0]
Santa Ynez--->[ 4.0 , 5.0]
Irvine--->[ 4.0 , 4.0]
Irvine--->[ 4.0 , 4.0]
Coronado--->[ 4.0 , 6.0]
Coronado--->[ 4.0 , 6.0]
Danville--->[ 5.0 , 6.0]
Danville--->[ 5.0 , 6.0]
Laguna Niguel--->[ 6.0 , 4.0]
Laguna Niguel--->[ 6.0 , 4.0]
Angwin--->[ 6.0 , 5.0]
Angwin--->[ 6.0 , 5.0]
Diamond Bar--->[ 6.0 , 6.0]
Diamond Bar--->[ 6.0 , 6.0]
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + @ @ @ + + +
 + + + + @ @ @ + + +
 + + + + @ @ @ + + +
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
findCenterSphere
----------------------

Emerald Lake Hills--->[ 5.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Emerald Lake Hills--->[ 5.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Kensington--->[ 5.0 , 3.0]
Kensington--->[ 5.0 , 3.0]
Santa Ynez--->[ 4.0 , 5.0]
Santa Ynez--->[ 4.0 , 5.0]
San Ramon--->[ 3.0 , 5.0]
San Ramon--->[ 3.0 , 5.0]
Irvine--->[ 4.0 , 4.0]
Irvine--->[ 4.0 , 4.0]
La Palma--->[ 4.0 , 3.0]
La Palma--->[ 4.0 , 3.0]
Rossmoor--->[ 3.0 , 4.0]
Rossmoor--->[ 3.0 , 4.0]
Ross--->[ 3.0 , 3.0]
Ross--->[ 3.0 , 3.0]
Newport Beach--->[ 5.0 , 2.0]
Newport Beach--->[ 5.0 , 2.0]
La Habra Heights--->[ 4.0 , 2.0]
La Habra Heights--->[ 4.0 , 2.0]
Woodside--->[ 2.0 , 5.0]
Woodside--->[ 2.0 , 5.0]
Santa Monica--->[ 2.0 , 4.0]
Santa Monica--->[ 2.0 , 4.0]
Huntington Beach--->[ 2.0 , 6.0]
Huntington Beach--->[ 2.0 , 6.0]
Atherton--->[ 3.0 , 6.0]
Atherton--->[ 3.0 , 6.0]
Cerritos--->[ 3.0 , 7.0]
Cerritos--->[ 3.0 , 7.0]
Coronado--->[ 4.0 , 6.0]
Coronado--->[ 4.0 , 6.0]
Blackhawk-Camino Tassajara--->[ 4.0 , 7.0]
Blackhawk-Camino Tassajara--->[ 4.0 , 7.0]
Rancho Santa Margarita--->[ 4.0 , 8.0]
Rancho Santa Margarita--->[ 4.0 , 8.0]
Danville--->[ 5.0 , 6.0]
Danville--->[ 5.0 , 6.0]
Highlands-Baywood Park--->[ 5.0 , 7.0]
Highlands-Baywood Park--->[ 5.0 , 7.0]
Camarillo--->[ 5.0 , 8.0]
Camarillo--->[ 5.0 , 8.0]
Toro Canyon--->[ 6.0 , 2.0]
Toro Canyon--->[ 6.0 , 2.0]
Hermosa Beach--->[ 6.0 , 3.0]
Hermosa Beach--->[ 6.0 , 3.0]
Laguna Niguel--->[ 6.0 , 4.0]
Laguna Niguel--->[ 6.0 , 4.0]
Thousand Oaks--->[ 7.0 , 3.0]
Thousand Oaks--->[ 7.0 , 3.0]
Torrance--->[ 7.0 , 4.0]
Torrance--->[ 7.0 , 4.0]
Angwin--->[ 6.0 , 5.0]
Angwin--->[ 6.0 , 5.0]
El Segundo--->[ 7.0 , 5.0]
El Segundo--->[ 7.0 , 5.0]
Fairbanks Ranch--->[ 8.0 , 4.0]
Fairbanks Ranch--->[ 8.0 , 4.0]
Orange--->[ 8.0 , 5.0]
Orange--->[ 8.0 , 5.0]
Diamond Bar--->[ 6.0 , 6.0]
Diamond Bar--->[ 6.0 , 6.0]
Fountain Valley--->[ 6.0 , 7.0]
Fountain Valley--->[ 6.0 , 7.0]
Rancho Santa Fe--->[ 7.0 , 6.0]
Rancho Santa Fe--->[ 7.0 , 6.0]
Westlake Village--->[ 7.0 , 7.0]
Westlake Village--->[ 7.0 , 7.0]
Cypress--->[ 6.0 , 8.0]
Cypress--->[ 6.0 , 8.0]
Chino Hills--->[ 8.0 , 6.0]
Chino Hills--->[ 8.0 , 6.0]
 + + + + + + + + + +
 + + + + @ @ @ + + +
 + + + @ @ @ @ @ + +
 + + @ @ @ @ @ @ @ +
 + + @ @ @ @ @ @ @ +
 + + @ @ @ @ @ @ @ +
 + + + @ @ @ @ @ + +
 + + + + @ @ @ + + +
 + + + + + + + + + +
 + + + + + + + + + +
findNear
----------------------

Irvine--->[ 4.0 , 4.0]
Irvine--->[ 4.0 , 4.0]
Santa Ynez--->[ 4.0 , 5.0]
Santa Ynez--->[ 4.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Lafayette--->[ 5.0 , 4.0]
La Palma--->[ 4.0 , 3.0]
La Palma--->[ 4.0 , 3.0]
Rossmoor--->[ 3.0 , 4.0]
Rossmoor--->[ 3.0 , 4.0]
Emerald Lake Hills--->[ 5.0 , 5.0]
Emerald Lake Hills--->[ 5.0 , 5.0]
San Ramon--->[ 3.0 , 5.0]
San Ramon--->[ 3.0 , 5.0]
Kensington--->[ 5.0 , 3.0]
Kensington--->[ 5.0 , 3.0]
Ross--->[ 3.0 , 3.0]
Ross--->[ 3.0 , 3.0]
Santa Monica--->[ 2.0 , 4.0]
Santa Monica--->[ 2.0 , 4.0]
La Habra Heights--->[ 4.0 , 2.0]
La Habra Heights--->[ 4.0 , 2.0]
Coronado--->[ 4.0 , 6.0]
Coronado--->[ 4.0 , 6.0]
Laguna Niguel--->[ 6.0 , 4.0]
Laguna Niguel--->[ 6.0 , 4.0]
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
 + + + + @ + + + + +
 + + + @ @ @ + + + +
 + + @ @ @ @ @ + + +
 + + + @ @ @ + + + +
 + + + + @ + + + + +
 + + + + + + + + + +
 + + + + + + + + + +
findNearSphere
----------------------

Emerald Lake Hills--->[ 5.0 , 5.0]
Emerald Lake Hills--->[ 5.0 , 5.0]
Santa Ynez--->[ 4.0 , 5.0]
Santa Ynez--->[ 4.0 , 5.0]
Angwin--->[ 6.0 , 5.0]
Angwin--->[ 6.0 , 5.0]
Lafayette--->[ 5.0 , 4.0]
Lafayette--->[ 5.0 , 4.0]
Danville--->[ 5.0 , 6.0]
Danville--->[ 5.0 , 6.0]
Coronado--->[ 4.0 , 6.0]
Coronado--->[ 4.0 , 6.0]
Diamond Bar--->[ 6.0 , 6.0]
Diamond Bar--->[ 6.0 , 6.0]
Irvine--->[ 4.0 , 4.0]
Irvine--->[ 4.0 , 4.0]
Laguna Niguel--->[ 6.0 , 4.0]
Laguna Niguel--->[ 6.0 , 4.0]
San Ramon--->[ 3.0 , 5.0]
San Ramon--->[ 3.0 , 5.0]
El Segundo--->[ 7.0 , 5.0]
El Segundo--->[ 7.0 , 5.0]
Kensington--->[ 5.0 , 3.0]
Kensington--->[ 5.0 , 3.0]
Highlands-Baywood Park--->[ 5.0 , 7.0]
Highlands-Baywood Park--->[ 5.0 , 7.0]
Atherton--->[ 3.0 , 6.0]
Atherton--->[ 3.0 , 6.0]
Rancho Santa Fe--->[ 7.0 , 6.0]
Rancho Santa Fe--->[ 7.0 , 6.0]
Rossmoor--->[ 3.0 , 4.0]
Rossmoor--->[ 3.0 , 4.0]
Torrance--->[ 7.0 , 4.0]
Torrance--->[ 7.0 , 4.0]
Blackhawk-Camino Tassajara--->[ 4.0 , 7.0]
Blackhawk-Camino Tassajara--->[ 4.0 , 7.0]
Fountain Valley--->[ 6.0 , 7.0]
Fountain Valley--->[ 6.0 , 7.0]
La Palma--->[ 4.0 , 3.0]
La Palma--->[ 4.0 , 3.0]
Hermosa Beach--->[ 6.0 , 3.0]
Hermosa Beach--->[ 6.0 , 3.0]
Cerritos--->[ 3.0 , 7.0]
Cerritos--->[ 3.0 , 7.0]
Westlake Village--->[ 7.0 , 7.0]
Westlake Village--->[ 7.0 , 7.0]
Ross--->[ 3.0 , 3.0]
Ross--->[ 3.0 , 3.0]
Thousand Oaks--->[ 7.0 , 3.0]
Thousand Oaks--->[ 7.0 , 3.0]
Woodside--->[ 2.0 , 5.0]
Woodside--->[ 2.0 , 5.0]
Orange--->[ 8.0 , 5.0]
Orange--->[ 8.0 , 5.0]
Newport Beach--->[ 5.0 , 2.0]
Newport Beach--->[ 5.0 , 2.0]
Camarillo--->[ 5.0 , 8.0]
Camarillo--->[ 5.0 , 8.0]
Huntington Beach--->[ 2.0 , 6.0]
Huntington Beach--->[ 2.0 , 6.0]
Chino Hills--->[ 8.0 , 6.0]
Chino Hills--->[ 8.0 , 6.0]
Santa Monica--->[ 2.0 , 4.0]
Santa Monica--->[ 2.0 , 4.0]
Fairbanks Ranch--->[ 8.0 , 4.0]
Fairbanks Ranch--->[ 8.0 , 4.0]
Rancho Santa Margarita--->[ 4.0 , 8.0]
Rancho Santa Margarita--->[ 4.0 , 8.0]
Cypress--->[ 6.0 , 8.0]
Cypress--->[ 6.0 , 8.0]
La Habra Heights--->[ 4.0 , 2.0]
La Habra Heights--->[ 4.0 , 2.0]
Toro Canyon--->[ 6.0 , 2.0]
Toro Canyon--->[ 6.0 , 2.0]
 + + + + + + + + + +
 + + + + @ @ @ + + +
 + + + @ @ @ @ @ + +
 + + @ @ @ @ @ @ @ +
 + + @ @ @ @ @ @ @ +
 + + @ @ @ @ @ @ @ +
 + + + @ @ @ @ @ + +
 + + + + @ @ @ + + +
 + + + + + + + + + +
 + + + + + + + + + +