2019年6月5日水曜日

横浜市保育所&幼稚園MAPのSPARQLクエリについて

このたび公開させていただいた 横浜市保育所&幼稚園MAP は、横浜市オープンデータポータルのWEB API(SPARQLエンドポイント)から必要なデータを取得している。

・横浜市WEB APIの説明は こちら
・横浜市SPARQLエンドポイントは こちら

このAPIデータは、共通語彙基盤の語彙とデータ構造が用いられている。保育所等のオープンデータを共通語彙基盤対応のLODとしたのはおそらく全国初であり、とても先駆的な取り組みといえる。

やや残念な点は、施設の座標情報(緯度経度)データがないところ。自分の通勤経路にマッチした保育施設を探すには、やはり座標情報が欲しい!

さて本稿では、横浜市APIで使えるSPARQLクエリと、それに対する考察を紹介する。

1 全ての施設のID、名称、区、住所を取得するクエリ

select *
where {
 ?s ic:ID [ic:識別値 ?id ]  ;
    ic:住所 [ ic:区 ?ku ; ic:表記 ?jusho ].
 OPTIONAL{?s rdfs:label ?name .}
}ORDER BY xsd:decimal(?id)

【備考1】
施設の「名称」データが不存在のインスタンスがいくつかある。
(データ作成時の何らかのミスが原因?)
不存在に対応するため、名称を取得する部分はOPTIONAL句を付けている。
OPTIONAL{?s rdfs:label ?name .}

【備考2】
結果を「施設ID」順に並べるのにORDER BYを利用するが、このIDは「桁が揃っていない文字列」なので、数値型に変換してから並べ直す必要がある。
ORDER BY xsd:decimal(?id)
ID番号は、桁数を揃えることが重要だよね。


2 保土ケ谷区の施設を抽出するクエリ

select *
where {
 ?s ic:ID [ic:識別値 ?id ]  ;
    ic:住所 [ ic:区 "保土ケ谷区" ; ic:表記 ?jusho ].
  OPTIONAL{?s rdfs:label ?name .}
}


3 「認可保育所」を抽出するクエリ

select *
where {
 ?s ic:ID [ic:識別値 ?id ]  ;
    ic:住所 [ ic:区 ?ku ;  ic:表記 ?jusho ].
  OPTIONAL{?s rdfs:label ?name .}
  FILTER CONTAINS(STR(?s),"保育所型/10")
}

【考察】
すべての施設は、「保育所型」か「幼稚園型」のいずれかのクラスに属している。
ただし、保育所型クラスに属する施設の、さらに詳細な施設種別は、クラスではなくプロパティで分類されている。よって、詳細な施設種別で分類するのは条件分岐がやや煩雑となる。(そもそもプロパティ設定自体が怪しい施設もあるし…)
そこで着目したのが対象施設のSubject URI(各施設の主語URI。?s のこと)。
施設種別で分類するには、?s に対し、下記の文字列を含むかどうかでフィルタリングするのが一番手っ取り早い。
FILTER CONTAINS(STR(?s),"保育所型/10")

幼稚園型施設   → 「幼稚園型」文字列が含まれる
認可保育所    → 「保育所型/10」文字列が含まれる
幼保連携型認定こども園 → 「保育所型/20」文字列が含まれる
小規模保育事業  → 「保育所型/30」文字列が含まれる
家庭的保育事業  → 「保育所型/40」文字列が含まれる
事業所内保育事業 → 「保育所型/50」文字列が含まれる
横浜保育室    → 「保育所型/60」文字列が含まれる
届出済認可外保育施設 → 「保育所型/70」文字列が含まれる


4 1歳児の入所が可能な施設を抽出

select *
where {
 ?s ic:ID [ic:識別値 ?id ]  ;
    ic:住所 [ ic:区 ?ku ;  ic:表記 ?jusho ];
    dsv:入所可能人数 [ic:種別 "1歳児" ; ic:数値 ?h_kanou_ninzu ].
   OPTIONAL{?s rdfs:label ?name .}
   FILTER (xsd:decimal(?h_kanou_ninzu) > 0 )
}


5 「認定こども園 日野幼稚園」の全情報を取得

