10 空間索引付け機能の拡張

この章では、ジオメトリ列以外のオブジェクトに対して空間索引を作成および使用する方法を説明します。他の章では、SDO_GEOMETRY型の単一列に格納された空間データの索引付けおよび問合せについて説明しています。

この章では、次の操作を実行する方法を説明します。

  • SDO_GEOMETRYオブジェクトをユーザー定義のオブジェクト型に埋め込み、その型のジオメトリ属性を索引付け

  • ファンクションがSDO_GEOMETRYオブジェクトを戻すファンクション索引を作成および使用

この章で説明する方法は、経験および知識の豊富なアプリケーション開発者を対象としています。他の章で説明するSpatial and Graphの概念および定義を十分に理解している必要があります。また、関連するOracle Databaseの機能(ユーザー定義データ型やファンクション索引付けなど)についても十分に理解しているか、またはこれらの機能を学習できる必要もあります。

10.1 ユーザー定義型定義のSDO_GEOMETRYオブジェクト

SDO_GEOMETRY型は、ユーザー定義のデータ型定義に埋め込むことができます。

その手順は、次に示すとおり、空間データ列にSDO_GEOMETRY型を使用する場合の手順に類似しています。

  1. ユーザー定義のデータ型を作成します。

  2. そのデータ型に基づいた列を含む表を作成します。

  3. その表にデータを挿入します。

  4. USER_SDO_GEOM_METADATAビューを更新します。

  5. ジオメトリ属性に対して空間索引を作成します。

  6. データに対して問合せを実行します。

たとえば、「空間データの挿入、索引付けおよび問合せの例」の例に示すコーラのマーケットの例に従って、マーケット名属性およびジオメトリ属性を単一の型に取り込むとします。まず、次に示すとおり、ユーザー定義のデータ型を作成します。この例では、MARKET_TYPEというオブジェクト型を作成します。

CREATE OR REPLACE TYPE market_type AS OBJECT 
  (name VARCHAR2(32), shape SDO_GEOMETRY);
/

そのユーザー定義型に基づいた列を含む表を作成します。次の例では、「空間データの挿入、索引付けおよび問合せの例」の例で使用されているCOLA_MARKETS表と同じ情報を含むCOLA_MARKETS_2という表を作成します。

CREATE TABLE cola_markets_2 (
  mkt_id NUMBER PRIMARY KEY,
  market MARKET_TYPE);

オブジェクト型名をコンストラクタとして使用して、その表にデータを挿入します。たとえば:

INSERT INTO cola_markets_2 VALUES(
  1,
  MARKET_TYPE('cola_a',
    SDO_GEOMETRY(
      2003,  -- two-dimensional polygon
      NULL,
      NULL,
      SDO_ELEM_INFO_ARRAY(1,1003,3), -- one rectangle (1003 = exterior)
      SDO_ORDINATE_ARRAY(1,1, 5,7) -- only 2 points needed to
            -- define rectangle (lower left and upper right)
      )
  )
);

ドット表記法を使用して列名および空間属性を指定し、USER_SDO_GEOM_METADATAビューを更新します。次の例では、MARKET.SHAPEをこのメタデータ・ビューのCOLUMN_NAME(「COLUMN_NAME」を参照)として指定します。

INSERT INTO user_sdo_geom_metadata
    (TABLE_NAME,
     COLUMN_NAME,
     DIMINFO,
     SRID)
  VALUES (
  'cola_markets_2',
  'market.shape',
  SDO_DIM_ARRAY(   -- 20X20 grid
    SDO_DIM_ELEMENT('X', 0, 20, 0.005),
    SDO_DIM_ELEMENT('Y', 0, 20, 0.005)
     ),
  NULL   -- SRID
);

ドット表記法を使用して列名および空間属性を指定し、空間索引を作成します。たとえば。

CREATE INDEX cola_spatial_idx_2
ON cola_markets_2(market.shape)
INDEXTYPE IS MDSYS.SPATIAL_INDEX_V2;

ドット表記法を使用してユーザー定義型の属性を参照し、データに対する問合せを実行します。次の単純な問合せは、cola_aというコーラのマーケットに関連する情報を戻します。

SELECT c.mkt_id, c.market.name, c.market.shape 
  FROM cola_markets_2 c
  WHERE c.market.name = 'cola_a';

