แอปพลิเคชัน Context Aware และสถาปัตยกรรมการประมวลผลเหตุการณ์ที่ซับซ้อน

เผยแพร่แล้ว: 2022-03-11

การใช้โทรศัพท์มือถือทั่วโลกเพิ่มขึ้นอย่างต่อเนื่อง ในปี 2556 ผู้ใช้อินเทอร์เน็ตประมาณ 73% ใช้เนื้อหาผ่านอุปกรณ์พกพา และคาดว่าเปอร์เซ็นต์นี้จะเพิ่มขึ้นเกือบ 90% ภายในปี 2560

มีเหตุผลหลายประการสำหรับการปฏิวัติอุปกรณ์พกพา แต่สิ่งหนึ่งที่สำคัญที่สุดคือ โดยทั่วไปแล้วแอปบนอุปกรณ์เคลื่อนที่จะเข้าถึงบริบทที่สมบูรณ์ยิ่งขึ้นได้ เนื่องจากสมาร์ทโฟนเกือบทั้งหมดในปัจจุบันมีเซ็นเซอร์ระบุตำแหน่ง เซ็นเซอร์ตรวจจับความเคลื่อนไหว บลูทูธ และ Wi-Fi การใช้ข้อมูลทำให้แอปสามารถบรรลุ "การรับรู้บริบท" ที่สามารถเพิ่มความสามารถและมูลค่าได้อย่างมาก และทำให้โดดเด่นใน App Store

ในบทช่วยสอนนี้ เราจะสำรวจการสร้างแอปที่รับรู้บริบทผ่านตัวอย่างการประมวลผลเหตุการณ์ที่ซับซ้อน เราจะใช้ตัวอย่างที่ค่อนข้างง่าย: แอปราคาน้ำมันที่ค้นหาราคาน้ำมันที่ดีที่สุดในพื้นที่ของคุณ

สามารถสร้างการรับรู้บริบทในแอปได้ผ่านบทช่วยสอนการประมวลผลเหตุการณ์ที่ซับซ้อนเช่นนี้

แอพที่ทราบบริบท

ในการออกแบบ Calm Technology นั้น Mark Weiser และ John Seely Brown กล่าวถึงเทคโนโลยีที่สงบว่าเป็น “สิ่งที่แจ้งแต่ไม่ต้องการการมุ่งเน้นหรือความสนใจของเรา”

แอปบนอุปกรณ์เคลื่อนที่ที่คำนึงถึงบริบทมีความสอดคล้องอย่างยิ่งกับแนวคิดนี้ และเป็นขั้นตอนที่สำคัญและมีค่าสำหรับเส้นทางนี้ พวกเขาใช้ข้อมูลเชิงบริบทที่รวบรวมจากเซ็นเซอร์ของพวกเขาเพื่อให้ข้อมูลที่มีค่าแก่ผู้ใช้ในเชิงรุก และพวกเขาทำโดยใช้ความพยายามเพียงเล็กน้อยในส่วนของผู้ใช้ Mark Weiser และ John Seely Brown จะปรบมือให้กับความก้าวหน้าทางเทคโนโลยีนี้อย่างไม่ต้องสงสัย

การตระหนักรู้บริบทเป็นแนวคิดที่แอปสามารถรับรู้และตอบสนองตามข้อมูลบริบทที่เข้าถึงได้ แอปดังกล่าวใช้ข้อมูลเซ็นเซอร์ที่หลากหลายซึ่งมีอยู่ในอุปกรณ์เคลื่อนที่เพื่อให้ข้อมูลที่ถูกต้องและเกี่ยวข้องกับผู้ใช้ในบริบทที่เหมาะสม แอปดังกล่าวสามารถ "เรียนรู้" ได้จริงตามแนวโน้มตลอดการใช้งานอุปกรณ์ และ/หรือจากข้อเสนอแนะที่ผู้ใช้ให้มา เมื่อเวลาผ่านไปจึงกลายเป็น "ฉลาดขึ้น" และมีประโยชน์มากขึ้น

การประมวลผลเหตุการณ์ที่ซับซ้อน

การประมวลผลเหตุการณ์ที่ซับซ้อน (CEP) คือรูปแบบหนึ่งของการประมวลผลเหตุการณ์ที่ใช้การวิเคราะห์ที่ซับซ้อนมากขึ้นของหลายเหตุการณ์ (เช่น เมื่อเวลาผ่านไป จากแหล่งที่มาต่างๆ เป็นต้น) การรวมและวิเคราะห์เนื้อหาเพื่อสรุปข้อมูลและรูปแบบที่มีความหมายมากขึ้น

ในแอพมือถือ CEP สามารถใช้กับเหตุการณ์ที่สร้างขึ้นจากเซ็นเซอร์ของอุปกรณ์มือถือรวมถึงแหล่งข้อมูลภายนอกที่แอพสามารถเข้าถึงได้

คุณสมบัติที่สำคัญของแอพราคาน้ำมันของเรา

