オープンデータ利用
静岡産業技術専門学校
2015年 4年生前期 水野信也
クラウド情報基盤研究室
データの循環から、
価値を生み出す
モバイル組み込み環境
IoT/M2M
・スマートフォン
・組み込みAndroid
・Arduino
・ウェアラブル
・動画
クラウド環境 ビッグデータ
・Paasの利用(GAE, AWS)
・各種Webシステム
データ
データ解析環境
・数学的アプローチ
・視覚化
・各種ツールの利用
各種APIの利用
DB
DB
DB
DB
DB
オープンデータとは?
「機械判読に適したデータ形式で、二次利用が可能な利用ルールで公開されたデータ」
「人手を多くかけずにデータの二次利用を可能とするもの」
→公的・公共機関のデータを利用し、新しいシステムを提案する
オープンデータ利用を
考えてみよう!
・利用するデータ
・提案する結果
例1
利用データ:AEDの設置場所
提案する結果:現在地から一番近いAEDの場所を提供
例2
利用するデータ:津波タワー
提案する結果:現在地から一番近い津波タワーの場所とルートを提供
オープンデータの種類
オープンデータ戦略の推進(総務省)
http://www.soumu.go.jp/menu_seisaku/ictseisaku/ictriyou/opendata/
ふじのくにオープンデータカタログ
http://www.pref.shizuoka.jp/kikaku/ki-330/opendata/
http://www.city.shizuoka.jp/186_000001.html (静岡市)
5/20 出席レポート
12:10までに、サイボウズ->情報理論(水野)
に
・利用するデータ
・提案する結果
を投稿しなさい。
→今回は静岡市のWiFiスポット一覧を利用する
本の紹介
[24時間365日] サーバ/インフラを支える技術 ‾スケーラビリティ、ハイパフォーマンス、省力運用 (WEB+DB PRESS plusシリーズ)
本の紹介
スッキリわかるサーブレット&JSP入門
5/27 静岡市WiFiスポット
WiFiスポット検索システム
目的:現在地から、各WiFiスポットの距離、時間を計算し、一番近いWiFiスポットを提案する
フェーズ1:データをアップロードし、利用出来る形にする
フェーズ2:Webシステムとして利用出来るようにする
フェーズ3:モバイルと連携して利用出来るようにする
データベースの準備
phpMyAdmin
http://学籍番号.sangi01.net/phpMyAdmin/
ID j120XX
PASS j120XX
データベースの準備
テーブル3個
テーブル名:spots 「WiFiスポット情報」
(id,name,address,campany,latitude,longitude,created,modified)
テーブル名:places 「現在地情報」
(id,name,address,latitude,longitude,created,modified)
テーブル名:「distances」 現在地とWiFiスポットのパラメタ(距離、時間)
(id, spot_id,place_id,distance,duration,created,modified)
spotsテーブル作成
placesテーブル
distancesテーブル
Cakephpの環境を作成
学生ファイルサーバ->student->J4->授業資料->Opendata->cakephp-2.6.4.zip
をデスクトップにコピー
zipファイルをサーバにFTPでアップロード
FTP ホスト:学籍番号.sangi01.net
ID j120XX, PASS sangij120XX
でログインし、wwwの中に入れる
※接続モードを「アクティブ」に変更
SSHでログイン
puttyで接続
ホスト名:j120XX.sangi01.net
変換->文字コードをUTF-8に変更
開くを押す
ユーザ名:j120XX
パスワード:sangij120XX
で接続
cakephp設定
$ cd www
$ ls
[j11000@ip-10-126-24-180 ~]$ cd www
[j11000@ip-10-126-24-180 www]$ ls
README cakephp-2.6.4.zip
解凍
$ unzip cakephp-2.6.4.zip
フォルダ名変更
$ mv cakephp-2.6.4 opendata
cakephp設定
$ cd opendata
opendata]$ chmod -R 777 lib/Cake/Cache/
opendata]$ cd app
app]$ chmod -R 777 tmp
ブラウザでアクセスして確認
http://j120XX.sangi01.net/opendata/
cakephp設定
app]$ vi Config/core.php
行番号を出す
: set number
行に移動(225行目に移動)
225G
これを適当な値に変更
保存して閉じる(Esc :wq)
cakephpの設定
ブラウザでアクセスするとNoticeが消えている
データベース設定
app]$ Console/cake bake
Name:
[default] >
Datasource: (Mysql/Postgres/Sqlite/Sqlserver)
[Mysql] >
Persistent Connection? (y/n)
[n] >
Database Host:
[localhost] >
Port?
[n] >
User:
[root] > j120XX
Password:
> j120XX
Database Name:
[cake] > j120XX
Table Prefix?
[n] >
Table encoding?
[n] > utf8
データベース設定
ブラウザで確認すると、緑が増えている
spotsテーブルのbake
app]$ Console/cake bake
Enter a number from the list above,
type in the name of another model, or 'q' to exit
[q] > 13(spotの番号)
Would you like to supply validation criteria
for the fields in your model? (y/n)
[y] >
この後はデフォルトでOK(Validationをつける)
stopsテーブル
Would you like to define model associations
(hasMany, hasOne, belongsTo, etc.)? (y/n)
[y] >
Spot hasMany Distance? (y/n)
[y] >
Would you like to define some additional model associations? (y/n)
[n] >
Look okay? (y/n)
[y] >
PHPUnit is not installed. Do you want to bake unit test files anyway? (y/n)
[y] > n
spotsテーブルのM(モデル)は終了
spotsテーブル(コントローラ)
What would you like to Bake? (D/M/V/C/P/F/T/Q)
> C
[q] > 13(spotの番号)
---------------------------------------------------------------
Baking SpotsController
---------------------------------------------------------------
Would you like to build your controller interactively? (y/n)
[y] >
spotsテーブル(コントローラ)
spotsテーブル(View)
What would you like to Bake? (D/M/V/C/P/F/T/Q)
> V
Enter a number from the list above,
type in the name of another controller, or 'q' to exit
[q] > 13(spotsの番号)
Would you like bake to build your views interactively?
Warning: Choosing no will overwrite Spots views if they exist. (y/n)
[n] >
spotsテーブル確認
placesテーブルも同様にbake
distancesテーブルも同様にbake
M -> C -> Vの順で実施
http://j120XX.sangi01.net/opendata/distances/
にアクセス
Mのとき
A displayField could not be automatically detected
would you like to choose one? (y/n)
> n
nを入力
distancesテーブル確認
今日の課題
6/5 データのアップロード
SSHで接続、cd www/opendata/appに移動
SpotsテーブルにデータをCSVでアップロードを行う
http://j12XXX.sangi01.net/opendata/spots/csv
spots : モデル名(テーブル名)
csv:コントローラーの中の関数名
SpotsController->csv関数
表示:
View/Spots/csv.ctp (作成)
http://ホスト名/ルートフォルダ名/モデル名/アクション名
csv.ctp(表示)を作成
add.ctpをコピーして利用する
app]$ cp View/Spots/add.ctp View/Spots/csv.ctp
コントローラにcsvアクションを追加する
app]$ vi Controller/SpotsController.php
public function csv(){ //空の関数
}
保存 Esc + :wq
確認
http://j12XXX.sangi01.net/opendata/spots/csv
にアクセス
この画面の必要ないものを削除
app]$ vi View/Spots/csv.ctp
削除
2 <?php echo $this->Form->create('Spot'); ?>
6 echo $this->Form->input('name');
7 echo $this->Form->input('address');
8 echo $this->Form->input('campany');
9 echo $this->Form->input('latitude');
10 echo $this->Form->input('longitude');
13 <?php echo $this->Form->end(__('Submit')); ?>
csv.ctp
追加
echo $this->Form->create('Spot',array('action'=>'import','type'=>'file'));
echo $this->Form->input('CsvFile',array('label'=>'','type'=>'file'));
echo $this->Form->end('Upload');
create(‘Spot’ SpotsではなくSpot
確認
http://j12XXX.sangi01.net/opendata/spots/csv
保存が出来なくなった場合
swpファイルが出来ている可能性あり
ls -la 指定ディレクトリ
.swpファイルがあった場合
rm 指定ディレクトリ/ファイル名.swp
でswpファイルを削除
Spots->importアクションの作成
app]$ vi Controller/SpotsController.php
public function import(){
if($this->request->is('post')){
$up_file = $this->data['Spot’]['CsvFile']['tmp_name'];
$fileName = 'post.csv';
if(is_uploaded_file($up_file)){
move_uploaded_file($up_file, $fileName);
$this->Spot->loadCSV($fileName);
$this->Session->setFlash('Uploaded');
$this->redirect(array('action'=>'index'));
}
}
}
Spots->loadCSV関数作成
アップロード
app]$ chmod 777 webroot/
ファイルを指定してアップロード
Spotsデータを地図表示
map関数の作成
app]$ vi Controller/SpotsController.php
public function map() {
$this->Spot->recursive = 0;
$this->paginate = array(
'conditions'=>array(),
'order' => array('id' => 'asc'),
'limit'=>200,
);
$this->set('spots', $this->Paginator->paginate());
}
map.ctpの作成
app]$ cp View/Spots/index.ctp View/Spots/map.ctp
app]$ vi View/Spots/map.ctp
1行目に追加
<?php echo $this->Html->script('http://maps.google.com/maps/api/js?sensor=true', false); ?>
を入れておく
マップ領域の作成
<h2><?php echo __('Spots'); ?></h2>の下に追加
<div id="map">
<?php echo $this->GoogleMap->map($map_options); ?>
</div>
map_optionsの作成:
<?php
$map_options = array(
'id' => 'map1',
'width' => '1200px',
'height' => '800px',
'zoom' => 13,
'type' => 'ROAD',
//'custom' => null,
'localize' => false,
'latitude' => 自分で指定,
'longitude' => 自分で指定,
'marker' => true,
'markerIcon' => 'http://google-maps-icons.googlecode.com/files/home.png',
'markerShadow' => 'http://google-maps-icons.googlecode.com/files/shadow.png',
'infoWindow' => true,
'windowText' => "自分で指定"
);
?>
中心、地図の設定を決める
マーカの作成
<?php $marker_index =1; ?>
<?php foreach ($spots as $spot): ?>
<?php
$marker_options = array(
'showWindow' => true,
'windowText' =>$spot['Spot']['id'].":".$spot['Spot']['name'],
'markerTitle' => 'Title',
'markerIcon' => 'http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld='.$spot['Spot']['id'].'|ff7e73|000000',
'markerShadow' => 'http://labs.google.com/ridefinder/images/mm_20_purpleshadow.png'
);
echo $this->GoogleMap->addMarker('map1', $marker_index, array('latitude' => $spot['Spot']['latitude'], 'longitude' =>$spot['Spot']['longitude'] ),$marker_options);
$marker_index ++;
?>
<?php endforeach; ?>
確認
今日の課題
本の紹介
“0”からはじめる入門データ・サイエンティスト
今後の予定
6/12 2コマ(レイアウト、パラメタ取得)
6/19 2コマ(解析手法)
7/3 2コマ(テーマ提出期限)
7/6〜8 テーマ課題制作
7/9 最終課題提出(プレゼン10分/人)4コマ
7/9 までの結果で評価
テーマ:各自考えておく
・オープンデータの利用(出典を明らかにする)
・APIの利用
・解析・計算、テーブル2個以上
6/12 レイアウト変更
www/opendata/app/View/Layout/
にj12000.ctp (テンプレート)を置く
自分の学籍番号にファイル名を変更しておく
www/opendata/app/webroot/css/
にcake.j12000.css をおく
自分の学籍番号にファイル名を変更しておく
2つのファイルをFTPでアップロード
j120XX.ctpを編集
$ cd www/opendata/app
$ vi View/Layout/j120XX.ctp
cake.j12XXX を自分の学籍番号(cssのファイル名)に変更
フッターも自分の情報に変更
文字化けした時の対処法
viの文字コードを変更
コマンドモードで
:set encoding=utf-8
を発行
全体にレイアウトを適用
$ vi Controller/AppController.php
クラス直下に
public $layout = "j120xx”;
確認
全ページにレイアウトが適用される
メニューの追加
テーブルに対してメニューを作成
・テーブル名:spots 「WiFiスポット情報」
・テーブル名:places 「現在地情報」
・テーブル名:distances 「現在地とWiFiスポットのパラメタ(距離、時間)」
・WiFiスポット情報:一覧、追加
(View、Edit、Deleteはメニューにいれない)
・現在地情報:一覧、追加
・現在地とスポットの距離・時間:一覧、追加
メニュー作成
メニュの反映
styles.css を app/webroot/css
にFTPでアップロード
$ vi View/Layout/j12XXX.ctp
メニュー用のcssを取り込み
メニューの追加
<div id='cssmenu'>
〜
</div> </body>の直前までをコピーして
<div id="content">
の上にはりつける
メニュー確認
リンクが飛ぶように確認
パラメータ取得の準備
Placesテーブル(現在地情報)に情報を追加すると、
distancesテーブルにplacesとspotsの組み合わせが登録されるようにする
準備
places/add.ctpを開き、latitude、longitudeの項目を削除
$ vi View/Places/add.ctp
現在地情報を入力
名前と住所を入力
->緯度、経度を取得
->distancesテーブルに、spotsテーブルとの組み合わせを追加
緯度、経度取得関数
緯度、経度の取得
$ vi Controller/PlacesController.php
add関数に追加
$result = $this->getLatLonElv($this->request->data['Place']['address']);
$this->request->data['Place']['latitude'] = $result[0];
$this->request->data['Place']['longitude'] = $result[1];
緯度、経度の動作確認
名前、住所をいれると緯度経度が取れる事を確認
今日の課題
6/19 Distancesテーブルへ格納
Placesテーブルにデータが追加されととき、PlacesテーブルとSpotsテーブルの組み合わせをDistancesテーブルへ格納
このときは(距離、時間は取得しない)
$ cd www/opendata/app
$ vi Controller/PlacesController.php
Spotsテーブルの情報を持ってくる
Placesモデルで別モデル(Spotsモデル、Distanceモデル)を使えるようにする
App::import('Model','Spot');
App::import('Model','Distance');
$this->Spot = new Spot;
$this->Distance = new Distance;
Spotsテーブルの情報
//Spots全件持ってくる
$spots = $this->Spot->find('all');
//SpotsとPlaceの組み合わせをDistanceに入れる
foreach($spots as $spot){
$data =array(
'spot_id' => $spot['Spot']['id'],
'place_id' => $this->Place->getLastInsertID()
);
$this->Distance->create();
$this->Distance->save($data);
}
動作確認
まず、Placesテーブルを空にする
Placesテーブル選択->操作->テーブルを空にする(Truncate)
同じようにDistancesテーブルも空にしておく
両テーブルにレコード無しの状態で、Placesテーブルに一見追加
->distancesテーブルに199件の組み合わせが入る
Distancesテーブルにレコード追加
distancesテーブルでデータ取得
1回につき、5件のデータを取得できるようにする
5件ずつ選択できるように、チェックボックスを作成
$ cp View/Distances/index.ctp View/Distances/choice.ctp
$ vi Controller/DistancesController.php
choice関数を作成
choice関数
index関数をコピー
choice.ctpを編集
$ vi View/Distances/choice.ctp
追加
<?php echo $this->Form->create('Distance',array('url'=> array('controller' => 'distances','action' => 'choiceIndex'))); ?>
choice.ctpを編集
<th>check</th>
を追加
choice.ctpを編集
追加
<td>
<?php
echo $this->Form->input('selectDistances.', array(
'type' => 'checkbox',
'value' => $distance['Distance']['id'],
'checked' => true,
'div' => false
));
?> </td>
choice.ctpを編集
submitボタン
<?php echo $this->Form->end('Submit'); ?>
チェックボックスを確認
choice関数を編集
distanceまたはdurationが空のものを5件ずつページング
$ vi Controller/DistancesController.php
$this->paginate = array(
'conditions'=>array(
'OR' => array(
array('distance' => ''),
array('duration' => '')
)
),
'order' => array('id' => 'asc'),
'limit'=>5,
);
choice関数
受け取り:choiceIndex関数
$ vi Controller/DistancesController.php
public function choiceIndex(){
$parameters = $this->Distance->find('all',array('conditions' => array('Distance.id' => $this->data['Distance']['selectDistances'])));
foreach($parameters as $parameter){
$result = $this->getDirection($parameter['Place']['latitude'],$parameter['Place']['longitude'],$parameter['Spot']['latitude'],$parameter['Spot']['longitude']);
$data = array(
'id' => $parameter['Distance']['id'],
'distance' => $result[0],
'duration' => $result[1]
);
$this->Distance->save($data);
}
return $this->redirect(array('action' => 'choice'));
}
距離、時間を取得する関数
$ vi Controller/AppController.php
public function getDirection($orglat, $orglon, $dstlat, $dstlon){
$datas = file_get_contents("http://maps.googleapis.com/maps/api/directions/json?origin=$orglat,$orglon&destination=$dstlat,$dstlon&sensor=false");
$directions = json_decode($datas);
$direction = $directions->routes[0]->legs[0];
$distance = $direction->distance->value;
$duration = $direction->duration->value;
$result = array($distance, $duration);
return $result;
}
確認
/distances/choce
でsubmitを押すと距離、時間が取得できる
6/19 課題
5件ずつ距離、時間を取得してDistancesテーブルに格納する(全件とらなくてよい)
メニューに
Spotsテーブル->CSVアップロード
(csv.ctpへのリンク)
Distancesテーブル->パラメータ取得
(choice.ctpへのリンク)
http://j120XX.sangi01.net/opendata/distances/
をサイボウズに投稿
7/3 Place->Viewの情報
現在のViewはパラメータ情報を持っている
Viewの下に関連情報が表示されている->これを利用
7/3 最短距離にあるWiFiSpotを表示
Placeテーブル->Viewに最短距離にあるWiFiSpot情報を表示する
$ vi Controller/PlacesController.php
Viewのfind文を変更
$place = $this->Place->find('first', array($options,'recursive'=>2));
recursive=>2 とすると関連・関連テーブル情報まで取得
Viewのfind �文
recursive=>2での情報
print_r($place);
spot_idの関連テーブル(spotテーブル)の情報も取得
Place->Viewを確認
View アクション
public function view($id = null) {
if (!$this->Place->exists($id)) {
throw new NotFoundException(__('Invalid place'));
}
$options = array('conditions' => array('Place.' . $this->Place->primaryKey => $id));
$place = $this->Place->find('first', array($options,'recursive'=>2));
print_r($place);
//ここまでがテーブルからの情報取得
View アクション 続き
最短距離の計算
$min_index = 0; //最短のWiFiSpotのID
$min_distance = 10000000; //最短距離
foreach ($place['Distance'] as $distance){
if($min_distance > $distance['distance']){
$min_distance = $distance['distance'];
$min_index = $distance['id'];
$min_latitude = $distance['Spot']['latitude'];
$min_longitude = $distance['Spot']['longitude'];
$min_name = $distance['Spot']['name'];
}
}
//最短距離のWiFiSpotが確定
View アクション 続き
最短距離WiFiSpot情報を配列に格納
$min = array('min_index' => $min_index, 'min_distance' => $min_distance, 'min_latitude' => $min_latitude, 'min_longitude' => $min_longitude, 'min_name' => $min_name);
//minとplaceという変数でViewに引き渡す
$this->set('min', $min);
$this->set('place', $place);
Viewアクション全体
$vi View/Place/view.ctp
1行目
<?php echo $this->Html->script('http://maps.google.com/maps/api/js?sensor=true', false); ?>
Place->view.ctp
地図を表示
<?php
$latitude = $place['Place']['latitude'];
$longitude = $place['Place']['longitude'];
$windowText = $place['Place']['name'];
$map_options = array(
'id' => 'map1',
'width' => '1200px',
'height' => '800px',
'zoom' => 13,
'type' => 'ROAD',
//'custom' => null,
'localize' => false,
'latitude' => $latitude,
'longitude' => $longitude,
'marker' => true,
'markerIcon' => 'http://google-maps-icons.googlecode.com/files/home.png',
'markerShadow' => 'http://google-maps-icons.googlecode.com/files/shadow.png',
'infoWindow' => true,
'windowText' => $windowText
);
?>
<div id="map">
<?php echo $this->GoogleMap->map($map_options); ?>
</div>
$vi View/Place/view.ctp
基本情報の下、アクションの上に地図を表示
マーカー追加
<?php
$marker_options = array(
'showWindow' => true,
'windowText' =>$min['min_name'].":".$min['min_distance']."m",
'markerTitle' => 'Title',
'markerIcon' => 'http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld='.$min['min_index'].'|ff7e73|000000',
'markerShadow' => 'http://labs.google.com/ridefinder/images/mm_20_purpleshadow.png'
);
echo $this->GoogleMap->addMarker('map1', 1, array('latitude' => $min['min_latitude'], 'longitude' =>$min['min_longitude'] ),$marker_options);
?>
ルート表示
<div id="directions01">
<?php
echo $this->GoogleMap->getDirections("map1", "directions1", array(
"from" => array("latitude" => $place['Place']['latitude'], "longitude" => $place['Place']['longitude']),
"to" => array("latitude" => $min['min_latitude'], "longitude" => $min['min_longitude'])
), array(
"travelMode" => "DRIVING",
"directionsDiv" => "directions01",
));
?>
</div>
完成
地図上にマーカ、ルート案内を出す
http://j11000.sangi01.net/opendata/places/view/1
課題提出について
課題0
授業でやった内容
課題1
メニュー->WiFiスポット情報->一覧
アクション->Viewにマップを追加(マーカ付き)
課題2
メニュー->現在地とスポットの距離時間->一覧
アクション->Viewにマップを追加(マーカ、ルート付き)
課題1(view.ctpのみ変更でOK)
Viewをクリック
ViewにMapが表示される
課題2(view.ctpのみ変更でOK)
現在地とスポットの距離時間->一覧->Viewを表示
ルートが表示される
課題提出
すべての課題を実施し、7月6日(月)朝9:30までにサイボウズにURLを提出
提出URL
http://j12XXX.sangi01.net/opendata/spots
最終課題テーマ提出
[最終課題内容提出]
タイトル:******を利用したXXXXXXXXXXXサイトの構築
(********はオープンデータ名、XXXXXXXXXXXは求める内容)
利用データURL:
概要:200字程度
提出期限 7月6日11:00まで
サイボウズに投稿すること