הוספת חיפוש וקטורים של Firestore לאפליקציות לנייד באמצעות תוספי Firebase

1. סקירה כללית

בסדנת הקוד הזו תלמדו איך להוסיף לאפליקציה תכונות חיפוש מתקדמות באמצעות חיפוש דמיון וקטורים ב-Firestore. תכינו תכונה של חיפוש סמנטי לאפליקציית ניהול הערות שנכתבה ב-Swift וב-SwiftUI.

מסוף Cloud Firestore שבו מוצגים כמה מסמכים, שגם מוצגים באפליקציה ל-iOS בצד שמאל.

מה תלמדו

  • איך להתקין את התוסף Vector Search with Firestore כדי לחשב הטמעות של וקטורים.
  • איך קוראים ל-Firebase Cloud Functions מאפליקציית Swift.
  • איך לסנן מראש את הנתונים לפי המשתמש שמחובר לחשבון.

מה נדרש

  • Xcode 15.3
  • הקוד לדוגמה ב-Codelab. תורידו אותו בשלב מאוחר יותר בקודלאב.

2. יצירה והגדרה של פרויקט Firebase

כדי להשתמש בתוסף Firebase Vector Search, צריך להיות לכם פרויקט Firebase. בקטע הזה של הקודלה, תיצורו פרויקט חדש ב-Firebase ותפעילו את השירותים הנדרשים, כמו Cloud Firestore ואימות Firebase.

יוצרים פרויקט Firebase

  1. נכנסים ל-Firebase.
  2. במסוף Firebase, לוחצים על Add project (הוספת פרויקט) ומזינים את שם הפרויקט Firestore Vector Search Labיצירת פרויקט, שלב 1 מתוך 3: בחירת שם הפרויקט
  3. לוחצים על האפשרויות ליצירת פרויקט. מאשרים את התנאים של Firebase אם מופיעה בקשה לעשות זאת.
  4. במסך של Google Analytics, מבטלים את הסימון בתיבה Enable Google Analytics for this project (הפעלת Google Analytics לפרויקט הזה), כי לא תשתמשו ב-Analytics לאפליקציה הזו.
  5. לסיום, לוחצים על Create project.

מידע נוסף על פרויקטים ב-Firebase זמין במאמר הסבר על פרויקטים ב-Firebase.

שדרוג של תוכנית התמחור ב-Firebase

כדי להשתמש בתוספים של Firebase ובשירותי הענן שעומדים בבסיסם, פרויקט Firebase צריך להיות בתוכנית התמחור 'תשלום לפי שימוש' (Blaze), כלומר הוא צריך להיות מקושר לחשבון לחיוב ב-Cloud.

  • כדי להשתמש בחשבון לחיוב ב-Cloud, צריך להוסיף אמצעי תשלום, למשל כרטיס אשראי.
  • אם אתם משתמשים חדשים ב-Firebase וב-Google Cloud, כדאי לבדוק אם אתם זכאים לקרדיט בסך 300$ ולחשבון לחיוב ב-Cloud בתקופת ניסיון בחינם.
  • אם אתם מבצעים את הקודלאב הזה כחלק מאירוע, כדאי לשאול את המארגן אם יש זיכויים ב-Cloud שזמינים.

כדי לשדרג את הפרויקט לתוכנית Blaze:

  1. במסוף Firebase, בוחרים באפשרות שדרוג התוכנית.
  2. בוחרים את תוכנית Blaze. פועלים לפי ההוראות במסך כדי לקשר חשבון לחיוב ב-Cloud לפרויקט.
    אם נדרשת יצירת חשבון לחיוב ב-Cloud כחלק מהשדרוג, יכול להיות שתצטרכו לחזור לתהליך השדרוג במסוף Firebase כדי להשלים את השדרוג.

הפעלה והגדרה של מוצרי Firebase במסוף

