政府統計情報 e-Stat を Apache Drill で分析してみる (2)

前回の記事の続きからです。

メタ情報の取得

前回は、平成22年度の国勢調査の人口増減のデータを含む統計表ID「0003038586」を探し出すところまでいきました。

次は、この表がどのような構造をしているか調べるために、表のメタ情報を次のAPIを使用して取得します。必要なパラメータは自分のアプリケーションIDと統計表ID「0003038586」です。

$ curl -o /tmp/meta_info.json "http://api.e-stat.go.jp/rest/2.0/app/json/getMetaInfo?appId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&statsDataId=0003038586"

実際のところ、ここで取得したデータは一部のデータ型に問題があるので、そのままDrillのクエリを実行するとエラーになってしまいます。問題についての詳細と対処方法についてはこの記事でも書きましたが、JSON加工ツール「jq」で次のようにデータを整形して使用することにします。

$ jq '(.. | objects | .CLASS | objects) |= [.]' /tmp/meta_info.json > /tmp/meta_info_modified.json

それでは、APIの出力データの仕様を見つつデータを眺めてみます。メタ情報JSONファイルの最上位のオブジェクトのキーは「GET_META_INFO」となっていますので、前回同様KVGEN()関数とFLATTEN()関数を使って中の要素を表示してみましょう。

