使ってみよう! Bing API/SDK

第25回使ってみよう! 地図データ用クラウドデータベース

はじめに

皆さんは、緯度・経度などの空間データをデータベースで扱ったことはありますか? たとえば、書店の場所をデータベースに格納し、ある地点から1km以内の書店を探すといった場合などです。SQL Server 2008からは空間データ(Spatial Data)型が利用できるようになり、そういったアプリ開発に使用できます。

SQL Serverと同じようには使えませんが、Bing Spatial Data Servicesで提供されているAPIを利用すれば、無償で空間データ用のクラウドデータベースが利用できます。このサービスを利用すれば、書店を探すアプリも作れるかもしれません。少し興味がわきましたか? 今回はこのBing Spatial Data Servicesを使ってみましょう!

Bing Spatial Data Services

Bing Spatial Data Servicesの大きな特徴として、RESTサービスであることがあげられます。すべての操作はHTTP(またはHTTPS)で行い、データはXMLやJSONなどを利用します。Bing Maps REST ServicesというREST API群もあり、リクエストやレスポンスのフォーマットはこれらと共通になっています。Bing Maps REST Servicesは第9回から第11回で紹介しています。

Bing Spatial Data Servicesは、大きくわけて2種類のサービスがあります。多数の地理情報のジオコーディング・逆ジオコーディングサービスと、冒頭で述べた地理情報を含むデータのストアと検索サービスです。これらのサービスは、次の3種類のAPIから利用します。

Geocode Dataflow API

住所や経緯度の地理情報の含む多数のデータを、一括でジオコーディング・逆ジオコーディングするAPIです。実は、Bing Spatial Data Servicesについては、一度第12回で紹介しています。このときは、このGeocode Dataflow APIしかありませんでしたが、2011年2月のアップデートにより次の2種類のAPIが追加されています。

Data Source Management API

このData Source Management APIと次のQuery APIが、今回のテーマとなる、空間データのデータベースを扱うAPIです。Spatial Data Servicesではデータベースという言葉は使わず、ユーザー(開発者)が定義およびアップロードしたデータをData Sourceと呼びます。このAPIでは、Data Sourceの作成(データのアップロード)や、削除、データ定義の参照などを行います。

Query API

3個目は、Data Sourceにあるデータを問い合わせるAPIです。Data Sourceの制限として、一部のデータを更新したり削除することはできません。つまりData Sourceからデータの検索のみ行えます。このAPIによって、ある地点から1kmに含まれるデータなどの検索ができます。位置情報を使った検索だけでなく、別の項目(たとえば書店名)などから検索も可能です。ただし文字列の検索の場合、完全一致か不一致しか扱えません。

特長と制限

Bing Spatial Data Servicesのデータストアと検索サービスの特長は、既に紹介したように、無償であり、JavaScriptからも利用できるRESTサービスであり、また空間データを扱えます。そして、ユーザーが定義したデータをBingサービスのサーバー上にアップロードして利用できます。アプリ側で空間データ用のストレージを用意する必要はありません。

制限としては、圧縮していない状態でひとつのData Sourceは300MBまで、テキスト情報はUTF-8エンコーディングのみ。ひとつのアカウントにつき作成できるData Sourceは25個までなどの制限があります。また、Data Sourceの一部のデータの削除や更新は現状ではできません。Data Sourceの更新は、Data Sourceの内容を入れ替えるということになります。

利用手順

Data Sourceの利用は、次のような手順になります。

  1. 地理情報を含んだデータの準備
  2. データのアップロード(Data Sourceの作成)
  3. データの検索

またサービスの利用には、これまでの連載と同様、Bing Maps Keyが必要です。あらかじめBing Maps Account Centerでアカウントを登録し、Bing Maps Keyを取得してください。

Bing Maps Keyについて、これまでとは異なる点があります。開発用に試す分には問題ありませんが、アプリを公開する場合は、2個のBing Maps Keyが必要ですので注意してください。Data Sourceの作成・削除を行うKeyマスターキーと、Data Sourceの検索用のKeyクエリーキーをわけて使う仕組みになっています。Bing Spatial Data ServicesはRESTサービスのため、アプリのユーザーは、アプリの通信内容からBing Maps Keyを知ることができます。マスターキーを公開してはいけません。

データの準備

それではData Sourceの元となるデータを準備します。ここではData Sourceを構成するデータの定義と実データを、書式に従ったテキストファイルとして作成します。

サンプルデータ

書店を題材にしてみましょう。書店は次のような情報(プロパティ)を持っています。

  • 店名
  • 住所
  • 電話番号