האפליקציה שאתם מפתחים משתמשת בכמה מוצרים של Firebase שזמינים לאפליקציות ל-Apple:

  • אימות ב-Firebase כדי לאפשר למשתמשים להיכנס בקלות לאפליקציה שלכם.
  • Cloud Firestore כדי לשמור נתונים מובְנים בענן ולקבל התראות מיידיות כשהנתונים משתנים.
  • כללי אבטחה של Firebase לאבטחת מסד הנתונים שלכם.

חלק מהמוצרים האלה דורשים הגדרה מיוחדת או צריך להפעיל אותם באמצעות מסוף Firebase.

הפעלת אימות אנונימי לאימות ב-Firebase

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

  1. בחלונית שמשמאל במסוף Firebase, לוחצים על Build > Authentication (אימות). לאחר מכן לוחצים על מתחילים.הפעלת הדפדפן ב-Firebase
  2. עכשיו אתם נמצאים במרכז הבקרה של אימות הזהות, שבו אפשר לראות משתמשים שנרשמו, להגדיר ספקי כניסה ולנהל את ההגדרות.
  3. בוחרים בכרטיסייה שיטת כניסה (אפשר גם ללחוץ כאן כדי לעבור ישירות לכרטיסייה).
  4. לוחצים על אנונימי באפשרויות הספק, מעבירים את המתג למצב הפעלה ולוחצים על שמירה.

הגדרת Cloud Firestore

באפליקציית Swift הזו נעשה שימוש ב-Cloud Firestore כדי לשמור הערות.

כך מגדירים את Cloud Firestore בפרויקט Firebase:

  1. בחלונית הימנית של מסוף Firebase, מרחיבים את Build ובוחרים באפשרות Firestore database.
  2. לוחצים על Create database.
  3. משאירים את הערך (default) בשדה Database ID.
  4. בוחרים מיקום למסד הנתונים ולוחצים על הבא.
    אם מדובר באפליקציה אמיתית, כדאי לבחור מיקום שקרוב למשתמשים שלך.
  5. לוחצים על התחלה במצב בדיקה. קוראים את כתב הוויתור לגבי כללי האבטחה.
    בהמשך הסדנה תוסיפו כללי אבטחה כדי לאבטח את הנתונים. אין להפיץ או לחשוף אפליקציה באופן ציבורי בלי להוסיף כללי אבטחה למסד הנתונים.
  6. לוחצים על יצירה.

הגדרה של Cloud Storage for Firebase

באפליקציית האינטרנט נעשה שימוש ב-Cloud Storage for Firebase כדי לאחסן, להעלות ולשתף תמונות.

כך מגדירים את Cloud Storage for Firebase בפרויקט Firebase:

  1. בחלונית השמאלית של מסוף Firebase, מרחיבים את Build ובוחרים באפשרות Storage (אחסון).
  2. לוחצים על תחילת העבודה.
  3. יש לבחור מיקום לקטגוריית האחסון המוגדרת כברירת מחדל.
    קטגוריות ב-US-WEST1, ב-US-CENTRAL1 וב-US-EAST1 יכולות לנצל את המסלול 'חינם תמיד' ל-Google Cloud Storage. קטגוריות בכל המיקומים האחרים כפופות לתמחור ולשימוש ב-Google Cloud Storage.
  4. לוחצים על התחלה במצב בדיקה. צריך לקרוא את כתב הוויתור לגבי כללי האבטחה.
    בהמשך ב-Codelab הזה יתווסף כללי אבטחה לאבטחת הנתונים שלך. אין להפיץ או לחשוף אפליקציה באופן ציבורי בלי להוסיף כללי אבטחה לקטגוריית האחסון.
  5. לוחצים על יצירה.

3. חיבור האפליקציה לנייד

בקטע הזה של Codelab, תורידו את קוד המקור של אפליקציה פשוטה לניהול הערות ותקשרו אותה לפרויקט Firebase שיצרתם זה עתה.

הורדת האפליקציה לדוגמה

  1. עוברים אל https://github.com/FirebaseExtended/codelab-firestore-vectorsearch-ios, ומשכפלים את המאגר למכונה המקומית
  2. פותחים את הפרויקט Notes.xcodeproj ב-Xcode.