สำหรับวัตถุประสงค์ของบทช่วยสอนการประมวลผลเหตุการณ์ที่ซับซ้อนของเรา สมมติว่าคุณสมบัติของแอปราคาน้ำมันของเราจำกัดดังต่อไปนี้:

  • ตรวจหาตำแหน่งที่เกี่ยวข้องกับผู้ใช้ตามภูมิศาสตร์ โดยอัตโนมัติ (เช่น ตำแหน่งบ้านของผู้ใช้และตำแหน่งที่ทำงานของผู้ใช้)
  • ระบุสถานีบริการน้ำมัน โดยอัตโนมัติ ภายในระยะทางที่เหมาะสมจากบ้านและที่ทำงานของผู้ใช้
  • แจ้งผู้ใช้บริการน้ำมันราคาดีที่สุดใกล้บ้านและที่ทำงาน โดยอัตโนมัติ

ตกลง มาเริ่มกันเลย

การตรวจจับตำแหน่งบ้านและที่ทำงานของผู้ใช้

เริ่มจากตรรกะในการตรวจจับตำแหน่งบ้านและที่ทำงานของผู้ใช้โดยอัตโนมัติ เพื่อให้ง่ายสำหรับตัวอย่างการประมวลผลเหตุการณ์ที่ซับซ้อน เราจะถือว่าผู้ใช้มีตารางการทำงานที่ค่อนข้างปกติ ดังนั้นเราจึงสามารถสรุปได้ว่าโดยทั่วไปผู้ใช้จะอยู่บ้านระหว่าง 2 ถึง 03.00 น. และโดยทั่วไปจะอยู่ที่สำนักงานระหว่างเวลา 14.00 น. ถึง 15.00 น.

จากสมมติฐานดังกล่าว เรากำหนดกฎ CEP สองข้อและรวบรวมข้อมูลตำแหน่งและเวลาจากสมาร์ทโฟนของผู้ใช้:

  • กฎของตำแหน่งบ้าน
    • รวบรวมข้อมูลตำแหน่งระหว่าง 2 ถึง 3 โมงเช้าเป็นเวลาหนึ่งสัปดาห์
    • จัดกลุ่มข้อมูลตำแหน่งเพื่อรับที่อยู่บ้านโดยประมาณ

  • กฎสถานที่ทำงาน
    • รวบรวมข้อมูลตำแหน่งระหว่าง 14.00 ถึง 15.00 น. สำหรับวันธรรมดา
    • จัดกลุ่มข้อมูลตำแหน่งเพื่อรับตำแหน่งงานโดยประมาณ

อัลกอริทึมระดับสูงในการตรวจจับตำแหน่งแสดงไว้ด้านล่าง

ไดอะแกรมนี้แสดงให้เห็นว่าแอปพลิเคชั่นทราบบริบทในบทช่วยสอนนี้ทำงานอย่างไร

ให้ถือว่าโครงสร้างข้อมูล JSON ง่าย ๆ ต่อไปนี้สำหรับข้อมูลตำแหน่ง:

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

หมายเหตุ: แนวทางปฏิบัติที่ดีคือการทำให้ข้อมูลเซ็นเซอร์ไม่เปลี่ยนรูปแบบ (หรือประเภทค่า) เพื่อให้สามารถใช้งานได้อย่างปลอดภัยโดยโมดูลต่างๆ ในเวิร์กโฟลว์ CEP

การดำเนินการ

เราจะใช้อัลกอริทึมของเราโดยใช้ รูปแบบโมดูล ที่เขียนได้ โดยแต่ละโมดูลทำงานเพียงงานเดียวและเรียกใช้งานถัดไปเมื่องานเสร็จสมบูรณ์ สิ่งนี้สอดคล้องกับปรัชญา Unix Rule of Modularity

โดยเฉพาะอย่างยิ่ง แต่ละโมดูลเป็นฟังก์ชันที่ยอมรับอ็อบเจ็กต์ 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); } }; }

โมดูลสะสม

ความรับผิดชอบของ accumulator คือการรวบรวมข้อมูลตำแหน่งเพื่อส่งต่อไปยังโมดูล 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; } }; }

โมดูลการจัดกลุ่ม

มีเทคนิคที่ซับซ้อนหลายอย่างในเรขาคณิตเชิงพิกัดเพื่อจัดกลุ่มข้อมูล 2D นี่เป็นวิธีง่ายๆ ในการจัดกลุ่มข้อมูลตำแหน่ง:

  • หาเพื่อนบ้านในแต่ละสถานที่ในชุดของสถานที่
  • ถ้าเพื่อนบ้านบางส่วนอยู่ในคลัสเตอร์ที่มีอยู่แล้วให้ขยายเพื่อนบ้านด้วยคลัสเตอร์
  • หากสถานที่ในชุดเพื่อนบ้านมากกว่าเกณฑ์ ให้เพิ่มเพื่อนบ้านเป็นคลัสเตอร์ใหม่

นี่คือการใช้งานอัลกอริธึมการจัดกลุ่มนี้ (โดยใช้ 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);

