コンテキストアウェアアプリケーションと複合イベント処理アーキテクチャ

公開: 2022-03-11

世界中で携帯電話の使用は絶えず増加しています。 2013年の時点で、インターネットユーザーの約73%がモバイルデバイスを介してコンテンツを消費しており、この割合は2017年までに90%近くに達すると予想されています。

もちろん、モバイル革命には多くの理由があります。 しかし、最も重要なことの1つは、今日のほとんどすべてのスマートフォンに位置センサー、モーションセンサー、Bluetooth、Wi-Fiが搭載されているため、モバイルアプリは一般的に豊富なコンテキストにアクセスできることです。 アプリはデータを利用することで、機能と価値を劇的に向上させる「コンテキストアウェアネス」を実現し、アプリストアで目立つようにすることができます。

このチュートリアルでは、複雑なイベント処理の例を通じて、コンテキストアウェアアプリの作成について説明します。 かなり単純な例を使用します。お住まいの地域で最高の燃料価格を見つける燃料価格アプリです。

アプリのコンテキストアウェアネスは、このような複雑なイベント処理チュートリアルを通じて作成できます。

コンテキストアウェアアプリ

穏やかなテクノロジーの設計において、マーク・ワイザーとジョン・シーリー・ブラウンは、穏やかなテクノロジーを「情報を提供するが、私たちの焦点や注意を要求しないもの」と説明しています。

コンテキストアウェアモバイルアプリは、この概念と非常に一貫性があり、この道を進むための重要で価値のあるステップです。 センサーから収集したコンテキスト情報を使用して、ユーザーに貴重な情報を積極的に提供し、ユーザーの労力を最小限に抑えます。 マーク・ワイザーとジョン・シーリー・ブラウンは間違いなくこの技術の進歩を称賛するでしょう。

コンテキストアウェアネスとは、アプリがアクセスできるコンテキストデータに基づいてアプリが感知して反応できるという考え方です。 このようなアプリは、モバイルデバイスで利用できる豊富なセンサーデータを利用して、適切なコンテキストでユーザーに正確で関連性のある情報を提供します。 デバイスの使用過程で観察される傾向や、ユーザーから提供されるフィードバックを通じて、このようなアプリは実際に時間の経過とともに「学習」し、それによって「よりスマート」でより便利になります。

複合イベント処理

複合イベント処理(CEP)は、複数のイベントのより高度な分析(つまり、時間の経過とともに、さまざまなソースからのものなど)を使用し、それらのコンテンツを統合および分析して、より意味のある情報とパターンを推測するイベント処理の形式です。

モバイルアプリでは、CEPは、モバイルデバイスのセンサーから生成されたイベントと、アプリがアクセスできる外部データソースに適用できます。

私たちの燃料価格アプリの主な機能

複雑なイベント処理チュートリアルの目的で、燃料価格アプリの機能が次のように制限されていると仮定します。

  • ユーザーに地理的に関連する場所を自動的に検出します(たとえば、ユーザーの自宅の場所やユーザーの職場の場所)
  • ユーザーの自宅や職場から妥当な距離内にある燃料ステーションを自動的に識別します
  • 自宅や職場の近くで最高の燃料価格をユーザーに自動的に通知します

OK、始めましょう。

ユーザーの自宅と職場の場所の検出

ユーザーの自宅と職場の場所を自動的に検出するためのロジックから始めましょう。 複雑なイベント処理の例で物事を単純にするために、ユーザーの作業スケジュールはかなり正常であると想定します。 したがって、ユーザーは通常、午前2時から3時の間に自宅にいて、午後2時から3時の間にオフィスにいると想定できます。

これらの仮定に基づいて、2つのCEPルールを定義し、ユーザーのスマートフォンから位置と時刻のデータを収集します。

  • ホームロケーションルール
    • 1週間の午前2時から午前3時までの位置データを収集します
    • 位置データをクラスター化して、おおよその自宅住所を取得します

  • 勤務地ルール
    • 平日の午後2時から午後3時までの位置データを収集します
    • 位置データをクラスター化して、おおよその作業位置を取得します

場所を検出するための高レベルのアルゴリズムを以下に示します。

この図は、このチュートリアルのコンテキストアウェアアプリケーションがどのように機能するかを示しています。

位置データの次の単純なJSONデータ構造を想定します。

 { "uid": "some unique identifier for device/user", "location": [longitude, latitude] "time": "time in user's timezone" }

注:CEPワークフローのさまざまなモジュールで安全に使用できるように、センサーデータを不変(または値型)にすることは常に良い習慣です。

実装

構成可能なモジュールパターンを使用してアルゴリズムを実装します。これにより、各モジュールは1つのタスクのみを実行し、タスクが完了すると次に呼び出します。 これは、Unixのモジュラリティのルールの哲学に準拠しています。

