GeoJSONデータの管理
GeoJson仕様は、地形(ジオメトリ)を表すjsonオブジェクトの構造およびコンテンツを定義します。
GeoJson仕様によれば、JSONオブジェクトがジオメトリ・オブジェクトになるには、typeおよびcoordinatesという2つのフィールドを持つ必要があります。ここで、typeフィールドの値はジオメトリの種類を指定し、coordinatesの値は、要素がジオメトリの形状を定義する配列である必要があります。様々なタイプのジオメトリ・オブジェクトの詳細は、GeoJSONデータの概要に関する項を参照してください。すべての種類のジオメトリが、一連の位置によって指定されます。ただし、行文字列やポリゴンの場合、実際の幾何学的図形は、位置を結ぶ線によって形成されます。GeoJson仕様では、水平軸と垂直軸がそれぞれ経度と緯度である、(フラットな)デカルト座標系の点を結ぶ直線として、2点間の線を定義します。詳細は、線および座標系に関する項を参照してください。
例のとおりに操作する場合は、スクリプトgeojsonschema_loaddata.sqlをダウンロードして、次に示すように実行します。このスクリプトにより、例で使用する表が作成され、表にデータがロードされます。
java -jar lib/kvstore.jar kvlite -secure-config disable
java -jar lib/sql.jar -helper-hosts localhost:5000 -store kvstore
load
コマンドを使用して、スクリプトを実行します。load -file geojsonschema_loaddata.sql
geo_inside
boolean geo_inside(any*, any*)
- 最初のパラメータ
any*
には、任意のジオメトリ・オブジェクトを指定できます。 - 2番目のパラメータ
any*
はポリゴンである必要があります。
この関数は、最初のパラメータが指すジオメトリが、2番目のパラメータが指すポリゴン内に完全に含まれているかどうかを判断します。
2つのパラメータのいずれかが単一の有効なジオメトリ・オブジェクトを返さず、そのことがコンパイル時に検出された場合は、エラーが発生します。
- いずれかのパラメータが0個または複数の項目を返した場合はfalseを返します。
- いずれかのパラメータがNULLを返した場合はNULLを返します。
- いずれかのパラメータ(実行時)が有効なジオメトリ・オブジェクトではない項目を返した場合は、falseを返します。
- 2番目のパラメータがポリゴンではないジオメトリ・オブジェクトを返した場合は、falseを返します。
- 両方のパラメータがそれぞれ1つのジオメトリ・オブジェクトを返し、2番目のジオメトリがポリゴンである場合。
- 最初のジオメトリが2番目のポリゴンの内部に完全に含まれている場合、つまり、そのすべてのポイントがポリゴンの内部に属している場合は、trueを返します。
- それ以外の場合はfalseを返します。
ノート:
ポリゴンの内部とは、ポリゴンの境界を定義する線形リング上のポイントを除く、ポリゴン領域内のすべてのポイントです。SELECT t.poi.name AS park_name,
t.poi.address.street AS park_location
FROM PointsOfInterest t
WHERE t.poi.kind = "nature park"
AND geo_inside(t.poi.location,
{ "type" : "polygon",
"coordinates": [[
[-120.1135253906249, 36.99816565700228],
[-119.0972900390625, 37.391981943533544],
[-119.2840576171875, 37.97451499202459],
[-120.2069091796874, 38.035112420612975],
[-122.3822021484375, 37.74031329210266],
[-122.2283935546875, 37.15156050223665],
[-121.5362548828124, 36.85325222344018],
[-120.1135253906249, 36.99816565700228]
]]
});
PointsOfInterest
表を問い合せて、nature parkの行をフィルタします。geo_inside
関数の2番目のパラメータとしてポリゴンを指定します。- 指定したポリゴンの座標は、米国カリフォルニア州の北部の座標に対応しています。
geo_inside
関数は、自然公園の場所が指定された場所のポイント内に完全に含まれている場合にのみ行を返します。
{"park_name":"portola redwoods state park",
"park_location":"15000 Skyline Blvd"}
geo_intersect
boolean geo_intersect(any*, any*)
1番目と2番目のパラメータany*
には、任意のジオメトリ・オブジェクトを指定できます。
この関数は、パラメータとして指定された2つのジオメトリに共通するポイントがあるかどうかを判断します。2つのパラメータのいずれかが単一の有効なジオメトリ・オブジェクトを返さず、そのことがコンパイル時に検出された場合は、エラーが発生します。
- いずれかのパラメータが0個または複数の項目を返した場合はfalseを返します。
- いずれかのパラメータがNULLを返した場合はNULLを返します。
- いずれかのパラメータ(実行時)が有効なジオメトリ・オブジェクトではない項目を返した場合は、falseを返します。
両方のパラメータがそれぞれ単一のジオメトリ・オブジェクトを返す場合、2つのジオメトリに共通するポイントがあればtrueを返し、そうでない場合はfalseを返します。
例: テキサスでは、地下水供給へのアクセスの規制を検討しています。帯水層は、水を含む透水層、岩盤の割れ目または未固結の物質からなる地下層です。政府は、帯水層に非常に近い場所に新たな規制を課す必要があります。
SELECT t.poi.county AS County_needs_regulation,
t.poi.contact AS Contact_phone
FROM PointsOfInterest t WHERE
geo_intersect(
t.poi.location,
{
"type" : "polygon",
"coordinates": [
[
[-97.668457031249, 29.34387539941801],
[-95.207519531258, 29.19053283229458],
[-92.900390625653, 30.37287518811801],
[-94.636230468752, 32.21280106801518],
[-97.778320312522, 32.45415593941475],
[-99.799804687541, 31.18460913574325],
[-97.668457031249, 29.34387539941801]
]
]
}
);
- 前述の問合せでは、帯水層の場所と交差する場所をフェッチしています。つまり、その場所の座標に帯水層の場所と共通するポイントがある場合です。
geo_intersect
を使用して、場所の座標に、指定された帯水層の座標と共通するポイントがあるかどうかを確認します。
{"County_needs_regulation":"Tarrant","Contact_phone":"469 745 5687"}
{"County_needs_regulation":"Kinga","Contact_phone":"469 384 7612"}
geo_distance
double geo_distance(any*, any*)
1番目と2番目のパラメータany*
には、任意のジオメトリ・オブジェクトを指定できます。
この関数は2つの入力ジオメトリ間の測地距離を返します。返される距離は、1つ目のポイントが1つ目のジオメトリに属し、2つ目のポイントが2つ目のジオメトリに属しているポイントのペアの距離の最小値として定義されます。このような2つのポイントの間の距離は、ポイントを結ぶ測地線の長さです。
測地線の概要
2点間の測地線は、地球の楕円体表面上の2点間に描画できる最短の線です。単純な、ただしより実例的な定義にするために、地球の表面が球面であると想定します。地球上の2点間の測地線は、これらの点に対応する大円の2点間にある劣弧です。つまり、地球の中心と2点で定義された球面と平面の交差で形成される円です。
次の図は、ロサンゼルスとロンドンの間の測地線と直線の違いを示しています。
図geodetic-vs-straight-line.jpgの説明
2つのパラメータのいずれかが単一の有効なジオメトリ・オブジェクトを返さず、そのことがコンパイル時に検出された場合は、エラーが発生します。
- いずれかのパラメータが0個または複数の項目を返した場合は-1を返します。
- いずれかのパラメータがNULLを返した場合はNULLを返します。
- パラメータのいずれかがジオメトリ・オブジェクトでない場合は-1を返します。
ノート:
結果は距離に基づいて昇順にソートされます(最短距離が最初に表示されます)。SELECT
t.poi.name AS restaurant_name,
t.poi.address.street AS street_name,
geo_distance(
t.poi.location,
{
"type" : "point",
"coordinates": [-121.94034576416016,37.2812239247177]
}
) AS distance_in_meters
FROM PointsOfInterest t
WHERE t.poi.kind = "restaurant" ;
PointsOfInterest
表を問い合せて、restaurantの行をフィルタします。- 正しい場所のポイントを指定し、
geo_distance
関数を使用して距離を決定します。
{"restaurant_name":"Coach Sports Bar & Grill","street_name":"80 Edward St","distance_in_meters":799.2645323337218}
{"restaurant_name":"Ricos Taco","street_name":"80 East Boulevard St","distance_in_meters":976.5361117138553}
{"restaurant_name":"Effie's Restaurant and Bar","street_name":"80 Woodeard St","distance_in_meters":2891.0508307646282}
現在の場所から最も近いレストランまでの距離は799 mです。
geo_within_distance
boolean geo_within_distance(any*, any*,double)
1番目と2番目のパラメータany*
には、任意のジオメトリ・オブジェクトを指定できます。
この関数は、1番目のジオメトリが2番目のジオメトリからN mの距離内にあるかどうかを判断します。
2つのパラメータのいずれかが単一の有効なジオメトリ・オブジェクトを返さず、そのことがコンパイル時に検出された場合は、エラーが発生します。
- いずれかのパラメータが0個または複数の項目を返した場合はfalseを返します。
- 最初の2つのパラメータのいずれかがNULLを返した場合はNULLを返します。
- 最初の2つのパラメータのいずれかが有効なジオメトリ・オブジェクトではない項目を返した場合は、falseを返します。
最終的に、両方のパラメータがそれぞれ単一のジオメトリ・オブジェクトを返す場合、1番目のジオメトリが2番目のジオメトリからN m以内の距離にあればtrueを返します。Nは3番目のパラメータで返される数値です。それ以外の場合はfalseを返します。2つのジオメトリの間の距離は、1つ目のポイントが1つ目のジオメトリに属し、2つ目のポイントが2つ目のジオメトリに属しているポイントのペアの距離の最小値として定義されます。Nが負の数の場合は、0に設定されます。
SELECT t.poi.address.street AS city_hall_address,
geo_distance(
t.poi.location,
{
"type" : "point",
"coordinates" : [-120.653828125,38.85682013474361]
}
) AS distance_in_meters
FROM PointsOfInterest t
WHERE t.poi.kind = "city hall" AND
geo_within_distance(
t.poi.location,
{
"type" : "point",
"coordinates" : [-120.653828125,38.85682013474361]
},
5000
);
PointsOfInterest
表を問い合せて、city hallの行をフィルタします。geo_within_distance
関数を使用して、指定した場所から5 km (5000m)以内の市役所をフィルタします。- また、
geo_distance
関数を使用して、その場所と市役所の間の実際の距離をフェッチします。
{"city_hall_address":"70 North 1st street","distance_in_meters":1736.0144040331768}
市役所は現在の場所から1736 m(1.73 km)です。
geo_near
boolean geo_near(any*, any*, double)
1番目と2番目のパラメータany*
には、任意のジオメトリ・オブジェクトを指定できます。
この関数は、1番目のジオメトリが2番目のジオメトリからN mの距離内にあるかどうかを判断します。
2つのパラメータのいずれかが単一の有効なジオメトリ・オブジェクトを返さず、そのことがコンパイル時に検出された場合は、エラーが発生します。
- いずれかのパラメータが0個または複数の項目を返した場合はfalseを返します。
- 最初の2つのパラメータのいずれかがNULLを返した場合はNULLを返します。
- 最初の2つのパラメータのいずれかが有効なジオメトリ・オブジェクトではない項目を返した場合は、falseを返します。
ノート:
geo_nearは、内部でgeo_within_distanceに変換され、2つのジオメトリ間の距離に(暗黙的な) ORDER BYが指定されます。ただし、問合せに(明示的な) ORDER BYがすでに存在する場合、距離による順序付けは実行されません。geo_near関数はWHERE句にのみ使用できます。この場合、最上位レベルの述語(ORまたはNOT演算子の下にネストされていない)にする必要があります。SELECT
t.poi.name AS hospital_name,
t.poi.address.street AS hospital_address
FROM PointsOfInterest t
WHERE t.poi.kind = "hospital"
AND
geo_near(
t.poi.location,
{"type" : "point",
"coordinates" : [-122.03493933105469,37.32949164059004]
},
3000
);
PointsOfInterest
表を問い合せて、hospitalの行をフィルタします。geo_near
関数を使用して、指定された場所の3000m以内の病院をフィルタします。
{"hospital_name":"St. Marthas hospital","hospital_address":"18000 West Blvd"}
{"hospital_name":"Memorial hospital","hospital_address":"10500 South St"}
SELECT
t.poi.address.street AS gas_station_address,
geo_distance(
t.poi.location,
{
"type" : "point",
"coordinates" : [-121.90768646240233,37.292081740702365]
}
) AS distance_in_meters
FROM PointsOfInterest t
WHERE t.poi.kind = "gas station" AND
geo_near(
t.poi.location,
{
"type" : "point",
"coordinates" : [-121.90768646240233,37.292081740702365]
},
1600
);
PointsOfInterest
表を問い合せて、gas stationの行をフィルタします。geo_near
関数を使用して、指定された場所の1マイル(1600m)以内のガソリン・スタンドをフィルタします。- また、
geo_distance
関数を使用して、その場所とガソリン・スタンドの間の実際の距離をフェッチします。
{"gas_station_address":"33 North Avenue","distance_in_meters":886.7004173859665}
次の1マイル以内にある最も近いガソリン・スタンドまでの実際の距離は886mです。
geo_is_geometry
boolean geo_is_geometry(any*)
パラメータany*
には、任意のジオメトリ・オブジェクトを指定できます。
- パラメータが0個または複数の項目を返した場合はfalseを返します。
- パラメータがNULLを返した場合はNULLを返します。
- 入力が単一の有効なジオメトリ・オブジェクトである場合はtrueを返します。それ以外の場合は、falseです。
SELECT geo_is_geometry(t.poi.location) AS city_hall
FROM PointsOfInterest t
WHERE t.poi.kind = "city hall"
説明: 関数geo_is_geometryを使用して、指定された場所が有効なジオメトリ・オブジェクトであるかどうかを判断します。
{ "city_hall" : true}