PREFIX hoiku:<https://data.city.yokohama.lg.jp/lod/v2/保育所型/> 
PREFIX yochi:<https://data.city.yokohama.lg.jp/lod/v2/幼稚園型/> 
select *
where {
{
 hoiku:202060017 ic:メタデータ / ic:日付 [ic:標準型日付 ?a_joho_koshinbi]  .
}UNION{
 hoiku:202060017 ic:ID [ic:識別値 ?a_id ]  .
}UNION{
 hoiku:202060017 rdfs:label ?a_name  .
}UNION{
 hoiku:202060017 ic:種別コード [ic:種別 ?a_shubetsu ; ic:識別値 ?a_shubetsuData ] .
}UNION{
 hoiku:202060017 ic:住所 ?bn5 .
 ?bn5 ic:区 ?a_ku .
 ?bn5 ic:表記 ?a_jusho .
 OPTIONAL {?bn5 ic:郵便番号 ?a_yuubin.}
}UNION{
 hoiku:202060017 ic:アクセス ?bn5_2 .
 OPTIONAL {?bn5_2 ic:備考 ?h_ikikata .}
}UNION{
 hoiku:202060017 ic:連絡先 ?bn6 .
 OPTIONAL{ ?bn6 ic:電話番号 ?a_tel.}
 OPTIONAL{ ?bn6 ic:FAX番号  ?a_fax.}
 OPTIONAL{ ?bn6 ic:Webサイト ?a_Web.}
}UNION{
 hoiku:202060017 ic:関与 ?bn8 .
 OPTIONAL{ ?bn8 ic:関与者 [ic:名称 [ic:表記 ?a_secchisha]].}
 OPTIONAL{ ?bn8 ic:関与者 [ic:氏名 [ic:表記 ?y_encho]].}
}UNION{
 hoiku:202060017 ic:記述 ?bn10 .
 OPTIONAL{ ?bn10 ic:種別 ?a_sonotaL .}
 OPTIONAL{ ?bn10 ic:説明 ?a_sonotaD .}
}UNION{
hoiku:202060017 ic:利用可能時間 ?bn6_2 .
 OPTIONAL{ ?bn6_2 ic:種別 ?h_syubetsu }
 OPTIONAL{ ?bn6_2 ic:説明 ?h_setsumei }
}UNION{
 hoiku:202060017 ic:建物 ?bn7 .
 OPTIONAL{ ?bn7 ic:建物面積 [ic:数値 ?h_tatemono]. }
 OPTIONAL{ ?bn7 ic:敷地面積 [ic:数値 ?h_shikichi]. }
}UNION{
 hoiku:202060017 dsv:評価 ?bn9 .
 ?bn9 dsv:評価ステータス ?h_dai3sya .
 OPTIONAL{ ?bn9 dsv:結果公表日時 ?h_dai3date .}
 OPTIONAL{ ?bn9 ic:参照 [ic:参照先 ?h_dai3URL ] .}
}UNION{
 hoiku:202060017 ic:収容人数 [ic:種別 ?h_syuyou ; ic:数値 ?h_syuyouninzu ].
}UNION{
 hoiku:202060017 dsv:入所児童数 ?bn12 .
 OPTIONAL{ ?bn12 ic:種別 ?h_nyusyojidou .}
 OPTIONAL{ ?bn12 ic:数値 ?h_nyusyojidou_ninzu .}
 OPTIONAL{ ?bn12 ic:メタデータ / ic:日付 / ic:標準型日付 ?h_nyusyojidou_meta. }
}UNION{
 hoiku:202060017 dsv:入所可能人数 ?bn13 .
 OPTIONAL{ ?bn13  ic:種別 ?h_kanou .}
 OPTIONAL{ ?bn13 ic:数値 ?h_kanou_ninzu .}
 OPTIONAL{ ?bn13 ic:メタデータ / ic:日付 / ic:標準型日付 ?h_kanou_meta. }
}UNION{
 hoiku:202060017 dsv:入所待ち人数 ?bn14 .
 OPTIONAL{ ?bn14  ic:種別 ?h_machi .}
 OPTIONAL{ ?bn14 ic:数値 ?h_machi_ninzu .}
 OPTIONAL{ ?bn14 ic:メタデータ/ ic:日付 / ic:標準型日付 ?h_machi_meta. }
}UNION{
 hoiku:202060017 ic:備考 ?y_bikou .
}UNION{
 hoiku:202060017 ic:料金 [ ic:種別 ?y_ryokins ; ic:説明 ?y_ryokin ].
}UNION{
 hoiku:202060017 dsv:認可年月日 ?y_ninka .
}
}

【雑感】
上記が、ある施設が有している全プロパティの値を表示させるクエリだ。
施設によって、プロパティの存在・不存在がバラバラなので、UNION句とOPTIONAL句の組み合わせを工夫することによりそれに対応させている。

しかしながらいつも思うのが、共通語彙基盤のRDFをグラフ型データベースから抽出するには、このような複雑な呪文を詠唱する必要があるため、利活用のハードルがどーんと上がってしまうのが残念すぎること。呪文が長い分、抽出効率も悪いし。

一方、フラットな構造であるウィキデータから、例えば「横浜市役所」の持つ全部の情報を手に入れるのは、たった1行のクエリでできる。超かんたんで速い。スマート。
SELECT * WHERE { wd:Q11543018 ?p ?o .}

共通語彙基盤のデータ構造はマークアップ的でありXMLとは相性がいいが、それをグラフ構造(トリプル)にするとブランクノードが挟まりすぎて非常に扱いづらくなる。
共通語彙基盤対応データは、グラフデータベースに突っ込んで使うより、XMLを直接パーシングするなり、JSON-LDのままjavascriptで取り込んじゃったりするほうが向いてるのではないかと思えてきた。このあたり、IMI関係者や有識者の意見をじっくり聞いてみたいところ。

なお、横浜市の保育所等LODはURIの参照解決に対応しており、施設のSubject URIにアクセスするとJSON-LD形式で当該施設の全データが取り出せる。
https://data.city.yokohama.lg.jp/lod/v2/保育所型/202060017
(読みたいときはUnicode(UTF16)でデコードしてください。)
エンドポイントに呪文を送るより、素直に参照解決データを使うほうが簡単だったかも、とアプリを完成させてから思うのでありました。うーむ。。。

2019年3月6日水曜日

統計LOD「社会・人口統計体系」について

社会・人口統計体系 とは、別名「統計でみる都道府県・市区町村のすがた」ともいい、あらゆる統計データを収集・加工し、これを地域別に編成し整備したものである。

このデータをLOD化し、統計LODのエンドポイントからAPIでデータを取得できるようしたのは、総務省統計局及び(独)統計センターの大きな成果の一つだ。

この社会・人口統計体系LOD、上手に使いこなせれば非常に便利で、アイディア次第で面白いことがたくさんできる。

あんなこと や こんなこと

しかしながら現在、社会・人口統計体系LODが、世の中に広く普及し多くの人に利用されているとは全く言い難い状況だ。
(私以外にガチで使っている人っています?)

そして今後、統計LODの予算が減らされ、更新が停止してしまったり、事業そのものが無くなってしまうことを私は危惧している。

