Bağlama Duyarlı Uygulamalar ve Karmaşık Olay İşleme Mimarisi

Yayınlanan: 2022-03-11

Dünya genelinde cep telefonu kullanımı sürekli artıyor. 2013 itibariyle, İnternet kullanıcılarının yaklaşık %73'ü bir mobil cihaz aracılığıyla içerik tüketiyor ve bu oranın 2017 yılına kadar %90'a yaklaşması bekleniyor.

Elbette mobil devrimin birçok nedeni var. Ancak en önemlilerinden biri, günümüzde neredeyse tüm akıllı telefonlar konum sensörleri, hareket sensörleri, bluetooth ve wifi ile donatıldığından, mobil uygulamaların genellikle daha zengin içeriğe erişmesidir. Uygulamalar, verilerini kullanarak, yeteneklerini ve değerlerini önemli ölçüde artırabilecek ve uygulama mağazalarında gerçekten öne çıkmalarını sağlayabilecek “bağlam farkındalığı” elde edebilir.

Bu öğreticide, karmaşık bir olay işleme örneği aracılığıyla bağlama duyarlı uygulamalar oluşturmayı keşfedeceğiz. Oldukça basit bir örnek kullanacağız: Bölgenizdeki en iyi yakıt fiyatlarını bulan bir yakıt fiyatı uygulaması.

Uygulamalarda bağlam farkındalığı, bunun gibi karmaşık bir olay işleme öğreticisi aracılığıyla oluşturulabilir.

Bağlama duyarlı uygulamalar

Designing Calm Technology'de Mark Weiser ve John Seely Brown, sakin teknolojiyi “bilgi veren ama bizim odaklanmamızı veya dikkatimizi gerektirmeyen şey” olarak tanımlıyorlar.

Bağlama duyarlı mobil uygulamalar bu kavramla son derece tutarlıdır ve bu yolda önemli ve değerli bir adımdır. Kullanıcıya proaktif olarak değerli bilgiler sağlamak için sensörlerinden toplanan bağlamsal bilgileri kullanırlar ve bunu kullanıcı adına minimum çabayla yaparlar. Mark Weiser ve John Seely Brown kuşkusuz bu teknolojik gelişmeyi alkışlayacaklardır.

Bağlam farkındalığı, bir uygulamanın eriştiği bağlamsal verilere dayanarak algılayabildiği ve tepki verebildiği fikridir. Böyle bir uygulama, kullanıcıya uygun bağlamda doğru ve alakalı bilgiler sağlamak için bir mobil cihazda bulunan zengin sensör verilerini kullanır. Bu tür bir uygulama, cihazın kullanımı boyunca gözlemlediği trendler ve/veya kullanıcı tarafından sağlanan geri bildirimler aracılığıyla aslında zaman içinde “öğrenebilir” ve böylece daha “akıllı” ve daha kullanışlı hale gelebilir.

Karmaşık olay işleme

Karmaşık olay işleme (CEP), daha anlamlı bilgi ve örüntüler elde etmek için içeriklerini bütünleştiren ve analiz eden birden çok olayın (yani zaman içinde, farklı kaynaklardan vb.) daha karmaşık analizlerini kullanan bir olay işleme biçimidir.

Bir mobil uygulamada, CEP, mobil cihazın sensörlerinden oluşturulan olaylara ve uygulamanın erişime sahip olduğu harici veri kaynaklarına uygulanabilir.

Yakıt fiyatı uygulamamızın temel özellikleri

Karmaşık olay işleme eğitimimizin amaçları doğrultusunda, yakıt fiyatı uygulamamızın özelliklerinin aşağıdakilerle sınırlı olduğunu varsayalım:

  • kullanıcı için coğrafi olarak alakalı konumları otomatik olarak algılama (örneğin, kullanıcının ev konumu ve kullanıcının iş konumu)
  • kullanıcının ev ve iş yerlerine makul bir mesafede bulunan yakıt istasyonlarını otomatik olarak belirleme
  • ev ve iş yeri yakınında en iyi yakıt fiyatlarını kullanıcıya otomatik olarak bildirir

Tamam, başlayalım.

Kullanıcının ev ve iş konumlarını algılama

Kullanıcının ev ve iş konumlarını otomatik olarak algılama mantığıyla başlayalım. Karmaşık olay işleme örneğimizde işleri basit tutmak için, kullanıcının oldukça normal bir çalışma programına sahip olduğunu varsayacağız. Bu nedenle, kullanıcının tipik olarak sabah 2 ile 3 arasında evde olacağını ve tipik olarak öğleden sonra 2 ile 3 arasında ofisinde olacağını varsayabiliriz.