実際のデータは次のような感じになります。

ほげほげ書店, 名古屋県○○区, 052-XXX-XXXX
ぴよぴよ書房, 名古屋県□□区, 052-YYY-YYYY
ふがふが堂, 名古屋県△△区, 052-ZZZ-ZZZZ

ひとつのデータには必ず、経度と緯度が含まれている必要があります。またID(一意な文字列)も必要です。それ以外の情報は上記のプロパティのように自由に定義できます。IDと緯度・経度を追加したデータは次のようになります。

001, 34.98261, 136.79583, ほげほげ書店, 名古屋県○○区, 052-XXX-XXXX
002, 34.97023, 136.69696, ぴよぴよ書房, 名古屋県□□区, 052-YYY-YYYY
003, 34.89705, 136.74502, ふがふが堂, 名古屋県△△区, 052-ZZZ-ZZZZ

プロパティの定義

これらのデータに、プロパティ名と型を定義します。プロパティ名は次の制約があります。

  • 英数字とアンダースコア(_)を使用
  • 最大50文字
  • 先頭の文字は数字以外
  • 2文字のアンダースコア(__)で始まる名前は禁止
  • 大文字・小文字は区別しない

また、必須の緯度と経度のプロパティは、LatitudeLongitudeになります。オプションとして位置情報に高度を含める場合は、Elevationを使用します。

プロパティに使用できるデータ型は、次の5種類です。OData(Open Data)というHTTPベースのデータサービスのための規格の型名を使用しています。

データ型OData Typeひとつのデータに使用できる個数
文字列Edm.String50(最大文字数は256文字)
整数Edm.Int6420
論理Edm.Boolean40
実数Edm.Double20
日時Edm.DateTime5

今回のデータでは、次のように定義しました。

名前データ型説明
IDEdm.StringID
LatitudeEdm.Double緯度
LongitudeEdm.Double経度
NameEdm.String店名
AddressEdm.String住所
TelEdm.String電話番号

ちなみに、今回使用していない論理型はtrue・falseのいずれか、日時型の場合は「2011-06-14T12:00」のように値を表現します。

ファイルの書式