מחברים את האפליקציה לפרויקט Firebase

כדי שהאפליקציה תהיה מסוגלת לגשת לשירותי Firebase, תצטרכו להגדיר אותה במסוף Firebase. אפשר לקשר כמה אפליקציות לקוח לאותו פרויקט Firebase. לדוגמה, אם אתם יוצרים אפליקציה ל-Android או לאינטרנט, עליכם לקשר אותן לאותו פרויקט Firebase.

מידע נוסף על פרויקטים ב-Firebase זמין במאמר הסבר על פרויקטים ב-Firebase.

  1. במסוף Firebase, נכנסים לדף הסקירה הכללית של פרויקט Firebase.דף הסקירה הכללית של מסוף Firebase
  2. לוחצים על סמל הפלוס + ל-iOS כדי להוסיף את אפליקציית ה-iOS.
  3. במסך Add Firebase to your Apple app (הוספת Firebase לאפליקציה של Apple), מזינים את מזהה החבילה מהפרויקט ב-Xcode‏ (com.google.firebase.codelab.Notes).
  4. אם רוצים, אפשר להזין כינוי לאפליקציה (הערות לגבי iOS).
  5. לוחצים על 'רישום אפליקציה' כדי לעבור לשלב הבא.
  6. מורידים את הקובץ GoogleServices-Info.plist.
  7. גוררים את האפשרות GoogleServices-Info.plist אל התיקייה Notes (הערות) בפרויקט ה-Xcode. דרך טובה לעשות זאת ולשחרר אותו מתחת לקובץ Assets.xcassets.גרירה של קובץ ה-plist ל-Xcode
  8. בוחרים באפשרות העתקת פריטים לפי הצורך, מוודאים שהיעד Notes (הערות) מסומן בקטע Add to targets (הוספה ליעדים) ולוחצים על Finish (סיום).בחירה באפשרות 'העתקה אם יש צורך' בתיבת הדו-שיח לבחירת אפשרויות להוספת קבצים
  9. במסוף Firebase, עכשיו תוכלו ללחוץ על המשך תהליך ההגדרה: בדוגמה שהורדתם בתחילת הקטע הזה כבר מותקן Apple SDK של Firebase, וגם הגדרתם את האתחול. כדי לסיים את התהליך, לוחצים על Continue to console.

הפעלת האפליקציה

זה הזמן להתנסות באפליקציה!

  1. חוזרים ל-Xcode ומריצים את האפליקציה בסימולטור iOS. בתפריט הנפתח Run Destinations, בוחרים קודם את אחד מהסימולטורים של iOS.בחירת סימולטור של iOS בתפריט הנפתח 'הרצת יעדים'
  2. לאחר מכן, לוחצים על הלחצן Run או על ‎⌘ + R.
  3. אחרי שהאפליקציה מופעלת בהצלחה בסימולטור, מוסיפים כמה הערות.
  4. במסוף Firebase, עוברים לדפדפן הנתונים של Firestore כדי לראות מסמכים חדשים שנוצרים כשאתם מוסיפים הערות חדשות באפליקציה.מסוף Cloud Firestore שבו מוצגים מסמכים מסוימים, לצד סימולטור iOS שבו מוצגים אותם מסמכים

4. התקנת התוסף Vector Search באמצעות Firestore

בקטע הזה של סדנת הקוד, תתקינו את התוסף Vector Search with Firestore ותגדירו אותו בהתאם לדרישות של אפליקציית ניהול התעודות שאתם עובדים עליה.

