Applications sensibles au contexte et architecture de traitement d'événements complexes

Publié: 2022-03-11

L'utilisation du téléphone mobile dans le monde est en constante augmentation. En 2013, environ 73 % des internautes consommaient du contenu via un appareil mobile et ce pourcentage devrait atteindre près de 90 % d'ici 2017.

Il y a, bien sûr, de nombreuses raisons à la révolution mobile. Mais l'un des plus importants est que les applications mobiles ont généralement accès à un contexte plus riche, car presque tous les smartphones d'aujourd'hui sont équipés de capteurs de localisation, de capteurs de mouvement, de Bluetooth et de Wi-Fi. En utilisant leurs données, les applications peuvent atteindre une «conscience du contexte» qui peut augmenter considérablement leurs capacités et leur valeur, et peut vraiment les faire ressortir dans les magasins d'applications.

Dans ce didacticiel, nous allons explorer la création d'applications contextuelles à l'aide d'un exemple de traitement d'événements complexes. Nous allons utiliser un exemple assez simple : une application de prix du carburant qui trouve les meilleurs prix du carburant dans votre région.

La prise en compte du contexte dans les applications peut être créée grâce à un didacticiel de traitement d'événements complexe comme celui-ci.

Applications sensibles au contexte

Dans Designing Calm Technology, Mark Weiser et John Seely Brown décrivent la technologie calme comme "ce qui informe mais n'exige pas notre concentration ou notre attention".

Les applications mobiles sensibles au contexte sont très cohérentes avec cette notion et constituent une étape importante et précieuse sur cette voie. Ils utilisent des informations contextuelles glanées à partir de leurs capteurs pour fournir de manière proactive à l'utilisateur des informations précieuses et ils le font avec un minimum d'effort de la part de l'utilisateur. Mark Weiser et John Seely Brown applaudiraient sans aucun doute cette avancée technologique.

La sensibilité au contexte est l'idée qu'une application peut détecter et réagir en fonction des données contextuelles auxquelles elle a accès. Une telle application utilise des données de capteur riches disponibles sur un appareil mobile pour fournir des informations précises et pertinentes à l'utilisateur dans le contexte approprié. Grâce aux tendances qu'elle observe au cours de l'utilisation de l'appareil et/ou grâce aux commentaires fournis par l'utilisateur, une telle application peut réellement « apprendre » au fil du temps, devenant ainsi « plus intelligente » et plus utile.

Traitement d'événements complexes

