Коришћење мобилних телефона широм света се непрестано повећава. Од 2013. године око 73% корисника Интернета конзумирало је садржај путем мобилног уређаја и очекује се да ће овај проценат достићи близу 90% до 2017. године.
Разлога за мобилну револуцију, наравно, има много. Али једно од најзначајнијих је да мобилне апликације углавном добијају приступ богатијем контексту, јер су готово сви паметни телефони данас опремљени сензорима локације, сензорима покрета, блуетоотхом и ВиФи-јем. Користећи своје податке, апликације могу постићи „свест о контексту“ што може драматично повећати њихове могућности и вредност и заиста их може истакнути у продавницама апликација.
У овом упутству ћемо истражити стварање контекстуалних апликација кроз сложени пример обраде догађаја. Користићемо прилично једноставан пример: апликацију за цене горива која проналази најбоље цене горива у вашем подручју.
У Дизајнирање смирене технологије , Марк Веисер и Јохн Сеели Бровн описује мирна технологија као „оно што обавештава, али не захтева наш фокус или пажњу“.
Контекстуалне мобилне апликације у потпуности се подударају са овим појмом и важан су и вредан корак на овом путу. Они користе контекстуалне информације прикупљене из њихових сензора како би проактивно пружали кориснику драгоцене информације и то уз минималан напор корисника. Марк Веисер и Јохн Сеели Бровн несумњиво би поздравили овај технолошки напредак.
Свест о контексту је идеја коју апликација може да осети и реагује на основу контекстуалних података којима има приступ. Таква апликација користи богате сензорске податке који су доступни на мобилном уређају како би пружила тачне и релевантне информације кориснику у одговарајућем контексту. Кроз трендове које примећује током употребе уређаја и / или путем повратних информација које пружа корисник, таква апликација заправо може временом да се „научи“, постајући тако „паметнија“ и кориснија.
Сложена обрада догађаја (ЦЕП) је облик обраде догађаја који користи софистициранију анализу више догађаја (тј. временом из различитих извора и тако даље), интегришући и анализирајући њихов садржај како би се извеле значајније информације и обрасци.
У мобилној апликацији ЦЕП се може применити на догађаје генерисане са сензора мобилног уређаја, као и на спољне изворе података којима апликација има приступ.
За потребе нашег сложеног водича за обраду догађаја, претпоставимо да су карактеристике наше апликације за цене горива ограничене на следеће:
ОК, почнимо.
Почнимо са логиком за аутоматско откривање локације корисника и куће и посла. Да бисмо поједноставили ствари за наш пример сложене обраде догађаја, претпоставићемо да корисник има прилично нормалан распоред рада. Стога можемо претпоставити да ће корисник обично бити код куће између 2 и 3 сата ујутро, а обично ће бити у својој канцеларији између 14 и 15 сати.
На основу тих претпоставки, дефинишемо два ЦЕП правила и сакупљамо податке о локацији и времену са корисничког паметног телефона:
Алгоритам високог нивоа за откривање локација приказан је у наставку.
Претпоставимо следећу једноставну структуру података ЈСОН за податке о локацији:
{ 'uid': 'some unique identifier for device/user', 'location': [longitude, latitude] 'time': 'time in user's timezone' }
Напомена: Увек је добра пракса учинити податке сензора непроменљивим (или тип вредности), тако да их могу различито користити модули у току ЦЕП процеса.
Наш алгоритам ћемо применити помоћу а узорак модула који се може саставити , при чему сваки модул извршава само један задатак и позива следећи када је задатак завршен. Ово је у складу са Уник-ом Правило модуларности филозофија.
Конкретно, сваки модул је функција која прихвата 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
модул. Ова функција одржава интерну сефу фиксне величине за чување података. Свака нова локација која се нађе додаје се у сегме док се сефа не напуни. Акумулирани подаци о локацији у сегменту се затим шаљу следећем модулу као низ.
Подржане су две врсте акумулаторских кашика. Тип сегмента утиче на то шта се ради са садржајем сегмента након што се подаци проследе у следећу фазу, како следи:
Превртање сегмента прозора (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; } }; }
Постоје наравно много софистицираних техника у координатној геометрији за кластеризацију 2Д података. Ево једног једноставног начина груписања података о локацији:
Ево примене овог алгоритма за груписање (помоћу 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; }); }
Горњи код претпоставља постојање distance()
функција која израчунава удаљеност (у метрима) између две географске локације. Прихвата две тачке локације у облику [longitude, latitude]
и враћа растојање између њих. Ево примера примене такве функције:
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);
Сада кад год се подаци о локацији примају са паметног телефона (путем вебсоцкет-а, ТЦП-а, ХТТП-а), прослеђујемо их на 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]; }
Сличан приступ би се могао применити за одређивање места рада, с једином разликом што би се користио временски филтер између 14 и 15 сати (за разлику од 2 и 3 ујутру).
Наша апликација за гориво тако може аутоматски откријте корисникове радне и кућне локације без потребе за корисниковом интервенцијом. Ово је рачунарско окружење у најбољем реду!
Напоран посао на успостављању свести о контексту је сада завршен, али још увек нам је потребно још једно правило да бисмо утврдили које цене бензинских пумпи надгледати (тј. Које бензинске пумпе су довољно близу корисникове куће или радног места да би биле релевантне). Овом правилу је потребан приступ свим локацијама бензинских пумпи за све регионе подржане апликацијом за гориво. Правило је следеће:
Ово се лако може применити помоћу функције растојања која је раније приказана као филтер локације за примену на свим бензинским пумпама познатим апликацији.
Једном када апликација за гориво прибави листу пожељних (тј. Оближњих) бензинских пумпи за корисника, лако може да потражи најбоље цене горива на тим станицама. Такође може обавестити корисника када једна од ових бензинских пумпи има посебне цене или понуде, посебно када се утврди да је корисник у близини ових бензинских пумпи.
У овом сложеном упутству за обраду догађаја заиста смо једва огребали површину рачунара заснованог на контексту.
У нашем једноставном примеру додали смо контекст локације у иначе једноставну апликацију за извештавање о ценама горива и учинили је паметнијом. Апликација се сада понаша другачије на сваком уређају и временом открива обрасце локације како би аутоматски побољшала вредност информација које пружа својим корисницима.
Сигурно се може додати много више логике и података сензора да би се повећала тачност и корисност наше контекстуалне апликације. А. паметан програмер за мобилне уређаје могли, на пример, да користе податке о друштвеним мрежама, временске податке, податке о трансакцијама на ПОС терминалу, и тако даље да би додали још већу свест о контексту нашој апликацији и чине га одрживијим и тржишним .
Са рачунањем заснованим на контексту, могућности су безбројне. Све више паметних апликација и даље ће се појављивати у продавницама апликација које користе ову моћну технологију како би нам живот учинили једноставнијим.