MongoDB
 sql >> Cơ Sở Dữ Liệu >  >> NoSQL >> MongoDB

Hỗ trợ không gian địa lý trong MongoDB

1. Tổng quan

Trong hướng dẫn này, chúng ta sẽ khám phá hỗ trợ Không gian địa lý trong MongoDB.

Chúng ta sẽ thảo luận về cách lưu trữ dữ liệu không gian địa lý, lập chỉ mục địa lý và tìm kiếm không gian địa lý. Chúng tôi cũng sẽ sử dụng nhiều truy vấn tìm kiếm theo không gian địa lý như gần , geoWithin geoIntersects .

2. Lưu trữ dữ liệu không gian địa lý

Trước tiên, hãy xem cách lưu trữ dữ liệu không gian địa lý trong MongoDB.

MongoDB hỗ trợ nhiều GeoJSON các loại để lưu trữ dữ liệu không gian địa lý. Trong suốt các ví dụ của chúng tôi, chúng tôi sẽ chủ yếu sử dụng Point Đa giác các loại.

2.1. Điểm

Đây là GeoJSON cơ bản và phổ biến nhất và nó được sử dụng để đại diện cho một điểm cụ thể trên lưới .

Ở đây, chúng ta có một đối tượng đơn giản, ở vị trí của chúng ta bộ sưu tập , có trường vị trí như một Điểm :

{
  "name": "Big Ben",
  "location": {
    "coordinates": [-0.1268194, 51.5007292],
    "type": "Point"
  }
}

Lưu ý rằng giá trị kinh độ đứng trước, sau đó đến vĩ độ.

2.2. Đa giác

Đa giác phức tạp hơn một chút GeoJSON loại.

Chúng tôi có thể sử dụng Đa giác để xác định một khu vực có đường viền bên ngoài của nó và cả các lỗ bên trong nếu cần.

Hãy xem một đối tượng khác có vị trí của nó được xác định là một Đa giác :

{
  "name": "Hyde Park",
  "location": {
    "coordinates": [
      [
        [-0.159381, 51.513126],
        [-0.189615, 51.509928],
        [-0.187373, 51.502442],
        [-0.153019, 51.503464],
        [-0.159381, 51.513126]
      ]
    ],
    "type": "Polygon"
  }
}

Trong ví dụ này, chúng tôi đã xác định một mảng các điểm đại diện cho các giới hạn bên ngoài. Chúng ta cũng phải đóng giới hạn sao cho điểm cuối cùng bằng điểm đầu tiên.

Lưu ý rằng chúng ta cần xác định các điểm giới hạn bên ngoài theo hướng ngược chiều kim đồng hồ và giới hạn lỗ theo hướng kim đồng hồ.

Ngoài những loại này, cũng có nhiều loại khác như LineString, MultiPoint, MultiPolygon, MultiLineString, GeometryCollection.

3. Lập chỉ mục không gian địa lý

Để thực hiện các truy vấn tìm kiếm trên dữ liệu không gian địa lý mà chúng tôi đã lưu trữ, chúng tôi cần tạo chỉ mục không gian địa lý trên vị trí của chúng tôi trường.

Về cơ bản, chúng tôi có hai tùy chọn: 2d 2dsphere .

Nhưng trước tiên, hãy xác định địa điểm của chúng ta c ollection :

MongoClient mongoClient = new MongoClient();
MongoDatabase db = mongoClient.getDatabase("myMongoDb");
collection = db.getCollection("places");

3.1. 2ngày Chỉ mục không gian địa lý

2d chỉ mục cho phép chúng tôi thực hiện các truy vấn tìm kiếm hoạt động dựa trên tính toán mặt phẳng 2d.

Chúng tôi có thể tạo một 2d lập chỉ mục trên vị trí trong ứng dụng Java của chúng tôi như sau:

collection.createIndex(Indexes.geo2d("location"));

Tất nhiên, chúng ta có thể làm tương tự trong mongo vỏ:

db.places.createIndex({location:"2d"})

