הוספת חיפוש וקטורים של 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. בוחרים בכרטיסייה Sign-in method (או לוחצים כאן כדי לעבור ישירות לכרטיסייה).
  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. לוחצים על התחלה במצב בדיקה. קוראים את כתב הוויתור לגבי כללי האבטחה.
    בהמשך הסדנה תוסיפו כללי אבטחה כדי לאבטח את הנתונים. אין להפיץ או לחשוף אפליקציה באופן ציבורי בלי להוסיף כללי אבטחה לקטגוריית האחסון.
  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. בוחרים באפשרות Copy items if needed (העתקת פריטים לפי הצורך), מוודאים שהיעד Notes (הערות) מסומן בקטע Add to targets (הוספה ליעדים) ולוחצים על Finish (סיום).בחירה באפשרות 'העתקה אם יש צורך' בתיבת הדו-שיח לבחירת אפשרויות להוספת קבצים
  9. במסוף Firebase, אפשר עכשיו ללחוץ על שאר שלבי תהליך ההגדרה: בקוד לדוגמה שהורדתם בתחילת הקטע הזה כבר מותקן Firebase Apple SDK וההפעלה הראשונית מוגדרת. כדי לסיים את התהליך, לוחצים על Continue to console.

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

עכשיו הגיע הזמן לבדוק את האפליקציה!

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

4. התקנת התוסף Vector Search with Firestore

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

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

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

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

איך פועל חיפוש וקטורים

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

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

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

לפני שמשתמשים בתוסף Vector Search with Firestore באפליקציית iOS שהורדתם מוקדם יותר בקודלאב הזה, אפשר לנסות את התוסף במסוף 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 (או לוחצים על הלחצן Run) כדי להפעיל את האפליקציה בסימולטור iOS.
  2. אמורים להופיע אותן הערות שהוספתם לאפליקציה מוקדם יותר בקודלאב הזה, וגם הערות שהוספתם דרך מסוף Firebase.
  3. שדה חיפוש אמור להופיע בחלק העליון של הרשימה הערות.
  4. מקלידים מונח שמופיע באחד מהמסמכים שהוספתם. שוב, האפשרות הזו מתאימה במיוחד לשאילתות סמנטיות, כמו "איך אפשר לקרוא ל-Firebase APIs אסינכרוני מ-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 פשוטה כדי ליצור אינטראקציה עם מסד הנתונים.
  • הטמעת סרגל חיפוש באמצעות המאפיין search-able view modifier של SwiftUI והמאפיין task modifier.
  • קריאה ל-Cloud Function כדי לבצע חיפוש סמנטי במסד הנתונים, באמצעות ממשק הקריאה של Firestore SDK.

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

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