データは、XML形式、または CSV(カンマ区切り⁠⁠、タブ区切り、パイプ(|)区切りのテキストファイルとして用意します。文字エンコーディングはUTF-8です。CSVは単純なカンマ区切りで、カンマを含む文字列の値などは扱えません。

今回は、XML形式は割愛し、区切り文字によるテキストファイルを作成します。例では、区切り文字にパイプを使用します。

まずファイルの1行目に、Bing Spatial Data ServicesのバージョンとData Sourceのエンティティの種類の名前(データのコレクションを表す名前)を記述します。現在のサービスのバージョンは1.0です。

Bing Spatial Data Services, 1.0, Bookstores

2行目は、プロパティ名と型の定義を記述します。⁠プロパティ名(型名⁠⁠」のように記述し、区切り文字で区切ります。IDとなるプロパティは「プロパティ名(型名, primaryKey⁠⁠」と記述します。

ID(Edm.String,primaryKey)|Latitude(Edm.Double)|Longitude(Edm.Double)|Name(Edm.String)|Address(Edm.String)|Tel(Edm.String)

3行目以降には実際のデータを記述します。最終的には以下の内容のテキストファイルができます。

Bing Spatial Data Services, 1.0, Bookstores
 ID(Edm.String,primaryKey)|Latitude(Edm.Double)|Longitude(Edm.Double)|Name(Edm.String)|Address(Edm.String)|Tel(Edm.String)
 001|34.98261|136.79583|ほげほげ書店|名古屋県○○区|052-XXX-XXXX
 002|34.97023|136.69696|ぴよぴよ書房|名古屋県□□区|052-YYY-YYYY
 003|34.89705|136.74502|ふがふが堂|名古屋県△△区|052-ZZZ-ZZZZ

以上でアップロードするデータの準備ができました。

データのアップロード

次は用意したテキストファイルをData Source Management APIを利用してサーバーへアップロードします。アップロードしてすぐにData Sourceが作成されるわけではなく、実際にはData Source作成のジョブを登録する作業になります。

リクエスト

Data Sourceの作成(ジョブの登録)は、次のURLへHTTP POSTメソッドでテキストファイルをアップロードします。

  • http://spatial.virtualearth.net/REST/v1/Dataflows/LoadDataSource?
      dataSourceName=dataSourceName&
      loadOperation=complete&
      input=pipe&
      output=json&
      key=masterKey&
      queryKey=queryKey

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

名前説明
dataSourceNameData Source名
50文字以下
次の記号は使えません
*?"<>:|\\
loadOperationcomplete を指定
Data Source内のすべてのデータを新しいデータに置き換えます
input入力形式
次のいずれか
xml, csv, tab, pipe
outputレスポンスの形式
xmlまたは json(規定の値)
keyマスターキーとなるBing Maps Key
queryKeyクエリーキーとなるBing Maps Key
オプションですが指定推奨です

HTTPリクエストヘッダーのContent-typeの値は、入力形式に応じて、次のいずれかである必要があります。

  • application/xml
  • text/xml
  • text/plain
  • application/octet-stream

POSTデータに含めるのではなく、Windows AzureのデータストレージのBLOBリソースの指定する方法もあります。その場合はdataLocationパラメーターを追加し、dataLocation=http://***.blob.core.windows.net/myEntityDataのように指定します。詳細については割愛します。

レスポンス

アップロードにより、Data Source作成のジョブが登録されました。レスポンスにはジョブの状態が含まれています。ジョブが正しく登録された場合の、JSON形式のレスポンスは次のようになります。

{
    "authenticationResultCode": "ValidCredentials", 
    "brandLogoUri": "http://spatial.virtualearth.net/Branding/logo_powered_by.png", 
    "copyright": "Copyright c 2011 Microsoft and its suppliers. (省略)", 
    "resourceSets": [
        {
            "estimatedTotal": 1, 
            "resources": [
                {
                    "__type": "DataflowJob:http://schemas.microsoft.com/search/local/ws/rest/v1", 
                    "createdDate": "Wed, 08 Jun 2011 17:29:46 GMT", 
                    "failedEntityCount": 0, 
                    "id": "XXX", 
                    "links": [
                        {
                            "role": "self", 
                            "url": "https://spatial.virtualearth.net/REST/v1/dataflows/LoadDataSource/XXX"
                        }
                    ], 
                    "processedEntityCount": 0, 
                    "status": "Pending", 
                    "totalEntityCount": 0
                }
            ]
        }
    ], 
    "statusCode": 201, 
    "statusDescription": "Created", 
    "traceId": "…"
}

レスポンス中の、statusの値がPendingになっていることがわかります。この値が、Pendingの時はジョブが処理中を表しています。処理が終了するとCompletedエラーにより中断した場合はAbortedです。

また、linksコレクションに以下の書式のURLがありますroleの値がselfであるurlの値⁠⁠。

  • https://spatial.virtualearth.net/REST/v1/dataflows/LoadDataSource/JobID?
      key=masterKey

ジョブの状態を確認するには、このURLにkeyパラメーターを付けてアクセスすると最新のジョブ状態を得ることができます(同じ形式のレスポンスを得ます⁠⁠。

既に述べたようにリクエスト方法やレスポンスの内容は、Bing Maps Rest ServicesやBing Spatial Data ServicesのGeocode Dataflow APIと共通しています。少し詳しい内容は、これまでの連載第9回第12回を参照してください。

サンプルコード

データをアップロードするC#のサンプルコードを示します。Visual C# 2010 ExpressやVisual Studio 2010からC#のコンソールアプリケーション プロジェクトを作成し、下記のコードをMainメソッド内に記述すると動作します。コード中のファイルパスやBing Maps Keyは環境にあわせて変更してください。

var file = @"C:\Users\Owner\Documents\bookstores.txt"; // 準備したデータのテキストファイル

var name = "GihyoSample"; // Data Source 名
var masterKey = "MasterKey"; // マスターキー用の Bing Maps Key
var queryKey = "QueryKey"; // クエリーキー用の Bing Maps Key

var url = string.Format("http://spatial.virtualearth.net/REST/v1/Dataflows/LoadDataSource?dataSourceName={0}&loadOperation=complete&input=pipe&output=json&key={1}&queryKey={2}",
    name, masterKey, queryKey);

using (var reader = new System.IO.StreamReader(file, System.Text.Encoding.UTF8))
{
    using (var client = new System.Net.WebClient())
    {
        client.Encoding = System.Text.Encoding.UTF8;
        client.Headers[System.Net.HttpRequestHeader.ContentType] = "text/plain";
        var response = client.UploadString(url, reader.ReadToEnd());
        Console.WriteLine(response); // レスポンスの表示
    }
}

実行すると、JSON形式のレスポンスが表示されます。もし処理の結果エラーのレスポンスが返ってきたり、ジョブの処理が中断している場合は、エラーメッセージ内容、データの形式が正しいかなどを確認してください。

データの検索

データをアップロードし、ジョブの処理が完了すると、Data Sourceが作成完了し、データの検索ができるようになります。最後は、作成したData Sourceからデータを検索してみましょう。検索はQuery APIを利用します。HTTP・HTTPSの両方を使用でき、制限として一度に取得できる結果は最大250件です。

リクエストとレスポンス

データの検索は、次のURLへHTTP GETメソッドでアクセスします。ここで示しているURLは地理情報から検索する場合です。Query APIでは、地理情報を検索条件に使用した場合、ある経緯度から半径○km以内の結果を取得する方法と、南北の緯度・東西の経度を指定し、その範囲内の結果を取得する方法があります。

  • http://spatial.virtualearth.net/REST/v1/data/accessId/dataSourceName/entityTypeName?
      spatialFilter=nearby(latitude,longitude,distance)&
      queryoption1&
      queryoption2&
        :
      queryoptionN&
      jsonp=jsonCallBackFunction&
      jsonso=jsonState&
      key=queryKey

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

名前 説明
accessId Data SourceのID(後述)
dataSourceName Data Source名
entityTypeName Data Sourceのエンティティの種類の名前
spatialFilter 地理情報による検索範囲の指定(後述)
queryoption1, 2, …N クエリーのオプション
取得する形式や項目、並び替えなどを指定します(後述)
jsonp JSONP形式で取得する場合、JavaScriptのコールバック関数名を指定
例:jsonp=MyCallbackFunction
jsonso jsonp使用時に任意のデータを指定。コールバック関数の第2引数の値になる
例:jsons
queryKey クエリーキーに指定したBing Maps Key

URLのパスの、dataSourceNameは、データアップロード時にパラメーターに指定した値です。entityTypeNameは、アップロードしたデータの中に指定した値(1行目に記述したコレクションの名前)です。例ではそれぞれ、GihyoSampleとBookstoresと指定していました。

レスポンスで得られるデータは、JSON形式の場合次のようになります。resultsコレクションに条件に一致したデータが含まれています。

{
    "d": {
        "__copyright": "© 2011 Microsoft and its suppliers.  (省略)", 
        "results": [
            {
                "Address": "名古屋県△△区", 
                "ID": "003", 
                "Latitude": 34.89705, 
                "Longitude": 136.74502000000001, 
                "Name": "ふがふが堂", 
                "Tel": "052-ZZZ-ZZZZ", 
                "__metadata": {
                    "uri": "https://spatial.virtualearth.net/REST/v1/data/XXX/GihyoSample/Bookstores('003')"
                }
            }
        ]
    }
}

Atom形式の場合は次のような内容になります。

<feed xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
    <title type="text">
    </title>
    <id>...</id>
    <rights type="text">
        © 2011 Microsoft and its suppliers.(省略)
    </rights>
    <updated>
        2011-06-12T19:45:13Z
    </updated>
    <entry>
        <id>
            https://spatial.virtualearth.net/REST/v1/data/xxx/GihyoSample/Bookstores('003')
        </id>
        <title type="text">
        </title>
        <updated>
            2011-06-12T19:45:13Z
        </updated>
        <content type="application/xml">
            <m:properties>
                <d:id>
                    003
                </d:id>
                <d:latitude m:type="Edm.Double">
                    34.897050
                </d:latitude>
                <d:longitude m:type="Edm.Double">
                    136.745020
                </d:longitude>
                <d:name>
                    ふがふが堂
                </d:name>
                <d:address>
                    名古屋県△△区
                </d:address>
                <d:tel>
                    052-ZZZ-ZZZZ
                </d:tel>
            </m:properties>
        </content>
    </entry>
</feed>

今回は割愛しますが、地理情報を条件とする以外にも、プロパティの値を条件とすることも可能です。絞り込みも可能です。

続いて、検索時のパラメーターについてもう少し詳しくみてみましょう。

Access ID

accessIdAccess IDは、Data Sourceごとに割り当てられるIDです。この値は、検索の前にあらかじめこのIDの値を取得しておく必要があります。Access IDを知るには、いくつか方法があります。

ひとつは、データのアップロードのときに述べたジョブの状態を確認する方法です。ジョブの状態がCompletedのとき、レスポンスのlinksコレクションの値を確認すると、次のようにroleの値がdataSourceのものが含まれています。urlの値を確認すると、accessId/dataSourceName/entityTypeName形式のURLになっています。この方法は、ジョブが完了してから一定の日数のみ可能です。

もうひとつは、Bing Maps Keyに属しているData Sourceの一覧を取得する方法です。次のURLにGETメソッドでアクセスします。

  • http://spatial.virtualearth.net/REST/v1/data?
      $format=json&
     key=BingMapsKey

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

名前 説明
$format 取得する形式
atom(規定の値)または json
key マスターキーまたはクエリーキーに指定したBing Maps Key

Atom(XML)形式の場合の結果は次のようになります。

<?xml version='1.0' encoding='utf-8'?>
<app:service xmlns:app="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:bsi="http://schemas.microsoft.com/bing/spatial/2010/11/odata">
    <bsi:copyright>
        © 2011 Microsoft and its suppliers. (省略)
    </bsi:copyright>
    <app:workspace bsi:updated="2011-06-08T17:29:46Z">
        <atom:title>
            GihyoSample
        </atom:title>
        <app:collection app:href="https://spatial.virtualearth.net/REST/v1/data/XXX/GihyoSample/Bookstores">
            <atom:title>
                Bookstores
            </atom:title>
        </app:collection>
    </app:workspace>
 </app:service>

<app:workspace>要素内に、Data Source名、Entity Type名があることがわかります。<app:collection>要素のapp:href属性が、accessId/dataSourceName/entityTypeName形式のURLとなっており、ここからAccess IDがわかります。ただし、この方法の場合、JSON形式で取得した結果には、Access IDが含まれていません。

地理情報による検索条件の指定

次は、spatialFilterパラメーターについてです。ある地点から○km以内に含まれるデータを取得するには、次のように緯度・経度・距離(km)を指定します。

  • spatialFilter=nearby(34.9,136.7,5.0)

4点の東西南北の経緯度で指定した領域に含まれるデータを取得するには、次のように南の緯度、西の経度、北の緯度、東の経度の順で値を指定します。

  • spatialFilter=bbox(34.9,136.7,35.0,136.8)

クエリーオプションの指定

queryoptionNパラメーターは、ODataのクエリーオプションで定義されている内容です(ただしBing Spatial Data Serbvicesで使用できる内容には制限があります⁠⁠。いくつか例を示します。

取得するデータ形式

$formatパラメーターで取得するデータ形式を指定できます。XML(Atom⁠⁠・JSON形式のいずれかです。

  • $format=json

規定の値はatomです。

プロパティの選択

規定では結果に、すべてのプロパティが含まれています。取得するプロパティを選択するには$selectパラメーターを使用して、プロパティ名をカンマ区切りで指定します。

  • $select=Name,Address
取得件数とオフセットの指定

$skip$topパラメーターを使用して、取得データの件数と位置を指定します。

  • $skip=0&$top=10 … ⁠データの1〜10件を取得)
  • $skip=10&$top=10 … ⁠データの11〜20件目を取得)

その他のクエリーオプションは、次の機会に紹介します。

サンプルコード

最後に、データ検索のサンプルコードを示します。データ検索の場合、HTTP GETメソッドですので、単純にWebブラウザーでリクエストURLにアクセスするだけでも結果を得られます図1

図1 データの検索
図1 データの検索

データのアップロードサンプルと同じくC#のコンソールアプリケーションです。

// MEMO: using System.Xml.Linq; を追加すること
static void Main(string[] args)
{
    var dataSrouceName = "GihyoSample";
    var entityTypeName = "BookStores";
    var accessId = "AccessID";
    var queryKey = "QueryKey";
    var spatialFilter = "nearby(34.9,136.7,5.0)";

    var url = string.Format("http://spatial.virtualearth.net/REST/v1/data/{0}/{1}/{2}?$format=atom&key={3}&spatialFilter={4}", accessId, dataSrouceName, entityTypeName, queryKey, spatialFilter);
    XNamespace a = "http://www.w3.org/2005/Atom";
    XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
    XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";

    var doc = XDocument.Load(url);

    foreach (var entry in doc.Element(a + "feed").Elements(a + "entry"))
    {
        var props = entry.Element(a + "content").Element(m + "properties");
        Console.WriteLine(string.Format("{0}, {1}", props.Element(d + "Name").Value, props.Element(d + "Address").Value));
    }
}

データはC#で扱いやすいAtom形式を指定しています。コードでは結果の書店名と住所を表示しています。


今回はここまでです。いかがでしたか。次回はData Source Management APIとQuery APIについてもう少し紹介して、簡単なWebアプリを作成する予定です。

おすすめ記事

記事・ニュース一覧