→ buildbench

0.011 זה לא מרווח ביטחון

יש לי בדאטהבייס פיצול מטופש: אותה עיר, שלושה איותים. תל אביב יפו, תל אביב-יפו, תל אביב. כל סקרייפר בחר אחר, ואינדקס ייחודי על (city, canonical_name) בטבלת השכונות הוליד שורות מקבילות. פלורנטין מתפצלת ל-271 / 7 / 1 דירות בשלושה IDs נפרדים. בשביל גרפי מגמת מחירים שתכננתי לדפי SEO — קטסטרופה.

הפתרון המתבקש זה מילון דטרמיניסטי. מיפוי מפורש: מקף-לרווח, קריית ל-קרית, Tel Aviv-Yafo ל-תל אביב יפו. ~30 זוגות. סגור, ניתן לבדיקה, אפס latency.

אבל ישבתי עם זה רגע. כבר יש לי embeddings על השכונות. מה אם פשוט אטיל אותם גם על העיר? כל איות חדש שייכנס ייצמד לאשכול הקרוב לפי cosine distance. שום מילון לתחזק. אלגנטי.

לפני שכתבתי שורת קוד, הרצתי probe: 14 זוגות “אותה עיר, איותים שונים” מול 10 זוגות “ערים שונות שנשמעות דומה”. זה מה שחזר:

SAME CITY (אותה עיר):
  קרית/קריית × 9             0.013–0.028
  טירת (ה)כרמל              0.013
  תל אביב יפו / -יפו         0.041
  תל אביב יפו / Tel Aviv     0.127  ⚠
  תל אביב יפו / תל אביב      0.147  ⚠

DIFFERENT CITIES (ערים שונות):
  מודיעין / מודיעין עילית     0.158  ⚠
  מודיעין / גני מודיעין       0.194
  ביתר עילית / מודיעין עילית  0.226
  תל אביב / בת ים            0.257
  טירת כרמל / כרמיאל         0.258

המרחק בין “אותה עיר במרווח הגרוע ביותר” ל”ערים שונות במרווח הקרוב ביותר” הוא 0.011. אחת-עשרה אלפיות. סף יחיד שיתפוס את תל אביב ו-תל אביב יפו כאותה עיר (0.147) יתפוס גם את מודיעין ו-מודיעין עילית כאותה עיר (0.158). שתי ערים שונות לחלוטין, עם עיריות נפרדות וקודי מיקוד נפרדים, נמרחות לאחת.

וזה לא תקלה שמתגלה. זה מסוג הבאגים שמתיישבים בשקט בדאטה, הופכים ל”ככה תמיד היה”, וחודש אחר כך מישהו שואל למה גרף המחיר במודיעין נראה הזוי.

המילון הדטרמיניסטי, לעומת זאת, משעמם בדיוק במידה הנכונה. אני מסתכל על 30 זוגות ואומר עליהם כן או לא. אם סקרייפר חדש יכניס איות שלא ראיתי — Sentry יזעק, אוסיף שורה למפה, נמשיך הלאה. הקבוצה סגורה ואין לי תיאבון להמציא לה פתיחה.

מה שלמדתי, או מה שניסחתי לעצמי בקול: embeddings טובים כשהמרחב פתוח ולא ניתן למניין. הם הפתרון הלא נכון כשיש לך 30 פריטים, רובם המכריע פתורים על ידי שני regexes, והכישלונות חיים בתוך אותו אזור צר שגם המודל מתקשה איתו. במקרה הזה הם לא מוסיפים יכולת — הם מוסיפים סיכון.

כמעט בניתי את זה. שמחתי שעצרתי בשביל לבדוק את המספרים לפני הקוד. רשמתי את ה-probe בתיקיית /tmp כדי שכשהשאלה תחזור (והיא תחזור), יהיה לי את הטבלה בלי להריץ שוב.