התחלת ההתקנה של התוסף

  1. עדיין בקטע Firestore, לוחצים על הכרטיסייה תוספים.בחירת הכרטיסייה 'תוספים ל-Firebase' במסוף Firestore
  2. לוחצים על כניסה למרכז התוספים.הכרטיסייה 'תוספים ל-Firebase' במסוף Firestore
  3. מקלידים 'vector'.
  4. לוחצים על 'חיפוש וקטורים באמצעות תוסף Firestore'.דף הנחיתה של Firebase Extensios Hub הלחיצה תעביר אתכם לדף הפרטים של התוסף, שבו אפשר לקרוא מידע נוסף על התוסף, איך הוא פועל, אילו שירותי Firebase הם נדרשים ואיך להגדיר אותו.
  5. לוחצים על התקנה במסוף Firebase.לחצן ההתקנה של התוסף Vector Search with Firestore
  6. תוצג רשימה של כל הפרויקטים שלכם.
  7. בוחרים את הפרויקט שיצרתם בשלב הראשון ב-Codelab הזה.המסך לבחירת פרויקט ב-Firebase

הגדרת התוסף

  1. כדאי לבדוק את ממשקי ה-API שהופעלו ואת המשאבים שנוצרו.בדיקת ממשקי ה-API המופעלים
  2. צריך להפעיל את השירותים הנדרשים.הפעלת השירותים הנדרשים
  3. אחרי שמפעילים את כל השירותים, לוחצים על הבא.לוחצים על 'הבא' אחרי הפעלת כל השירותים
  4. גישת ביקורת הוענקה לתוסף הזה.
  5. מגדירים את התוסף:
    • בוחרים ב-Vertex AI בתור LLM.
    • נתיב האוסף: notes
    • מגבלת השאילתות שמוגדרת כברירת מחדל: 3
    • שם השדה להזנת קלט: text
    • שם שדה הפלט: embedding
    • שם שדה הסטטוס:* *status*
    • הטמעה של מסמכים קיימים: כן
    • עדכון מסמכים קיימים: כן
    • מיקום הפונקציה ב-Cloud Functions: us-central1
  6. לוחצים על Install extension (התקנת התוסף) כדי לסיים את ההתקנה.

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

5. רקע

בזמן ההמתנה לסיום ההתקנה, ריכזנו כאן מידע רקע על אופן הפעולה של התוסף Vector Search with Firestore.

מהם וקטורים, הטמעות (embeddings) ומסדי נתונים וקטוריים?

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

כיצד פועל חיפוש וקטורי?

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

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

6. ניסיון עם התוסף Vector Search עם Firestore

לפני השימוש בתוסף Vector Search with Firestore באפליקציה ל-iOS שהורדתם קודם ב-Codelab הזה, אפשר לנסות את התוסף במסוף Firebase.

קוראים את התיעוד

התוספים של Firebase כוללים מסמכי עזרה שמסבירים איך הם פועלים.

  1. בסיום ההתקנה של התוסף, לוחצים על הלחצן תחילת העבודה. דף הסקירה הכללית של התוספים ב-Firebase במסוף Firebase
  2. מעיינים בכרטיסייה 'איך התוסף הזה עובד' – המדריך כולל:
    • איך מחשבים הטמעות (embeddings) של מסמכים על ידי הוספת המסמכים לאוסף notes,
    • איך שולחים שאילתה לאינדקס באמצעות קריאה לפונקציה הניתנת לקריאה ext-firestore-vector-search-queryCallable,
    • או איך להוסיף שאילתה לאינדקס על ידי הוספת מסמך שאילתה לאוסף _firestore-vector-search/index/queries.
    • נסביר גם איך להגדיר פונקציית הטמעה בהתאמה אישית. האפשרות הזו מועילה אם אף אחד מה-LLM שנתמך על ידי התוסף לא עומד בדרישות שלכם, ואתם רוצים להשתמש ב-LLM אחר כדי לחשב הטמעות. המסמכים של התוסף Vector Search with Firestore
  3. לוחצים על הקישור לוח הבקרה של Cloud Firestore כדי לעבור למכונה של Firestore.
  4. עוברים למסמך _firestore-vector-search/index. אמור להופיע דיווח על כך שהתוסף סיים לחשב את הטמעות הנתונים (embeddings) לכל מסמכי ההערות שיצרתם בשלב מוקדם יותר בקודלאב הזה.הגדרת האינדקס במסוף Firestore
  5. כדי לוודא זאת, פותחים אחד ממסמכי ההערות, ואמור להופיע שדה נוסף בשם embedding מסוג vector<768>, וגם שדה status.שדה של הטמעת וקטורים במסוף Firestore

