בניית פיד המלצות אלגוריתמי לאפליקציות מובייל
אנו מפתחים פידי המלצות אלגוריתמיים לאפליקציות מובייל שמדרגים תוכן בזמן אמת עבור כל משתמש. בניגוד לפיד כרונולוגי, המערכת שלנו משתמשת בציון מעורבות חזוי ואוספת אותות ישירות מהאפליקציה—מ-video_completion_rate ועד למהירות החלקה. זה מגדיל את המעורבות ב-20–40% (בהתבסס על ניסיון הפרויקטים שלנו). במשך 5+ שנים, יישמנו פידים כאלה לאפליקציות חדשות, וידאו ומסחר אלקטרוני, וצברנו פרקטיקות הנדסיות שאנו חולקים להלן. אנו מבטיחים פעילות יציבה גם בעומסי שיא.
כיצד פועלת ארכיטקטורת פיד ההמלצות
פיד אלגוריתמי פועל בשני שלבים, והאפליקציה הניידת תלויה באופן קריטי בשניהם.
יצירת מועמדים—מתוך מיליוני פריטי תוכן, אנו בוחרים כמה מאות מועמדים עבור משתמש ספציפי. זה בדרך כלל מודל קל משקל (Approximate Nearest Neighbor על embedding של משתמש) או קבוצת כללים: משתמשים שנעקבו, טרנדים גיאוגרפיים, זיקה לנושאים. שלב זה חייב להסתיים תוך 50–100ms.
דירוג—מועמדים מדורגים על ידי מודל כבד שמנבא את הסתברות האינטראקציה (לייק, שיתוף, תגובה, שיעור השלמה). עצים מוגברים (XGBoost, LightGBM), רשתות נוירונים דו-מגדליות, או DLRM. התוצאה היא רשימה מסודרת עם ציונים.
שירות—האפליקציה הניידת מבקשת את N פריטי הפיד הבאים, ומקבלת אותם עם סדר מחושב מראש. בצע prefetch לעמוד הבא לפני שהמשתמש מגיע לסוף העמוד הנוכחי.
למה איכות האותות היא החשובה ביותר
איכות האלגוריתם נקבעת על ידי איכות האותות. האפליקציה הניידת היא המקור העיקרי. אנו אוספים אותות מפורשים (לייק, שיתוף, תגובה) ואותות מרומזים (שיעור השלמה, זמן שהייה, מהירות החלקה החוצה). הקשר מכשיר (שעה ביום, סוג רשת, רמת סוללה) גם משפר את הדירוג.
| סוג אות | דוגמאות | משקל בדירוג |
|---|---|---|
| מפורש | לייק, שיתוף, תגובה | גבוה |
| מרומז | שיעור השלמה, זמן שהייה | בינוני |
| הקשרי | שעה ביום, סוג רשת | נמוך (אך משפר) |
| שלילי | דילוג < 0.5s, דיווח | גבוה מאוד |
מעקב אחר השלמת וידאו ב-iOS:
דוגמת יישום ב-iOS
class VideoProgressTracker {
private var timeObserver: Any?
private let player: AVPlayer
private let itemId: String
private var maxProgress: Float = 0
init(player: AVPlayer, itemId: String) {
self.player = player
self.itemId = itemId
setupObserver()
}
private func setupObserver() {
let interval = CMTime(seconds: 0.5, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
timeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in
guard let self, let duration = self.player.currentItem?.duration.seconds, duration > 0 else { return }
let progress = Float(time.seconds / duration)
if progress > self.maxProgress {
self.maxProgress = progress
}
}
}
func reportCompletion() {
Analytics.track(.videoProgress(itemId: itemId, completionRate: maxProgress, source: .algorithmicFeed))
}
}ב-Android—השתמש ב-class VideoProgressTracker { private var timeObserver: Any? private let player: AVPlayer private let itemId: String private var maxProgress: Float = 0 init(player: AVPlayer, itemId: String) { self.player = player self.itemId = itemId setupObserver() } private func setupObserver() { let interval = CMTime(seconds: 0.5, preferredTimescale: CMTimeScale(NSEC_PER_SEC)) timeObserver = player.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in guard let self, let duration = self.player.currentItem?.duration.seconds, duration > 0 else { return } let progress = Float(time.seconds / duration) if progress > self.maxProgress { self.maxProgress = progress } } } func reportCompletion() { Analytics.track(.videoProgress(itemId: itemId, completionRate: maxProgress, source: .algorithmicFeed)) } } עם ExoPlayer ו-AnalyticsListener.onPlaybackStateChanged().
כיצד ליישם גלילה אינסופית מבלי לפגוע בחוויית המשתמש
המשתמש לא צריך לראות loader בזמן גלילה. הגישה הסטנדרטית: טען מראש את העמוד הבא כשהמשתמש מגיע לפריט השני-לאחרון בעמוד הנוכחי. Prefetch עם סף של 7–10 פריטים לפיד וידאו מפחית את זמן הטעינה פי 2–3 בהשוואה ללא prefetch.
// Android, RecyclerView + ViewModel
recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val lastVisible = layoutManager.findLastVisibleItemPosition()
val total = layoutManager.itemCount
if (total - lastVisible <= PREFETCH_THRESHOLD) {
viewModel.loadNextPage()
}
}
})Player.Listener.onPositionDiscontinuity() הוא בדרך כלל 3–5 פריטים. עבור פיד וידאו, אנו מגדילים אותו ל-7–10 כי טעינת וידאו לוקחת יותר זמן. הסרת כפילויות: השרת עשוי להחזיר את אותו פריט בשתי תגובות pagination. הלקוח שומר // Android, RecyclerView + ViewModel recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { val layoutManager = recyclerView.layoutManager as LinearLayoutManager val lastVisible = layoutManager.findLastVisibleItemPosition() val total = layoutManager.itemCount if (total - lastVisible <= PREFETCH_THRESHOLD) { viewModel.loadNextPage() } } }) של מזההים שהוצגו ומסנן כפילויות לפני הוספה לרשימה.
כיצד אנו בודקים ומפרסמים
גרסת מודל דירוג חדשה לא משוחררת לכולם בבת אחת. סכמה אופיינית: 5% תנועה → 20% → 50% → 100%, עם ניטור מדדי session (שימור D1/D7, זמן ממוצע באפליקציה, שיעור מעורבות) בכל שלב. ניהול feature flags נעשה דרך Firebase Remote Config או מערכת ביתית. הלקוח שולח PREFETCH_THRESHOLD בכל בקשה ל-API של הפיד—זה מאפשר לשרת לבחור את ranker המתאים.
מה כלול בעבודה
- ביקורת על מעקב ואנליטיקה קיימים
- עיצוב סכמת אירועים וארכיטקטורת פיד
- פיתוח צד לקוח (iOS/Android) עם prefetch, הסרת כפילויות, מעקב
- אינטגרציה עם API של הפיד (REST/GraphQL)
- יישום תוויות הסבר ובקרות ממשק
- הקמת A/B testing וניטור
- תיעוד וסקירת קוד
- תמיכה לאחר השקה (חודשיים)
הערכות לוחות זמנים
| שלב | משך |
|---|---|
| ביקורת ועיצוב | 1–2 שבועות |
| פיתוח לקוח | 2–3 שבועות |
| Ranker שרת (אופציונלי) | 4–6 שבועות |
| A/B testing | 2–3 שבועות |
העלות מחושבת באופן אישי, בהתאם לנפח התוכן, זמן השהיה הנדרש, וקיומה של תשתית אנליטיקה קיימת.
למה לבחור בנו
יש לנו 5+ שנות ניסיון בפיתוח מערכות המלצות וביצענו מעל 30 פרויקטים בתחום. המהנדסים שלנו מיומנים במלא הטכנולוגיות: Swift, Kotlin, Flutter, Python, ML. אנו מבטיחים פעילות יציבה של הפיד תחת עומס גבוה ודיווח שקוף בכל שלב.
צור קשר כדי לדון במשימה שלך ולקבל הערכת תקציב ראשונית.







