路線・駅検索をPHPで実装する方法解説。GoogleMapsの緯度経度から計算し検索
2018/09/04
路線・駅検索をPHPで実装する方法を解説
路線・駅検索を利用するシステムはいっぱいあります。
例えば Webサイトでは、求人検索サイトや、不動産の物件検索サイト、飲食店検索サイトなどです。
路線、駅を選択し、駅から 5分、10分の距離にある企業や物件、店舗などを検索するシステムです。
その路線・駅検索のシステムをより簡単に実装できないか、ということを考えました。
一般的な路線・駅検索の仕組み
一般的な路線・駅検索の仕組みは、検索対象となるスポット(求人企業の事務所の位置、不動産物件の位置など)の「最寄りとなる駅」と「駅からの距離(もしくは、徒歩でかかる時間)」を登録しておきます。
最寄りの駅が複数ある場合は、複数の駅を登録しておきます。
そして、検索をする際には、その登録している駅と駅からの距離の情報を対象に検索を実行し、結果を処理します。
一般的な路線・駅検索の問題点
ですが、路線・駅検索は結構ハードルが高いのです。
かかるコストも高いのです。
なぜなら、そもそも、路線、駅のデータが公的な情報としてまとまって提供されているわけではないためです。
また、路線、駅のデータは相応に膨大な量になり、かつ、駅や路線は増えたり減ったりすることがあるからです。
そして、もう一つの根本的な問題点として、鉄道には駅で電車を乗り換える、ということがある点です。
例えば、日本一の乗降客がある新宿駅。
新宿駅には多くの路線が乗り入れています。
JR、京王線、小田急線、東京メトロ丸の内線、都営地下鉄大江戸線などです。
また、最初に JRと書きましたが、JRの中にも山手線、中央線、総武線各駅などなど複数路線があります。
また、「新宿駅」という名前ではないものの、実際には乗換駅である場合もあります。
東京メトロ丸の内線、副都心線の新宿三丁目駅、都営大江戸線の新宿西口駅などです。
さらに、西武新宿線の「新宿駅」は、「新宿駅」という名前が付いていますが、都営大江戸線の新宿西口駅よりも遠くにあります。
乗り換えには、屋根がない地上を数百メートルほど歩く必要があり(横断歩道などで大通りを通る必要などもあります)、同じ新宿駅としていいのか、という疑問がわきます。
同じように、同じ駅名なのに離れた場所にある駅や、違う駅名なのにすぐ近くの駅であったり、ということが全国にあるのです。
どの駅を乗換駅とするか、しないか、それをどう判断するのかは非常に煩雑なのです。
駅・路線検索の問題点の一つの解決策
そのため、一般的な最寄りの駅を登録する方法を止め、指定された駅と、検索対象となるスポットの緯度経度を取得し、そこから 2点間の距離を計算し、それに基づいて条件抽出したらいいんじゃないか、という発想をしたわけです。
(まぁ、この発想に基づいて処理をする APIがすでにあるようなので、特段新しい発想ではありませんが...)
ただし、この方法の問題点は、駅からの距離は分かるものの、駅から徒歩で何分かかるのかが分からない、ということです。
駅から 500mであったとしても、直線で行ける場合と、遠回りしないとたどり着けない場合とあり、どれだけかかるかが分からないという点です。
また、駅の場所として処理される緯度経度は、駅の中の特定の場所で、駅の出口からの距離ではないところも問題点となりえます。
もっとも、一般的な表示である「駅から徒歩 5分」と書かれていても、坂道や信号待ちの時間などは考慮されていませんし、そもそも地下鉄や大きな駅など、ホームから駅の出口までに 10分ほどかかるような駅もありますので、「駅から徒歩 5分」と書かれていても、電車を降りてからどれくらい時間がかかるのかを正確に示したものではない、ということになります。
それを考えると、「どういう計算で算出している情報なのか」さえ明記しておけばいいんじゃないか、と考えました。
(一般的には道のりで時間を出していますので、誤解は発生しやすいかとは思いますが。)
路線・駅の情報は「駅データ.jp」を利用
今回紹介している路線・駅のデータは、下記の「駅データ.jp」さんのデータを利用しています。
「駅データ.jp」さんが路線、駅のデータ、および、検索の APIを提供してくださっていますので、このサービスが提供されている間は駅、路線のデータは容易に取得することができるでしょう。
システムをより簡易に作成したい場合は、APIを利用すると便利でしょう。
https://www.ekidata.jp/
路線・駅検索のサンプルプログラム
路線・駅検索のサンプルプログラムの使い方
路線・駅検索のサンプルプログラムを下記にアップしました。
https://s-giken.info/station_search/station_search.php
上記のような入力画面があり、都道府県、路線、駅を選択し、そこからの距離を数値で入力すると、指定の距離以内にある駅の一覧が表示されます。
普通は、不動産の物件や、求人企業の事務所、飲食店などの場所を検索するものだと思いますが、サンプル用にそれらの物件の位置情報のデータベースを構築することが現実的ではなかったため、物件情報の代わりに「駅データ.jp」から取得した駅の情報を検索対象の物件としても利用しています。
そのため、駅から駅を検索するという一般的には見ない路線・駅検索システムが出来上がっています(笑)。
路線・駅検索のサンプルプログラムのテーブルの構成
テーブルは、Company(事業者データ)、Line(路線データ)、Station(駅データ)の 3つで構成されていまして、それぞれ以下の構成をしています。
「駅データ.jp」の csvファイルをそのまま使うことを目的としましたので、「駅データ.jp」の構成と同じです。
【Company(事業者データ)】
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CREATE TABLE IF NOT EXISTS `company` ( `company_cd` int(11) NOT NULL, `rr_cd` int(11) NOT NULL, `company_name` text NOT NULL, `company_name_k` text, `company_name_h` text, `company_name_r` text, `company_url` text, `company_type` char(1) DEFAULT NULL, `e_status` char(1) DEFAULT NULL, `e_sort` int(11) DEFAULT NULL, UNIQUE KEY `company_cd` (`company_cd`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
【Line(路線データ)】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
CREATE TABLE IF NOT EXISTS `line` ( `line_cd` int(11) NOT NULL, `company_cd` int(11) NOT NULL, `line_name` text NOT NULL, `line_name_k` text, `line_name_h` text, `line_color_c` text, `line_color_t` text, `line_type` char(1) DEFAULT NULL, `lon` decimal(9,6) DEFAULT NULL, `lat` decimal(9,6) DEFAULT NULL, `zoom` char(2) DEFAULT NULL, `e_status` char(1) DEFAULT NULL, `e_sort` int(11) DEFAULT NULL, UNIQUE KEY `line_cd` (`line_cd`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
【Station(駅データ)】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
CREATE TABLE IF NOT EXISTS `station` ( `station_cd` int(11) NOT NULL, `station_g_cd` int(11) NOT NULL, `station_name` text NOT NULL, `station_name_k` text, `station_name_r` text, `line_cd` int(11) NOT NULL, `pref_cd` int(11) DEFAULT NULL, `post` varchar(10) DEFAULT NULL, `address` text, `lon` decimal(9,6) DEFAULT NULL, `lat` decimal(9,6) DEFAULT NULL, `open_ymd` char(10) DEFAULT NULL, `close_ymd` char(10) DEFAULT NULL, `e_status` char(1) DEFAULT NULL, `e_sort` int(11) DEFAULT NULL, UNIQUE KEY `station_cd` (`station_cd`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; |
路線・駅検索のサンプルプログラムの駅を検索する SQL文
そして、一番重要な検索する際の SQLは以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
select a.company_name, b.line_name, c.station_name, c.pref_cd, c.address, c.lon, c.lat, sqrt ( pow ( ( c.lat - 【駅の緯度】 ) * 【緯度1°の距離】, 2 ) + pow ( ( c.lon - 【駅の経度】 ) * 【経度1°の距離】, 2 ) ) as d from company as a, line as b, station as c where c.line_cd = b.line_cd and b.company_cd = a.company_cd and ( 【入力の距離】 > sqrt ( pow ( ( c.lat - 【駅の緯度】 ) * 【緯度1°の距離】, 2 ) + pow ( ( c.lon - 【駅の経度】 ) * 【経度1°の距離】, 2 ) ) ) order by d |
「【入力の距離】」は、入力された値です。
「【駅の緯度】」「【駅の経度】」は、選択された「駅」の情報から「駅データ.jp」の APIを利用して、算出した値を編集します。
計算式を含む SQL文ですのでちょっと長いですが、SQL文としては非常にシンプルな形式です。
また、「【緯度1°の距離】」「【経度1°の距離】」は、あらかじめ計算をして算出をしておきます。
詳細な解説は、2点間の緯度経度から距離を計算する記事「路線・駅検索のために緯度経度からPHPで2点間の距離を計算する処理解説」を読んでいただければ、と思いますが、計算式は以下のようになります。
単位は「m」です。
1 2 3 |
【緯度1°の距離】=【極半径】 × 2 × π ÷ 360 × 1000 【経度1°の距離】= cos ( 【駅の緯度】 ÷ 180 × π ) × 【赤道半径】 × 2 × π ÷ 360 × 1000 |
路線・駅検索についてのまとめ
路線・駅検索は、作ってみると意外に簡単でしたね。
考え方もそれほど難しいものではないですので、路線・駅検索を必要としている方は、あなたのシステムにも組み込んでいけるんじゃないでしょうか。
ただ、緯度と経度がごっちゃになったり、すっかり忘れてしまっていた三角関数など、違うところで苦戦しました...
また、この記事は 3本で 1セットの内容です。
まず「2地点の緯度経度から距離を計算する方法を考察」し、2つ目のこの記事で、その 2点間の距離を計算する方法を基にして、「路線・駅検索の仕組みを考察」しました。
そして、3本目の記事で、その「路線・駅検索の仕組みを WordPressに実装する方法を考察」する、という流れです。
これだけのステップを踏まないとたどり着けない、ということではありますが、ブログの記事としては 3本の記事を作ることができました(笑)。
路線・駅検索のために緯度経度からPHPで2点間の距離を計算する処理解説
路線・駅検索をPHPで実装する方法解説。GoogleMapsの緯度経度から計算し検索
「WordPressで駅検索を実装」(鋭意執筆中)
3本目の記事は、現在鋭意作成中です。
なぜ、WordPressに組み込むことを目指すのか、と言いますと、「月極駐車場検索エース」というサイトを作りましたが、ここには都道府県検索はありますが、路線・駅検索がありません。
そのため、「月極駐車場検索エース」に路線・駅検索を組み込むことを目指して思考を始めましたので、最終目標は WordPressへの組み込みなわけです。
ただ、WordPressに組み込むには、カスタムフィールドだけで処理するのは難しく、オリジナルのテーブルを構築する必要がありそうで、オリジナルテーブルにアクセスする方法と、オリジナルテーブルにデータを保存する方法、さらに、それらとカテゴリ検索や各フィールドの条件検索と組み合わせる方法などを理解する必要がありそうで、少し時間がかかりそうです。
GoogleAdwords
GoogleAdwords
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズする関数の作成解説
PHPの配列・連想配列のキーと値をまとめてhtmlspecialchars()関数でサニタイズ(無害化、無毒化)を行う関数を作成。連想配列のキーはarray_map()関数でのサニタイズは無理。
-
SEO対策用タイトル、ディスクリプションの文字数カウントツール
SEO対策に使える文字数カウントツールで文字数の条件の説明も行っています。
-
PHPで特定の日間の日付を for、strtotimeで表示する
ある特定の間の日付の情報を for文、strtotimeを使って作成し、その解説をしています。
-
PHPのデバッグで使う print_r、var_dump、var_exportの動作の違い
PHPのデバッグ等で変数や配列の中身を確認するために使用する関数print_r、var_dump、var_exportの動作の違い、仕様の違いについて確認した。var_exportがオススメ。
-
Basic認証の.htaccess、.htpasswd生成ツールと解説
Basic認証を設定する際に必要となる.htaccess、.htpasswdファイルを生成するツール。ID、PASS、.htpasswdへのパスを入力することで編集する情報を生成します。
-
QRコード(二次元バーコード)作成サービスを公開
QRコード(二次元バーコード)を生成するサービス。QRコードにする文字列を入力するだけで QRコードが簡単に作れる。オプションとして、画像サイズ、余白サイズ、エラー訂正レベルがある。
-
GMOペイメントゲートウェイのjava.io.IOExceptionのエラー
ECCUBEの決済でGMOペイメントゲートウェイのモジュールを使ってテスト決済を行った場合の不具合、java.io.IOExceptionと言うエラーの原因と対策方法の解説です。
-
JSON形式の値を配列形式に変換・PHPでは json_decode()、json_encode()
JSONとは「JavaScript Object Notation」の略でテキストベースのデータフォーマット。JSONの値をPHPで配列に変換するWebツールの紹介とその処理「json_encode()」「json_decode()」関数の解説。
-
複数銘柄を指定して株価チャートを一覧するツール公開
入力銘柄の5日間、3か月間、6か月間、1年間、2年間の株価チャートを一覧表示しますのでチャートで売買判断をするのに最適です。
-
PHP画面が真っ白 header(“Location: $url”);
PHPの開発で header(“Location: $url”);を使うと画面が真っ白になる不具合が出る場合もあります。
Comment
掲載されてる以下のSQLに緯度1°の距離が一度も出てきていないので間違いだと思うのですが、どうでしょうか。
select
a.company_name,
b.line_name,
c.station_name,
c.pref_cd,
c.address,
c.lon,
c.lat,
sqrt ( pow ( ( c.lat – 【駅の緯度】 ) * 【経度1°の距離】, 2 ) + pow ( ( c.lon – 【駅の経度】 ) * 【経度1°の距離】, 2 ) ) as d
from
company as a,
line as b,
station as c
where
c.line_cd = b.line_cd and
b.company_cd = a.company_cd and
( 【入力の距離】 > sqrt ( pow ( ( c.lat – 【駅の緯度】 ) * 【経度1°の距離】, 2 ) + pow ( ( c.lon – 【駅の経度】 ) * 【経度1°の距離】, 2 ) ) )
order by d
やまちゃんさん、コメントありがとうございます。
ご指摘の通り、間違いがありましたので修正をさせていただきました。
記事を書くときに文字列をコピペして、必要な変更を仕切れていなかったんだろうな、と思います。
ご連絡ありがとうございました。