使ってみよう! Bing API/SDK

第12回使ってみよう! Bing Spatial Data Services─⁠─ジオコーディングをバッチ処理

Bing Spatial Data Services

第9回から3回に渡って、Bing Maps REST Servicesを紹介しました。今回は、違うサービスとして区分されていますが、REST Servicesと同様にREST APIを持つBing Spatial Data Servicesを使ってみましょう。Spatial Data(空間データ)とは、地図や経緯度・住所などの地理情報です。

Bing Spatial Data Servicesには今のところ、Geocode Dataflow APIというひとつのAPIが含まれています。このAPIを利用すると住所から経緯度などの地理情報を得るジオコーディング経緯度情報から住所などの情報を得る逆ジオコーディングが行えます。REST ServicesのLocation APIと同じ内容ですが、異なる点は、大量のデータのバッチ処理にあります。

REST Servicesとレスポンス構造などは共通していますので、REST Servicesの内容も参照すると(特に第9回⁠⁠、理解の手助けになるかと思います。

Geocode Dataflow API

Geocode Dataflow APIの利用手順は次のようになります。

  1. ジオコーディングまたは逆ジオコーディングするデータを次のURLへアップロードし、ジョブを作成します。

    • http://spatial.virtualearth.net/REST/v1/dataflows/Geocode?input=xml&output=xml&key=BingMapsKey

    アップロードしたデータは順次、サーバーで処理されていきます。

  2. ジョブの進行状態を次のURLで確認します。

    • https://spatial.virtualearth.net/REST/v1/dataflows/jobID?output=xml&key=BingMapsKey
  3. ジョブが完了したら、次のURLから処理後のデータをダウンロードします。

    • https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/jobID/output/succeeded&key=BingMapsKey

アップロードおよびダウンロードするデータは、XML形式やCSV(カンマ区切り⁠⁠、タブ区切り、パイプ(|)区切りに対応しています。ジョブの進行状態は、XMLまたはJSON形式で確認できます。

日本のサポート状況

日本への対応ですが、残念ながらあまりよくありません。第9回で紹介しているLocation APIによるジオコーディングでは日本語の住所から経緯度情報の取得が可能でしたが、このGeocode Dataflow APIでは少なくとも執筆時点では日本語から変換は確認できませんでした。また、逆ジオコーディングについてはLocation APIと同等で、都道府県レベルまでとなっています。

なお、同じリクエストを行った場合も、結果が得られる場合と得られない場合がある現象が確認できています。また日本語の場合、逆ジオコーディングのときと同じ内容のリクエストであるにも関わらず、日本語で地名が得られる場合とローマ字で得られる場合があります。

このように執筆時点ではAPIの結果が不安定であること、および日本のサポート状況を踏まえたうえで、参考程度に利用してください。

Bing Maps Key

Geocode Dataflow APIの利用には、これまでのAPIと同じく認証のためBing Maps Keyが必要になります。あらかじめ、Bing Maps Account Center図1で取得してください。

図1 Maps Account Center――Bing Maps Keyの作成
図1 Maps Account Center――Bing Maps Keyの作成

それではもう少し詳しく手順を確認しコードを書いてみましょう。

データのアップロードとジョブの作成

ジオコーディング・逆ジオコーディングを行うデータは、サーバーにアップロードしジョブとして登録します。

リクエストURLの書式

データは、以下の書式のURLにHTTP POSTメソッドによりアップロードします。ひとつのBing Maps Keyで同時に10個までデータをアップロードし処理できます。またひとつのデータは100MBまでです。

  • http://spatial.virtualearth.net/REST/version/dataflows/Geocode?
      description=description&
      input=input&
      output=output&
      key=BingMapsKey

※ HTTPだけではなくHTTPSも使用できます。

URLの各パラメーターの内容は次の通りです。

パラメーター(省略名) 説明
version APIのバージョン(必須)
vと数字の組み合わせで記述します。
例:v1
description データを説明するテキスト
アプリケーションで使用するためのユーザー定義です。
input アップロードするデータ形式(必須)
以下のいずれかを指定します。
  • xml
  • csv
  • tab
  • pipe
output(o) レスポンスの形式
JSON・XML形式を指定します。
  • json(規定値)
  • xml
例:o=xml
key Bing Maps Key(必須)

versionとkeyパラメーターは、APIのすべてのURLで使用します。versionの値は現在v1です。これ以降の説明は省略します。

アップロードデータ

アップロードするデータは、XML・CSV(カンマ区切り⁠⁠・タブ区切り・パイプ区切りのテキストデータをサポートしています。HTTPリクエストのContentTypeヘッダーにはデータ形式に合わせて次のいずれかを指定します。

  • xml:application/xml
  • csv, tab, pipe:text/plain

データ形式についてはこの後に詳しく説明します。

レスポンス

データをアップロードすると指定した形式(JSONまたはXML)でジョブの状態を表すレスポンスが返ってきます。レスポンス形式についても後ほど詳しく説明します。

データ形式

まずアップロードするデータ形式についてみてみましょう。アップロードしたデータに処理結果が追加されたデータをダウンロードするため、アップロード・ダウンロードとも同じデータ形式となります。また、ジオコーディング・逆ジオコーディングとも同じ形式です。

サポートしている形式は、既に紹介したように、XML・CSV・タブ区切り・パイプ区切りのテキストデータです。

XML形式のサンプル

まずは、サンプルをみてみましょう。XML形式の場合は次のようなテキストデータです。

XML形式のアップロードデータ
<GeocodeFeed>
  <GeocodeEntity Id="001" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <GeocodeRequest Culture="en-us">
      <Address AddressLine="16630 Redmond Way" AdminDistrict="WA" Locality="Redmond" PostalCode="98052" />
    </GeocodeRequest>
  </GeocodeEntity>
  <GeocodeEntity Id="002" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <GeocodeRequest Culture="ja-jp">
      <Address AddressLine="" AdminDistrict="Tokyo" Locality="Shinjuku-ku" />
    </GeocodeRequest>
  </GeocodeEntity>
  <GeocodeEntity Id="003" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <ReverseGeocodeRequest Culture="en-us">
      <Location Longitude="-122.11871" Latitude="47.673099"/>
    </ReverseGeocodeRequest>
  </GeocodeEntity>
  <GeocodeEntity Id="004" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <ReverseGeocodeRequest Culture="ja-jp">
      <Location Longitude="139.71426866948605" Latitude="35.689996182918549"/>
    </ReverseGeocodeRequest>
  </GeocodeEntity>
</GeocodeFeed>

<GeocodeFeed>要素の中に、ジオコーディングするデータの数だけ<GeocodeEntity>要素が含まれています。上記の例では4個の<GeocodeEntity>要素のうち、はじめの2個がジオコーディング用に住所情報を記述し、残り2個が逆ジオコーディング用に経緯度情報を記述しています。

ここで処理結果のデータもみてみましょう。ダウンロードデータは、処理に成功したものと、指定したパラメーターの不正などにより失敗したものと分けてダウンロードします。

XML形式のダウンロードデータ(処理に成功した場合)
<?xml version="1.0"?>
<GeocodeFeed >
  <GeocodeEntity Id="001" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <GeocodeRequest Culture="en-us">
    <Address AddressLine="16630 Redmond Way" AdminDistrict="WA" Locality="Redmond" PostalCode="98052" />
    </GeocodeRequest>
    <GeocodeResponse DisplayName="16630 Redmond Way, Redmond, WA 98052-4434" EntityType="Address" Confidence="High" StatusCode="Success">
    <Address AddressLine="16630 Redmond Way" AdminDistrict="WA" CountryRegion="United States" FormattedAddress="16630 Redmond Way, Redmond, WA 98052-4434" Locality="Redmond" PostalCode="98052-4434" />
    <InterpolatedLocation Latitude="47.673018" Longitude="-122.11844" />
    </GeocodeResponse>
  </GeocodeEntity>
  <GeocodeEntity Id="002" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <GeocodeRequest Culture="ja-jp">
    <Address AddressLine="" AdminDistrict="Tokyo" Locality="Shinjuku-ku" />
    </GeocodeRequest>
    <GeocodeResponse DisplayName="Shinjuku-ku, Japan" EntityType="PopulatedPlace" Confidence="Medium" StatusCode="Success">
    <Address AdminDistrict="Tokyo" CountryRegion="Japan" FormattedAddress="Shinjuku-ku, Japan" Locality="Shinjuku-ku" />
    <RooftopLocation Latitude="35.6899961829185" Longitude="139.714268669486" />
    </GeocodeResponse>
  </GeocodeEntity>
  <GeocodeEntity Id="003" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <ReverseGeocodeRequest Culture="en-us">
    <Location Latitude="47.673099" Longitude="-122.11871" />
    </ReverseGeocodeRequest>
    <GeocodeResponse DisplayName="16638 Redmond Way, Redmond, WA 98052" EntityType="Address" Confidence="Medium" StatusCode="Success">
    <Address AddressLine="16638 Redmond Way" AdminDistrict="WA" CountryRegion="United States" FormattedAddress="16638 Redmond Way, Redmond, WA 98052" Locality="Redmond" PostalCode="98052" />
    <InterpolatedLocation Latitude="47.6730955392122" Longitude="-122.118710651994" />
    </GeocodeResponse>
  </GeocodeEntity>
  <GeocodeEntity Id="004" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <ReverseGeocodeRequest Culture="ja-jp">
    <Location Latitude="35.6899961829185" Longitude="139.714268669486" />
    </ReverseGeocodeRequest>
    <GeocodeResponse DisplayName="東京都" EntityType="AdminDivision1" Confidence="Medium" StatusCode="Success">
    <Address AdminDistrict="東京都" CountryRegion="日本" FormattedAddress="東京都" />
    <RooftopLocation Latitude="35.6899961829185" Longitude="139.714268669486" />
    </GeocodeResponse>
  </GeocodeEntity>
</GeocodeFeed>

冒頭でもふれていますが、同じリクエスト内容でも正しく結果を得られない現象が今のところあり、StatusCode属性がSuccessになっているにも関わらず必要な結果が含まれていないこともあります。上記結果では、逆ジオコーディングで日本語の地名で結果が得られていますが、ローマ字になってしまう場合もあります。

上記のアップロードデータにはありませんでしたが、処理に失敗した場合は次のようなデータになります。失敗した理由が記述されています。

XML形式のダウンロードデータ(処理に失敗した場合)
<?xml version="1.0"?>
<GeocodeFeed >
  <GeocodeEntity Id="002" xmlns="http://schemas.microsoft.com/search/local/2010/5/geocode">
    <GeocodeRequest Culture="ja-jp" Query="Osaka">
    <Address AddressLine="" AdminDistrict="Tokyo" Locality="Shinjuku-ku" />
    </GeocodeRequest>
  <GeocodeResponse StatusCode="BadRequest" FaultReason="Query and Address cannot both be specified." />
  </GeocodeEntity>
</GeocodeFeed>

CSV形式のデータ

続いてCSV形式です。XML形式と同じ内容のデータは次のようになります。当然ながら値の並びには決まりがあります。その内容は後で説明します。

CSV形式のアップロードデータ
1,en-us,,16630 Redmond Way,WA,,,,Redmond,98052,,,,,,,,,,,,,,,,,,,,,,
2,ja-jp,,,Tokyo,,,,Shinjuku-ku,,,,,,,,,,,,,,,,,,,,,,,
3,en-us,,,,,,,,,,,,,,,,,,,,,,,,,,,,47.673099,-122.11871
4,ja-jp,,,,,,,,,,,,,,,,,,,,,,,,,,,,35.689996182918549,139.71426866948605
CSV形式のダウンロードデータ(処理に成功した場合)
1,en-us,,16630 Redmond Way,WA,,,,Redmond,98052,,,16630 Redmond Way,WA,United States,,"16630 Redmond Way, Redmond, WA 98052-4434",Redmond,98052-4434,,47.673302,-122.118576,47.673099,-122.11871,High,"16630 Redmond Way, Redmond, WA 98052-4434",Address,Success,,,
2,ja-jp,,,Tokyo,,,,Shinjuku-ku,,,,,Tokyo,Japan,,"Shinjuku-ku, Japan",Shinjuku-ku,,,35.6899961829185,139.714268669486,,,Medium,"Shinjuku-ku, Japan",PopulatedPlace,Success,,,
3,,,,,,,,,,,,16638 Redmond Way,WA,United States,,"16638 Redmond Way, Redmond, WA 98052",Redmond,98052,,,,47.6730955392122,-122.118710651994,Medium,"16638 Redmond Way, Redmond, WA 98052",Address,Success,,47.673099,-122.11871
4,,,,,,,,,,,,,Tokyo,Japan,,Tokyo,,,,35.6899961829185,139.714268669486,,,Medium,Tokyo,AdminDivision1,Success,,35.6899961829185,139.714268669486

タブ区切りとパイプ区切り形式のデータ

タブ区切りとパイプ区切りは、CSV形式のカンマをそれぞれタブとパイプ(|)に置き換えたものと同じです。ここではパイプ区切りのみ示します。

パイプ区切り形式のアップロードデータ
1|en-us||16630 Redmond Way|WA||||Redmond|98052||||||||||||||||||||||
2|ja-jp|||Tokyo||||Shinjuku-ku|||||||||||||||||||||||
3|en-us||||||||||||||||||||||||||||47.673099|-122.11871
4|ja-jp||||||||||||||||||||||||||||35.689996182918549|139.71426866948605
パイプ区切り形式のダウンロードデータ(処理に成功した場合)
1|en-us||16630 Redmond Way|WA||||Redmond|98052|||16630 Redmond Way|WA|United States||16630 Redmond Way, Redmond, WA 98052-4434|Redmond|98052-4434||47.673302|-122.118576|47.673099|-122.11871|High|16630 Redmond Way, Redmond, WA 98052-4434|Address|Success||| 
2|ja-jp|||Tokyo||||Shinjuku-ku|||||Tokyo|Japan||Shinjuku-ku, Japan|Shinjuku-ku|||35.6899961829185|139.714268669486|||Medium|Shinjuku-ku, Japan|PopulatedPlace|Success|||
3||||||||||||16630 Redmond Way|WA|United States||16630 Redmond Way, Redmond, WA 98052-4434|Redmond|98052-4434||47.673302|-122.118576|||High|16630 Redmond Way, Redmond, WA 98052-4434|Address|Success||47.673099|-122.11871
4|||||||||||||Tokyo|Japan||Tokyo||||35.6899961829185|139.714268669486|||Medium|Tokyo|AdminDivision1|Success||35.6899961829185|139.714268669486

データの項目

次は、データの項目についてです。CSV・タブ区切り・パイプ区切り形式の場合、以下の31項目の順にデータを指定します。レスポンス用の項目も含まれていますので、その項目の箇所は記述せずアップロードすることになります。

@Id
GeocodeRequest/@Culture
GeocodeRequest/@Query
GeocodeRequest/Address/@AddressLine
GeocodeRequest/Address/@AdminDistrict
GeocodeRequest/Address/@CountryRegion
GeocodeRequest/Address/@District
GeocodeRequest/Address/@FormattedAddress
GeocodeRequest/Address/@Locality
GeocodeRequest/Address/@PostalCode
GeocodeRequest/Address/@PostalTown
GeocodeRequest/ConfidenceFilter/@MinimumConfidence
GeocodeResponse/Address/@AddressLine
GeocodeResponse/Address/@AdminDistrict
GeocodeResponse/Address/@CountryRegion
GeocodeResponse/Address/@District
GeocodeResponse/Address/@FormattedAddress
GeocodeResponse/Address/@Locality
GeocodeResponse/Address/@PostalCode
GeocodeResponse/Address/@PostalTown
GeocodeResponse/RooftopLocation/@Latitude
GeocodeResponse/RooftopLocation/@Longitude
GeocodeResponse/InterpolatedLocation/@Latitude
GeocodeResponse/InterpolatedLocation/@Longitude
GeocodeResponse/@Confidence
GeocodeResponse/@DisplayName
GeocodeResponse/@EntityType
GeocodeResponse/@StatusCode
GeocodeResponse/@FaultReason
ReverseGeocodeRequest/Location/@Latitude
ReverseGeocodeRequest/Location/@Longitude

少しわかりづらいと思いますが、XML形式の場合は、上記の内容は<GeocodeEntity>要素の中の値になります。たとえば、⁠GeocodeRequest/Address/@AddressLine」は次の構造になることを示しています。<GeocodeRequest>要素の中に、<Address>要素があり、<Address>要素のAddressLine属性を示しています。

<GeocodeEntity>
    <GeocodeRequest>
        <Address AddressLine="..." />
    </GeocodeRequest>
</GeocodeEntity>

XML形式の場合、すべての値は属性値として指定し、処理結果も属性値に格納されます。

上記の各項目の内容は次の通りです。リクエスト(アップロード)で使用する項目、リクエスト・レスポンス(ダウンロード)の両方で使用する項目、レスポンスで使用する項目別に示します。両方で使用する項目は、たとえば、ジオコーディング処理では経緯度情報はレスポンス時に結果が返りますが、逆ジオコーディング処理ではリクエストに指定するといった具合です。

リクエスト用
項目 説明
Id 入力データを区別する一意の値(文字列)を指定
例:1
Culture 言語・地域を指定
規定値はen-us
例:ja-jp
Query クエリー形式で住所などの地域情報を指定
住所の指定と併せての使用はできません。
District AdminDistrict(広域な行政区域以下)のサブレベルにあたる区域
すべての地域で使用するものではありません。
PostalTown 住所を特定するための郵便区域
MinimumConfidence 結果に求める最低限の一致度を指定
Location.Latitude
Location.Longitude
逆ジオコーディング時に経緯度を指定
リクエスト・レスポンス用
項目 説明
AddressLine 番地なども含む住所
AdminDistrict 広域な行政区域
日本では都道府県にあたります。
CountryRegion 国名コード
例:JP
Locality AdminDistrict以下の行政上の都市など
日本では主に市区群になります。
PostalCode 郵便番号
レスポンス用
項目 説明
FormattedAddress 住所
RooftopLocation.Latitude
RooftopLocation.Longitude
住所の経緯度
InterpolatedLocation.Latitude
InterpolatedLocation.Longitude
2地点で補間した経緯度
道路を表す場合などに使用されます。
Confidence 結果の一致度
DisplayName 表示名
EntityType 場所の種類
例:Address, Airport, Park など
StatusCode HTTPのステータスコード
FaultReason 処理に失敗した理由

EntityTypeは多数ありますので、一覧はMSDN Libraryを参照してください。

ジョブの状態の確認

データをアップロードし、ジョブの作成後は進行状況を確認し、完了を待つことになります。

リクエストURLの書式

ジョブの状態は、以下の書式のURLにHTTP GETメソッドでアクセスし、レスポンスを得ます。

  • http://spatial.virtualearth.net/REST/version/dataflows/Geocode/jobID?
      output=output&
      key=BingMapsKey

※ HTTPおよびHTTPSが使用できます。

URLの各パラメーターの内容は次の通りです。

パラメーター(省略名) 説明
jobID データをアップロード時のレスポンスに含まれるジョブID
output(o) レスポンスの形式
JSON・XML形式を指定します。
  • json(規定値)
  • xml
例:o=xml

レスポンス

データをアップロードしたときと同様のジョブの状態を表すレスポンスが返ってきます。レスポンスにはジョブIDを含めた上記URL書式に従った状態を確認するURL自身も含まれています。

レスポンス形式は、既に紹介したように、XMLとJSON形式を選択できそれぞれのHTTP ContentTypeヘッダーは次の通りです。

  • xml:application/xml
  • json:application/json

それでは、そのレスポンスの内容をみてみましょう。

レスポンス内容

レスポンス内容には、ジョブの進行状態(処理中・完了・中断)やアップロードしたデータ数(Geocode Entity数⁠⁠・処理が完了したデータ数・処理に失敗したデータ数、ダウンロード先のURLなどが含まれています。

RESTサービス共通部分

レスポンスの構造は、Bing Maps REST Servicesの各APIでも使用したREST Services共通の構造をしています。このことは第9回でも紹介しています。

JSON・XML形式のレスポンスのサンプルは次のとおりです。まず共通部分です。

JSON形式 RESTサービス共通部分
{
    "authenticationResultCode": "ValidCredentials", 
    "brandLogoUri": "http://spatial.virtualearth.net/Branding/logo_powered_by.png", 
    "copyright": "Copyright © 2010 Microsoft and its suppliers. (省略)", 
    "resourceSets": [
        {
            "estimatedTotal": 1, 
            "resources": [
            (ジョブ情報)
            ]
        }
    ], 
    "statusCode": 200, 
    "statusDescription": "OK", 
    "traceId": "..."
}
XML形式 RESTサービス共通部分
<Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          xmlns="http://schemas.microsoft.com/search/local/ws/rest/v1">
  <Copyright>Copyright © 2010 Microsoft and its suppliers. (省略)</Copyright>
  <BrandLogoUri>http://spatial.virtualearth.net/Branding/logo_powered_by.png</BrandLogoUri>
  <StatusCode>200</StatusCode>
  <StatusDescription>OK</StatusDescription>
  <AuthenticationResultCode>ValidCredentials</AuthenticationResultCode>
  <TraceId>...</TraceId>
  <ResourceSets>
    <ResourceSet>
      <EstimatedTotal>1</EstimatedTotal>
      <Resources>
        (ジョブ情報)
      </Resources>
    </ResourceSet>
  </ResourceSets>
</Response>

各要素の内容は次の通りです。JSON・XML形式で大文字・小文字などが異なりますが適宜読み替えてください。

要素名 説明
StatusCode HTTPのステータスコード
StatusDescription HTTPのステータスコードの説明
TraceId リクエストごとに一意な値
Copyright コピーライト情報
BrandLogoUri Bingロゴ画像のURL
ResourceSets ResourceSetのコレクション
ErrorDetails エラー内容の文字列の配列
結果がエラーの場合に含まれています。

ResourceSetsResourceSetのコレクションですが、Geocode Dataflow APIの場合 ResourceSetはひとつです。ResourceSetの内容は次の通りです。

要素名 説明
esitmatedTotal ResruoceSetに含まれるResrouces内の項目数の概算値
Resources ジョブ情報のコレクション

ジョブ情報

続いて、Geocode Dataflow APIのジョブの情報部分です。

JSON形式 ジョブ情報部分
{
    "__type": "DataflowJob:http://schemas.microsoft.com/search/local/ws/rest/v1", 
    "completedDate": "Wed, 17 Nov 2010 00:00:00 GMT", 
    "createdDate": "Wed, 17 Nov 2010 00:00:00 GMT", 
    "failedEntityCount": 1, 
    "id": "0940d2a7852942c88b94108db64a5b56", 
    "links": [
        {
            "role": "self", 
            "url": "https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56"
        }, 
        {
            "name": "succeeded", 
            "role": "output", 
            "url": "https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/succeeded"
        }, 
        {
            "name": "failed", 
            "role": "output", 
            "url": "https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/failed"
        }
    ], 
    "processedEntityCount": 19, 
    "status": "Completed", 
    "totalEntityCount": 19
}
XML形式 ジョブ情報部分
<DataflowJob>
  <Id>0940d2a7852942c88b94108db64a5b56</Id>
  <Link role="self">https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56</Link>
  <Link role="output" name="succeeded">https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/succeeded</Link>
  <Link role="output" name="failed">https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/failed</Link>
  <Status>Completed</Status>
  <CreatedDate>2010-11-17T00:00:00.00-08:00</CreatedDate>
  <CompletedDate>2010-11-17T00:00:00.00-08:00</CompletedDate>
  <TotalEntityCount>19</TotalEntityCount>
  <ProcessedEntityCount>19</ProcessedEntityCount>
  <FailedEntityCount>1</FailedEntityCount>
</DataflowJob>

各要素の内容は次の通りです。共通部分と同様にJSON・XML形式で大文字・小文字などが異なりますが適宜読み替えてください。

要素名 説明
Id ジョブID
Link role属性・name属性の値により次の3種類のURLが格納されている
role="self":
ジョブの状態を確認するURL
role="output", name="succeeded":
処理が成功したデータのダウンロード先
role="output", name="failed":
処理が失敗したデータのダウンロード先
Description リクエスト時に設定したDescriptionの値
Status ジョブの状態
Pending:処理中
Completed:完了
Aborted:エラーによる中断
CreateDate ジョブが作成された日時
CompletedDate ジョブが完了した日時
TotalEntityCount アップロードしたデータ数
ProcessedEntityCount 処理済みのデータ数
FailedEntityCount 処理に失敗したデータ数
ErrorMessage 処理が中断された場合のエラー情報

それぞれの要素、またその値は、必ずしも含まれているものではないので注意してください。たとえば処理中の場合、CompletedDate要素は含まれていない場合があります。

HTTPステータスとHTTPヘッダー

補足として、ジョブを作成するリクエストを行い成功した場合、HTTPステータスコードは201(Created)です。このときジョブの進行状態を確認するURLは、HTTP Locationヘッダーにも含まれています。

リクエストが失敗した場合、HTTPステータスコードは、400、500、503が返ります。ジョブ作成時の503エラーは、一度に処理できるジョブ数(10個)を越えていることを示しています。

結果のダウンロード

最後は結果のダウンロードです。ジョブの状態を確認し、処理が完了していれば、Link要素にあるURLからデータをダウンロード可能です。処理後のデータは、成功したものと失敗したものと分けてダウンロードします。完了したジョブの結果は14日間ダウンロード可能です。

JSON形式
{
    "name": "succeeded", 
    "role": "output", 
    "url": "https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/succeeded"
}, 
{
    "name": "failed", 
    "role": "output", 
    "url": "https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/failed"
}
XML形式
<Link role="output" name="succeeded">https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/succeeded</Link>
<Link role="output" name="failed">https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/0940d2a7852942c88b94108db64a5b56/output/failed</Link>

ただし、Link要素にあるURLにはBing Maps Keyが設定されていませんので、keyパラメーターを付加した次のURLからダウンロードします。

処理に成功したデータ

  • https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/jobID/output/succeeded&key=BingMapsKey

処理に失敗したデータ

  • https://spatial.virtualearth.net/REST/v1/dataflows/Geocode/jobID/output/failed&key=BingMapsKey

データ形式は、既に紹介した通りです。

サンプルコード

それでは、ここまでの一連の処理をコードで記述してみましょう。RESTサービスですので、HTTPアクセスとJSONまたはXML形式のデータを処理できれば、プログラミング言語は問いません。ここでは、C#によるコードを示します。Visual C# 2010 ExpressやVisual Studio 2010から、C#のコンソールアプリケーション プロジェクトを作成してください。

MSDN LibraryにもC#のサンプルコードがありますが、少し内容は変更しています。また、各種エラー処理はしていませんので、実際に使用する場合は例外処理やレスポンス内容のチェックが必要です。

ジョブクラスの作成

最初にジョブを表すクラスを作ります。実際にコードで使用するジョブ情報は、進行状態と、成功・失敗したときデータのダウンロード先URL、状態を取得するURLのため、それらのプロパティーのみを持つクラスを用意します。

class Job
{
    public string Status { get; set; }
    public Uri SuceededUri { get; set; }
    public Uri FailedUri { get; set; }
    public Uri SelfUri { get; set; }
}

データのアップロードとジョブの作成

次にデータをアップロードしジョブを作成するメソッドをProgramクラス内に記述します。引数はデータファイルと、データ形式のパラメーター(xmlなど)と、Bing Maps Keyです。戻り値の型は作成したJobクラスです。

private static Job CreateJob(string dataFilePath, string dataFormat, string key, string description)
{
    var uri = new Uri(string.Format("http://spatial.virtualearth.net/REST/v1/dataflows/Geocode?description={0}&input={1}&output=xml&key={2}",
        Uri.EscapeUriString(description ?? ""),
        Uri.EscapeUriString(dataFormat),
        key));

    using (var dataStream = File.OpenRead(dataFilePath))
    {
        // リクエスト作成
        var request = (HttpWebRequest)WebRequest.Create(uri);

        request.Method = "POST";
        request.ContentType = (dataFormat.ToLower() == "xml") ?
            "application/xml; charset=UTF-8" :
            "text/plain; charset=UTF-8";

        using (var requestStream = request.GetRequestStream())
        {
            var buffer = new byte[16384];
            var bytesRead = dataStream.Read(buffer, 0, buffer.Length);
            while (bytesRead > 0)
            {
                requestStream.Write(buffer, 0, bytesRead);
                bytesRead = dataStream.Read(buffer, 0, buffer.Length);
            }
        }

        // レスポンス取得
        using (var response = (HttpWebResponse)request.GetResponse())
        {
            using (var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
            {
                var doc = XDocument.Parse(reader.ReadToEnd());
                return ParseXDocument(doc);
            }
        }
    }

    throw new Exception();
}

上記コードのParseXDocumentメソッドは、レスポンス内容のXML文書をJobクラスに変換するメソッドで、この後作成します。

ジョブの進行状態の確認

ジョブの進行状態の確認を行うメソッドを作ります。引数にはJobクラスのオブジェクトとBing Maps Keyを指定し、戻り値はJobオブジェクトです。

private static Job CheckStatus(Job job, string key)
{
    var uri = new Uri(job.SelfUri.ToString() + "?output=xml&key=" + key);

    var request = (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "GET";

    using (var response = (HttpWebResponse)request.GetResponse())
    {
        var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
        var doc = XDocument.Parse(reader.ReadToEnd());
        return ParseXDocument(doc);
    }
}

ParseXDocumentメソッドの内容は次の通りです。

private static Job ParseXDocument(XDocument document)
{
    var job = new Job();

    XNamespace x = "http://schemas.microsoft.com/search/local/ws/rest/v1";

    // <DataflowJob> 要素の参照
    var element = (from j in document.Descendants(x + "DataflowJob") select j).First<XElement>();

    // <Status> 要素の参照
    job.Status = element.Element(x + "Status").Value;

    // <Link> 要素の参照
    foreach (var link in element.Descendants(x + "Link"))
    {
        if (link.Attribute("role").Value == "output")
        {
            switch (link.Attribute("name").Value)
            {
                case "succeeded":
                    job.SuceededUri = new Uri(link.Value);
                    break;
                case "failed":
                    job.FailedUri = new Uri(link.Value);
                    break;
            }

        }
        else if (link.Attribute("role").Value == "self")
        {
            job.SelfUri = new Uri(link.Value);
        }
    }

    return job;
}

データのダウンロード

指定したURLからデータをダウンロードし、指定したファイルへ書き出すメソッドを作成します。

private static void DownloadResult(Uri uri, string path)
{
    var request = (HttpWebRequest)WebRequest.Create(uri);
    request.Method = "GET";

    using (var response = (HttpWebResponse)request.GetResponse())
    {
        using (var stream = response.GetResponseStream())
        {
            using (var writer = new StreamWriter(path))
            {
                using (var reader = new StreamReader(stream))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        writer.WriteLine(line);
                    }
                }
            }
        }
    }
}

メイン処理

以上で、APIのリクエストと対応したメソッドができました。これらのメソッドをMainメソッドから呼ぶようにしましょう。ここではコードに直接、データファイルやデータ形式を記述しています。

static void Main(string[] args)
{
    string dataFilePath = "UploadData.xml";
    string dataFormat = "xml";
    string key = "取得した Bing Maps Key";
    string description = null;

    try
    {
        var job = new Job();

        job = CreateJob(dataFilePath, dataFormat, key, description);
        Console.WriteLine("Dataflow Job Location: {0}", job.SelfUri);

        while (true)
        {
            job = CheckStatus(job, key);
            Console.WriteLine("Dataflow Job Status: {0}", job.Status);

            if (job.Status == "Aborted")
            {
                throw new Exception();
            }
            else if (job.Status == "Pending")
            {
                Thread.Sleep(TimeSpan.FromSeconds(30));
            }
            else
            {
                // job.Status == "Completed"
                break;
            }
        }

        // 結果のダウンロード
        if (job.SuceededUri != null)
        {
            DownloadResult(new Uri(job.SuceededUri.ToString() + "?key=" + key), "Success.txt");
        }
        if (job.FailedUri != null)
        {
            DownloadResult(new Uri(job.FailedUri.ToString() + "?key=" + key), "Failed.txt");
        }
    }

    catch (Exception e)
    {
        Console.WriteLine("Exception :" + e.Message);
    }
}

以上で完成です。上記のコードではUploadData.xmlというファイルをアップロードしジョブを作成します。ジョブの処理が完了するまで待ち、最後に結果をダウンロードし、成功・処理結果をそれぞれSuccess.txt、Failed.txtというファイルに書き出しています。データ形式の章で示したサンプルを参考にファイルを用意し実行してみてください。

おわりに

今回の内容は以上です。ジオコーディングのバッチ処理を行うAPIについて紹介しました。現在利用できるBing Spatial Data Servicesについてはすべての内容を紹介したことになります。実際にAPIを利用するとなると、今のところ日本語のサポートなど不便な点がいくつかありますが、知っておくと今後サービスがアップデートされたときに役立つかもしれませんね。

おすすめ記事

記事・ニュース一覧