Bağlama Duyarlı Uygulamalar ve Karmaşık Olay İşleme Mimarisi
Yayınlanan: 2022-03-11Dü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ı.
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.
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.
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.
Çö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.