PHPでのOracle利用(19)──形式指定検索式

戦慄の事実に気がつく。タイトルが統一されてる所為で、何書いたか訳がわからん
仕方ないので今週末は、順次タイトルの修正をすることにする
そもそもカテゴリと内容が微妙に一致していない(php話題が存在しないにも関らずphpカテゴライズされてたり)のが問題だ。書く前と書いた後では意思が違う。そう言うこと
具体的には内容を示すサブタイトルでも取り付けよう。世に広いブログ形式に変えてしまえば楽なのだろうが、そこはそれ。リスクとリターンの天秤だ

さて、いい加減このままチューニングしていても好転しないと遅まきに感じ始めた
よって、高速化は直接的な手法に出よう。現在はジオメトリ情報を空間検索で探し出しWKTにて習得。習得した情報をphpによって文字列分割等を行い《形式》《座標データ》の二つを抽出する解析処理を行っている。要求されていない形式はここで弾かれているという内訳だ
これだとポリゴンのみの要求した場合とラインのみの要求をした場合のループ回転数が全く同じになる
よって現在タイムアウトしている空間範囲での検索は、例え望んでいるのがたった二つPOINTだったとしてもタイムアウトしてしまうのだ
流石にこれはまずい
よってクエリの条件式に空間検索だけではなく、形状検索も付け加えようと企んで見た
要求仕様は一つ。ジオメトリカラムを目標にしてなんとか形状を条件にする

さあ、頑張って見よう

SELECT SDO_UTIL.TO_WKTGEOMETRY(geom) FROM gis_t WHERE 
SDO_FILTER(geom,SDO_UTIL.FROM_WKTGEOMETRY(
'POLYGON ((
137.39095774868213 34.75005318382283,
137.41757782718457 34.75005318382283,
137.41757782718457 34.76906752256343,
137.39095774868213 34.76906752256343,
137.39095774868213 34.75005318382283
))'))='TRUE';

これが今現在発行している空間検索のクエリ──の一例。実際には条件空間は動的に変化する──だ
こいつに新しく条件を付け加えたい

とりあえずジオメトリカラムの仕様を把握する
テーブルに存在するジオメトリカラムをそのままで抽出すると、項目に分かれたデータになっている
その中でSDO_GTYPEという一番初めの四桁数字が形式を表している

・dl00	UNKNOWN_GEOMETRY
・dl01	POINT
・dl02	LINEまたはCURVE
・dl03	POLYGON
・dl04	COLLECTION
・dl05	MULTIPOINT
・dl06	MULTILINEまたはMULTICURVE
・dl07	MULTIPOLYGON
※dとは次元数(2、3あるいは4)。※要するにポリゴンは2003という事

で、SDO_GEOMETRYのメソッドに面白いものを見つけた

Get_Gtype	SDO_GTYPE値に指定された、ジオメトリ・オブジェクトのジオメトリ・タイプを戻します。

実際に試してみよう
こんな簡単な構文を編んでみた

SELECT SDO_GEOMETRY.Get_GType(geom) FROM gis_t WHERE id<3;

で、実行結果は以下のとおり

SDO_GEOMETRY.GET_GTYPE(GEOM)
----------------------------
                           1
                           1

hitしている情報はPOINTのはず
このメソッドは四桁ではなく、下一桁が帰ってくる様子だ。MULTILINEを指定してみたら6が帰ってきた
これで形式を指定した条件式が作成できる。ジオメトリカラム単体が目標だから、汎用性も落ちていない(と願いたい
以下のような構文になった

SELECT SDO_UTIL.TO_WKTGEOMETRY(geom) FROM gis_t WHERE 
SDO_FILTER(geom,SDO_UTIL.FROM_WKTGEOMETRY(
'POLYGON ((
137.39095774868213 34.75005318382283,
137.41757782718457 34.75005318382283,
137.41757782718457 34.76906752256343,
137.39095774868213 34.76906752256343,
137.39095774868213 34.75005318382283
))'))='TRUE' AND SDO_GEOMETRY.Get_GType(geom)=1;

実行結果は…

SDO_UTIL.TO_WKTGEOMETRY(GEOM)
--------------------------------------------------------------------------------
POINT (137.392631542416 34.7681512449333)
POINT (137.398996108983 34.766970194284)
POINT (137.398256644964 34.7672105020236)
POINT (137.399236681549 34.7632753638547)
POINT (137.394549706386 34.7597679897803)
POINT (137.393622007971 34.7600218738271)
POINT (137.391361972267 34.7587117582309)
POINT (137.399583867814 34.7567093879392)
POINT (137.394837771902 34.7531407408202)
─以下省略─

見事戻ってきた。POINTのみの指定も出来ている
条件を詳細にしたお陰で、検索も早い

が、あくまでもこれは少ない情報を求めた場合の高速化である
タイプを区別なく、広範囲に全て求めればあっという間にタイムアウトするのは目に見えている
高速化作業は続く…

・追記
複数のタイプを指定する場合は以下のような形式のクエリを発行した

SELECT SDO_GEOMETRY.Get_GType(geom) FROM gis_t WHERE SDO_FILTER(
geom,SDO_UTIL.FROM_WKTGEOMETRY('POLYGON ((
137.4026040332094 34.758371957011434,
137.4059315426573 34.758371957011434,
137.4059315426573 34.76074874937483,
137.4026040332094 34.76074874937483,
137.4026040332094 34.758371957011434
))'))='TRUE' 
AND (SDO_GEOMETRY.Get_GType(geom)=1 OR 
SDO_GEOMETRY.Get_GType(geom)=7);

括弧が重要
上の例文だとマルチポリゴンとポイントが返される

PHPでのOracle利用(20)──ジオメトリカラムカスタマイズ

条件を絞る事で、かなりの高速化が図れた。やはりOracleはタイトな利用かしっかりとした効率化を前提として運営しなければならないらしい
アバウトの占める割合が他のDBに比べて狭いのだろう。そりゃ、解説も発売される

高速化もある程度(それでも完全とは言いがたいが…)完成したのでようやく後回しにしていたジオメトリカラムの設定に手を出せる
以前、テーブルに大量のインサート文を発行した際に幾つかのインサート文が失敗していた。今回はその解決を図る
失敗のエラーは以下の内容

SP2-0027: 入力が長すぎます(> 2499文字)。この行は無視されました

ジオメトリカラムに格納するデータサイズの問題化と想ったが、これは違うことが判明
元々、このエラーはsqlファイルをSQL Plusにて読み込んでインサートした場合に発生したエラーだった。どうやらこれは一行で発行しようとした情報量が多すぎるのが問題であって、改行して続きを入力すれば問題なく処理が通るらしい

んげ…
4数件のインサート文を手作業で改行するのか…?
とんでもない問題が出てきたぞ…

・追記
phpスクリプトを通すよりも手作業の方が時間的に短いので、手作業で改行してインサートを行った
その折に別の問題が浮上した。SDO_UTIL.FROM_WKTGEOMETRYで変換できるWKTの上限に達してしまったorz
リファレンスでは特に明記していなかったが、どうやらSDO_UTIL.FROM_WKTGEOMETRYにはある程度の変換上限があるらしい。まあ、よく考えれば当然なんだが…
解決策としては問題の空間データを切り刻んで、細切れにしてインサートするしか…ぬぅぅ…