Bu varsayımlara dayanarak, iki CEP kuralı tanımlıyor ve kullanıcının akıllı telefonundan konum ve zaman verilerini topluyoruz:

  • Ev Konumu kuralı
    • bir hafta boyunca 2 ile 3 AM arasında konum verilerini toplayın
    • yaklaşık ev adresi almak için konum verilerini kümeleyin

  • İş Yeri kuralı
    • hafta içi 2 ile 3 PM arasında konum verilerini toplayın
    • yaklaşık çalışma konumu elde etmek için konum verilerini kümeleyin

Konumları tespit etmek için yüksek seviyeli algoritma aşağıda gösterilmiştir.

Bu diyagram, bu öğreticideki bağlama duyarlı uygulamanın nasıl çalışacağını gösterir.

Konum verileri için aşağıdaki basit JSON veri yapısını varsayalım:

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

Not: CEP iş akışında farklı modüller tarafından güvenle kullanılabilmesi için sensör verilerini değişmez (veya değer tipi) yapmak her zaman iyi bir uygulamadır.

uygulama

Algoritmamızı, her modülün yalnızca bir görevi gerçekleştirdiği ve görev tamamlandığında bir sonraki çağrıyı yaptığı, şekillendirilebilir bir modül modeli kullanarak uygulayacağız. Bu, Unix Modülerlik Kuralı felsefesine uygundur.

Spesifik olarak, her modül, bir config nesnesini ve verileri sonraki modüle geçirmek için çağrılan bir next işlevi kabul eden bir işlevdir. Buna göre, her modül sensör verilerini kabul edebilen bir fonksiyon döndürür. İşte bir modülün temel imzası:

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

Kullanıcının ev ve iş konumlarını çıkarmaya yönelik algoritmamızı uygulamak için aşağıdaki modüllere ihtiyacımız olacak:

  • Zaman filtresi modülü
  • akümülatör modülü
  • kümeleme modülü

Bu modüllerin her biri, izleyen alt bölümlerde daha ayrıntılı olarak açıklanmaktadır.

Zaman filtresi modülü

Zaman filtremiz, konum verileri olaylarını girdi olarak alan ve yalnızca olay ilgili zaman dilimi içinde meydana gelirse verileri next modüle ileten basit bir işlevdir. Bu modül için config verileri, bu nedenle, ilgilenilen zaman diliminin başlangıç ​​ve bitiş zamanlarından oluşur. (Modülün daha gelişmiş bir sürümü, birden çok zaman dilimine göre filtre uygulayabilir.)

İşte zaman filtresi modülünün bir sözde kod uygulaması:

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

akümülatör modülü

Akümülatörün sorumluluğu, basitçe konum verilerini toplayarak bir next modüle iletmektir. Bu işlev, verileri depolamak için dahili bir sabit boyutlu paket tutar. Karşılaşılan her yeni konum, kova dolana kadar kovaya eklenir. Kovada biriken konum verileri daha sonra bir dizi olarak sonraki modüle gönderilir.

