PDF - IBM

ツイートの件数を地図上で視覚化する WebSocket アプリ
ケーションを作成する
Michele Crudele (https://www.ibm.com/developerworks/
community/profiles/html/profileView.do?
userid=060000UYRR&tabid=dwAboutMe )
Software Architect
IBM
2015年 1月 15日
WebSocket、Twitter 検索、Google Maps API を使用してツイートの発信元をリアルタイムで地
図上に表示する Node.js Web アプリケーションを作成してください。
このチュートリアルでは、WebSocket、Twitter 検索、および Google Maps API を使用してツイー
トの発信元をリアルタイムで地図上に表示する、Node.js Web アプリケーションを作成する方法を
紹介します。また、アプリケーションを IBM Bluemix に (そして一般には、Cloud Foundry ベース
のあらゆる PaaS に) デプロイする方法も説明します。
このアプリケーションを作成した理由は、特定のトピックを話題にしているツイートがどの地域
から発信されているのかをひと目で把握できるビューが欲しかったからです。例えば、イノベー
ションに関してツイートしている人々が世界のどこにいるかがわかるようなビューです。
この TOTEM (Tweets On ThE Map) という名前のアプリケーションには単純な UI があり、この UI
に (Twitter での場合と同じように) クエリーを入力すると、地図上にはそのクエリーにマッチする
ツイートの発信元が上下に跳ねるツイート・アイコンで示されます。 :
© Copyright IBM Corporation 2015
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
商標
ページ 1 / 8
developerWorks®
ibm.com/developerWorks/jp/
私が興味を持っているのは、メッセージの内容ではなく、各地で発信されたツイートの件数で
す。そのため、TOTEM アプリケーションでは、発信場所を示す円のサイズが、その場所から発信
されるツイートの件数が増えるに従って大きくなるようになっています。円をクリックすると、
その場所の名前、検索を開始してから投稿されたツイートの件数、そしてその場所から発信され
た最新のツイートが表示されます。
このアプリケーションでは、HTTP を使用した複雑なポーリング・ロジックは使用しておらず、
代わりに単一の全二重 WebSocket チャネルを開きます。このチャネルを介して、クライアントと
サーバーはそれぞれ独自のプロトコルに従ってメッセージを交換できるようになっています。
読む: What is WebSocket?
読む: Twitter による「The Search API」
読む: Node.js: 基本を越えて
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
ページ 2 / 8
ibm.com/developerWorks/jp/
developerWorks®
アプリケーションを作成するために必要となるもの
• Node.js、Node.js 開発環境、そして Node で Express を使用して Web アプリケーションを作成
する方法についての十分な知識。(このアプリケーションは、Nodeclipse プラグインをインス
トールした Eclipse を使用して開発しました。)
• Twitter アカウント。
• Google Maps JavaScript API の十分な知識。
• Bluemix 上にデプロイする場合:
• Bluemix アカウント。
• Cloud Foundry コマンドライン・ツール。
このチュートリアルを手引きに、皆さんも同様のアプリケーションを作成することができます。
ステップ 1 でコードを入手した後、アプリケーションを試してみたいと思ったら、ローカルで
コードの変更をテストしてから (ステップ 5 で概説しているように) アプリケーションを Bluemix
にデプロイして試すことができます。アプリケーションをローカルで実行する方法について
は、私の DevOps Services プロジェクトにある README.md ファイルを参照してください。
アプリを実行する
コードを入手する
“ このアプリケーションでは、HTTP を使用した複雑なポー
リング・ロジックは使用しておらず、代わりに単一の全二
重 WebSocket チャネルを開きます。このチャネルを介し
て、クライアントとサーバーはそれぞれ独自のプロトコル
に従ってメッセージを交換できるようになっています。 ”
ステップ 1. ソース・コードを入手して環境を構築する
1. コードを入手するために、お好みの Git クライアントを使用して TOTEM プロジェクトの Git
リポジトリーを複製します。
git clone https://hub.jazz.net/git/mcrudele/totem
2. ルート・フォルダーから npm install を実行します。このコマンドにより、package.json に
記載されている依存関係が node_modules ディレクトリーにインストールされます。依存関
係には、Express と Jade の他に、ws という WebSocket ライブラリーと、ntwitter という非同
期 Twitter クライアント API があります。
3. ローカル・プロジェクトの node_modules/ntwitter フォルダーにカレント・ディレクトリー
を変更して、ntwitter パッケージに必要な修正を適用します。
• lib/keys.js で、search_base: 'http://search.twitter.com' を search_base: 'https://
api.twitter.com/1.1/search' で置き換えます。
• lib/twitter.js で、var url = this.options.search_base + '/search.json'; を var url =
this.options.search_base + '/tweets.json'; で置き換えます。
4. Twitter アクセス・トークンと API キーを生成します。(Twitter API の使用法がよくわからない
場合は、「How to get my api key」を参照するか、直接 Twitter の Application Management に
アクセスしてください)。
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
ページ 3 / 8
developerWorks®
ibm.com/developerWorks/jp/
ステップ 2. WebSocket エンドポイントを Node.js サーバーに追加する
私は Nodeclipse 環境で Node パースペクティブに切り替えてから「New (新規)」 > 「Node.js
Express」の順にクリックするという方法で、この Web アプリケーションのスケルトンを作成しま
した。皆さんは、express という名前の NPM パッケージに提供されている express コマンドを実
行することで、同じスケルトンを取得することができます。
このスケルトンは、Node.js サーバーである app.js ファイルの他に、画像ファイル、CSS ファイ
ル、HTML ファイルなどの静的リソースが含まれるディレクトリー (public など)、Jade テンプレー
ト・ファイルが含まれるディレクトリー (views)、REST ハンドラー・ファイルが含まれるディレク
トリー (routes) で構成されています。
TOTEM アプリケーションが定義する WebSocket エンドポイントは、message イベントのクエ
リー・ストリングを受け取って、そのクエリーとマッチするツイートの定期的な検索を開始し、
マッチしたツイートをクライアントに送信します。
定期的な検索を扱うために、ntwitter Node.js モジュールを使用して (tfinder.js モジュール内に)
TwitterFinder クラスを作成しました。TwitterFinder は Node.js の EventEmitter であり、クエ
リーにマッチする新規ツイートを受信すると、data イベントを発生させます。
明確にするために、ここに記載する app.js コード・スニペットは簡略化されています。
以下のコードが、WebSocket /search エンドポイントを作成します。
var WebSocket = require('ws');
var WebSocketServer = WebSocket.Server;
var app = express();
var server = http.createServer(app).listen(app.get('port'), function() {
console.log('TOTEM server listening on port ' + app.get('port'));
});
// Create the WebSocket endpoint that does the job
//
var searchServer = new WebSocketServer( {server: server, path: '/search'});
WebSocketServer は、Node.js の WebSocket モジュール ws で定義されています。WebSocketServer
は、WebSocket プロトコルのサーバー・サイドを実装する Node.js の EventEmitter です。した
がって、クライアントとの新規 WebSocket 接続が確立された時点でトリガーされる connection
イベントのハンドラーを追加しました。接続が確立されている間は、このイベントがパラメー
ターとして指定している WebSocket クライアントを使用しなければならず、WebSocket 上で
message イベントを処理してクエリー・ストリングを受け取らなければなりません。
// One connection manages one twitter search.
// To stop current search simply close this connection.
//
searchServer.on('connection', function(ws) {
// Create a twitter finder for the duration of the connection
//
var finder = new TwitterFinder(TwitterKeys);
ws.on('message', function(searchstring, flags) {
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
ページ 4 / 8
ibm.com/developerWorks/jp/
developerWorks®
// Ignore the message if the search is already running
// The client must close the connection to stop searching
//
if ( finder.isRunning() ) {
console.log('Finder already running.');
return;
}
// Set the data handler on the twitter finder
//
finder.on('data', function(tweets) {
// This is the format of the object that should be sent:
//
// {
//
address: "user.location attribute of the tweet",
//
text: "text attribute of the tweet formatted as html"
// }
//
// Get tweets from the bottom of the array to start
// from the oldest.
//
for (var i=tweets.length-1; i>=0; i--) {
var data = { address: tweets[i].user.location,
text:
tweetToText(tweets[i]) };
ws.send(JSON.stringify(data));
}
});
console.log('Start a new search for: ', searchstring);
finder.start(searchstring);
});
});
ステップ 3. HTML ビューを作成する
次に、ユーザーと対話するための HTML ファイル (public/index.html) を作成しました。Web レイ
アウトは、このチュートリアルの冒頭に記載したページで構成されていて、そこに、以下の統計
を示すパネルが追加されています。
• 地図に送信されたツイートの合計数。
• エラーが発生したツイートの数。これらのツイートは、user.location 属性が空になってい
るか、Google Geocoder サービスが解決できない値 (なかには、自分のプロファイルに架空の
場所を指定する Twitter ユーザーもいます) に設定されているために、地図に送信できなかっ
たツイートを指します。
• Google Geocoder サービスが繰り返し query limit エラーを返しているため (クライアントが
大量のツイートを受信すると、このエラーが発生する場合があります)、地図に送信できな
かったツイートの数。
以下に、TOTEM Web レイアウトのコードを記載します。
<body>
<div id="panel">
<input id="search" type="search" title="Write a search, click the Search button,
and see what's going on on Twitter! Tips: use OR, AND logical operators for multiple-words query">
<input type="button" value="Search" onclick="startSearch()" title="Click to start searching">
</div>
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
ページ 5 / 8
developerWorks®
ibm.com/developerWorks/jp/
<div id="map-canvas"></div>
<div id="panel-monitor">
<div>Tweets on the Map</div>
<input id="num-tweets" type="text" readonly title="Number of tweets posted to the map"><br>
<div>Tweets in error</div>
<input id="num-tweets-in-error" type="text" readonly
title="Number of tweets not posted to the map because of invalid location provided"><br>
<div>Tweets discarded</div>
<input id="num-tweets-discarded" type="text" readonly title="Number of tweets discarded
because of errors with the Geocoder service (query limit)"><br>
<div>Tweets/secs</div>
<input id="tweets-per-sec" type="text" readonly title="Tweets per seconds posted to the map">
</div>
</body>
ステップ 4. JavaScript クライアント・コードを作成する
ユーザー・クエリーを受け入れて WebSocket エンドポイントに接続し、受信ツイートを処理する
ためのクライアント・ロジックを作成しました。
明確にするために、ここに記載する app.js コード・スニペットは簡略化されています。
すべては、検索ボタンの onclick ハンドラーである startSearch() から始まります。
function startSearch() {
var search = document.getElementById('search').value;
if ( search.trim().length===0 ) {
alert('Cannot submit an empty search.');
return;
}
// Create the connection for the new search
// Use secure WebSocket (wss) when running on Bluemix
//
if ( window.document.location.host.match(/localhost/) ) {
var wsUri = 'ws://' + window.document.location.host + '/search';
} else {
var wsUri = 'wss://' + window.document.location.host + '/search';
}
wssearch = new WebSocket(wsUri);
wssearch.onopen = function(evt) { onOpen(evt) };
wssearch.onclose = function(evt) { onClose(evt) };
wssearch.onmessage = function(evt) { onMessage(evt) };
wssearch.onerror = function(evt) { onError(evt) };
}
function onOpen(e) {
// Submit the search to the server
//
var search = document.getElementById('search').value.trim();
wssearch.send(search);
}
startSearch() 関数は新規 WebSocket オブジェクトを作成し、open、close、message、および
error の各イベントのハンドラーを設定します。WebSocket が開始したハンドシェークが完了す
ると同時に、onOpen() ハンドラーが呼び出されます。すると、このハンドラーがユーザー・クエ
リーを取得して、検索を開始するためにそのクエリーを送信します。
最後に、onMessage() ハンドラーがデータを解析して地図に書き込むという楽しい処理が行われ
ます。この処理では msg.address の座標を取得するために、Google Geocoder サービスを利用し
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
ページ 6 / 8
ibm.com/developerWorks/jp/
developerWorks®
ました。しかし、このサービスを頻繁に呼び出すと OVER_QUERY_LIMIT エラーが返されるので、こ
の状況を緩和するために次の 2 つのことを行いました。1 つは、解決されたアドレスをメモリー
に保管することで、呼び出しの回数を減らすようにしました。そしてもう 1 つは、メッセージを
可変の時間間隔で処理するようにしました。具体的には、OVER_QUERY_LIMIT に達した時点で、処
理の間隔を長くするようにしました。
プロジェクト・コードに含まれる public/index.html を表示して、onMessage() ハンドラーと、地
図に結果を書き込むロジックを実装するその他の関数を確認してください。
ステップ 5. アプリケーションを Bluemix にデプロイする
1. manifest.yml.change_me ファイル (ルート・ディレクトリーにあります) の名前を
manifest.yml に変更します。
2. manifest.yml で、host 値をアプリケーションに固有の名前に設定し、TWITTER_KEYS 値を入力
します。
--applications:
- name: totem
memory: 512M
domain: mybluemix.net
instances: 1
host: CHANGE_ME
path: .
env:
TWITTER_KEYS: '{"consumer_key":"CHANGE_ME","consumer_secret":
"CHANGE_ME","access_token_key":"CHANGE_ME","access_token_secret":"CHANGE_ME"}'
consumer_key と consumer_secret の値は、Twitter Application Settings ページから取得した
API Key と API Secret の値です。
3. ルート・ディレクトリーにある package.json ファイルを編集して、依存関係から ntwitter
モジュールを削除します。こうすることで、Bluemix にプッシュするときに、このモジュー
ルがローカル・ディレクトリーからアップロードされるようになります (このステップ
は、ntwitter パッケージに対して行った修正を維持するために必要です。このステップを行
わなければ、Bluemix はアプリケーションをステージングするときに、修正されたモジュー
ルを上書きしてしまいます)。
4. アプリケーションのルート・ディレクトリーから cf push コマンドを実行した後、ブラウ
ザーで https://yourappname.mybluemix.net/ に接続してアプリケーションの動作を確認しま
す。
まとめ
TOTEM アプリケーションは、リアルタイムでの通信が必要とされる Web アプリケーションを作
成する場合の WebSocket の強力さを実証しています。HTTP は、こうしたことが要求されるアプ
リケーションで使用するには、重要な部分が不足していて不向きですが、WebSocket はこれらの
部分に対処します。HTTP でポーリングする場合と比べ、WebSocket はパフォーマンスを向上させ
て、単純さを高めることができるため、HTML5 接続仕様の標準となっています。
関連トピック: Twitter データ視覚化
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
ページ 7 / 8
developerWorks®
ibm.com/developerWorks/jp/
著者について
Michele Crudele
@mkrudele on Twitter
Find me on LinkedIn
© Copyright IBM Corporation 2015
(www.ibm.com/legal/copytrade.shtml)
商標
(www.ibm.com/developerworks/jp/ibm/trademarks/)
ツイートの件数を地図上で視覚化する WebSocket アプリケー
ションを作成する
ページ 8 / 8