sql >> データベース >  >> NoSQL >> MongoDB

MongoDBでの地理空間サポート

    1。概要

    このチュートリアルでは、MongoDBでの地理空間サポートについて説明します。

    地理空間データ、地理インデックス、および地理空間検索を保存する方法について説明します。 nearのような複数の地理空間検索クエリも使用します 、 geoWithin 、および geoIntersects

    2。地理空間データの保存

    まず、地理空間データをMongoDBに保存する方法を見てみましょう。

    MongoDBは複数のGeoJSONをサポートしています 地理空間データを保存するタイプ。 例全体を通して、主にポイントを使用します。 およびポリゴン タイプ。

    2.1。 ポイント

    これは最も基本的で一般的なGeoJSON タイプし、グリッド上の1つの特定のポイントを表すために使用されます

    ここでは、場所に単純なオブジェクトがあります コレクション フィールドlocation ポイントとして :

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

    経度の値が最初に来て、次に緯度が来ることに注意してください。

    2.2。 ポリゴン

    ポリゴン もう少し複雑ですGeoJSON タイプ。

    Polygonを使用できます 外側の境界線で領域を定義するには 必要に応じて内部の穴もあります。

    場所がポリゴンとして定義されている別のオブジェクトを見てみましょう。 :

    {
      "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"
      }
    }

    この例では、外部境界を表す点の配列を定義しました。また、最後のポイントが最初のポイントと等しくなるように、境界を閉じる必要があります。

    反時計回りの方向に外部境界点を定義し、時計回りの方向に穴の境界を定義する必要があることに注意してください。

    これらのタイプに加えて、 LineString、のような他の多くのタイプもあります。 MultiPoint、 MultiPolygon、 MultiLineString、 およびGeometryCollection。

    3。地理空間インデックス

    保存した地理空間データに対して検索クエリを実行するには、場所に地理空間インデックスを作成する必要があります。 フィールド。

    基本的に2つのオプションがあります: 2d および2dsphere

    ただし、最初に、場所の収集を定義しましょう。

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

    3.1。 2d 地理空間インデックス

    2d indexを使用すると、2次元平面計算に基づいて機能する検索クエリを実行できます。

    2dを作成できます 場所のインデックス 次のようにJavaアプリケーションのフィールド:

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

    もちろん、 mongoでも同じことができます。 シェル:

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

    3.2。 2dsphere 地理空間インデックス

    2dsphere インデックスは、球の計算に基づいて機能するクエリをサポートします。

    同様に、 2dsphereを作成できます 同じインデックスを使用したJavaのインデックス 上記のクラス:

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

    またはmongo シェル:

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

    4。地理空間クエリを使用した検索

    それでは、エキサイティングな部分として、地理空間クエリを使用して、オブジェクトの場所に基づいてオブジェクトを検索しましょう。

    4.1。クエリの近く

    nearから始めましょう。 近くを使用できます 指定された距離内の場所を検索するためのクエリ。

    近く クエリは両方で機能します2d および2dsphere インデックス

    次の例では、指定された位置から1km未満で10メートル以上離れている場所を検索します。

    @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"));
    }

    そして、 mongoの対応するクエリ シェル:

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

    結果は最も近いものから最も遠いものへとソートされていることに注意してください。

    同様に、非常に離れた場所を使用すると、近くの場所は見つかりません:

    @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());
    }

    nearSphereもあります メソッド。near、とまったく同じように機能します。 ただし、球面幾何学を使用して距離を計算します。

    4.2。クエリ内

    次に、 geoWithinについて説明します。 クエリ。

    geoWithin クエリを使用すると、特定のジオメトリ内に完全に存在する場所を検索できます。 、円、ボックス、またはポリゴンのように。これは、両方の2dでも機能します および2dsphere インデックス。

    この例では、指定された中心位置から半径5km以内に存在する場所を探しています。

    @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"));
    }

    距離をkmからラジアンに変換する必要があることに注意してください(地球の半径で割るだけです)。

    そして、結果のクエリ:

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

    次に、長方形の「ボックス」内に存在するすべての場所を検索します。ボックスを左下の位置と右上の位置で定義する必要があります:

    @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"));
    }

    mongoの対応するクエリは次のとおりです シェル:

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

    最後に、検索する領域が長方形または円でない場合は、ポリゴンを使用してより具体的な領域を定義できます

    @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"));
    }

    対応するクエリは次のとおりです:

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

    外部境界を持つポリゴンのみを定義しましたが、それに穴を追加することもできます。各穴はリストになります ポイントの s:

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

    4.3。交差クエリ

    最後に、 geoIntersectsを見てみましょう。 クエリ。

    geoIntersects クエリは、特定のジオメトリと少なくとも交差するオブジェクトを検索します。 比較すると、 geoWithin 特定のジオメトリ内に完全に存在するオブジェクトを検索します 。

    このクエリは2dsphereで機能します インデックスのみ。

    ポリゴンと交差する場所を探す例を使って、これを実際に見てみましょう。 :

    @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"));
    }

    結果のクエリ:

    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. セロリタスクは常に保留中

    2. MongoDB:静的な値を持つ集計$project追加フィールド

    3. JSONを表すRedis文字列とRedisハッシュ:効率?

    4. Redis AOF fsync(ALWAYS)とLSMツリー