次の問合せは、指定した問合せウィンドウ(左下の座標に(4,6)、右上の座標に(8,8)を持つ矩形)と空間的に相互作用するすべてのジオメトリに関連する情報を戻します。

SELECT c.mkt_id, c.market.name, c.market.shape
  FROM cola_markets_2 c
  WHERE SDO_RELATE(c.market.shape,
            SDO_GEOMETRY(2003, NULL, NULL,
              SDO_ELEM_INFO_ARRAY(1,1003,3),
              SDO_ORDINATE_ARRAY(4,6, 8,8)),
            'mask=anyinteract' = 'TRUE';

10.2 ファンクション索引のSDO_GEOMETRYオブジェクト

ファンクション空間索引を使用すると、ファンクションまたは式によって戻される(SDO_GEOMETRY型の)位置情報を使用した問合せが容易になります。この場合、空間索引は、ファンクションまたは式によって戻される事前計算値に基づいて作成されます。

ファンクション索引のメリット、オプション、要件の詳細および使用例については、次のマニュアルを参照してください。

ファンクション索引でのSDO_GEOMETRYオブジェクトの使用手順は次のとおりです。

  1. SDO_GEOMETRYオブジェクトを戻すファンクションを作成します。

    このファンクションは、DETERMINISTICとして宣言される必要があります。

  2. 空間データ表が存在しない場合は、空間データ表を作成し、その表にデータを挿入します。

  3. USER_SDO_GEOM_METADATAビューを更新します。

  4. 空間索引を作成します。

    ファンクション空間索引の場合、パラメータ数は32以下である必要があります。

  5. データに対して問合せを実行します。

この項の後半では、ファンクション索引の2つの使用例を示します。どちらの例でも、SDO_GEOMETRYオブジェクトを戻すファンクションを作成し、そのファンクションに対して空間索引を作成しています。最初の例では、ファンクションへの入力パラメータは、標準のOracleデータ型(NUMBER)です。2つ目の例では、ファンクションへの入力は、ユーザー定義のオブジェクト型です。

10.2.1 例: 標準型を使用したファンクション

次の例では、ファンクション索引に使用されるファンクションへの入力パラメータは、標準の数値(経度および緯度)です。

ある点の経度および緯度を戻すファンクションを作成し、そのファンクションを空間索引で使用するとします。まず、次の例に示すとおり、ファンクションを作成します。この例では、get_long_lat_ptというファンクションを作成します。

-- Create a function to return a point geometry (SDO_GTYPE = 2001) with
-- input of 2 numbers: longitude and latitude (SDO_SRID = 8307, for
-- "Longitude / Latitude (WGS 84)",  probably the most widely used 
--  coordinate system, and the one used for GPS devices.
-- Specify DETERMINISTIC for the function.

CREATE OR REPLACE FUNCTION get_long_lat_pt(longitude IN NUMBER, 
                                           latitude IN NUMBER)
RETURN SDO_GEOMETRY DETERMINISTIC IS
BEGIN
     IF (longitude IS NULL) OR (latitude IS NULL) THEN
         RETURN NULL;
     END IF;
     RETURN SDO_GEOMETRY(2001, 8307, 
                SDO_POINT_TYPE(longitude, latitude, NULL),NULL, NULL);
END;
/

空間データ表が存在しない場合は、次の例に示すとおり、その表を作成し、それにデータを追加します。この例では、long_lat_tableという表を作成します。

CREATE TABLE long_lat_table 
(lon NUMBER, lat NUMBER, name VARCHAR2(32));

INSERT INTO long_lat_table VALUES (10,10, 'Place1');
INSERT INTO long_lat_table VALUES (20,20, 'Place2');
INSERT INTO long_lat_table VALUES (30,30, 'Place3');

ドット表記法を使用してスキーマ名およびファンクション名を指定し、USER_SDO_GEOM_METADATAビューを更新します。次の例では、SCOTT.GET_LONG_LAT_PT(LON,LAT)をこのメタデータ・ビューのCOLUMN_NAME(「COLUMN_NAME」を参照)として指定します。

-- Set up the metadata entry for this table.
-- The column name sets up the function on top
-- of the two columns used in this function,
-- along with the owner of the function.
INSERT INTO USER_SDO_GEOM_METADATA VALUES('LONG_LAT_TABLE',
 'scott.get_long_lat_pt(lon,lat)',
 SDO_DIM_ARRAY(
   SDO_DIM_ELEMENT('Longitude', -180, 180, 0.005),
   SDO_DIM_ELEMENT('Latitude', -90, 90, 0.005)), 8307);

パラメータでファンクション名を指定して、空間索引を作成します。たとえば:

CREATE INDEX long_lat_table_idx ON 
   long_lat_table(get_long_lat_pt(lon,lat))
   INDEXTYPE IS mdsys.spatial_index_v2;

データに対して問合せを実行します。次の例では、SDO_FILTER演算子へのコールで前述のユーザー定義ファンクションを指定します。

SELECT NAME FROM long_lat_table a
  WHERE SDO_FILTER(
    get_long_lat_pt(a.lon,a.lat), 
    SDO_GEOMETRY(2001, 8307, SDO_POINT_TYPE(10,10,NULL), NULL, NULL)
  )='TRUE';

NAME
--------------------------------
Place1

10.2.2 例: ユーザー定義のオブジェクト型を使用したファンクション

次の例では、ファンクション索引に使用されるファンクションへの入力パラメータは、経度および緯度を含むユーザー定義型のオブジェクトです。

ある点の経度および緯度を戻すファンクションを作成し、そのファンクションに対して空間索引を作成するとします。まず、次の例に示すとおり、ユーザー定義データ型を作成します。この例では、long_latというオブジェクト型、およびそのメンバー・ファンクションGetGeometryを作成します。

CREATE TYPE long_lat as object ( 
   longitude NUMBER, 
   latitude NUMBER, 
MEMBER FUNCTION GetGeometry(SELF IN long_lat) 
RETURN SDO_GEOMETRY DETERMINISTIC) 
/ 

CREATE OR REPLACE TYPE BODY long_lat AS 
  MEMBER FUNCTION GetGeometry(SELF IN long_lat) 
  RETURN SDO_GEOMETRY IS 
    BEGIN 
       IF (longitude IS NULL) OR (latitude IS NULL) THEN
         RETURN NULL;
       END IF;
       RETURN SDO_GEOMETRY(2001, 8307, 
           SDO_POINT_TYPE(longitude, latitude, NULL), NULL,NULL); 
    END; 
END; 
/ 
  

空間データ表が存在しない場合は、次の例に示すとおり、その表を作成し、それにデータを追加します。この例では、test_long_latという表を作成します。

CREATE TABLE test_long_lat 
   (location long_lat, name VARCHAR2(32)); 

INSERT INTO test_long_lat VALUES (long_lat(10,10), 'Place1'); 
INSERT INTO test_long_lat VALUES (long_lat(20,20), 'Place2'); 
INSERT INTO test_long_lat VALUES (long_lat(30,30), 'Place3'); 

ドット表記法を使用してスキーマ名、表名、ファンクション名およびパラメータ値を指定し、USER_SDO_GEOM_METADATAビューを更新します。次の例では、SCOTT.LONG_LAT.GETGEOMETRY(LOCATION)をこのメタデータ・ビュー内のCOLUMN_NAME (「COLUMN_NAME」を参照)として指定します。

INSERT INTO USER_SDO_GEOM_METADATA VALUES('test_long_lat', 
 'scott.long_lat.GetGeometry(location)', 
 SDO_DIM_ARRAY( 
   SDO_DIM_ELEMENT('Longitude', -180, 180, 0.005),
   SDO_DIM_ELEMENT('Latitude', -90, 90, 0.005)), 8307);

ドット表記法を使用して列名およびファンクション名を指定し、空間索引を作成します。たとえば:

CREATE INDEX test_long_lat_idx ON test_long_lat(location.GetGeometry()) 
  INDEXTYPE IS MDSYS.SPATIAL_INDEX_V2;

データに対して問合せを実行します。次の問合せでは、点(10,10)と空間的に相互作用するジオメトリの名前を要求する1次フィルタ処理を実行します。

SELECT a.name FROM test_long_lat a
  WHERE SDO_FILTER(a.location.GetGeometry(),
            SDO_GEOMETRY(2001, 8307,
                SDO_POINT_TYPE(10,10,NULL), NULL, NULL)
            ) = 'TRUE';