22 GeoJSON地理データの使用

GeoJSONオブジェクトは、地理的データを表すJSONオブジェクトです。GeoJSONデータの作成、索引付けおよび問合せの例を示します。

GeoJSONオブジェクト: ジオメトリ、機能、機能コレクション

GeoJSONは、様々なジオメトリ・エンティティを表すJSONオブジェクトやこれらの組合せとユーザー定義のプロパティを一緒に使用します。

位置は、2つ以上の空間(数値)座標の配列で、先頭から3つは、一般的に経度、緯度および標高を表します。

ジオメトリ・オブジェクトには、表22-1に示すように、typeフィールドと(ジオメトリ・コレクション・オブジェクトを除いて)coordinatesフィールドがあります。

ジオメトリ・コレクションは、typeGeometryCollectionのジオメトリ・オブジェクトです。このオブジェクトには、coordinatesフィールドのかわりにgeometriesフィールドがあります。この値は、GeometryCollectionオブジェクト以外のジオメトリ・オブジェクトの配列です。

表22-1 ジオメトリ・コレクション以外のGeoJSONジオメトリ・オブジェクト

typeフィールド coordinatesフィールド
Point 位置。
MultiPoint 位置の配列。
LineString 2つ以上の位置の配列。
MultiLineString 位置のLineString配列の配列。
Polygon 最初と最後の位置が一致する(同等の)LineStringが配列として含まれるMultiLineString。ポリゴンの配列に複数の配列が含まれる場合、最初の配列は外側のポリゴンを表し、その他はその中の穴を表します。
MultiPolygon 位置のPolygon配列の配列。つまり、位置の多次元の配列。

機能オブジェクトには、値がFeaturetypeフィールドと、値がジオメトリ・オブジェクトのgeometryフィールドと、任意のJSONオブジェクトを値にできるpropertiesフィールドがあります。

機能コレクション・オブジェクトには、値がFeatureCollectiontypeフィールドと、値が機能オブジェクトの配列のfeaturesフィールドがあります。

例22-1に、features配列に3つの機能が含まれる機能コレクション・オブジェクトを表します。最初の機能のgeometryのタイプはPointで、2つ目のタイプはLineStringで、3つ目のタイプはPolygonです。

GeoJSONデータの問合せおよび索引付け

SQL/JSON問合せファンクションおよび条件を使用して、GeoJSONデータを調べたり、その一部を(Oracle Spatial and GraphのSDO_GEOMETRYオブジェクト型インスタンスを含む)非JSONデータとして投影できます。これは例22-2例22-3例22-5で説明しています。

問合せのパフォーマンスを向上させるために、GeoJSONデータに適用する関数json_valueで、Oracle Spatial and Graphの索引(型MDSYS.SPATIAL_INDEX)を作成できます。これを、例22-4に示します。

例22-4では、ジオメトリ機能の配列(最初の要素)の特定の1つの要素のみを索引付けします。ファンクションjson_valueのBツリー索引は、スカラー値のみを対象にできます。例22-3のような、任意の数の配列要素を対象とした問合せのパフォーマンスを改善するために、次の操作を実行できます。

  • ON STATEMENTの、リフレッシュ可能な配列データのマテリアライズド・ビューを作成し、インメモリーにそのビューを配置します。

  • 配列データに対して空間索引を作成します。

例22-6および例22-7を参照してください。

SDO_GEOMETRYオブジェクト型インスタンスと空間操作

Oracle Spatial and GraphのSDO_GEOMETRYオブジェクト型インスタンスをGeoJSONオブジェクトに、また、GeoJSONオブジェクトをSDO_GEOMETRYインスタンスに変換できます。

Oracle Spatial and Graphでの操作を、GeoJSONオブジェクトから取得したSDO_GEOMETRYオブジェクトに対して使用できます。たとえば、PL/SQLパッケージSDO_GEOMで演算子sdo_distanceを使用して、2つのジオメトリ・オブジェクト間の最短距離を計算できます。これは、最も近い2つの地点または2つのセグメント間(各オブジェクトから1つの地点またはセグメントまで)の距離です。これを、例22-5に示します。

