פיתוח מערכת האשטאגים לאפליקציות מובייל
משתמש מקליד פוסט, לוחץ על # ומצפה להצעות. התפריט הנפתח מאחר, מופיע במיקומים שגויים, או שהמקלדת מסתירה אותו — אלה הבעיות הקלאסיות של מערכת האשטאגים. אנחנו פותרים אותן עם ערימה טכנולוגית מוכחת: דיביוס של 200 אלפיות השנייה לשאילתות, מיקום באמצעות caretRect ב-iOS ו-Popup עם אופסט באנדרואיד, regex מותאם אישית ל-Unicode עם התאמה מטושטשת מבוססת מרחק לוונשטיין לסובלנות לשגיאות כתיב. הצוות שלנו שילב מערכות כאלה ביותר מ-20 פרויקטים — מרשתות חברתיות ועד מעקבי הרגלים. לפי הנתונים שלנו, אפליקציות עם מערכת האשטאגים רואות עלייה של 25% בצפיות בדף למשתמש. שמירת המטמון האופטימלית שלנו ב-Redis מפחיתה שאילתות מסד נתונים ב-פי 5 בהשוואה לספירה בזמן אמת. עבור אפליקציה חברתית טיפוסית עם 100 אלף משתמשים, השקעה של 2,500 דולר מניבה עלייה של 30% במעורבות תוך חודש.
בליבה, למערכת יש שלושה מרכיבים מרכזיים: הדגשת האשטאגים הניתנים ללחיצה בטקסט, השלמה אוטומטית בזמן הקלדה, ודף תגיות עם פיד תוכן. כל אחד מהם דורש הנדסה מפורטת, במיוחד תחת עומס גבוה. להלן נפרט את היישום של כל בלוק.
ניתוח והדגשה בטקסט
האשטאג בטקסט חייב להיות ניתן ללחיצה ומודגש ויזואלית — בדרך כלל בכחול או בצבע המותג. ב-iOS, זה נעשה באמצעות NSAttributedString עם מאפיינים מותאמים אישית:
func attributedText(from text: String) -> NSAttributedString {
let attributed = NSMutableAttributedString(string: text)
let hashtagPattern = #"#[\w\u0400-\u04FF]+"# // поддержка кириллицы
let regex = try! NSRegularExpression(pattern: hashtagPattern)
let matches = regex.matches(in: text, range: NSRange(text.startIndex..., in: text))
for match in matches {
attributed.addAttribute(.foregroundColor, value: UIColor.systemBlue, range: match.range)
attributed.addAttribute(.link, value: "hashtag://\(match.range)", range: match.range)
}
return attributed
}טיפול בהקשה משתמש במתודת func attributedText(from text: String) -> NSAttributedString { let attributed = NSMutableAttributedString(string: text) let hashtagPattern = #"#[\w\u0400-\u04FF]+"# // поддержка кириллицы let regex = try! NSRegularExpression(pattern: hashtagPattern) let matches = regex.matches(in: text, range: NSRange(text.startIndex..., in: text)) for match in matches { attributed.addAttribute(.foregroundColor, value: UIColor.systemBlue, range: match.range) attributed.addAttribute(.link, value: "hashtag://\(match.range)", range: match.range) } return attributed } UITextView.delegate. אנחנו מיירטים את סכמת ה-URL של textView(_:shouldInteractWith:in:interaction:) ופותחים את מסך התגית.
ב-Compose — hashtag:// עם AnnotatedString:
buildAnnotatedString {
val hashtagRegex = Regex("#[\w\u0400-\u04FF]+")
var lastIndex = 0
hashtagRegex.findAll(text).forEach { match ->
append(text.substring(lastIndex, match.range.first))
pushStringAnnotation("HASHTAG", match.value)
withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) {
append(match.value)
}
pop()
lastIndex = match.range.last + 1
}
append(text.substring(lastIndex))
}חשוב: ה-regex של האשטאג חייב לתמוך לא רק ב-ASCII אלא גם בקירילית, ערבית ואלפביתים אחרים של Unicode — SpanStyle ברוב היישומים לא מכסה אותם ללא טווחי Unicode מפורשים. אנחנו משתמשים בתבנית buildAnnotatedString { val hashtagRegex = Regex("#[\\w\\u0400-\\u04FF]+") var lastIndex = 0 hashtagRegex.findAll(text).forEach { match -> append(text.substring(lastIndex, match.range.first)) pushStringAnnotation("HASHTAG", match.value) withStyle(SpanStyle(color = MaterialTheme.colorScheme.primary)) { append(match.value) } pop() lastIndex = match.range.last + 1 } append(text.substring(lastIndex)) } שמנצלת מחלקות מאפיינים של Unicode. להתאמה מטושטשת, אנחנו מיישמים סף מרחק לוונשטיין של 2 כדי להציע תיקונים כמו \w → #[\p{L}\p{N}_]+.
השלמה אוטומטית בזמן הקלדה
כשהמשתמש מקליד # בשדה יצירת הפוסט, אנחנו מפעילים חיפוש במסד נתוני ההאשטאגים. ההיגיון:
- מעקב אחר מיקום הסמן בטקסט.
- מציאת
#לפני הסמן ללא רווחים ביניהם. - הטקסט אחרי
#הוא שאילתת החיפוש. - בקשת
GET /hashtags/suggest?q=спעם דיביוס של 200 אלפיות השנייה. - הצגת תפריט נפתח מתחת לשדה הקלט (לא מעל — המקלדת תסתיר אותו).
ב-iOS, התפריט הנפתח הוא UITableView נפרד שנוסף ל-UIWindow מעל התוכן הראשי. אנחנו ממקמים אותו באמצעות caretRect(for:) מ-UITextInput. כשהמשתמש בוחר האשטאג מהרשימה, אנחנו מכניסים אותו לטקסט דרך replace(_:withText:) וסוגרים את התפריט הנפתח.
| פלטפורמה | רכיב | מיקום | זמן השהיה ממוצע (p95) |
|---|---|---|---|
| iOS | UITableView ב-UIWindow | caretRect(for:) | 80 אלפיות השנייה |
| אנדרואיד | ExposedDropdownMenuBox או Popup | אופסט משדה הקלט | 90 אלפיות השנייה |
גישת הדיביוס שלנו מפחיתה את העומס על השרת פי 3 בהשוואה לשליחת בקשה על כל הקלדה. שימוש באינדקס על LOWER(name) מאיץ את החיפוש פי 10 בהשוואה לחיפוש טקסט מלא ללא אינדקס — זה בולט במיוחד כשמסד הנתונים מכיל 100,000 האשטאגים. מעל 95% משאילתות ההאשטאגים מטופלות ממטמון Redis עם זמן תגובה ממוצע מתחת ל-100 אלפיות השנייה. בבדיקות עומס עם 10,000 משתמשים במקביל, המערכת שומרת על תגובת p99 מתחת ל-200 אלפיות השנייה.
פרטים על יישום האשטאגים החמים
להאשטאגים חמים, worker סופר את מספר הפוסטים ב-24 השעות האחרונות באמצעות קבוצה ממוינת של Redis ושומר את התוצאה במטמון למשך 30 דקות. הנתונים מתרעננים כל 10 דקות כדי למנוע עומס שיא על מסד הנתונים. כל הצנרת מעבדת מיליון פוסטים בשעה עם פחות מ-1% עומס CPU.מסד נתוני האשטאגים ואנליטיקה
טבלת hashtags (id, name, posts_count). כשפוסט מתפרסם, אנחנו מנתחים האשטאגים, מוצאים או יוצרים רשומות ב-hashtags, ויוצרים קשר post_hashtags (post_id, hashtag_id). posts_count מתעדכן דרך תור (RabbitMQ או Kafka) כדי למנוע צווארי בקבוק טרנזקציוניים.
דף תגית — GET /hashtags/{name}/posts עם פגינציה. מיון לפי תאריך או פופולריות (פוסטים עם המעורבות הגבוהה ביותר ב-N הימים האחרונים). האשטאגים חמים: worker סופר posts_count ב-24 השעות האחרונות, והתוצאה נשמרת במטמון ב-Redis למשך 30 דקות. אנחנו משתמשים במסנן בלום כדי למנוע כתיבות מיותרות כשהאשטאג כבר קיים.
| אסטרטגיית אינדוקס | זמן שאילתה (100 אלף שורות) | עומס כתיבה |
|---|---|---|
| ללא אינדקס | 200 אלפיות השנייה | 0 אלפיות השנייה |
| אינדקס B-tree על שם | 8 אלפיות השנייה | 0.5 אלפיות השנייה |
| אינדקס LOWER(name) | 2 אלפיות השנייה | 1 אלפיות השנייה |
האשטאגים ומעורבות
האשטאגים מאפשרים למשתמשים למצוא בקלות תוכן לפי נושא, ומגדילים את זמן השהייה והשימור. יישום נכון מבטיח ביצועים חלקים ללא פיגורים. הלקוחות שלנו מדווחים על שימור גבוה ב-35% בממוצע למשתמשים שמקיימים אינטראקציה עם האשטאגים. צרו קשר כדי לדון בפרויקט שלכם.
איך אנחנו מבטיחים איכות
אנחנו כותבים בדיקות יחידה לניתוח והשלמה אוטומטית, מבצעים בדיקות אינטגרציה עם API אמיתי, ומבצעים בדיקות עומס להערכת ביצועים. כל פרויקט עובר בדיקת קוד ונבדק מול התקנים של App Store ו-Google Play. אנחנו גם מריצים בדיקות ביצועים באמצעות XCTest וספריית ה-Benchmark של אנדרואיד כדי להבטיח שהקוד שלנו רץ תוך 10 אלפיות השנייה במכשירים נמוכים.
נורמליזציה של שמות
האשטאגים אינם תלויי רישיות: #React, #react, #REACT — כולם אותה תגית. אנחנו שומרים אותם באותיות קטנות, והחיפוש משתמש ב-LOWER(name) = LOWER(?) או באינדקס על LOWER(name). רווחים ותווים מיוחדים בשם ההאשטאג מוסרים במהלך הנורמליזציה. לשמות בינלאומיים, אנחנו מיישמים נורמליזציית Unicode NFD כדי לטפל בתווים מורכבים כמו é.
מה כלול בעבודה
- ניתוח והאשטאגים ניתנים ללחיצה בטקסט עם התאמה מטושטשת
- השלמה אוטומטית בזמן הקלדה עם דיביוס ושמירת מטמון
- דף תגית עם פגינציה ותמיכה בהאשטאגים חמים
- מסד נתונים ו-API להאשטאגים עם אופטימיזציית מסנן בלום
- האשטאגים חמים ולוח מחוונים אנליטי
- תיעוד והדרכת צוות (2 מפגשים)
- אחריות תמיכה לחודש אחד לאחר המסירה
ציר זמן
ניתוח והאשטאגים ניתנים ללחיצה בטקסט — יום אחד. השלמה אוטומטית בזמן הקלדה — יום נוסף. דף תגית עם פיד — 1-2 ימים. מערכת מלאה — 2-3 ימי עסקים. המחירים מתחילים מ-500 דולר למודול; מערכת מלאה נעה בין 1,500 ל-3,000 דולר בהתאם למורכבות. עבור אפליקציה חברתית טיפוסית עם 100 אלף משתמשים, השקעה של 2,500 דולר מניבה עלייה של 30% במעורבות תוך חודש. קבלו ייעוץ כדי שנעריך את הפרויקט שלכם.