İki tür akümülatör grubu desteklenir. Paket türü, veriler bir sonraki aşamaya iletildikten sonra paketin içeriğine ne yapıldığını aşağıdaki gibi etkiler:

  • Dönen pencere kovası ( type = 'tumbling' ): verileri ilettikten sonra, tüm kovayı boşaltır ve yeni başlar (kepçe boyutu tekrar 0'a düşürülür)

  • Çalışan pencere türü ( type = 'running' ): verileri ilettikten sonra, yalnızca kovadaki en eski veri öğesini atar (kepçe boyutunu 1 azaltır)

İşte akümülatör modülünün temel bir uygulaması:

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

kümeleme modülü

Elbette 2B verileri kümelemek için koordinat geometrisinde birçok karmaşık teknik vardır. Konum verilerini kümelemenin basit bir yolu:

  • bir dizi konumdaki her konum için komşuları bulun
  • bazı komşular mevcut bir kümeye aitse, komşuları küme ile genişletin
  • komşu kümedeki konumlar eşikten fazlaysa, komşuları yeni bir küme olarak ekleyin

İşte bu kümeleme algoritmasının bir uygulaması ( Lo-Dash kullanarak):

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

Yukarıdaki kod, iki coğrafi konum arasındaki mesafeyi (metre olarak) hesaplayan bir distance() fonksiyonunun varlığını varsayar. [longitude, latitude] şeklinde iki konum noktasını kabul eder ve aralarındaki mesafeyi döndürür. İşte böyle bir işlevin örnek bir uygulaması:

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

Tanımlanan ve uygulanan kümeleme algoritmamızla (daha önce gösterilen createClusters() işlevimizde), onu kümeleme modülümüz için temel olarak kullanabiliriz:

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

Hepsini bir araya getirerek

Gerekli tüm bileşen işlevleri artık tanımlanmıştır, bu nedenle ev/iş yeri konumu kurallarımızı kodlamaya hazırız.

Örneğin, ev konumu kuralının olası bir uygulamasını burada bulabilirsiniz:

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

Artık akıllı telefondan (websocket, TCP, HTTP aracılığıyla) konum verileri alındığında, bu verileri home_rule işlevine iletiyoruz, bu da kullanıcının evi için kümeleri algılıyor.

Kullanıcının "ev konumu"nun, ev konumu kümesinin merkezi olduğu varsayılır.

Not: Bu tamamen kesin olmasa da, basit örneğimiz için yeterlidir, özellikle de bu uygulamanın amacı her durumda kullanıcının evini çevreleyen alanı bilmek olduğundan, kullanıcının evinin kesin konumunu bilmek yerine basitçe bilmektir.

Küme kümesindeki tüm noktaların enlem ve boylamlarının ortalamasını alarak bir kümedeki bir dizi noktanın "merkezini" hesaplayan basit bir örnek fonksiyon:

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

Benzer bir yaklaşım, iş yerinin çıkarılması için kullanılabilir, tek fark, saat 2 ile 3 arasında bir zaman filtresi kullanmasıdır (2 ve 3 AM'nin aksine).

Böylece yakıt uygulamamız, herhangi bir kullanıcı müdahalesi gerektirmeden kullanıcının iş ve ev konumlarını otomatik olarak algılayabilir. Bu, en iyi şekilde bağlama duyarlı bilgi işlemdir!

Yakındaki yakıt istasyonlarını bulma

Bağlam farkındalığı oluşturmak için zorlu çalışma şimdi yapıldı, ancak hangi akaryakıt istasyonu fiyatlarının izleneceğini belirlemek için hala bir kurala daha ihtiyacımız var (yani, hangi akaryakıt istasyonları kullanıcının evine veya iş yerine uygun olacak kadar yakın). Bu kuralın, yakıt uygulaması tarafından desteklenen tüm bölgeler için tüm yakıt istasyonu konumlarına erişmesi gerekir. Kural aşağıdaki gibidir:

  • Akaryakıt istasyonu kuralı
    • her ev ve iş yeri için en yakın yakıt istasyonlarını bulun

Bu, uygulama tarafından bilinen tüm yakıt istasyonlarına uygulanacak bir konum filtresi olarak daha önce gösterilen mesafe işlevi kullanılarak kolayca uygulanabilir.

Bağlama duyarlı uygulamalar, bu eğitici uygulama gibi zamanla daha akıllı hale gelir.

Akaryakıt fiyatlarının izlenmesi

Akaryakıt uygulaması, kullanıcı için tercih edilen (yani yakındaki) akaryakıt istasyonlarının listesini aldığında, bu istasyonlardaki en iyi akaryakıt fiyatlarını kolayca izleyebilir. Ayrıca, bu akaryakıt istasyonlarından birinin özel fiyatları veya teklifleri olduğunda, özellikle kullanıcının bu akaryakıt istasyonlarının yakınında olduğunu tespit ettiğinde, kullanıcıyı bilgilendirebilir.

Bu karmaşık olay işleme öğreticisi, bir uygulamada bağlam farkındalığının nasıl oluşturulabileceğini gösterir.

Çözüm

Bu karmaşık olay işleme eğitiminde, içeriğe duyarlı bilgi işlemin yüzeyini gerçekten zar zor çizdik.

Basit örneğimizde, normalde basit olan bir yakıt fiyatı raporlama uygulamasına konum bağlamı ekledik ve onu daha akıllı hale getirdik. Uygulama artık her cihazda farklı davranıyor ve zaman içinde kullanıcılarına sağladığı bilgilerin değerini otomatik olarak iyileştirmek için konum modellerini algılıyor.

Bağlama duyarlı uygulamamızın doğruluğunu ve faydasını artırmak için kesinlikle çok daha fazla mantık ve sensör verisi eklenebilir. Akıllı bir mobil geliştirici, örneğin sosyal ağ verilerini, hava durumu verilerini, POS terminal işlem verilerini vb. kullanarak uygulamamıza daha fazla bağlam farkındalığı ekleyebilir ve onu daha uygulanabilir ve pazarlanabilir hale getirebilir.

Bağlama duyarlı bilgi işlem ile olanaklar sonsuzdur. Hayatımızı kolaylaştırmak için bu güçlü teknolojiyi kullanan uygulama mağazalarında giderek daha fazla akıllı uygulama görünmeye devam edecek.