יצירת מסמך לדוגמה

כדי לראות את התוסף בפעולה, אפשר ליצור מסמך חדש במסוף Firebase.

  1. עדיין בדפדפן הנתונים של Firestore, עוברים לאוסף notes ולוחצים על + הוספת מסמך בעמודה האמצעית.הוספת מסמך חדש
  2. לוחצים על Auto-ID (מזהה אוטומטי) כדי ליצור מזהה מסמך ייחודי חדש.
  3. מוסיפים שדה בשם text מסוג מחרוזת ומדביקים טקסט כלשהו בשדה value. חשוב שהטקסט לא יהיה lorem ipsum או טקסט אקראי אחר. לדוגמה, בוחרים כתבה חדשותית.הוספת שדה טקסט
  4. לוחצים על שמירה.
    • שימו לב שהתוסף מוסיף שדה סטטוס כדי לציין שהוא מעבד נתונים.
    • אחרי זמן קצר, אמור להופיע שדה חדש embedding עם הערך vector<768>.
    עדכון סטטוס של הטמעות וקטוריות במסמך החדש

ביצוע שאילתה

לתוסף Vector Search with Firestore יש תכונה קטנה ומגניבה שמאפשרת להריץ שאילתות על אינדקס המסמכים בלי לחבר אפליקציה.

  1. בקטע Firestore במסוף Firebase, עוברים למסמך _firestore-vector-search/index.
  2. לוחצים על + יצירת אוסףהוספת אוסף משנה חדש
  3. יוצרים אוסף משנה חדש בשם queries
  4. יוצרים מסמך חדש ומגדירים את השדה query לטקסט שמופיע באחד מהמסמכים. האפשרות הזו עובדת הכי טוב בשאילתות סמנטיות, כמו "איך אפשר למפות מסמכי Firestore באמצעות Swift" (בתנאי שלפחות אחת מההערות שהוספתם מכילה טקסט שמתייחס לנושא הזה).הוספת שדה שאילתה
  5. ייתכן שתופיע שגיאה בסטטוסהייתה שגיאה
  6. הסיבה לכך היא שחסרה אינדקס. כדי להגדיר את ההגדרות של האינדקס החסר, עוברים למסוף Google Cloud של הפרויקט באמצעות הקישור הזה ובוחרים את הפרויקט מהרשימהבחירת הפרויקט הנכון
  7. ב-Cloud Log Explorer אמורה להופיע עכשיו הודעת השגיאה "FAILED_PRECONDITION: Missing vector index configuration. צריך ליצור את האינדקס הנדרש באמצעות הפקודה הבאה של gcloud: ..."הודעת שגיאה בסייר היומנים
  8. הודעת השגיאה מכילה גם פקודת gcloud שצריך להריץ כדי להגדיר את האינדקס החסר.
  9. מריצים את הפקודה הבאה משורת הפקודה. אם ה-CLI של gcloud לא מותקן במחשב שלכם, צריך לפעול לפי ההוראות האלה כדי להתקין אותו.
    gcloud alpha firestore indexes composite create --project=INSERT-YOUR=PROJECT-ID-HERE --collection-group=notes --query-scope=COLLECTION --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding
    
    יצירת האינדקס נמשכת כמה דקות. אפשר לבדוק את ההתקדמות בכרטיסייה Indexes (אינדקסים) בקטע Firestore במסוף Firebase.הסטטוס של האינדקס החדש
  10. אחרי שמגדירים את האינדקס, אפשר ליצור מסמך שאילתות חדש.
  11. עכשיו אמורה להופיע רשימה של מזהי מסמכים תואמים בשדה התוצאותהתוצאה של ביצוע שאילתה סמנטית
  12. מעתיקים אחד מהמזהים האלה וחוזרים לאוסף notes.
  13. מקישים על ‎⌘+F כדי לחפש את מזהה המסמך שהעתקתם – המסמך הזה הוא זה שתואמת בצורה הטובה ביותר לשאילתה.איתור מזהה המסמך ברשימת המסמכים