具体的には、各モジュールは、 configオブジェクトを受け入れる関数と、データを次のモジュールに渡すために呼び出されるnext関数です。 したがって、各モジュールはセンサーデータを受け入れることができる関数を返します。 モジュールの基本的な署名は次のとおりです。

 // nominal structure of each composable module function someModule(config, next) { // do initialization if required return function(data) { // do runtime processing, handle errors, etc. var nextData = SomeFunction(data); // optionally call next with nextData next(nextData); } }

ユーザーの自宅と職場の場所を推定するためのアルゴリズムを実装するには、次のモジュールが必要です。

  • 時間フィルターモジュール
  • アキュムレータモジュール
  • クラスタリングモジュール

これらの各モジュールについては、次のサブセクションで詳しく説明します。

時間フィルターモジュール

時間フィルターは、位置データイベントを入力として受け取り、対象のタイムスライス内でイベントが発生した場合にのみ、データをnextモジュールに渡す単純な関数です。 したがって、このモジュールのconfigデータは、対象のタイムスライスの開始時刻と終了時刻で構成されます。 (モジュールのより洗練されたバージョンは、複数のタイムスライスに基づいてフィルタリングできます。)

タイムフィルターモジュールの擬似コードの実装は次のとおりです。

 function timeFilter(config, next) { function isWithin(timeval) { // implementation to compare config.start <= timeval <= config.end // return true if within time slice, false otherwise } return function (data) { if(isWithin(data.time)) { next(data); } }; }

アキュムレータモジュール

アキュムレータの役割は、単に位置データを収集してnextモジュールに渡すことです。 この関数は、データを格納するための内部固定サイズバケットを維持します。 バケットがいっぱいになるまで、検出された新しい場所がそれぞれバケットに追加されます。 バケットに蓄積された位置データは、配列として次のモジュールに送信されます。

2種類のアキュムレータバケットがサポートされています。 バケットタイプは、データが次のフェーズに転送された後、バケットのコンテンツに対して行われる処理に次のように影響します。

  • タンブリングウィンドウバケット( type = 'tumbling' ):データを転送した後、バケット全体を空にして、新しく開始します(バケットサイズを0に戻します)

  • 実行中のウィンドウタイプ( type = 'running' ):データを転送した後、バケット内の最も古いデータ要素のみを破棄します(バケットサイズを1つ減らします)

アキュムレータモジュールの基本的な実装は次のとおりです。

 function accumulate(config, next) { var bucket = []; return function (data) { bucket.unshift(data); if(bucket.length >= config.size) { var newSize = (config.type === 'tumbling' ? 0 : bucket.length - 1); next(bucket.slice(0)); bucket.length = newSize; } }; }

クラスタリングモジュール

もちろん、2Dデータをクラスター化するための座標ジオメトリには多くの高度な手法があります。 位置データをクラスタリングする簡単な方法の1つを次に示します。

  • 一連の場所で各場所の隣人を見つける
  • 一部のネイバーが既存のクラスターに属している場合は、クラスターを使用してネイバーを拡張します
  • ネイバーセット内の場所がしきい値を超えている場合は、ネイバーを新しいクラスターとして追加します

このクラスタリングアルゴリズムの実装は次のとおりです( Lo-Dashを使用)。

 var _ = require('lodash'); function createClusters(location_data, radius) { var clusters = []; var min_points = 5; // Minimum cluster size function neighborOf(this_location, all_locations) { return _.filter(all_locations, function(neighbor) { var distance = distance(this_point.location, neighbor.location); // maximum allowed distance between neighbors is 500 meters. return distance && (500 > distance); } } _.each(location_data, function (loc_point) { // Find neighbors of loc_point var neighbors = neighborOf(loc_point, location_data, radius); _.each(clusters, function (cluster, index) { // Check whether some of the neighbors belong to cluster. if(_.intersection(cluster, neighbors).length){ // Expand neighbors neighbors = _.union(cluster, neighbors); // Remove existing cluster. We will add updated cluster later. clusters[index] = void 0; } }); if(neighbors.length >= min_points){ // Add new cluster. clusters.unshift(neighbors); } }); return _.filter(clusters, function(cluster){ return cluster !== void 0; }); }

上記のコードは、2つの地理的な場所の間の距離(メートル単位)を計算するdistance()関数の存在を前提としています。 [longitude, latitude]の形式で2つのロケーションポイントを受け入れ、それらの間の距離を返します。 このような関数の実装例を次に示します。

 function distance(point1, point2) { var EARTH_RADIUS = 6371000; var lng1 = point1[0] * Math.PI / 180; var lat1 = point1[1] * Math.PI / 180; var lng2 = point2[0] * Math.PI / 180; var lat2 = point2[1] * Math.PI / 180; var dLat = lat2 - lat1; var dLon = lng2 - lng1; var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); var arc = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); var distance = EARTH_RADIUS * arc; return distance; }

クラスタリングアルゴリズムを定義して実装すると(前に示したcreateClusters()関数で)、クラスタリングモジュールの基礎として使用できます。

 function clusterize(config, next) { return function(data) { var clusters = createClusters(data, config.radius); next(clusters); }; }

それをすべて一緒に引っ張る

これで、必要なすべてのコンポーネント関数が定義されたので、自宅/職場の場所のルールをコーディングする準備が整いました。

たとえば、ホームロケーションルールの可能な実装は次のとおりです。

 var CLUSTER_RADIUS = 150; // use cluster radius of 150 meters var BUCKET_SIZE = 500; // collect 500 location points var BUCKET_TYPE = 'tumbling'; // use a tumbling bucket in our accumulator var home_cluster = clusterize({radius: CLUSTER_RADIUS}, function(clusters) { // Save clusters in db }); var home_accumulator = accumulate({size: BUCKET_SIZE, type: BUCKET_TYPE}, home_cluster); var home_rule = timeFilter({start: "2AM", end: "3AM"}, home_accumulator);

これで、スマートフォンから(websocket、TCP、HTTPを介して)位置データを受信するたびに、このデータをhome_rule関数に転送します。この関数は、ユーザーの自宅のクラスターを検出します。

その場合、ユーザーの「ホームロケーション」は、ホームロケーションクラスターの中心であると見なされます。

注:これは完全に正確ではない場合がありますが、特にこのアプリの目的は、ユーザーの正確な自宅の場所を知ることではなく、単にユーザーの自宅の周辺を知ることであるため、簡単な例には十分です。

これは、クラスターセット内のすべてのポイントの緯度と経度を平均して、クラスター内のポイントセットの「中心」を計算する簡単な関数の例です。

 function getCentre(cluster_data) { var len = cluster_data.length; var sum = _.reduce(cluster_data, function(memo, cluster_point){ memo[0] += cluster_point[0]; memo[1] += cluster_point[1]; return memo; }, [0, 0]); return [sum[0] / len, sum[1] / len]; }

同様のアプローチを使用して作業場所を推測することもできますが、唯一の違いは、午後2時から3時(午前2時から3時ではなく)の時間フィルターを使用することです。

したがって、私たちの燃料アプリは、ユーザーの介入を必要とせずに、ユーザーの職場と自宅の場所を自動的に検出することができます。 これは、最高のコンテキストアウェアコンピューティングです。

近くのガソリンスタンドを探す

コンテキストアウェアネスを確立するためのハードワークはこれで完了しましたが、監視するガソリンスタンドの価格を特定するためのもう1つのルールが必要です(つまり、どのガソリンスタンドがユーザーの自宅や職場に十分近く、関連性があるか)。 このルールは、燃料アプリでサポートされているすべての地域のすべての燃料ステーションの場所にアクセスする必要があります。 ルールは次のとおりです。

  • ガソリンスタンドのルール
    • 自宅と職場ごとに最寄りのガソリンスタンドを探す

これは、アプリで認識されているすべての燃料ステーションに適用するロケーションフィルターとして前に示した距離関数を使用して簡単に実装できます。

このチュートリアルアプリのように、コンテキストアウェアアプリケーションは時間の経過とともにスマートになります。

燃料価格の監視

燃料アプリがユーザーにとって優先される(つまり、近くの)燃料ステーションのリストを取得すると、これらのステーションでの最良の燃料価格を簡単に監視できます。 また、これらの燃料ステーションの1つに特別価格またはオファーがある場合、特にユーザーがこれらの燃料ステーションの近くにいることが検出された場合に、ユーザーに通知することもできます。

この複雑なイベント処理チュートリアルは、アプリケーションでコンテキストアウェアネスを作成する方法を示しています。

結論

この複雑なイベント処理のチュートリアルでは、コンテキストアウェアコンピューティングの表面をほとんど傷つけていません。

簡単な例では、場所のコンテキストを他の点では単純な燃料価格レポートアプリに追加し、よりスマートにしました。 アプリはデバイスごとに動作が異なり、時間の経過とともに位置パターンを検出して、ユーザーに提供する情報の価値を自動的に向上させます。

確かに、コンテキストアウェアアプリの精度と有用性を高めるために、はるかに多くのロジックとセンサーデータを追加できます。 賢いモバイル開発者は、たとえば、ソーシャルネットワークデータ、天気データ、POS端末トランザクションデータなどを利用して、アプリにさらにコンテキスト認識を追加し、アプリをより実行可能で市場性のあるものにすることができます。

コンテキストアウェアコンピューティングでは、可能性は無限大です。 この強力なテクノロジーを採用して私たちの生活をよりシンプルにするアプリストアには、ますます多くのスマートアプリが登場し続けるでしょう。