1. מבוא
התפתחויות האחרונות בלמידה עמוקה מאפשרות לייצג טקסט ונתונים אחרים באופן שמשקף את המשמעות הסמנטית שלהם. הגישה הזו הובילה לגישה חדשה לחיפוש, שנקראת חיפוש וקטורי. הגישה הזו משתמשת בייצוגים וקטוריים של טקסט (שנקראים הטמעות) כדי למצוא מסמכים שהכי רלוונטיים לשאילתה של המשתמש. חיפוש וקטורי עדיף על חיפוש מסורתי באפליקציות כמו חיפוש בגדים, שבהן המשתמשים מחפשים פריטים לפי התיאור, הסגנון או ההקשר שלהם ולא לפי שמות מוצרים או מותגים מדויקים. אפשר לשלב את מסד הנתונים של Cloud Spanner עם Vector Search כדי לבצע התאמה של דמיון וקטורי. הלקוחות יכולים להשתמש ב-Spanner וב-Vector Search יחד כדי ליצור שילוב עוצמתי שממזג בין הזמינות, המהימנות וההתאמה של Spanner לבין יכולות החיפוש המתקדמות של Vertex AI Vector Search. החיפוש הזה מתבצע על ידי השוואה של הטמעות של פריטים באינדקס של Vector Search, והחזרת ההתאמות הכי דומות.
תרחיש לדוגמה
נניח שאתם מדעני נתונים בחברה קמעונאית בתחום האופנה, ואתם מנסים להתעדכן במגמות שמשתנות במהירות, בחיפושי מוצרים ובהמלצות. הבעיה היא שיש לכם משאבים מוגבלים וסילו נתונים. בפוסט הזה בבלוג אנחנו מדגימים איך להטמיע תרחיש לדוגמה של המלצות לפריטי לבוש באמצעות גישה של חיפוש דמיון בנתונים של פריטי לבוש.אנחנו מסבירים את השלבים הבאים:
- נתונים שמקורם ב-Spanner
- וקטורים שנוצרו עבור נתוני הביגוד באמצעות ML.PREDICT ואוחסנו ב-Spanner
- נתוני וקטורים של Spanner משולבים עם Vector Search באמצעות משימות של Dataflow ושל תהליכי עבודה
- חיפוש וקטורי שבוצע כדי למצוא התאמה של דמיון לקלט שהמשתמש הזין
ניצור אפליקציית אינטרנט להדגמה כדי לבצע חיפוש של פריטי לבוש על סמך קלט של משתמשים. האפליקציה מאפשרת למשתמשים לחפש פריטי לבוש על ידי הזנת תיאור טקסטואלי.
Spanner לאינדקס Vector Search:
הנתונים של חיפוש ביגוד מאוחסנים ב-Spanner. אנחנו נפעיל את ה-API של Embeddings ב-Vertex AI במבנה ML.PREDICT ישירות מנתוני Spanner. לאחר מכן נשתמש במשימות Dataflow ובתהליכי עבודה כדי להעלות את הנתונים האלה (מלאי והטמעות) בכמות גדולה ל-Vector Search ב-Vertex AI ולרענן את האינדקס.
הפעלת שאילתות משתמש באינדקס:
כשמשתמש מזין תיאור של פריט לבוש, האפליקציה יוצרת את ההטמעות בזמן אמת באמצעות Text Embeddings API. התיאור הזה נשלח כקלט ל-Vector Search API כדי למצוא באינדקס 10 תיאורי מוצרים רלוונטיים ולהציג את התמונה המתאימה.
סקירה כללית של הארכיטקטורה
הארכיטקטורה של אפליקציית Spanner- Vector Search מוצגת בתרשים הבא שמחולק לשני חלקים:
Spanner to Vector Search Index: 
אפליקציית לקוח להרצת שאילתות משתמשים באינדקס:
מה תפַתחו
Spanner לאינדקס וקטורי:
- מסד נתונים ב-Spanner לאחסון וניהול של נתוני המקור וההטבעות התואמות
- משימת Workflow שמעלה נתונים (מזהה והטבעות) בכמות גדולה למסד הנתונים של חיפוש וקטורים ב-Vertex AI.
- ממשק Vector Search API שמשמש למציאת תיאורי מוצרים רלוונטיים מהאינדקס.
הפעלת שאילתות משתמש באינדקס:
- אפליקציית אינטרנט שמאפשרת למשתמשים להזין תיאורי טקסט של פריטי לבוש, מבצעת חיפוש דמיון באמצעות נקודת הקצה של האינדקס שנפרס ומחזירה את פריטי הלבוש הכי דומים לקלט.
איך זה עובד
כשמשתמש מזין תיאור טקסט של פריט לבוש, אפליקציית האינטרנט שולחת את התיאור ל-Vector Search API. לאחר מכן, ה-API של חיפוש וקטורים משתמש בהטמעות של תיאורי הבגדים כדי למצוא את תיאורי המוצרים הרלוונטיים ביותר מהאינדקס. לאחר מכן מוצגים למשתמש תיאורי המוצרים והתמונות התואמות. תהליך העבודה הכללי הוא כזה:
- יצירת הטמעות לנתונים שמאוחסנים ב-Spanner.
- ייצוא והעלאה של הטמעות לאינדקס Vector Search.
- שליחת שאילתה לאינדקס ב-Vector Search כדי לחפש פריטים דומים באמצעות חיפוש השכן הקרוב ביותר.
2. דרישות
לפני שמתחילים
- ב-מסוף Google Cloud, בדף לבחירת הפרויקט, בוחרים או יוצרים פרויקט ב-Google Cloud.
- הקפידו לוודא שהחיוב מופעל בפרויקט שלכם ב-Cloud. כך בודקים אם החיוב מופעל בפרויקט
- מוודאים שכל ממשקי ה-API הנדרשים (Cloud Spanner, Vertex AI, Google Cloud Storage) מופעלים.
- תשתמשו ב-Cloud Shell, סביבת שורת פקודה שפועלת ב-Google Cloud ומגיעה עם gcloud שנטען מראש. אפשר לעיין במאמרי העזרה בנושא פקודות gcloud ושימוש בהן. אם הפרויקט לא מוגדר, משתמשים בפקודה הבאה כדי להגדיר אותו:
gcloud config set project <YOUR_PROJECT_ID>
- כדי להתחיל, עוברים לדף Cloud Spanner עם פרויקט הענן הפעיל ב-Google Cloud.
3. בקצה העורפי: יצירת מקור נתונים והטמעות ב-Spanner
בתרחיש לדוגמה הזה, מסד הנתונים של Spanner מכיל את מלאי הפריטים של בגדים עם התמונות והתיאורים המתאימים. חשוב לוודא שאתם יוצרים הטמעות לתיאור הטקסט ומאחסנים אותן במסד הנתונים של Spanner בתור ARRAY<float64>.
- יצירת נתונים ב-Spanner
יוצרים מופע בשם spanner-vertex ומסד נתונים בשם spanner-vertex-embeddings. יוצרים טבלה באמצעות DDL:
CREATE TABLE
apparels ( id NUMERIC,
category STRING(100),
sub_category STRING(50),
uri STRING(200),
content STRING(2000),
embedding ARRAY<FLOAT64>
)
PRIMARY KEY
(id);
- הוספת נתונים לטבלה באמצעות SQL של INSERT
סקריפטים להוספת נתונים לדוגמה זמינים כאן.
- יצירת מודל Text Embeddings
הדרישה הזו נחוצה כדי שנוכל ליצור הטמנות לתוכן בקלט. בהמשך מופיע ה-DDL לאותו הדבר:
CREATE MODEL text_embeddings INPUT(content STRING(MAX))
OUTPUT(
embeddings
STRUCT<
statistics STRUCT<truncated BOOL, token_count FLOAT64>,
values ARRAY<FLOAT64>>
)
REMOTE OPTIONS (
endpoint = '//aiplatform.googleapis.com/projects/abis-345004/locations/us-central1/publishers/google/models/textembedding-gecko');
- יצירת הטמעות טקסט לנתוני המקור
יוצרים טבלה לאחסון ההטמעות ומכניסים את ההטמעות שנוצרו. ביישום של מסד נתונים בעולם האמיתי, טעינת הנתונים ל-Spanner עד שלב 2 תהיה טרנזקציונלית. כדי לשמור על השיטות המומלצות לעיצוב, אני מעדיף להשאיר את הטבלאות של הנתונים העסקיים בצורה מנורמלת, ולכן אני יוצר טבלה נפרדת להטמעות.
CREATE TABLE apparels_embeddings (id string(100), embedding ARRAY<FLOAT64>)
PRIMARY KEY (id);
INSERT INTO apparels_embeddings(id, embeddings)
SELECT CAST(id as string), embeddings.values
FROM ML.PREDICT(
MODEL text_embeddings,
(SELECT id, content from apparels)
) ;
אחרי שהתוכן וההטבעות מוכנים, ניצור אינדקס ונקודת קצה של Vector Search כדי לאחסן את ההטבעות שיעזרו לבצע את החיפוש הווקטורי.
4. Workflow Job: Spanner data export to Vector Search
- יצירת קטגוריה של Cloud Storage
הפעולה הזו נדרשת כדי לאחסן הטמעות מ-Spanner בקטגוריה ב-GCS בפורמט JSON שחיפוש וקטורי מצפה לקבל כקלט. יוצרים קטגוריה באותו אזור שבו נמצאים הנתונים ב-Spanner. אם צריך, יוצרים תיקייה בתוך התיקייה הזו, אבל בעיקר יוצרים בתוכה קובץ ריק בשם empty.json.
- הגדרה של Cloud Workflow
כדי להגדיר ייצוא באצווה מ-Spanner לאינדקס של חיפוש וקטורי ב-Vertex AI:
יצירת אינדקס ריק:
מוודאים שאינדקס החיפוש הווקטורי נמצא באותו אזור כמו קטגוריה של Cloud Storage והנתונים. פועלים לפי 11 השלבים של ההוראות בקטע יצירת אינדקס לחבילת עדכונים בכרטיסייה 'מסוף' בדף 'ניהול אינדקסים'. בתיקייה שמועברת אל contentsDeltaUri, יוצרים קובץ ריק בשם empty.json כי אי אפשר ליצור אינדקס בלי הקובץ הזה. כך נוצר אינדקס ריק.
אם כבר יש לכם אינדקס, אתם יכולים לדלג על השלב הזה. תהליך העבודה יחליף את האינדקס.
הערה: אי אפשר לפרוס אינדקס ריק לנקודת קצה. לכן אנחנו דוחים את שלב הפריסה לנקודת קצה לשלב מאוחר יותר, אחרי ייצוא נתוני הווקטור ל-Cloud Storage.
משכפלים את מאגר ה-Git הזה: יש כמה דרכים לשכפל מאגר Git. אחת מהן היא להריץ את הפקודה הבאה באמצעות GitHub CLI. מריצים את 2 הפקודות הבאות בטרמינל של Cloud Shell:
gh repo clone cloudspannerecosystem/spanner-ai
cd spanner-ai/vertex-vector-search/workflows
התיקייה הזו מכילה שני קבצים
-
batch-export.yaml: הגדרת תהליך העבודה. -
sample-batch-input.json: דוגמה לפרמטרים של הקלט של תהליך העבודה.
הגדרת הקובץ input.json מקובץ לדוגמה: קודם מעתיקים את קובץ ה-JSON לדוגמה.
cp sample-batch-input.json input.json
אחר כך עורכים את input.json ומוסיפים את פרטי הפרויקט. במקרה הזה, קובץ ה-JSON צריך להיראות כך:
{
"project_id": "<<YOUR_PROJECT>>",
"location": "<<us-central1>>",
"dataflow": {
"temp_location": "gs://<<YOUR_BUCKET>>/<<FOLDER_IF_ANY>>/workflow_temp"
},
"gcs": {
"output_folder": "gs://<<YOUR_BUCKET>>/<<FOLDER_IF_ANY>>/workflow_output"
},
"spanner": {
"instance_id": "spanner-vertex",
"database_id": "spanner-vertex-embeddings",
"table_name": "apparels_embeddings",
"columns_to_export": "embedding,id"
},
"vertex": {
"vector_search_index_id": "<<YOUR_INDEX_ID>>"
}
}
הגדרת הרשאות
בסביבות ייצור, מומלץ מאוד ליצור חשבון שירות חדש ולהקצות לו תפקיד IAM אחד או יותר שמכילים את ההרשאות המינימליות שנדרשות לניהול השירות. כדי להגדיר את תהליך העבודה לייצוא נתונים מ-Spanner (הטמעות) לאינדקס החיפוש הווקטורי, צריך את התפקידים הבאים:
חשבון שירות של Cloud Workflow:
כברירת מחדל, הוא משתמש בחשבון השירות שמוגדר כברירת מחדל ב-Compute Engine.
אם אתם משתמשים בחשבון שירות שהוגדר ידנית, אתם צריכים לכלול את התפקידים הבאים:
כדי להפעיל משימה ב-Dataflow: Dataflow Admin, Dataflow Worker.
כדי להתחזות לחשבון שירות של עובד Dataflow: משתמש בחשבון שירות.
כדי לכתוב יומנים: Logs Writer.
כדי להפעיל בנייה מחדש של חיפוש וקטורי ב-Vertex AI: משתמש Vertex AI
חשבון שירות של Dataflow Worker:
אם אתם משתמשים בחשבון שירות שהוגדר ידנית, אתם צריכים לכלול את התפקידים הבאים:
כדי לנהל את זרימת הנתונים: Dataflow Admin, Dataflow Worker. כדי לקרוא נתונים מ-Spanner: Cloud Spanner Database Reader הרשאות כתיבה ב-GCS Container Registry שנבחר: GCS Storage Bucket Owner (בעלים של קטגוריית GCS Storage).
- פריסת תהליך העבודה ב-Cloud Workflow
פורסים את קובץ ה-YAML של תהליך העבודה בפרויקט בענן שלכם ב-Google Cloud. אתם יכולים להגדיר את האזור או המיקום שבהם יופעל תהליך העבודה.
gcloud workflows deploy vector-export-workflow --source=batch-export.yaml --location="us-central1" [--service account=<service_account>]
or
gcloud workflows deploy vector-export-workflow --source=batch-export.yaml --location="us-central1"
עכשיו זרימת העבודה אמורה להופיע בדף Workflows במסוף Google Cloud.
הערה: אפשר גם ליצור ולפרוס את תהליך העבודה במסוף Google Cloud. פועלים לפי ההנחיות במסוף Cloud. להגדרת תהליך העבודה, מעתיקים ומדביקים את התוכן של batch-export.yaml.
אחרי שמסיימים את השלב הזה, מריצים את תהליך העבודה כדי להתחיל בייצוא הנתונים.
- הפעלת Cloud Workflow
מריצים את הפקודה הבאה כדי להפעיל את תהליך העבודה:
gcloud workflows execute vector-export-workflow --data="$(cat input.json)"
הביצוע אמור להופיע בכרטיסייה 'ביצועים' ב-Workflows. הפעולה הזו אמורה לטעון את הנתונים למסד הנתונים של חיפוש וקטורי ולאנדקס אותם.
הערה: אפשר גם להריץ את הפקודה מהמסוף באמצעות הלחצן 'הפעלה'. פועלים לפי ההנחיות, ובשלב ההזנה מעתיקים ומדביקים את התוכן של קובץ input.json המותאם אישית.
5. פריסת אינדקס של Vector Search
פריסת האינדקס בנקודת קצה
כדי לפרוס את האינדקס:
- בדף Vector Search indexes אמור להופיע לחצן DEPLOY לצד האינדקס שיצרתם בשלב 2 בקטע הקודם. אפשר גם לעבור לדף המידע של האינדקס וללחוץ על הלחצן DEPLOY TO ENDPOINT (פריסה לנקודת קצה).
- מספקים את המידע הנדרש ומפרסים את האינדקס לנקודת קצה.
אפשר גם לעיין ב-notebook הזה כדי לפרוס אותו לנקודת קצה (צריך לדלג לחלק הפריסה ב-notebook). אחרי הפריסה, רושמים את מזהה האינדקס ואת כתובת ה-URL של נקודת הקצה.
6. חלק הקצה: נתוני משתמש ל-Vector Search
כדי לבדוק במהירות את ההטמעה, נבנה אפליקציית Python פשוטה עם ממשק משתמש מבוסס-Gradio. אפשר לעיין בהטמעה כאן כדי להטמיע את אפליקציית ההדגמה הזו ב-notebook של Colab.
- נשתמש ב-aiplatform python sdk כדי לקרוא ל-Embeddings API וגם כדי להפעיל את נקודת הקצה של אינדקס Vector Search.
# [START aiplatform_sdk_embedding]
!pip install google-cloud-aiplatform==1.35.0 --upgrade --quiet --user
import vertexai
vertexai.init(project=PROJECT_ID, location="us-central1")
from vertexai.language_models import TextEmbeddingModel
import sys
if "google.colab" in sys.modules:
# Define project information
PROJECT_ID = " " # Your project id
LOCATION = " " # Your location
# Authenticate user to Google Cloud
from google.colab import auth
auth.authenticate_user()
- נשתמש ב-gradio כדי להדגים את אפליקציית ה-AI שאנחנו בונים במהירות ובקלות באמצעות ממשק משתמש. לפני שמיישמים את השלב הזה, צריך להפעיל מחדש את זמן הריצה.
!pip install gradio
import gradio as gr
- מתוך אפליקציית האינטרנט, אחרי קלט של משתמש, מפעילים את Embeddings API. נשתמש במודל הטמעת הטקסט: textembedding-gecko@latest
השיטה שבהמשך מפעילה את מודל הטמעת הטקסט ומחזירה את הטמעות הווקטור של הטקסט שהזין המשתמש:
def text_embedding(content) -> list:
"""Text embedding with a Large Language Model."""
model = TextEmbeddingModel.from_pretrained("textembedding-gecko@latest")
embeddings = model.get_embeddings(content)
for embedding in embeddings:
vector = embedding.values
#print(f"Length of Embedding Vector: {len(vector)}")
return vector
אני רוצה לנסות
text_embedding("red shorts for girls")
הפלט אמור להיראות כך (שימו לב שהתמונה נחתכה לאורך, כך שלא ניתן לראות את כל התגובה של הווקטור):