7. הטמעת חיפוש סמנטי

הגיע הזמן לחבר את האפליקציה לנייד לתוסף Vector Search with Firestore ולהטמיע תכונת חיפוש סמנטי שתאפשר למשתמשים לחפש את ההערות שלהם באמצעות שאילתות בשפה טבעית.

חיבור הפונקציה שניתן להפעיל כדי לבצע שאילתות

התוסף Vector Search with Firestore כולל Cloud Function שאפשר להפעיל מהאפליקציה לנייד כדי לשלוח שאילתה לאינדקס שיצרתם מוקדם יותר בסדנת הקוד הזו. בשלב הזה תיצרו חיבור בין האפליקציה לנייד לבין הפונקציה הניתנת לקריאה. ה-SDK של Firebase ל-Swift כולל ממשקי API שמאפשרים להפעיל פונקציות מרחוק בצורה חלקה.

  1. חוזרים ל-Xcode ומוודאים שנמצאים בפרויקט שהעתקתם בשלב קודם בקודלאב הזה.
  2. פותחים את הקובץ NotesRepository.swift.
  3. מוצאים את השורה שמכילה את private lazy var vectorSearchQueryCallable: Callable = functions.httpsCallable("")

כדי להפעיל פונקציה של Cloud Functions שאפשר לקרוא לה, צריך לציין את שם הפונקציה שרוצים להפעיל.

  1. נכנסים למסוף Firebase של הפרויקט ופותחים את פריט התפריט Functions בקטע Build.
  2. תוצג רשימה של הפונקציות שהותקנו על ידי התוסף.
  3. מחפשים את ה-VPC שנקרא ext-firestore-vector-search-queryCallable ומעתיקים את השם שלו.
  4. מדביקים את השם בקוד. הטקסט אמור להיראות כך:
    private lazy var vectorSearchQueryCallable: Callable<String, String> = functions.httpsCallable("ext-firestore-vector-search-queryCallable")
    

קריאה לפונקציית השאילתה

  1. מאתרים את השיטה performQuery
  2. קוראים לפונקציה הניתנת לקריאה באמצעות
    let result = try await vectorSearchQueryCallable(searchTerm)
    

זו שיחה מרחוק, ולכן יכול להיות שהיא תיכשל.

  1. אפשר להוסיף טיפול בסיסי בשגיאות כדי לזהות שגיאות ולרשום אותן במסוף של Xcode.
    private func performQuery(searchTerm: String) async -> [String] {
      do {
        let result = try await vectorSearchQueryCallable(searchTerm)
        return [result]
      }
      catch {
        print(error.localizedDescription)
        return []
      }
    }
    

חיבור ממשק המשתמש

כדי לאפשר למשתמשים לחפש בפתקים שלהם, צריך להטמיע סרגל חיפוש במסך של רשימת ההערות. כשהמשתמש מקלידים מונח חיפוש, צריך להפעיל את השיטה performQuery שהטמעתם בשלב הקודם. תודות למשתני התצוגה searchable ו-task ש-SwiftUI מספקת, אפשר לעשות זאת רק באמצעות כמה שורות קוד.

  1. קודם כול, פותחים את NotesListScreen.swift
  2. כדי להוסיף תיבת חיפוש לתצוגת הרשימה, צריך להוסיף את מקש הצירוף .searchable(text: $searchTerm, prompt: "Search") של התצוגה מעל השורה .navigationTitle("Notes")
  3. לאחר מכן, כדי להפעיל את פונקציית החיפוש, מוסיפים את הקוד הבא מתחת לקוד הקודם:
.task(id: searchTerm, debounce: .milliseconds(800)) {
  await notesRepository.semanticSearch(searchTerm: searchTerm)
}