関連項目:

例22-1 GeoJSONデータを使用した表

この例では、GeoJSON文書の列geo_docを持つ、表j_geoを作成します。

ここでは、このような文書が1つだけ挿入されます。この文書には、type FeatureCollectionのGeoJSONオブジェクトと、type Featureのオブジェクトのfeatures配列が1つずつ含まれます。これらのオブジェクトには、それぞれ、type PointLineStringおよびPolygongeometryがあります。

CREATE TABLE j_geo
  (id      VARCHAR2 (32) NOT NULL,
   geo_doc VARCHAR2 (4000) CHECK (geo_doc IS JSON));

INSERT INTO j_geo
  VALUES (1,
          '{"type"     : "FeatureCollection",
            "features" : [{"type"       : "Feature",
                           "geometry"   : {"type" : "Point",
                                           "coordinates" : [-122.236111, 37.482778]},
                           "properties" : {"Name" : Redwood City"}},
                          {"type" : "Feature",
                           "geometry" : {"type" : "LineString",
                                         "coordinates" : [[102.0, 0.0],
                                                          [103.0, 1.0],
                                                          [104.0, 0.0],
                                                          [105.0, 1.0]]},
                           "properties" : {"prop0" : "value0",
                                           "prop1" : 0.0}},
                          {"type"        : "Feature",
                            "geometry"   : {"type" : "Polygon",
                                            "coordinates" : [[[100.0, 0.0],
                                                              [101.0, 0.0],
                                                              [101.0, 1.0],
                                                              [100.0, 1.0],
                                                              [100.0, 0.0]]]},
                            "properties" : {"prop0" : "value0",
                                            "prop1" : {"this" : "that"}}}]}');

例22-2 GeoJSON機能のgeometryオブジェクトのSDO_GEOMETRYインスタンスとしての選択

この例では、SQL/JSONファンクションjson_valueを使用して、配列featuresの最初の要素からフィールドgeometryの値を選択します。値は、JSONデータとしてではなくOracle Spatial and Graphデータとして、つまり、SQL文字列やLOBインスタンスではなくPL/SQLオブジェクト型SDO_GEOMETRYとして戻されます。

SELECT json_value(geo_doc, '$.features[0].geometry'
                  RETURNING SDO_GEOMETRY 
                  ERROR ON ERROR)
  FROM j_geo;

戻される値は、次のようになります。これは、経度および緯度(座標)がそれぞれ122.236111と37.482778の地点を表します。

SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(-122.236111, 37.482778, NULL), NULL, NULL)

関連項目:

SQL/JSONファンクションjson_valueの詳細は、Oracle Database SQL言語リファレンスを参照してください。

例22-3 GeoJSON機能の複数のgeometryオブジェクトのSDO_GEOMETRYとしての取得

この例では、SQL/JSONファンクションjson_tableを使用して、配列features要素にあるフィールドgeometryの値を、仮想表の列sdo_valとして投影します。取得されたデータは、SDO_GEOMETRYとして戻されます。

SELECT jt.*
  FROM j_geo,
       json_table(geo_doc, '$.features[*]'
         COLUMNS (sdo_val SDO_GEOMETRY PATH '$.geometry')) jt;

関連項目:

Oracle Database SQL言語リファレンス(SQL/JSONファンクションjson_tableの詳細)

問合せに対して、次の3つの行が戻されます。1つ目の行は、例22-2と同じPointを表します。2つ目の行は、LineString配列を表します。3つ目はPolygonを表します。

SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(-122.236111, 37.482778, NULL), NULL, NULL)

SDO_GEOMETRY(2002, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 2, 1),
SDO_ORDINATE_ARRAY(102, 0, 103, 1, 104, 0, 105, 1))

SDO_GEOMETRY(2003, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1),
SDO_ORDINATE_ARRAY(100, 0, 101, 0, 101, 1, 100, 1, 100, 0))

属性SDO_ELEM_INFO_ARRAYの2つ目と3つ目の要素は、属性SDO_ORDINATE_ARRAYで提供される座標を解釈する方法を指定します。これらは、戻される最初の行が線ストリング(2)で直線セグメント(1)を持ち、2つ目の行がポリゴン(2003)で直線セグメント(1)を持つことを示します。