- הצהרה על מזהה האינדקס שנפרס ומזהה נקודת הקצה
from google.cloud import aiplatform
DEPLOYED_INDEX_ID = "spanner_vector1_1702366982123"
#Vector Search Endpoint
index_endpoint = aiplatform.MatchingEngineIndexEndpoint('projects/273845608377/locations/us-central1/indexEndpoints/2021628049526620160')
- מגדירים את שיטת החיפוש הווקטורי כדי לקרוא לנקודת הקצה של האינדקס ולהציג את התוצאה עם 10 ההתאמות הקרובות ביותר לתגובת ההטמעה שמתאימה לטקסט הקלט של המשתמש.
בהגדרת השיטה שלמטה לחיפוש וקטורים, שימו לב שהשיטה find_neighbors מופעלת כדי לזהות את 10 הווקטורים הקרובים ביותר.
def vector_search(content) -> list:
result = text_embedding(content)
#call_vector_search_api(content)
index_endpoint = aiplatform.MatchingEngineIndexEndpoint('projects/273845608377/locations/us-central1/indexEndpoints/2021628049526620160')
# run query
response = index_endpoint.find_neighbors(
deployed_index_id = DEPLOYED_INDEX_ID,
queries = [result],
num_neighbors = 10
)
out = []
# show the results
for idx, neighbor in enumerate(response[0]):
print(f"{neighbor.distance:.2f} {spanner_read_data(neighbor.id)}")
out.append(f"{spanner_read_data(neighbor.id)}")
return out
תראו גם את הקריאה לשיטה spanner_read_data. בשלב הבא נסביר איך עושים את זה.
- מגדירים את ההטמעה של שיטת קריאת הנתונים של Spanner שמפעילה את שיטת execute_sql כדי לחלץ את התמונות שתואמות למזהים של וקטורים של השכן הקרוב ביותר שהוחזרו מהשלב האחרון.
!pip install google-cloud-spanner==3.36.0
from google.cloud import spanner
instance_id = "spanner-vertex"
database_id = "spanner-vertex-embeddings"
projectId = PROJECT_ID
client = spanner.Client()
client.project = projectId
instance = client.instance(instance_id)
database = instance.database(database_id)
def spanner_read_data(id):
query = "SELECT uri FROM apparels where id = " + id
outputs = []
with database.snapshot() as snapshot:
results = snapshot.execute_sql(query)
for row in results:
#print(row)
#output = "ID: {}, CONTENT: {}, URI: {}".format(*row)
output = "{}".format(*row)
outputs.append(output)
return "\n".join(outputs)
הפונקציה צריכה להחזיר את כתובות ה-URL של התמונות שמתאימות לווקטורים שנבחרו.
- לסיום, נרכיב את כל החלקים בממשק משתמש ונפעיל את תהליך החיפוש הווקטורי
from PIL import Image
def call_search(query):
response = vector_search(query)
return response
input_text = gr.Textbox(label="Enter your query. Examples: Girls Tops White Casual, Green t-shirt girls, jeans shorts, denim skirt etc.")
output_texts = [gr.Image(label="") for i in range(10)]
demo = gr.Interface(fn=call_search, inputs=input_text, outputs=output_texts, live=True)
resp = demo.launch(share = True)
התוצאה שמתקבלת אמורה להיראות כך:

תמונה: קישור
כאן אפשר לצפות בסרטון התוצאות.
7. הסרת המשאבים
כדי לא לצבור חיובים לחשבון Google Cloud על המשאבים שבהם השתמשתם במאמר הזה:
- במסוף Google Cloud, עוברים לדף Manage resources.
- ברשימת הפרויקטים, בוחרים את הפרויקט שרוצים למחוק ולוחצים על Delete (מחיקה).
- כדי למחוק את הפרויקט, כותבים את מזהה הפרויקט בתיבת הדו-שיח ולוחצים על Shut down.
- אם לא רוצים למחוק את הפרויקט, צריך למחוק את מופע Spanner. כדי לעשות את זה, עוברים למופע שיצרתם לפרויקט ולוחצים על הלחצן DELETE INSTANCE (מחיקת המופע) בפינה השמאלית העליונה של דף סקירה כללית של המופע.
- אפשר גם לעבור לאינדקס של Vector Search, לבטל את הפריסה של נקודת הקצה והאינדקס ולמחוק את האינדקס.
8. סיכום
מעולה! השלמת בהצלחה את ההטמעה של Spanner - Vertex Vector Search על ידי
- יצירה של מקור נתונים ושל הטמעות ב-Spanner לאפליקציות שמקורן במסד נתונים של Spanner.
- יצירת אינדקס של מסד נתונים ב-Vector Search.
- שילוב נתוני וקטורים מ-Spanner ל-Vector Search באמצעות משימות של Dataflow ו-Workflow.
- פריסת האינדקס בנקודת קצה.
- בסוף, מפעילים את חיפוש הווקטורים על קלט של משתמשים בהטמעה מבוססת Python של Vertex AI SDK.
אתם יכולים להרחיב את ההטמעה לתרחיש שימוש משלכם או לשפר את תרחיש השימוש הנוכחי באמצעות תכונות חדשות. כאן אפשר לקרוא מידע נוסף על יכולות למידת המכונה של Spanner.