קטע הקוד הזה קורא לשיטה semanticSearch באופן אסינכרוני. אם מגדירים זמן קצוב לתפוגה של 800 אלפיות השנייה, מנחים את מגביל המשימה לבטל את החזרת הקלט של המשתמש ב-0.8 שניות. כלומר, הפונקציה semanticSearch תופעל רק אחרי שהמשתמש יפסיק להקליד למשך יותר מ-0.8 שניות.

הקוד אמור להיראות כך:

...
List(repository.notes) { note in
  NavigationLink(value: note) {
    NoteRowView(note: note)
  }
  .swipeActions {
    Button(role: .destructive, action: { deleteNote(note: note) }) {
      Label("Delete", systemImage: "trash")
    }
  }
}
.searchable(text: $searchTerm, prompt: "Search")
.task(id: searchTerm, debounce: .milliseconds(800)) {
  await notesRepository.semanticSearch(searchTerm: searchTerm)
}
.navigationTitle("Notes")
...

הפעלת האפליקציה

  1. מקישים על ⌘ + R (או לוחצים על לחצן ההפעלה) כדי להפעיל את האפליקציה בסימולטור של iOS.
  2. אמורים להופיע אותן הערות שהוספתם לאפליקציה מוקדם יותר בקודלאב הזה, וגם הערות שהוספתם דרך מסוף Firebase.
  3. שדה חיפוש אמור להופיע בחלק העליון של הרשימה הערות.
  4. מקלידים מונח שמופיע באחד מהמסמכים שהוספתם. שוב, האפשרות הזו מתאימה במיוחד לשאילתות סמנטיות, כמו "איך אפשר לקרוא ל-APIs אסינכררוניים של Firebase מ-Swift" (בתנאי שלפחות אחת מההערות שהוספתם מכילה טקסט שמתייחס לנושא הזה).
  5. סביר להניח שציפיתם לראות את תוצאת החיפוש, אבל במקום זאת תצוגת הרשימה ריקה ובמסוף Xcode מוצגת הודעת השגיאה: "The function was called with an invalid argument"

אפליקציית Notes עם רשימת תוצאות ריקה

המשמעות היא ששלחת את הנתונים בפורמט שגוי.

ניתוח הודעת השגיאה

  1. כדי לבדוק מה הבעיה, עוברים למסוף Firebase
  2. עוברים לקטע פונקציות.
  3. מאתרים את הפונקציה ext-firestore-vector-search-queryCallable, פותחים את תפריט ההוספה הנוספת בלחיצה על שלוש הנקודות האנכיות
  4. בוחרים באפשרות הצגת יומנים כדי לעבור לכלי לניהול יומנים.
  5. אמורה להופיע שגיאה
Unhandled error ZodError: [
  {
    "code": "invalid_type",
    "expected": "object",
    "received": "string",
    "path": [],
    "message": "Expected object, received string"
  }
]

המשמעות היא ששלחתם את הנתונים בפורמט שגוי.

שימוש בסוגי הנתונים הנכונים

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

  1. עוברים לקטע תוספים במסוף Firebase.
  2. לוחצים על ניהול ->ניהול התוסף Vector Search with Firestore
  3. בקטע איך התוסף הזה פועל מופיע מפרט של פרמטרים של קלט ופלט.תיעוד של פרמטר הקלט וערך התוצאה
  4. חוזרים ל-Xcode ועוברים אל NotesRepository.swift.
  5. מוסיפים את הקוד הבא בתחילת הקובץ:
    private struct QueryRequest: Codable {
      var query: String
      var limit: Int?
      var prefilters: [QueryFilter]?
    }
    
    private struct QueryFilter: Codable {
      var field: String
      var `operator`: String
      var value: String
    
    }
    
    private struct QueryResponse: Codable {
      var ids: [String]
    }
    
    QueryRequest תואם למבנה של פרמטר הקלט שהתוסף מצפה לו, בהתאם למסמכי התיעוד של התוסף. הוא מכיל גם מאפיין prefilter בתצוגת עץ שתצטרכו בהמשך.QueryResponse תואם למבנה התשובה של התוסף.
  6. איך למצוא את מפרט הפונקציה שניתן לקריאה ולעדכן את סוגי הקלט והפלט
    private lazy var vectorSearchQueryCallable: Callable<QueryRequest, QueryResponse> = functions.httpsCallable("ext-firestore-vector-search-queryCallable")
    
  7. מעדכנים את ההפעלה של הפונקציה הניתנת לקריאה ב-performQuery
    private func performQuery(searchTerm: String) async -> [String] {
      do {
        let queryRequest = QueryRequest(query: searchTerm,
                                        limit: 2)
        let result = try await vectorSearchQueryCallable(queryRequest)
        print(result.ids)
        return result.ids
      }
      catch {
        print(error.localizedDescription)
        return []
      }
    }
    