例22-4 スカラーGeoJSONデータの空間索引の作成

この例では、配列featuresの最初の要素のフィールドgeometryに対して、MDSYS.SPATIAL_INDEX型のjson_value関数ベースの索引を作成します。これにより、その値を取得するためのjson_valueを使用した問合せのパフォーマンスが向上します。

CREATE INDEX geo_first_feature_idx
  ON j_geo (json_value(geo_doc, '$.features[0].geometry'
                       RETURNING SDO_GEOMETRY))
  INDEXTYPE IS MDSYS.SPATIAL_INDEX;

例22-5 GeoJSONジオメトリと空間演算子の使用

この例では、最初のfeatures要素のgeometryフィールドが特定の地点から100キロメートル以内にある文書(この表では1つだけ)を選択します。ここでは、目的の地点はリテラルに表されています(coordinatesが、カリフォルニア州サンフランシスコの経度と緯度)。この地点から各ジオメトリ・オブジェクトまでの距離が計算されます。

問合せは、計算された距離を基準にして、選択した文書の順番を決めます。距離計算に対する許容誤差のメートル数は、この問合せではリテラル引数の100として指定されています。

SELECT id,
       json_value(geo_doc, '$features[0].properties.Name') "Name",
       SDO_GEOM.sdo_distance(
         json_value(geo_doc, '$features[0].geometry') RETURNING SDO_GEOMETRY,
         SDO_GEOMETRY(2001,
                      4326,
                      SDO_POINT_TYPE(-122.416667, 37.783333, NULL),
                      NULL,
                      NULL),
         100, -- Tolerance in meters
         'unit=KM') "Distance in kilometers"
  FROM  j_geo
  WHERE sdo_within_distance(
          json_value(geo_doc, '$.features[0].geometry' RETURNING SDO_GEOMETRY),
          SDO_GEOMETRY(2001,
                       4326,
                       SDO_POINT_TYPE(-122.416667, 37.783333, NULL),
                       NULL,
                       NULL),
          'distance=100 unit=KM')
        = 'TRUE';

関連項目:

SQL/JSONファンクションjson_valueの詳細は、Oracle Database SQL言語リファレンスを参照してください。

問合せの結果、次の1行が戻されます。

ID    Name           Distance in kilometers
----- -------------- ----------------------
1     Redwood City   26.9443035

例22-6 GeoJSONデータに対するマテリアライズド・ビューの作成

CREATE OR REPLACE MATERIALIZED VIEW geo_doc_view
  BUILD IMMEDIATE
  REFRESH FAST ON STATEMENT WITH ROWID
  AS SELECT g.rowid, jt.*
       FROM j_geo g,
            json_table(geo_doc, '$.features[*]'
              COLUMNS (sdo_val SDO_GEOMETRY PATH '$.geometry')) jt;

例22-7 GeoJSONデータに対するマテリアライズド・ビューの空間索引の作成

この例ではまず、いくつかの空間索引メタデータを移入することにより、空間索引の作成の準備を行います。それから、例22-6で作成されたマテリアライズド・ビューgeo_doc_viewSDO_GEOMETRYsdo_valに索引を作成します。ビュー名および列名を除き、索引メタデータを移入するためのコードは固定です。マテリアライズド・ビューの空間索引の作成が必要になるたびにそれを使用します。


-- Populate spatial-indexing metadata

INSERT INTO USER_SDO_GEOM_METADATA
  VALUES ('GEO_DOC_VIEW',
          'SDO_VAL',
          MDSYS.sdo_dim_array(
            MDSYS.sdo_dim_element('Longitude', -180, 180, 0.05),
            MDSYS.sdo_dim_element('Latitude', -90, 90, 0.05)),
          7
          4326);

-- Create spatial index on geometry column of materialized view

CREATE INDEX geo_all_features_idx ON geo_doc_view(sdo_val)
  INDEXTYPE IS MDSYS.SPATIAL_INDEX V2;