Le traitement d'événements complexes (CEP) est une forme de traitement d'événements qui utilise des analyses plus sophistiquées de plusieurs événements (c'est-à-dire au fil du temps, provenant de différentes sources, etc.), intégrant et analysant leur contenu pour en déduire des informations et des modèles plus significatifs.

Dans une application mobile, le CEP peut être appliqué aux événements générés par les capteurs de l'appareil mobile ainsi qu'aux sources de données externes auxquelles l'application a accès.

Principales caractéristiques de notre application de prix du carburant

Pour les besoins de notre didacticiel sur le traitement des événements complexes, supposons que les fonctionnalités de notre application de prix du carburant se limitent aux éléments suivants :

  • détection automatique des emplacements qui sont géographiquement pertinents pour l'utilisateur (par exemple, le domicile de l'utilisateur et le lieu de travail de l'utilisateur)
  • identifiant automatiquement les stations-service situées à une distance raisonnable du domicile et du lieu de travail de l'utilisateur
  • informer automatiquement l'utilisateur des meilleurs prix du carburant à proximité du domicile et du travail

D'accord, commençons.

Détection du domicile et du lieu de travail de l'utilisateur

Commençons par la logique de détection automatique des lieux de résidence et de travail de l'utilisateur. Afin de garder les choses simples pour notre exemple de traitement d'événements complexes, nous allons supposer que l'utilisateur a un horaire de travail assez normal. On peut donc supposer que l'utilisateur sera typiquement chez lui entre 2h et 3h du matin, et sera typiquement à son bureau entre 14h et 15h.

Sur la base de ces hypothèses, nous définissons deux règles CEP et collectons des données de localisation et d'heure à partir du smartphone de l'utilisateur :

  • Règle de localisation du domicile
    • collecter des données de localisation entre 2h et 3h du matin pendant une semaine
    • regrouper les données de localisation pour obtenir l'adresse approximative du domicile

  • Règle de lieu de travail
    • collecter des données de localisation entre 14h et 15h les jours de semaine
    • regrouper les données de localisation pour obtenir le lieu de travail approximatif

L'algorithme de haut niveau pour détecter les emplacements est décrit ci-dessous.

Ce diagramme montre comment l'application contextuelle de ce didacticiel fonctionnera.

Supposons la structure de données JSON simple suivante pour les données de localisation :

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

Remarque : Il est toujours recommandé de rendre les données de capteur immuables (ou type de valeur), afin qu'elles puissent être utilisées en toute sécurité par différents modules dans le flux de travail CEP.

Mise en œuvre

Nous allons implémenter notre algorithme en utilisant un modèle de module composable , dans lequel chaque module n'exécute qu'une seule tâche et appelle ensuite lorsque la tâche est terminée. Ceci est conforme à la philosophie Unix Rule of Modularity.

Plus précisément, chaque module est une fonction qui accepte un objet de config et une fonction next qui est appelée pour transmettre les données au module suivant. En conséquence, chaque module renvoie une fonction qui peut accepter des données de capteur. Voici la signature de base d'un module :

 // 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); } }

Pour implémenter notre algorithme permettant de déduire les lieux de résidence et de travail de l'utilisateur, nous aurons besoin des modules suivants :

  • Module de filtre horaire
  • Module accumulateur
  • Module de regroupement

Chacun de ces modules est décrit plus en détail dans les sous-sections qui suivent.

Module de filtre horaire

Notre filtre temporel est une fonction simple qui prend les événements de données de localisation en entrée et ne transmet les données au module next que si l'événement s'est produit dans la tranche de temps d'intérêt. Les données de config de ce module sont donc constituées des heures de début et de fin de la tranche de temps d'intérêt. (Une version plus sophistiquée du module pourrait filtrer en fonction de plusieurs tranches de temps.)

Voici une implémentation en pseudocode du module de filtre temporel :

 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); } }; }

Module accumulateur

La responsabilité de l'accumulateur est simplement de collecter les données de localisation pour ensuite les transmettre au module next . Cette fonction gère un compartiment interne de taille fixe pour stocker les données. Chaque nouvel emplacement rencontré est ajouté au seau jusqu'à ce que le seau soit plein. Les données de localisation accumulées dans le seau sont ensuite envoyées au module suivant sous forme de tableau.

Deux types de godets d'accumulateurs sont pris en charge. Le type de compartiment affecte ce qui est fait du contenu du compartiment une fois les données transmises à la phase suivante, comme suit :

  • Bucket de fenêtre tumbling ( type = 'tumbling' ): après avoir transféré les données, vide tout le seau et recommence (taille de seau réduite à 0)

  • Type de fenêtre en cours d'exécution ( type = 'running' ): après le transfert des données, ne supprime que l'élément de données le plus ancien du compartiment (réduit la taille du compartiment de 1)

Voici une implémentation de base du module accumulateur :

 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; } }; }

Module de regroupement

Il existe bien sûr de nombreuses techniques sophistiquées en géométrie de coordonnées pour regrouper les données 2D. Voici un moyen simple de regrouper les données de localisation :

  • trouver des voisins pour chaque emplacement dans un ensemble d'emplacements
  • si certains des voisins appartiennent à un cluster existant, développez les voisins avec le cluster
  • si les emplacements dans l'ensemble de voisins dépassent le seuil, ajouter des voisins en tant que nouveau cluster

Voici une implémentation de cet algorithme de clustering (en utilisant 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; }); }

Le code ci-dessus suppose l'existence d'une fonction distance() qui calcule la distance (en mètres) entre deux emplacements géographiques. Il accepte deux points de localisation sous la forme de [longitude, latitude] et renvoie la distance entre eux. Voici un exemple d'implémentation d'une telle fonction :

 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; }