ตอนนี้เมื่อใดก็ตามที่ได้รับข้อมูลตำแหน่งจากสมาร์ทโฟน (ผ่าน 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]; }

สามารถใช้วิธีการที่คล้ายกันในการอนุมานสถานที่ทำงาน โดยมีความแตกต่างเพียงอย่างเดียวคือจะใช้ตัวกรองเวลาระหว่าง 14.00 น. ถึง 15.00 น. (ตรงข้ามกับ 2 และ 3 น.)

แอปเชื้อเพลิงของเราสามารถตรวจจับตำแหน่งที่ทำงานและบ้านของผู้ใช้ได้ โดยอัตโนมัติโดย ที่ผู้ใช้ไม่ต้องดำเนินการใดๆ นี่คือการประมวลผลตามบริบทที่ดีที่สุด!

ค้นหาสถานีบริการน้ำมันใกล้เคียง

งานหนักเพื่อสร้างการรับรู้บริบทได้เสร็จสิ้นแล้ว แต่เรายังคงต้องการกฎอีกหนึ่งข้อในการระบุว่าราคาสถานีบริการน้ำมันใดที่ต้องติดตาม (กล่าวคือ สถานีบริการน้ำมันใดอยู่ใกล้กับบ้านหรือที่ทำงานของผู้ใช้มากพอที่จะมีความเกี่ยวข้อง) กฎนี้จำเป็นต้องเข้าถึงตำแหน่งสถานีบริการน้ำมันทั้งหมดสำหรับทุกภูมิภาคที่แอปเชื้อเพลิงรองรับ กฎมีดังนี้:

  • กฎสถานีบริการน้ำมัน
    • ค้นหาสถานีบริการน้ำมันที่ใกล้ที่สุดสำหรับแต่ละตำแหน่งบ้านและที่ทำงาน

สามารถใช้งานได้ง่ายโดยใช้ฟังก์ชันระยะทางที่แสดงไว้ก่อนหน้าเป็นตัวกรองตำแหน่งเพื่อนำไปใช้กับสถานีบริการน้ำมันทั้งหมดที่แอปรู้จัก

แอปพลิเคชันที่ทราบบริบทจะฉลาดขึ้นเมื่อเวลาผ่านไป เช่น แอปบทช่วยสอนนี้

ติดตามราคาน้ำมัน

เมื่อแอพเชื้อเพลิงได้รับรายการสถานีบริการน้ำมันที่ต้องการ (เช่น ใกล้เคียง) สำหรับผู้ใช้ ก็สามารถติดตามราคาน้ำมันที่ดีที่สุดที่สถานีเหล่านี้ได้อย่างง่ายดาย นอกจากนี้ยังสามารถแจ้งเตือนผู้ใช้เมื่อสถานีบริการน้ำมันเหล่านี้มีราคาหรือข้อเสนอพิเศษ โดยเฉพาะอย่างยิ่งเมื่อตรวจพบผู้ใช้อยู่ใกล้สถานีบริการน้ำมันเหล่านี้

บทช่วยสอนการประมวลผลเหตุการณ์ที่ซับซ้อนนี้แสดงให้เห็นว่าสามารถสร้างการรับรู้บริบทในแอปพลิเคชันได้อย่างไร

บทสรุป

ในบทช่วยสอนการประมวลผลเหตุการณ์ที่ซับซ้อนนี้ เราแทบไม่ได้ขีดข่วนพื้นผิวของการประมวลผลแบบทราบบริบทเลย

ในตัวอย่างง่ายๆ ของเรา เราได้เพิ่มบริบทของตำแหน่งลงในแอปการรายงานราคาน้ำมันแบบง่ายๆ และทำให้ฉลาดขึ้น ขณะนี้แอปทำงานแตกต่างกันในแต่ละอุปกรณ์ และเมื่อเวลาผ่านไปจะตรวจจับรูปแบบตำแหน่ง เพื่อปรับปรุงคุณค่าของข้อมูลที่มอบให้แก่ผู้ใช้โดยอัตโนมัติ

สามารถเพิ่มข้อมูลตรรกะและเซ็นเซอร์ได้มากขึ้นอย่างแน่นอนเพื่อเพิ่มความแม่นยำและประโยชน์ของแอพที่รับรู้บริบทของเรา ตัวอย่างเช่น นักพัฒนามือถือที่ชาญฉลาดสามารถใช้ประโยชน์จากข้อมูลเครือข่ายสังคม ข้อมูลสภาพอากาศ ข้อมูลธุรกรรมของเทอร์มินัล POS และอื่นๆ เพื่อเพิ่มการรับรู้บริบทให้กับแอปของเรา และทำให้ใช้งานได้จริงและทำการตลาดได้มากขึ้น

ด้วยการคำนวณตามบริบท ความเป็นไปได้ไม่มีที่สิ้นสุด แอพที่ชาญฉลาดมากขึ้นเรื่อยๆ จะยังคงปรากฏในร้านแอพที่ใช้เทคโนโลยีอันทรงพลังนี้เพื่อทำให้ชีวิตของเราง่ายขึ้น