מפעילים את האפליקציה שוב.

  1. מפעילים את האפליקציה שוב.
  2. יש להקליד שאילתת חיפוש שמכילה מונחים שמופיעים באחת מההערות שלך
  3. עכשיו אמורה להופיע רשימת הערות מסוננת.

צילום מסך של האפליקציה עם התוצאה הצפויה

סינון מראש של נתוני משתמשים

לפני שתתחילו לרקוד בחגיגה – יש בעיה בגרסה הנוכחית של האפליקציה: קבוצת התוצאות מכילה נתונים מכל המשתמשים.

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

כשמבצעים חיפוש, רואים שהקריאה ל-vectorSearchQueryCallable מחזירה מזהי מסמכים שאולי שייכים למשתמש השני. כדי למנוע זאת, אנחנו צריכים להשתמש במסנן מקדים.

ב-performQuery, מעדכנים את הקוד באופן הבא:

  let prefilters: [QueryFilter] = if let uid = user?.uid {
    [QueryFilter(field: "userId", operator: "==", value: uid)]
  }
  else {
    []
  }

  let queryRequest = QueryRequest(query: searchTerm,
                                  limit: 2,
                                  prefilters: prefilters)

כך יתבצע סינון מראש של הנתונים על סמך המזהה של המשתמש המקושר. כצפוי, כדי לעשות זאת צריך לעדכן את האינדקס של Firestore.

מריצים את הפקודה הבאה משורת הפקודה כדי להגדיר אינדקס חדש ב-Firestore שכולל גם את הטמעות ה-userId וגם את הטמעות הווקטור בשדה embedding.

gcloud alpha firestore indexes composite create --project=INSERT-YOUR-PROJECT-ID-HERE --collection-group=notes --query-scope=COLLECTION --field-config=order=ASCENDING,field-path=userId --field-config=vector-config='{"dimension":"768","flat": "{}"}',field-path=embedding

אחרי שהאינדקס יושלם, מריצים שוב את האפליקציה כדי לוודא שהיא פועלת כצפוי.

קבוצת תוצאות מסוננת מראש

8. מזל טוב

מזל טוב על השלמת ה-codelab הזה!

בשיעור ה-Codelab הזה למדתם:

  • הגדרת מסד נתונים ב-Cloud Firestore כשהחיפוש הסמנטי מופעל.
  • יוצרים אפליקציית SwiftUI פשוטה ליצירת אינטראקציה עם מסד הנתונים.
  • הטמעת סרגל חיפוש באמצעות המשתנה של תצוגה לחיפוש ומשתנה המשימה של SwiftUI.
  • קריאה ל-Cloud Function כדי לבצע חיפוש סמנטי במסד הנתונים, באמצעות ממשק ה-Callable של Firestore SDK.

בעזרת הידע שצברתם ב-codelab הזה, עכשיו תוכלו ליצור אפליקציות חזקות שמנצלות את יכולות החיפוש הסמנטי של Cloud Firestore כדי לספק למשתמשים חוויית חיפוש אינטואיטיבית ויעילה יותר.

מידע נוסף על שדה הוקטורים החדש של Firestore ועל חישוב הטמעות של וקטורים זמין במסמכי העזרה.