0: jdbc:drill:zk=local> SELECT FLATTEN(KVGEN(t.GET_META_INFO)) FROM dfs.`/tmp/meta_info_modified.json` t;
+------------------------------------------------------------------------------+
|                                                                              |
+------------------------------------------------------------------------------+
| {"key":"RESULT","value":{"STATUS":0,"ERROR_MSG":"正常に終了しました。","DATE":"2015-06 |
| {"key":"PARAMETER","value":{"LANG":"J","STATS_DATA_ID":"0003038586","DATA_FO |
| {"key":"METADATA_INF","value":{"TABLE_INF":{"@id":"0003038586","STAT_NAME":{ |
+------------------------------------------------------------------------------+
3 rows selected (0.367 seconds)

メタ情報本体である「METADATA_INF」を見てみます。

0: jdbc:drill:zk=local> SELECT FLATTEN(KVGEN(t.GET_META_INFO.METADATA_INF)) FROM dfs.`/tmp/meta_info_modified.json` t;
+------------------------------------------------------------------------------+
|                                                                              |
+------------------------------------------------------------------------------+
| {"key":"TABLE_INF","value":{"@id":"0003038586","STAT_NAME":{"@code":"0020052 |
| {"key":"CLASS_INF","value":{"STAT_NAME":{},"GOV_ORG":{},"TITLE":{},"MAIN_CAT |
+------------------------------------------------------------------------------+
2 rows selected (0.237 seconds)

「TABLE_INF」は指定した統計表の情報、「CLASS_INF」はデータのメタ情報です。「CLASS_INF」のほうを見てみましょう。

0: jdbc:drill:zk=local> SELECT FLATTEN(KVGEN(t.GET_META_INFO.METADATA_INF.CLASS_INF)) FROM dfs.`/tmp/meta_info_modified.json` t;
+------------------------------------------------------------------------------+
|                                                                              |
+------------------------------------------------------------------------------+
| {"key":"CLASS_OBJ","value":[{"@id":"tab","@name":"表章項目","CLASS":[{"@code":"0 |
+------------------------------------------------------------------------------+
1 row selected (5.208 seconds)

「CLASS_OBJ」はデータのメタ情報のオブジェクトですが、複数のオブジェクトが配列として格納されているので、次はFLATTEN()関数のみで展開します。

0: jdbc:drill:zk=local> SELECT FLATTEN(t.GET_META_INFO.METADATA_INF.CLASS_INF.CLASS_OBJ) FROM dfs.`/tmp/meta_info_modified.json` t;
+------------------------------------------------------------------------------+
|                                                                              |
+------------------------------------------------------------------------------+
| {"@id":"tab","@name":"表章項目","CLASS":[{"@code":"020","@name":"人口","@level":"" |
| {"@id":"cat01","@name":"全域・人口集中地区2010","CLASS":[{"@code":"00710","@name":"全域 |
| {"@id":"area","@name":"地域(2010)","CLASS":[{"@code":"00000","@name":"全国","@le |
| {"@id":"time","@name":"時間軸(年次)","CLASS":[{"@code":"2010000000","@name":"2010 |
+------------------------------------------------------------------------------+
4 row selected (0.148 seconds)

メタ情報としては、「表章項目(=テーブルのカラム)」「全域・人口集中地区2010(=カテゴリ分け)」「地域(2010)(=地域コード)」「時間軸(年次)(=時間)」の4種類があることがわかります。それぞれの要素は「CLASS」に配列として格納されていますので、これも見てみることにします。「CLASS_OBJ」は配列ですので、それぞれインデックスを指定する必要があります。

まずは「表章項目」

0: jdbc:drill:zk=local> SELECT FLATTEN(t.GET_META_INFO.METADATA_INF.CLASS_INF.CLASS_OBJ[0].CLASS) FROM dfs.`/tmp/meta_info_modified.json` t;
+--------------------------------------------------------------------+
|                               EXPR$0                               |
+--------------------------------------------------------------------+
| {"@code":"020","@name":"人口","@level":"","@unit":"人"}               |
| {"@code":"100","@name":"組替人口(平成17年)","@level":"","@unit":"人"}      |
| {"@code":"101","@name":"平成17年~22年の人口増減数","@level":"","@unit":"人"}  |
| {"@code":"102","@name":"平成17年~22年の人口増減率","@level":"","@unit":"%"}  |
| {"@code":"103","@name":"面積","@level":"","@unit":"平方km"}            |
| {"@code":"104","@name":"人口密度","@level":""}                         |
+--------------------------------------------------------------------+
6 rows selected (0.166 seconds)

続いて「全域・人口集中地区2010」。人口集中地区というのは国勢調査特有の用語で、人口集中地区 - Wikipediaによれば「市区町村の区域内で人口密度が4,000人/km²以上の基本単位区が互いに隣接して人口が5,000人以上となる地区」とのことです。

0: jdbc:drill:zk=local> SELECT FLATTEN(t.GET_META_INFO.METADATA_INF.CLASS_INF.CLASS_OBJ[1].CLASS) FROM dfs.`/tmp/meta_info_modified.json` t;
+----------------------------------------------------+
|                       EXPR$0                       |
+----------------------------------------------------+
| {"@code":"00710","@name":"全域","@level":"1"}        |
| {"@code":"00711","@name":"人口集中地区","@level":"1"}    |
| {"@code":"00712","@name":"人口集中地区01","@level":"1"}  |
| {"@code":"00713","@name":"人口集中地区02","@level":"1"}  |
| {"@code":"00714","@name":"人口集中地区03","@level":"1"}  |
| {"@code":"00715","@name":"人口集中地区04","@level":"1"}  |
| {"@code":"00716","@name":"人口集中地区05","@level":"1"}  |
| {"@code":"00717","@name":"人口集中地区06","@level":"1"}  |
| {"@code":"00718","@name":"人口集中地区07","@level":"1"}  |
| {"@code":"00719","@name":"人口集中地区08","@level":"1"}  |
| {"@code":"00720","@name":"人口集中地区09","@level":"1"}  |
+--------------------------------------------------------------------+
11 rows selected (0.184 seconds)

次に、最も要素の多い「地域(2010)」。

0: jdbc:drill:zk=local> SELECT FLATTEN(t.GET_META_INFO.METADATA_INF.CLASS_INF.CLASS_OBJ[2].CLASS) FROM dfs.`/tmp/meta_info_modified.json` t;
+-----------------------------------------------------------------------+
|                                EXPR$0                                 |
+-----------------------------------------------------------------------+
| {"@code":"00000","@name":"全国","@level":"1"}                           |
| {"@code":"00001","@name":"全国市部","@level":"1"}                         |
| {"@code":"00002","@name":"全国郡部","@level":"1"}                         |
| {"@code":"01000","@name":"北海道","@level":"2","@parentCode":"00000"}    |
| {"@code":"01001","@name":"北海道市部","@level":"3","@parentCode":"01000"}  |
| {"@code":"01002","@name":"北海道郡部","@level":"3","@parentCode":"01000"}  |
| {"@code":"01100","@name":"札幌市","@level":"3","@parentCode":"01000"}    |
| {"@code":"01101","@name":"中央区","@level":"4","@parentCode":"01100"}    |
| {"@code":"01102","@name":"北区","@level":"4","@parentCode":"01100"}     |
| {"@code":"01103","@name":"東区","@level":"4","@parentCode":"01100"}     |
| ...                                                                   |
+-----------------------------------------------------------------------+
4,499 rows selected (19.901 seconds)

最後に「時間軸(年次)」。もともと2010年のデータしか入っていないので、要素数は1です。

0: jdbc:drill:zk=local> SELECT FLATTEN(t.GET_META_INFO.METADATA_INF.CLASS_INF.CLASS_OBJ[3].CLASS) FROM dfs.`/tmp/meta_info_modified.json` t;
+------------------------------------------------------+
|                        EXPR$0                        |
+------------------------------------------------------+
| {"@code":"2010000000","@name":"2010年","@level":"1"}  |
+------------------------------------------------------+
1 row selected (0.167 seconds)

個々の統計データには上記の4つの属性がそれぞれ含まれることになります。

統計データの取得

では、いよいよ統計表ID「0003038586」の統計データを取得しましょう。ここでは「人口」「人口増減率」「人口密度」だけを対象としたいので、パラメータとして表章項目コード「020,102,104」を指定しています。また、統計データには前述のメタデータも含まれるので、同じようにjqでデータを整形します。

$ curl -o stats_data.json "http://api.e-stat.go.jp/rest/2.0/app/json/getStatsData?appId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&statsDataId=0003038586&cdTab=020,102,104"
$ jq '(.. | objects | .CLASS | objects) |= [.]' /tmp/stats_data.json > /tmp/stats_data_modified.json

APIの出力データの仕様によると、統計データJSONファイルの最上位のオブジェクトのキーは「GET_STATS_DATA」です。

0: jdbc:drill:zk=local> SELECT FLATTEN(KVGEN(t.GET_STATS_DATA)) FROM dfs.`/tmp/stats_data_modified.json` t;
+------------------------------------------------------------------------------+
|                                                                              |
+------------------------------------------------------------------------------+
| {"key":"RESULT","value":{"STATUS":0,"ERROR_MSG":"正常に終了しました。","DATE":"2015-06 |
| {"key":"PARAMETER","value":{"LANG":"J","STATS_DATA_ID":"0003038586","NARROWI |
| {"key":"STATISTICAL_DATA","value":{"NARROWING_COND":{},"RESULT_INF":{"TOTAL_ |
+------------------------------------------------------------------------------+
3 rows selected (0.495 seconds)

統計データ本体である「STATISTICAL_DATA」を見てみます。

0: jdbc:drill:zk=local> SELECT FLATTEN(KVGEN(t.GET_STATS_DATA.STATISTICAL_DATA)) FROM dfs.`/tmp/stats_data_modified.json` t;
+------------------------------------------------------------------------------+
|                                                                              |
+------------------------------------------------------------------------------+
| {"key":"RESULT_INF","value":{"TOTAL_NUMBER":19356,"FROM_NUMBER":1,"TO_NUMBER |
| {"key":"TABLE_INF","value":{"@id":"0003038586","STAT_NAME":{"@code":"0020052 |
| {"key":"CLASS_INF","value":{"STAT_NAME":{},"GOV_ORG":{},"TITLE":{},"MAIN_CAT |
| {"key":"DATA_INF","value":{"STAT_NAME":{},"GOV_ORG":{},"TITLE":{},"MAIN_CATE |
+------------------------------------------------------------------------------+
4 rows selected (0.429 seconds)

「RESULT_INF」は取得結果の情報、「TABLE_INF」は指定した統計表の情報、「CLASS_INF」はデータのメタ情報、「DATA_INF」はデータ本体です。メタ情報の部分は前のステップで取得したものと共通です。「DATA_INF」の中を見てみましょう。

0: jdbc:drill:zk=local> SELECT FLATTEN(KVGEN(t.GET_STATS_DATA.STATISTICAL_DATA.DATA_INF)) FROM dfs.`/tmp/stats_data_modified.json` t;
+------------------------------------------------------------------------------+
|                                                                              |
+------------------------------------------------------------------------------+
| {"key":"NOTE","value":[{"@char":"***","$":"当該数値がないもの"},{"@char":"-","$":"当該数 |
| {"key":"VALUE","value":[{"$":"128057352","@tab":"020","@cat01":"00710","@are |
+------------------------------------------------------------------------------+
2 rows selected (199.208 seconds)

「NOTE」は備考の文字列を列挙している配列、「VALUE」はデータの配列です。「VALUE」をFLATTEN()関数で展開してみます。「VALUE」はDrillでは予約語なので、バッククォートで囲う必要があります。

0: jdbc:drill:zk=local> SELECT FLATTEN(t.GET_STATS_DATA.STATISTICAL_DATA.DATA_INF.`VALUE`) FROM dfs.`/tmp/stats_data_modified.json` t;
+---------------------------------------------------------------------------------------------------+
|                                              EXPR$0                                               |
+---------------------------------------------------------------------------------------------------+
| {"@tab":"020","@cat01":"00710","@area":"00000","@time":"2010000000","@unit":"人","$":"128057352"}  |
| {"@tab":"020","@cat01":"00710","@area":"00001","@time":"2010000000","@unit":"人","$":"116156631"}  |
| {"@tab":"020","@cat01":"00710","@area":"00002","@time":"2010000000","@unit":"人","$":"11900721"}   |
| {"@tab":"020","@cat01":"00710","@area":"01000","@time":"2010000000","@unit":"人","$":"5506419"}    |
| {"@tab":"020","@cat01":"00710","@area":"01001","@time":"2010000000","@unit":"人","$":"4449360"}    |
| {"@tab":"020","@cat01":"00710","@area":"01002","@time":"2010000000","@unit":"人","$":"1057059"}    |
| {"@tab":"020","@cat01":"00710","@area":"01100","@time":"2010000000","@unit":"人","$":"1913545"}    |
| {"@tab":"020","@cat01":"00710","@area":"01101","@time":"2010000000","@unit":"人","$":"220189"}     |
| {"@tab":"020","@cat01":"00710","@area":"01102","@time":"2010000000","@unit":"人","$":"278781"}     |
| {"@tab":"020","@cat01":"00710","@area":"01103","@time":"2010000000","@unit":"人","$":"255873"}     |
| ...                                                                                               |
+---------------------------------------------------------------------------------------------------+
19,356 rows selected (303.648 seconds)

各要素には「表章項目」「全域・人口集中地区」「地域」「時間軸」の属性のほか、「$unit(=単位)」と「$(=値)」が含まれていることがわかります。

これでデータが揃いました。次の記事で、分析をしてみることにします。