Avec notre algorithme de clustering défini et implémenté (dans notre fonction createClusters() montrée précédemment), nous pouvons l'utiliser comme base pour notre module de clustering :

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

Rassembler le tout

Toutes les fonctions requises des composants sont maintenant définies, nous sommes donc prêts à coder nos règles de lieu de résidence/travail.

Voici, par exemple, une implémentation possible de la règle de localisation du domicile :

 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);

Désormais, chaque fois que des données de localisation sont reçues d'un smartphone (via websocket, TCP, HTTP), nous transmettons ces données à la fonction home_rule qui, à son tour, détecte les clusters pour le domicile de l'utilisateur.

La « localisation du domicile » de l'utilisateur est alors supposée être le centre de la grappe de localisation du domicile.

Remarque : bien que cela ne soit pas tout à fait précis, cela convient à notre exemple simple, d'autant plus que le but de cette application est dans tous les cas simplement de connaître la zone entourant le domicile de l'utilisateur, plutôt que de connaître l'emplacement précis du domicile de l'utilisateur.

Voici un exemple de fonction simple qui calcule le "centre" d'un ensemble de points dans un cluster en faisant la moyenne des latitudes et longitudes de tous les points du cluster :

 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]; }

Une approche similaire pourrait être utilisée pour déduire le lieu de travail, à la seule différence qu'elle utiliserait un filtre horaire entre 14h et 15h (au lieu de 2h et 3h).

Notre application de carburant est ainsi capable de détecter automatiquement les lieux de travail et de domicile de l'utilisateur sans nécessiter aucune intervention de l'utilisateur. C'est l'informatique contextuelle à son meilleur !

Recherche de stations-service à proximité

Le travail acharné pour établir la connaissance du contexte a maintenant été fait, mais nous avons encore besoin d'une règle supplémentaire pour identifier les prix des stations-service à surveiller (c'est-à-dire, quelles stations-service sont suffisamment proches du domicile ou du lieu de travail de l'utilisateur pour être pertinentes). Cette règle nécessite l'accès à tous les emplacements des stations-service pour toutes les régions prises en charge par l'application de carburant. La règle est la suivante :

  • Règle de la station-service
    • trouver les stations-service les plus proches pour chaque domicile et lieu de travail

Cela peut facilement être mis en œuvre en utilisant la fonction de distance présentée précédemment comme filtre de localisation à appliquer à toutes les stations-service connues de l'application.

Les applications sensibles au contexte deviennent plus intelligentes au fil du temps, comme cette application de didacticiel.

Surveillance des prix du carburant

Une fois que l'application de carburant obtient la liste des stations-service préférées (c'est-à-dire à proximité) pour l'utilisateur, elle peut facilement rechercher les meilleurs prix du carburant dans ces stations. Il peut également informer l'utilisateur lorsque l'une de ces stations-service propose des prix ou des offres spéciales, en particulier lorsque l'utilisateur est détecté à proximité de ces stations-service.

Ce didacticiel de traitement d'événements complexes montre comment créer une prise en compte du contexte dans une application.

Conclusion

Dans ce didacticiel complexe sur le traitement des événements, nous avons à peine effleuré la surface de l'informatique contextuelle.

Dans notre exemple simple, nous avons ajouté un contexte de localisation à une application de rapport sur le prix du carburant par ailleurs simple et l'avons rendue plus intelligente. L'application se comporte désormais différemment sur chaque appareil et détecte au fil du temps les modèles de localisation pour améliorer automatiquement la valeur des informations qu'elle fournit à ses utilisateurs.

Bien sûr, beaucoup plus de données logiques et de capteurs peuvent être ajoutées pour augmenter la précision et l'utilité de notre application sensible au contexte. Un développeur mobile intelligent pourrait, par exemple, utiliser les données des réseaux sociaux, les données météorologiques, les données de transaction des terminaux de point de vente, etc. pour ajouter encore plus de sensibilité au contexte à notre application et la rendre plus viable et commercialisable.

Avec l'informatique contextuelle, les possibilités sont infinies. De plus en plus d'applications intelligentes continueront d'apparaître dans les magasins d'applications qui utilisent cette puissante technologie pour nous simplifier la vie.