3.2. 2dsphere Chỉ mục không gian địa lý

2dsphere chỉ mục hỗ trợ các truy vấn hoạt động dựa trên tính toán hình cầu.

Tương tự, chúng ta có thể tạo 2dsphere lập chỉ mục trong Java bằng cách sử dụng cùng một Chỉ mục lớp như trên:

collection.createIndex(Indexes.geo2dsphere("location"));

Hoặc trong mongo vỏ:

db.places.createIndex({location:"2dsphere"})

4. Tìm kiếm bằng Truy vấn không gian địa lý

Bây giờ, đến phần thú vị, chúng ta hãy tìm kiếm các đối tượng dựa trên vị trí của chúng bằng cách sử dụng các truy vấn không gian địa lý.

4.1. Truy vấn gần

Hãy bắt đầu với gần. Chúng tôi có thể sử dụng gần truy vấn để tìm kiếm các địa điểm trong một khoảng cách nhất định.

Các gần truy vấn hoạt động với cả 2d 2dsphere chỉ số .

Trong ví dụ tiếp theo, chúng tôi sẽ tìm kiếm các địa điểm cách vị trí đã cho dưới 1 km và hơn 10 mét:

@Test
public void givenNearbyLocation_whenSearchNearby_thenFound() {
    Point currentLoc = new Point(new Position(-0.126821, 51.495885));
 
    FindIterable<Document> result = collection.find(
      Filters.near("location", currentLoc, 1000.0, 10.0));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Và truy vấn tương ứng trong mongo vỏ:

db.places.find({
  location: {
    $near: {
      $geometry: {
        type: "Point",
        coordinates: [-0.126821, 51.495885]
      },
      $maxDistance: 1000,
      $minDistance: 10
    }
  }
})

Lưu ý rằng các kết quả được sắp xếp từ gần nhất đến xa nhất.

Tương tự, nếu chúng tôi sử dụng một vị trí rất xa, chúng tôi sẽ không tìm thấy bất kỳ địa điểm nào gần đó:

@Test
public void givenFarLocation_whenSearchNearby_thenNotFound() {
    Point currentLoc = new Point(new Position(-0.5243333, 51.4700223));
 
    FindIterable<Document> result = collection.find(
      Filters.near("location", currentLoc, 5000.0, 10.0));

    assertNull(result.first());
}

Chúng tôi cũng có nearSphere , hoạt động chính xác như gần, ngoại trừ nó tính toán khoảng cách bằng hình học hình cầu.

4.2. Trong Truy vấn

Tiếp theo, chúng ta sẽ khám phá geoWithin truy vấn.

geoWithin truy vấn cho phép chúng tôi tìm kiếm các địa điểm hoàn toàn tồn tại trong một Hình học nhất định , như hình tròn, hộp hoặc đa giác. Điều này cũng hoạt động với cả 2d 2dsphere chỉ số.

Trong ví dụ này, chúng tôi đang tìm kiếm các địa điểm tồn tại trong bán kính 5 km từ vị trí trung tâm nhất định:

@Test
public void givenNearbyLocation_whenSearchWithinCircleSphere_thenFound() {
    double distanceInRad = 5.0 / 6371;
 
    FindIterable<Document> result = collection.find(
      Filters.geoWithinCenterSphere("location", -0.1435083, 51.4990956, distanceInRad));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Lưu ý rằng chúng ta cần chuyển đổi khoảng cách từ km sang radian (chỉ cần chia cho bán kính Trái đất).

Và truy vấn kết quả:

db.places.find({
  location: {
    $geoWithin: {
      $centerSphere: [
        [-0.1435083, 51.4990956],
        0.0007848061528802386
      ]
    }
  }
})

Tiếp theo, chúng tôi sẽ tìm kiếm tất cả các địa điểm tồn tại trong một “hộp” hình chữ nhật. Chúng ta cần xác định hộp theo vị trí phía dưới bên trái và vị trí phía trên bên phải:

@Test
public void givenNearbyLocation_whenSearchWithinBox_thenFound() {
    double lowerLeftX = -0.1427638;
    double lowerLeftY = 51.4991288;
    double upperRightX = -0.1256209;
    double upperRightY = 51.5030272;

    FindIterable<Document> result = collection.find(
      Filters.geoWithinBox("location", lowerLeftX, lowerLeftY, upperRightX, upperRightY));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Đây là truy vấn tương ứng trong mongo vỏ:

db.places.find({
  location: {
    $geoWithin: {
      $box: [
        [-0.1427638, 51.4991288],
        [-0.1256209, 51.5030272]
      ]
    }
  }
})

Cuối cùng, nếu khu vực chúng tôi muốn tìm kiếm bên trong không phải là hình chữ nhật hoặc hình tròn, chúng tôi có thể sử dụng đa giác để xác định một khu vực cụ thể hơn :

@Test
public void givenNearbyLocation_whenSearchWithinPolygon_thenFound() {
    ArrayList<List<Double>> points = new ArrayList<List<Double>>();
    points.add(Arrays.asList(-0.1439, 51.4952));
    points.add(Arrays.asList(-0.1121, 51.4989));
    points.add(Arrays.asList(-0.13, 51.5163));
    points.add(Arrays.asList(-0.1439, 51.4952));
 
    FindIterable<Document> result = collection.find(
      Filters.geoWithinPolygon("location", points));

    assertNotNull(result.first());
    assertEquals("Big Ben", result.first().get("name"));
}

Và đây là truy vấn tương ứng:

db.places.find({
  location: {
    $geoWithin: {
      $polygon: [
        [-0.1439, 51.4952],
        [-0.1121, 51.4989],
        [-0.13, 51.5163],
        [-0.1439, 51.4952]
      ]
    }
  }
})

Chúng tôi chỉ xác định một đa giác với các giới hạn bên ngoài của nó, nhưng chúng tôi cũng có thể thêm các lỗ vào nó. Mỗi lỗ sẽ là một Danh sách trong tổng số Point s:

geoWithinPolygon("location", points, hole1, hole2, ...)

4.3. Truy vấn Intersect

Cuối cùng, hãy xem xét geoIntersects truy vấn.

geoIntersects truy vấn tìm các đối tượng ít nhất giao nhau với một Hình học nhất định. Để so sánh, geoWithin tìm các đối tượng tồn tại đầy đủ trong một Hình học nhất định .

Truy vấn này hoạt động với 2dsphere chỉ mục.

Hãy xem điều này trong thực tế, với một ví dụ về tìm kiếm bất kỳ địa điểm nào giao với Đa giác :

@Test
public void givenNearbyLocation_whenSearchUsingIntersect_thenFound() {
    ArrayList<Position> positions = new ArrayList<Position>();
    positions.add(new Position(-0.1439, 51.4952));
    positions.add(new Position(-0.1346, 51.4978));
    positions.add(new Position(-0.2177, 51.5135));
    positions.add(new Position(-0.1439, 51.4952));
    Polygon geometry = new Polygon(positions);
 
    FindIterable<Document> result = collection.find(
      Filters.geoIntersects("location", geometry));

    assertNotNull(result.first());
    assertEquals("Hyde Park", result.first().get("name"));
}

Truy vấn kết quả:

db.places.find({
  location:{
    $geoIntersects:{
      $geometry:{
        type:"Polygon",
          coordinates:[
          [
            [-0.1439, 51.4952],
            [-0.1346, 51.4978],
            [-0.2177, 51.5135],
            [-0.1439, 51.4952]
          ]
        ]
      }
    }
  }
})

  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Meteor và DBRefs

  2. MongoDB Regex, Chỉ mục &Hiệu suất

  3. Tạo khu vực quản trị trong năm phút với AdminBro, express, mongoDB, mongoose

  4. Làm thế nào để lắng nghe các thay đổi đối với bộ sưu tập MongoDB?

  5. MongoDB $ radiansToDegrees