ということで、本日はもっと多くの方に社会・人口統計体系LODの良さを知っていただくために、便利なクエリをご紹介。

自作の 統計指標の一覧表(CC0)もプレゼント。

1 ある統計データの自治体ランキングクエリ

これは、ある統計指標(この例では2015年の人口総数)について、全国の自治体(この例では都道府県)の状況を調べるためのクエリ。

PREFIX g00200502-dimension:<http://data.e-stat.go.jp/lod/ontology/g00200502/dimension/>
PREFIX g00200502-code:<http://data.e-stat.go.jp/lod/ontology/g00200502/code/>
PREFIX cd-dimension:<http://data.e-stat.go.jp/lod/ontology/crossDomain/dimension/>
PREFIX sdmx-measure:<http://purl.org/linked-data/sdmx/2009/measure#>
PREFIX sdmx-dimension:<http://purl.org/linked-data/sdmx/2009/dimension#>
PREFIX sacs:<http://data.e-stat.go.jp/lod/terms/sacs#>
PREFIX ic:<http://imi.go.jp/ns/core/rdf#>
select  ?pref ?observation
where {
?s  g00200502-dimension:indicator  g00200502-code:indicator-A1101 ;
    cd-dimension:timePeriod  "2015"^^xsd:gYear ;
    sdmx-measure:obsValue  ?observation ;
    sdmx-dimension:refArea  ?areacode .
?areacode  sacs:administrativeClass  sacs:Prefecture ;
           ic:表記  ?pref .
} ORDER BY DESC(?observation)


2 ある自治体の様々な統計データを並べるクエリ

これは、ある自治体(この例では京都府)について、社会・人口統計体系にあるすべての統計データを調べるためのクエリ。

以下のクエリはすべての調査年のデータが吐き出されるため、データ量が多くブラウザが固まる可能性大。
PREFIX g00200502-dimension:<http://data.e-stat.go.jp/lod/ontology/g00200502/dimension/>
PREFIX cd-dimension:<http://data.e-stat.go.jp/lod/ontology/crossDomain/dimension/>
PREFIX sdmx-measure:<http://purl.org/linked-data/sdmx/2009/measure#>
PREFIX sdmx-dimension:<http://purl.org/linked-data/sdmx/2009/dimension#>
PREFIX sac:<http://data.e-stat.go.jp/lod/sac/>
select ?indicator ?year ?o
where {
?s  sdmx-dimension:refArea  sac:C26000-19700401 ;
    cd-dimension:timePeriod  ?year ;
    g00200502-dimension:indicator  ?indicator ;
    sdmx-measure:obsValue  ?o .


2015年調査のデータのみ取得の場合はこう。これは固まらない。
PREFIX g00200502-dimension:<http://data.e-stat.go.jp/lod/ontology/g00200502/dimension/>
PREFIX cd-dimension:<http://data.e-stat.go.jp/lod/ontology/crossDomain/dimension/>
PREFIX sdmx-measure:<http://purl.org/linked-data/sdmx/2009/measure#>
PREFIX sdmx-dimension:<http://purl.org/linked-data/sdmx/2009/dimension#>
PREFIX sac:<http://data.e-stat.go.jp/lod/sac/>
select ?indicator ?o
where {
?s  sdmx-dimension:refArea  sac:C26000-19700401 ;
    cd-dimension:timePeriod  "2015"^^xsd:gYear ;
    g00200502-dimension:indicator  ?indicator ;
    sdmx-measure:obsValue  ?o .
} ORDER BY ASC(?indicator)


2013~2015年調査のデータを取得する場合はこうなる。
PREFIX g00200502-dimension:<http://data.e-stat.go.jp/lod/ontology/g00200502/dimension/>
PREFIX cd-dimension:<http://data.e-stat.go.jp/lod/ontology/crossDomain/dimension/>
PREFIX sdmx-measure:<http://purl.org/linked-data/sdmx/2009/measure#>
PREFIX sdmx-dimension:<http://purl.org/linked-data/sdmx/2009/dimension#>
PREFIX sac:<http://data.e-stat.go.jp/lod/sac/>
select ?indicator ?year ?o
where {
?s  sdmx-dimension:refArea  sac:C26000-19700401 ;
    g00200502-dimension:indicator  ?indicator ;
    sdmx-measure:obsValue  ?o ;
    cd-dimension:timePeriod ?year .
 { ?s  cd-dimension:timePeriod  "2015"^^xsd:gYear .}
 UNION
 { ?s  cd-dimension:timePeriod  "2014"^^xsd:gYear .}
 UNION
 { ?s  cd-dimension:timePeriod  "2013"^^xsd:gYear .}
} ORDER BY ASC(?indicator) DESC(?year)





IODD2019大阪 ウィキデータ・ソン

インターナショナル・オープンデータ・デイ2019(IODD2019)の大阪会場に参加してきた。

今回のテーマは、ウィキデータの編集。

「ウィキペディア本文」を編集したり新規で項目を作成するのは相応の知識が必要だが、今回はウィキデータに地理情報を追加するという、誰でも手軽に実施できる内容。

具体的には、ウィキペディアに掲載されている様々な施設について、そのウィキデータを見て、座標や住所などの地理情報データがないものを、ネットで情報を調べてどんどん追加していくというもの。

私自身はこれまでウィキペディアの編集やウィキデータの利用をしたことがなかったため、当イベントは、自身の見識を深め、新たなアイディアのインスピレーションを得るのに大いに参考になった。

また、当イベントのおまけ成果物として、ウィキデータを使ったWEBアプリを会場でこしらえた。
これ→ https://www.mirko.jp/iodd2019/

ウィキデータはオープンなSPARQL APIで提供されており、またCORS(クロスオリジンリソースシェアリング)にも対応しているため、ブラウザJavascriptのみで手軽に活用アプリが作成できる。

以下、私がよく使うJavascriptのみのお手軽Webアプリのひな形だ。
これをベースとして色々作れちゃうので、ご参考に。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>ウィキデータ可視化アプリ</title>
<script>
function execute() { // ボタンクリック時の動作
    var endpoint = 'https://query.wikidata.org/sparql'; //Endpointをセット
    var method = "POST"; //メソッド(POST or GET)
    //都市コードを取得
    var index = document.selectForm.cityselect.selectedIndex;
       var cityCode = document.selectForm.cityselect.options[index].value;
    //クエリ文字列をセット
    var query =  'SELECT DISTINCT ?s ?label ?point ';
        query += 'WHERE{ ?s rdfs:label ?label;';
        query += 'wdt:P131 wd:' + cityCode +';';
        query += 'wdt:P625 ?point.';
        query += 'FILTER(lang(?label)="ja")}';
    sparqlQuery(query,endpoint,method) ; //スパークルクエリ送信
}
function sparqlQuery(queryStr,endpoint,method) { // XMLHttpRequestでクエリ送信
    var querypart = "query=" + encodeURIComponent(queryStr);
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open(method, endpoint, true);
    xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xmlhttp.setRequestHeader("Accept", "application/sparql-results+json");
    xmlhttp.onreadystatechange = function() {
        if(xmlhttp.readyState == 4) {
            if(xmlhttp.status == 200 || xmlhttp.status == 201 ) {
                onSuccessQuery(xmlhttp.responseText);
            } else {
                document.getElementById("results").innerHTML = "エラー" ;
            }
        }
    }
    xmlhttp.send(querypart);
}
function onSuccessQuery(text) { // 結果(JSON文字列)を配列に格納
    var jsonObj = JSON.parse(text);
    var head , rows ;
    if (jsonObj.responseJSON) {
        head = jsonObj.responseJSON.head.vars;
        rows = jsonObj.responseJSON.results.bindings;
    } else {
        if(!(jsonObj.head)){
            document.getElementById("results").innerHTML = "スパークル構文エラー" ;
            return;
        }
        head = jsonObj.head.vars;
        rows = jsonObj.results.bindings;
    }
    if (rows.length === 0) {
        document.getElementById("results").innerHTML = "検索条件の該当データなし" ;
        return;
    }
    makeTable(head, rows);
}
function makeTable(head, rows) { // 配列をテーブルにして出力
    var html = "<table border='1'><tr>";
    for (var i=0; i<head.length; i++) { //ヘッダ部分の書込み
        html += "<th>" + head[i] + "</th>";
    }
    html += "</tr>";
    for (var i=0; i<rows.length; i++) { //内容の書込み
        html += "<tr>";
        for (var j=0; j<head.length; j++) {
            var col = head[j];
            if(rows[i][col] != null){
                html += "<td>" + rows[i][col].value + "</td>";
            }else{
                html += "<td></td>";
            }
        }
        html += "</tr>";
    }
    html += "</table>";
    document.getElementById("results").innerHTML = html;
}
</script>
</head>
<body>
<form name="selectForm">
<select name='cityselect'>
<option value="Q35765">大阪市</option>
<option value="Q193428">堺市</option>
<option value="Q335423">高槻市</option>
<option value="Q270912">枚方市</option>
<option value="Q467479">豊中市</option>
<option value="Q243863">東大阪市</option>
<option value="Q740456">岸和田市</option>
<option value="Q653510">吹田市</option>
<option value="Q502403">茨木市</option>
<option value="Q389633">寝屋川市</option>
</select>
<input type="button" value="クエリ実行" onclick="execute()">
</form>
<div id="results"></div>
</body>
</html> 

2018年11月11日日曜日

LODチャレンジ2018

自作のWebアプリ、 ザ・地域統計パワーバトル が、LODチャレンジ2018において、グランプリにあたる最優秀賞をいただきました。また、併せて日立株式会社様より Inspire the LOD賞を頂きました。

さらに、自作のオントロジー、OWL de ラーメンオントロジー は、オントロノミー合同会社様から オントロジー賞を頂きました。

自作アプリ等の公表の場を与えてくださるだけでも本当にありがたいことで、それに加えて賞までいただけるのは感謝しきれないくらいです。関係者様ありがとうございます。


僕がデータの利活用やプログラミングに取り組み始めたのは3年ほど前で、それ以前はさほど興味を持っていませんでした。

以前は、休日は大好きな魚釣りに行くことが多かったのですが、一日家を空けて魚を釣って楽しんで帰ってくると、家族から白い目で見られることが多く、やむ無く封印することになりました。

冬はスノーボードに行くのを楽しみにしていましたが、行くたびに時間とお金と体力を使い果たしすぎるために、これもやむ無く封印しています。

そこで目を付けたのがオープンデータ利活用です。

1.家にいながらスキマ時間でできるので家族サービスの支障にならない。
2.PCひとつでできるのでお金がかからず、家計にやさしい。
3.社会貢献にもなる。
4.お父さん意外とすごい人だったんだ、って娘に褒められる。

長く続けていけたらなぁ、と思っています。

2018年9月11日火曜日

IMIツール Ver 1.0.0

共通語彙を利活用するためのツールである IMIツール は、先日まで検証版だったが、このたび待望の正式版 Ver 1.0.0 がリリースされた。
さっそく使ってみる。

とりあえず、検証版で作ったDMDを読み込ませる。

む、エラーだ  (-_-)

まあ、仕様が変わったのだろう。しようがない…

オヤジギャグはさておき、気を取り直して、一からDMDを作り直す。
手持ちのエクセル表を読み込ませて、適切なクラス・プロパティをブラウザ上で選んでいく。
応用語彙を、IMI語彙記法を用いて追加する。
この辺りの操作感は検証版と同じだ。

さて、DMDが無事完成し、RDF出力だ。
果たして検証版のダメな点は直っているのだろうか。

1 JSON-LD ⇒ 検証版から据え置き。不具合解消なし。
2 RDF-XML ⇒ 検証版から据え置き。不具合解消なし。
3 Turtle  ⇒ 検証版から据え置き。不具合解消なし。
4 主語の扱い ⇒ 検証版から据え置き。不具合解消なし。

…ぶっちゃけこれでは使い物にならないっす。
技術委員さん、このRDFちゃんとチェックしてます?ほんとにいいのこれで??
経産省やIPAは、共通語彙基盤を本気で流行らせたい気が無いのだろうか… (-_-)

1千万くれたら僕が最高のツールを作ります。
(ウソです)

2018年8月11日土曜日

統計LODのSPARQLクエリ解説(小地域編)

このたび、Webアプリ 「ザ・地域統計パワーバトル」 を公開した。

このアプリは「シビックパワーバトル」に着想を得て開発したものだ。

バトル自体は興味を引くためのジョークだが、地域と地域を比較したり、また日本(全国値)と比較することで、自分の住んでいる地域の特徴を知り、どのような問題点を持つか把握することが可能となる。地域分析ツールという観点で遊んでいただけたら幸いだ。

さて、このアプリは、e-StatのWeb APIからデータを取得し表示させている。
都道府県と市区町村のデータは REST API から、町丁・字の「小地域」のデータは、統計LOD のSPARQL APIから取得している。

都道府県と市区町村のデータは、SPARQL APIからも取得することが可能だが、実行速度のより高速なREST APIを利用している。
小地域データは現在、SPARQL APIからのみの提供だ。

本稿では、統計LODの小地域データを扱うためのSPARQLクエリを紹介する。クエリをコピペして、統計LODのエンドポイントでお試しあれ。


1 平成27年国勢調査の対象自治体の一覧
PREFIX sdmx-dimension: <http://purl.org/linked-data/sdmx/2009/dimension#>
PREFIX qb: <http://purl.org/linked-data/cube#>
PREFIX sacs: <http://data.e-stat.go.jp/lod/terms/sacs#>
PREFIX ic: <http://imi.go.jp/ns/core/rdf#>
select distinct ?code ?pref ?area
where {
?s  sdmx-dimension:refArea  ?code ;
    qb:dataSet  <http://data.e-stat.go.jp/lod/dataset/g00200521/d0003148521>.
?code  sacs:prefectureLabel  ?pref ;
       ic:表記  ?area ;
}order by ?code

このクエリで、平成27年国勢調査の対象自治体の「期間付き標準地域コード」を取得することができる。(重いので乱発しないこと!)


2 京都市左京区に含まれる小地域の一覧
PREFIX smallArea: <http://data.e-stat.go.jp/lod/terms/smallArea/>
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX sac: <http://data.e-stat.go.jp/lod/sac/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
select *
where {
?s  a  smallArea:SmallAreaCode ;
    dcterms:isPartOf  sac:C26103-19700401 ;
    rdfs:label  ?name .
} order by ?s

上記の sac:C26103-19700401 は平成27年国勢調査時点の、京都市左京区の期間付き標準地域コードである。この部分を変えることで他の市区町村の情報を得ることができる。


3 京都市左京区聖護院山王町の情報
PREFIX sa-g00200521-2015: <http://data.e-stat.go.jp/lod/smallArea/g00200521/2015/>
select *
where {
  sa-g00200521-2015:S26103018006 ?p ?o .
}


4 京都市左京区聖護院山王町のポリゴン
PREFIX sa-g00200521-2015: <http://data.e-stat.go.jp/lod/smallArea/g00200521/2015/>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
select ?polygon
where {
  sa-g00200521-2015:S26103018006  geo:hasGeometry  [ geo:asWKT  ?polygon ] .
}
小地域のポリゴンを取得することもできる。当アプリではこのクエリは使っていないが、オープンストリートマップなどで領域を表示させるのも面白いと思う。


5 京都市左京区聖護院山王町の年齢別・男女別人口
PREFIX sdmx-dimension: <http://purl.org/linked-data/sdmx/2009/dimension#>
PREFIX sa-g00200521-2015: <http://data.e-stat.go.jp/lod/smallArea/g00200521/2015/>
PREFIX qb: <http://purl.org/linked-data/cube#>
PREFIX cd-dimension: <http://data.e-stat.go.jp/lod/ontology/crossDomain/dimension/>
PREFIX estat-measure: <http://data.e-stat.go.jp/lod/ontology/measure/>
select ?age ?sex ?population
where {
?s  sdmx-dimension:refArea  sa-g00200521-2015:S26103018006 ;
    qb:dataSet  <http://data.e-stat.go.jp/lod/dataset/g00200521/ds012015003>;
    cd-dimension:age  ?age;
    cd-dimension:sex  ?sex;
    estat-measure:population  ?population.
}order by ?sex ?age

このクエリで、いわゆる「人口ピラミッド」に必要な情報を得ることができる。


6 京都市左京区聖護院山王町の年齢別・男女別人口、外国人人口、世帯数、配偶関係、労働力状態
PREFIX sdmx-dimension: <http://purl.org/linked-data/sdmx/2009/dimension#>
PREFIX sa-g00200521-2015: <http://data.e-stat.go.jp/lod/smallArea/g00200521/2015/>
PREFIX qb: <http://purl.org/linked-data/cube#>
PREFIX cd-dimension: <http://data.e-stat.go.jp/lod/ontology/crossDomain/dimension/>
PREFIX estat-measure: <http://data.e-stat.go.jp/lod/ontology/measure/>
PREFIX g00200521-dimension-2015: <http://data.e-stat.go.jp/lod/ontology/g00200521/dimension/2015/>
PREFIX g00200521-dimension-2010: <http://data.e-stat.go.jp/lod/ontology/g00200521/dimension/2010/>
select ?dataset ?sex ?age ?maritalStatus ?labourForce ?population ?households ?avrage
where {
?s  sdmx-dimension:refArea  sa-g00200521-2015:S26103018006 ;
    qb:dataSet  ?dataset .
OPTIONAL{
?s  cd-dimension:age  ?age;
    cd-dimension:sex  ?sex;
    estat-measure:population  ?population.
}
OPTIONAL{
?s  estat-measure:households  ?households .
}
OPTIONAL{
?s  cd-dimension:sex  ?sex;
    estat-measure:population  ?population.
}
OPTIONAL{
?s  cd-dimension:sex  ?sex;
    estat-measure:age  ?avrage.
}
OPTIONAL{
?s  cd-dimension:sex  ?sex;
    g00200521-dimension-2015:maritalStatus  ?maritalStatus;
    estat-measure:population  ?population.
}
OPTIONAL{
?s  cd-dimension:sex  ?sex;
    g00200521-dimension-2010:labourForce  ?labourForce;
    estat-measure:population  ?population.
}
}order by ?dataset ?sex ?age ?maritalStatus ?labourForce

「ザ・地域統計パワーバトル」では、実際にこのクエリを使ってデータを取得している。
OPTIONAL句で各種データを並列させているところがポイント。
短いクエリを連発するのが良いのか、このような重いクエリにするのが良いのか悩んだが、プログラムが複雑化するのを避けるために、今回は重いクエリ一発で、情報を一気に取得する方法を採用した。

統計LODの実行速度が倍くらいになってくれたらなぁ…。
統計局さん、統計センターさん、日立さん、よろしくお願いします。

統計LODの実行速度が5倍くらい高速になりました!!
おかげさまで快適になりました。
関係者のみなさま、ありがとうございます!!!

2018年6月25日月曜日

(各論)IMIツールの「データ形式変換」機能について

作成したDMDを、元データ(エクセル表など)と一緒に、IMIツール「データ形式変換」に読み込ませると、簡単に共通語彙対応データ(JSON-LD、RDF/XML、Turtle)が出力できる。

ここでは、データ形式変換 から出力された各データについて、私見を紹介する。


1 JSON-LD形式 ⇒ (^^)

(例)共通語彙基盤「妖精」(JSON-LD形式) 

データの階層構造もきれいに収まっており、視認性もよくGOOD!
一点疑問に思うのは、URIを示す表現が以下のようになっていること。

"ic:参照先": {
   "@value": "http://example.com/xxx/aaa.html",
   "@type": "xsd:anyURI"
}

JSON-LDでは、次のように、目的語がURIの場合は @id を使うのが一般的な記法だと思う。

"ic:参照先": {
   "@id": "http://example.com/xxx/aaa.html"
}


2 RDF/XML形式 ⇒ (-_-)

(例)共通語彙基盤「妖精」(RDF/XML形式)

JSON-LD同様、データの階層構造はきれいに収まっているが、出力されるテキストに、改行コードやインデントスペースが全く入っていないのがつらすぎる。
ブラウザに読み込ませたら構造が分かるが、そのままの状態ではテキストエディターでの編集は困難。

また、JSON-LD同様、URIを示す表現に疑問符。
<ic:画像 rdf:datatype="xsd:anyURI">http://example.com/xxx.jpg</ic:画像>

rdf:resource を使って以下のように記述するのが一般的。
<ic:画像 rdf:resource="http://example.com/xxx.jpg"/>


3 Turtle形式 ⇒ (-"-)

(例)共通語彙基盤「妖精」(Turtle形式)

ブランクノード表現が多用されており読みにくい。
形式的には一応Turtleの要件を満たしているが、これではN-Triplesとほとんど一緒。
Turtleの優れているところは人間が読みやすい点。これではダメだ。
また、冒頭で名前空間接頭辞の宣言をしているにも関わらず、データ内で接頭辞を使っていないところもダメダメな感じ。

あと、上述の2形式と同様、URIの扱いに疑問符。
"http://example.com/xxx/aaa.html"^^xsd:anyURI

スタンダードなのはこちら。
<http://example.com/xxx/aaa.html>

ちなみに私はRDFタートルズの一員である。
個人的な思いとしても、もっとTurtle生成プログラムを作りこんでいただきたいところだ。最低でもこのくらいにはしてほしいなぁ。


4 主語の扱い

すべての出力データに関して、共通の問題点は 主語(subject) がないところ。

RDFはご存じのとおり主語・述語・目的語のトリプル構造となっており、文法的には、主語には URI 又は ブランクノード を使うこととされている。

中間ノード」の主語に対し、ブランクノードを利用するのは何ら問題ない。
一方で、ある事物を示す「おおもとの主語」に対しては、ブランクノードではなくURIを付与するのが普通だ。

しかしながら、IMIツールから出力されるRDFは、おおもとの主語もブランクノードになってしまっている。
おおもとの主語にURIが設定されていないと、RDFとしては扱いづらく、トリプルストアに入れ込んだときも扱いが困難となる。

私は、何とかして主語を設定しようと、IMIツールの設定項目をいろいろ試したり、IMI語彙記法でいろいろと書き込んでみたが、上手くいかなかった。
(他に方法があるのかもしれないが…)

IPAさんにお願いしたいのは、IMIツールのGUI上に、主語の名前空間URIの設定項目を作り、そこに入力したURIに、データ内のいずれかの列のデータをくっつけたものを、主語URIとして出力できるようにすること。


5 まとめ

目につく不具合はいくつかあるものの、一旦DMDを作ってしまえば、様々な形式のRDFが簡単に出力できるのは非常に便利。
上記で挙げた不具合をすべて解消し、(^^♪ になった 正式版IMIツール の早期リリースを望みます。よろしくお願いします m(__)m

(各論)IMIツールの「DMD作成支援」機能について

共通語彙対応データを作るには、まず DMD(Data Model Description / データモデル記述)を作る必要がある。

DMDは、特定のデータを共通語彙対応にするための「設計図」のようなもの。

一旦DMDを作ってしまえば、元データ(エクセル表など)と一緒に、IMIツール に読み込ませるだけで、簡単に共通語彙対応のRDFデータ(JSON-LD、RDF/XML、Turtle)ができる、という仕組みだ。

良い点は、IMIツールを使えば、ほぼマウス操作のみで割と簡単にDMDが作れるところ。
また、一旦DMDを作ってしまえば、何度でも使い回しができ、そのDMDを配布すれば誰でも同じように使えるところ。優れたDMDを作れば、それが全国津々浦々に広まる可能性を秘めている。

悪い点は、構造化項目明記法により、データ構造が非常に複雑になるため、IMIツール以外の方法(手作業など)で作るのが現実的でないところ。


さて、ここで、IMIツールの DMD作成支援 を実際にに使ってみて感じた点を、以下に紹介させていただく。

良いと感じたところは、GUIがなかなか良くできていて、クラス(型)やプロパティの設定を、マウス操作のみで直観的に行うことができるところだ。

一方、難しいと思った点は 応用語彙 の追加だ。

「徳川将軍一覧」のデータを例にあげると、将軍は「人」なので、ルートとなるクラスは ic:人型 にする、と、誰しも考えるところだろう。

そして、コア語彙だけでは表現できない、徳川将軍固有の項目については、応用語彙として追加したい、と考える。

そこで私は、ルートである ic:人型クラスに、応用語彙のプロパティを追加しようと頑張ったのだが、どうしてもできない。

しばらく悩んで理解したのは、コア語彙クラスには、そのクラスが持つコア語彙プロパティしかセットできない、ということ。

言い換えると、応用語彙のプロパティを追加したい場合は、ic:人型クラスを継承した独自定義のクラスを作って、そいつをルートクラスとしなければならない、ということだ。

理解すれば簡単なことだが、理解するまでかなり悩んだので、もうちょっと分かりやすくしてほしい点の一つとして挙げておく。


新しいクラスを作ったり、応用語彙を追加するには、IMI語彙記法 を用いて、その内容を記述する必要がある。その記載例は次の通り。

# 人型クラスを継承した「将軍型クラス」を新規作成する
 class ex:将軍型 {@ic:人型};

# 「官位」を示すプロパティを作る
 property ex:官位 {@xsd:string} ;

# 将軍型クラスのプロパティとして「官位」を設定する。
 set ex:将軍型 > ex:官位;

それほど難しくはないのだが、IMIの固有の記法であるため、やはりある程度の勉強や試行錯誤が必要となる。
これもGUIでできるようになるのが理想的だが、どうしてもできなければ、記載例をもっと豊富に提示していただきたいところだ。

「DMD作成支援」では、応用語彙の追加が最も難しい。
さらに使いやすくなるよう、正式版リリース時にはぜひ改善していただきたい。

2018年6月24日日曜日

(総論)共通語彙基盤の活用に関する考察

共通語彙基盤の活用を検討する際、誰しもまず悩むのは、「手持ちの表形式のデータを、どのように共通語彙基盤対応とするか」、という点に尽きるのではないだろうか。

例えば、次のような表形式のデータがあるとする。

名前年齢(享年)
徳川 家康
75
徳川 秀忠
54
徳川 家光
48

上記の表データを、汎用性を考慮せず、単純にRDFに変換すると次のようになる。(Turtle形式)

@prefix shogun: <http://example.org/shogun_schema#> .
:001   shogun:名前   "徳川 家康" ;
          shogun:年齢    75 .
:002   shogun:名前   "徳川 秀忠" ;
          shogun:年齢    54 .
:003   shogun:名前   "徳川 家光" ;
          shogun:年齢    48 .

上記で使っている shogun:名前  shogun:年齢 は、私が適当に定義した語彙であり、こういった語彙は「独自定義語彙」などと呼ばれている。

独自定義語彙は、政府組織や権威のある学術機関がきっちり定義したものであれば再利用性が生じるが、そうでなければ、作成者限りの「狭い語彙」とみなされる。

上記のような、すべてが「狭い語彙」のRDFの価値は無に等しく、元データのエクセル表のほうがよっぽど汎用的で分かりやすい。

次に、世界標準の語彙を使って書き直したRDFを示す。

@prefix foaf: <http://xmlns.com/foaf/0.1/> .
:001   foaf:name   "徳川 家康" ;
          foaf:age      75 .
:002   foaf:name   "徳川 秀忠" ;
          foaf:age      54 .
:003   foaf:name   "徳川 家光" ;
          foaf:age      48 .

上記であれば、誰もが納得の「開かれた」RDFであることが一目瞭然だ。
しかしながら、作成者のセンスによっては、次のように書かれることもあろう。

@prefix schema: <http://schema.org/> .
@prefix foaf: <http://xmlns.com/foaf/0.1/> .
:001   schema:familyName   "徳川" ;
          schema:givenName    "家康" ;
          foaf:age                      75 .
:002   schema:familyName   "徳川" ;
          schema:givenName    "秀忠" ;
          foaf:age                      54 .
:003   schema:familyName   "徳川" ;
          schema:givenName    "家光" ;
          foaf:age                      48 .

これはこれで、世界標準のRDFとしてきちんと成立している。
じゃあ、どっちが正しいの、と聞かれると、どっちも正しい、としか言いようがない。

(日本語)これはラーメンです。
(英語) This is a ramen.
(フランス語) C'est un ramen.
(日本語・大阪弁)これはラーメンやねん。
(日本語・博多弁)これはラーメンばい。

上記がどれも正しいのと一緒。使っている言語や方言が違うだけだ。


これらを踏まえた上で、さて、共通語彙基盤はどこを目指しているのか。
我々ユーザーは、どう理解し、どう活用したらいいのか。

IMIのホームページには次の記載がある。

国・地方公共団体等が公開するデータの標準化を通じて、データの作成、流通、交換を容易にし促進するための基盤で、データに「価値」を生み出すことを目指しています。

ここ数年で、国や自治体のオープンデータ事業はかなり進み、官が保有している膨大なデータが、二次利用可能な形で、徐々に公開されるようになってきた。
その一方で、その提供されるデータ群は、省庁や自治体ごとに形式がバラバラで、使い勝手が良いとは言い難い。

これらのまとまりのないデータを標準化し、ユーザーが使いやすいものにするためのアプローチの一つが「政府推奨データセット」であり、もう一つがこの共通語彙基盤だ。

徳川将軍のデータに戻って、その二つの役割分担を考えてみる。

【政府推奨データセット】
⇒ 徳川将軍データセットに必要な項目は「名前」及び「年齢」であると決める。

【共通語彙基盤】
⇒ 徳川将軍データセットにおける「名前」及び「年齢」という各項目が、具体的に何を示しているかを明確にする。

もう少し具体的にいうと、共通語彙基盤を用いて、例えば「ものごとの名前」を表現するときは、その対象の性質により表現方法が変わる。

(人の名前の場合)         人型>氏名型>ic:氏名>ic:姓名 ⇒ 徳川家康
(組織の名称の場合)      組織型>名称型>ic:表記 ⇒ 加賀藩
(イベントの名称の場合)イベント型>名称型>ic:表記 ⇒ 大政奉還

このような形で、対象項目が何を示しているかをきっちり指し示し、曖昧さを排除した表現とするのが、共通語彙基盤の役割であろう。

【共通語彙基盤の適用例】
@prefix ic: <http://imi.go.jp/ns/core/rdf#> .
:001  a  ic:人型 ;
         ic:氏名 [ ic:姓名 "徳川 家康"^^xsd:string ] ;
         ic:年齢 [ ic:数値 "75"^^xsd:integer ] .
:002  a  ic:人型 ;
         ic:氏名 [ ic:姓名 "徳川 秀忠"^^xsd:string ] ;
         ic:年齢 [ ic:数値 "54"^^xsd:integer ] .
:003  a  ic:人型 ;
         ic:氏名 [ ic:姓名 "徳川 家光"^^xsd:string ] ;
         ic:年齢 [ ic:数値 "48"^^xsd:integer ] .


曖昧さや多様性といったものは必ずしも悪いものではなく、それがあるからこそ発展があり、新しい知見が生み出されていく。

しかし、曖昧さや多様性が障害となる分野もある。コンピューターのプログラムや、法律などがそれにあたる。

もし刑法に「悪いやつには、罰を与える」と書いてあったら、何をしたらどんな罰を受けるのか全く分からないし、戦前の治安維持法のような運用も可能となる。
そのような曖昧さを回避し、「ものを盗んだ人には、懲役3年の刑罰を与える」と具体的に示すのが、共通語彙基盤の本質的な意義だろう。

法の執行者であり、公共性や中立性が求められる公務の分野においては、共通語彙基盤の思想は比較的馴染みやすい。公的機関が共通語彙基盤を利用する土壌は少しずつ整ってきており、次は実践が必要な段階だ。

そのためには、IPAは、共通語彙基盤の技術情報や活用ツールの充実だけでなく、背景にある思想の周知や、利用者のメリットの広報に、これまで以上にリソースを割くべきだろう。
共通語彙基盤の魅力を存分に語ることができる「IMI伝道師」を育成して、日本各地を巡ってもらうのもいいかもしれないなぁ。

2018年6月3日日曜日

IMI意見交換会

6月1日、IPAのIMI意見交換会で講演させていただいた。


何をしゃべろうか悩んだが、やはり共通語彙基盤ネタがウケるだろうと考え、共通語彙基盤と Linked Open Data という超壮大なテーマを、超コンパクトにまとめてしゃべってきた。

しゃべったのは、「共通語彙基盤って、ぶっちゃけ難しすぎるよね」みたいな、身も蓋もない内容。
お気を悪くされた関係者もいたと思う。すいませんでした。

しかし今回の意見交換会、IPAの本気が感じられる素晴らしい会で、参加してほんとに良かったと感じている。データをめぐる最新の動向を知る良い機会ともなり、非常に勉強になった。

意外だったのは、拙作の共通語彙基盤ラーメンデータセットがニッチに人気があったこと。鯖江の福野さんの一日一創ブログでも紹介していただいた。

福野さんの、共通語彙基盤に対する感性はさすがに鋭く、ユーザーとして、また技術者としての様々な見解は、非常に共感できるものだった。
全角日本語の語彙は、グローバル社会の中で受け入れられるのは難しいのではないかという問題提起、Schema.orgとの互換性、などなど。
多様性と信頼の共存、まさにそれが必要だろう。

みんなの幸せのための共通語彙基盤の発展に、私も、少しでも力添えができたらと考えている。