ניהול של אינדקסים של וקטורים
במאמר הזה מוסבר איך ליצור ולנהל אינדקסים של וקטורים כדי להאיץ את החיפושים של וקטורים.
אינדקס וקטורי הוא מבנה נתונים שנועד לאפשר לפונקציות VECTOR_SEARCH ו-AI.SEARCH לפעול בצורה יעילה יותר, במיוחד במערכי נתונים גדולים.
כשמשתמשים באינדקס, פונקציות החיפוש האלה משתמשות באלגוריתמים של שכן קרוב משוער (ANN) כדי להפחית את זמן האחזור של השאילתה ואת העלות החישובית. למרות שהשימוש ב-ANN מוביל לקירוב מסוים, כלומר ההחזרה לא תמיד תהיה ב-100%, שיפורי הביצועים בדרך כלל מועילים לרוב האפליקציות.
תפקידים והרשאות
כדי ליצור אינדקס וקטורי, אתם צריכים את הרשאת ה-IAM bigquery.tables.createIndex בטבלה שבה אתם יוצרים את האינדקס. כדי להסיר אינדקס וקטורי, צריכה להיות לכם ההרשאה bigquery.tables.deleteIndex. כל אחד מהתפקידים הבאים שמוגדרים מראש ב-IAM כולל את ההרשאות שנדרשות לעבודה עם אינדקסים של וקטורים:
- בעלים של נתונים ב-BigQuery (
roles/bigquery.dataOwner) - עריכה של נתוני BigQuery (
roles/bigquery.dataEditor)
בחירת סוג אינדקס וקטורי
BigQuery מציע שני סוגים של אינדקסים וקטוריים, IVF ו-TreeAH, שכל אחד מהם תומך בתרחישי שימוש שונים. BigQuery תומך בעיבוד באצווה של חיפוש וקטורי, על ידי עיבוד של כמה שורות של נתוני הקלט ב-VECTOR_SEARCH.
עדיף להשתמש באינדקסים של IVF לקבוצות קטנות של שאילתות. עדיף להשתמש באינדקסים של TreeAH, שמבוססים על אלגוריתם ScaNN של Google, עבור קבוצות גדולות של שאילתות.
IVF Index
IVF הוא אינדקס של קובץ הפוך, שמשתמש באלגוריתם k-means כדי ליצור קבוצות של נתוני הווקטורים, ואז מחלק את נתוני הווקטורים על סמך הקבוצות האלה. הפונקציות VECTOR_SEARCH ו-AI.SEARCH יכולות להשתמש במחיצות האלה כדי להפחית את כמות הנתונים שהן צריכות לקרוא כדי לקבוע את התוצאה.
TreeAH Index
סוג האינדקס TreeAH נקרא כך כי הוא משלב בין מבנה דמוי עץ לבין שימוש בגיבוב אסימטרי (AH), טכניקת קוונטיזציה מרכזית מאלגוריתם ScaNN הבסיסי. אינדקס TreeAH פועל באופן הבא:
- טבלת הבסיס מחולקת לחלקים קטנים יותר שקל יותר לנהל.
- מודל אשכולות מאומן, ומספר האשכולות נגזר מהאפשרות
leaf_node_embedding_countבארגומנטtree_ah_optionsשל הצהרתCREATE VECTOR INDEX. - הווקטורים נדחסים באמצעות קוונטיזציה של מוצרים, טכניקה שמקטינה את השימוש שלהם בזיכרון. הווקטורים הדחוסים מאוחסנים בטבלאות האינדקס במקום הווקטורים המקוריים, וכך מצטמצם גודל אינדקס הווקטורים.
- כשמריצים את הפונקציות
VECTOR_SEARCHאוAI.SEARCH, המערכת מחשבת ביעילות רשימת מועמדים לכל וקטור שאילתה באמצעות גיבוב אסימטרי, שעבר אופטימיזציה ברמת החומרה לחישובים של מרחק משוער. לאחר מכן, המערכת נותנת למועמדים האלה ציון מחדש ומדרגת אותם מחדש באמצעות הטמעות מדויקות.
האלגוריתם TreeAH מותאם לשאילתות אצווה שמעבדות מאות או יותר וקטורים של שאילתות. השימוש בכימות מוצרים יכול להפחית באופן משמעותי את זמן האחזור והעלות, ואולי אפילו בסדרי גודל בהשוואה ל-IVF. עם זאת, בגלל התקורה המוגדלת, אלגוריתם IVF עשוי להיות טוב יותר כשמספר וקטורי השאילתות קטן יותר.
מומלץ לנסות את סוג האינדקס TreeAH אם תרחיש השימוש שלכם עומד בקריטריונים הבאים:
הטבלה מכילה עד 200 מיליון שורות.
אתם מריצים לעיתים קרובות שאילתות באצווה גדולות שכוללות מאות או יותר וקטורים של שאילתות.
בשאילתות קטנות עם סוג האינדקס TreeAH, יכול להיות שהחיפוש VECTOR_SEARCH או AI.SEARCH יחזור לחיפוש בכוח ברוטלי.
במקרה כזה, המערכת מספקת את IndexUnusedReason כדי להסביר למה לא נעשה שימוש באינדקס הווקטורי.
יצירת אינדקס וקטורי של IVF
כדי ליצור אינדקס וקטורי של IVF, משתמשים בהצהרה של שפת הגדרת נתונים (DDL) CREATE VECTOR INDEX:
עוברים לדף BigQuery.
בעורך השאילתות, מריצים את הצהרת ה-SQL הבאה:
כדי ליצור אינדקס וקטורי של IVF:
CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME ON DATASET_NAME.TABLE_NAME(COLUMN_NAME) STORING(STORED_COLUMN_NAME [, ...]) OPTIONS(index_type = 'IVF', distance_type = 'DISTANCE_TYPE', ivf_options = '{"num_lists":NUM_LISTS}')
מחליפים את מה שכתוב בשדות הבאים:
-
INDEX_NAME: השם של אינדקס הווקטור שאתם יוצרים. האינדקס תמיד נוצר באותו פרויקט ובאותו מערך נתונים כמו טבלת הבסיס, ולכן אין צורך לציין אותם בשם. -
DATASET_NAME: שם מערך הנתונים שמכיל את הטבלה. -
TABLE_NAME: שם הטבלה שמכילה את העמודה עם נתוני ההטמעות.
COLUMN_NAME: השם של עמודה שמכילה את נתוני ההטמעות. הסוג של העמודה חייב להיותARRAY<FLOAT64>, או שאם משתמשים ביצירה אוטונומית של הטמעה, הסוג חייב להיותSTRUCT<result ARRAY<FLOAT64>, status STRING>.בכל המקרים, כל הרכיבים במערך ההטמעה צריכים להיות שונים מ-
NULL, ולכל הערכים בעמודה צריכים להיות אותם ממדים של מערך.אם סוג העמודה הוא
STRUCT<result ARRAY<FLOAT64>, status STRING>, אז הערךSTRUCTיכול להיותNULLאו המערךresultיכול להיותNULL. המערכת מתעלמת מכל השורות שבהן הערכים האלה מופיעים בשדהNULL.
STORED_COLUMN_NAME: השם של עמודה ברמה העליונה בטבלה שרוצים לאחסן באינדקס הווקטורי. סוג העמודה לא יכול להיותRANGE. המערכת לא משתמשת בעמודות מאוחסנות אם לטבלה יש מדיניות גישה ברמת השורה או אם לעמודה יש תג מדיניות. מידע על הפעלת עמודות מאוחסנות מופיע במאמר אחסון עמודות וסינון מראש.
DISTANCE_TYPE: מציין את סוג המרחק שמוגדר כברירת מחדל לשימוש כשמבצעים חיפוש וקטורי באמצעות האינדקס הזה. הערכים הנתמכים הםEUCLIDEAN,COSINEו-DOT_PRODUCT. ברירת המחדל היאEUCLIDEAN.תהליך יצירת האינדקס תמיד מתבסס על מרחק של
EUCLIDEANלצורך אימון, אבל המרחק שמשמש את פונקציית החיפוש יכול להיות שונה.אם מציינים ערך לארגומנט
distance_typeשל הפונקציהVECTOR_SEARCHאוAI.SEARCH, המערכת משתמשת בערך הזה במקום בערךDISTANCE_TYPE.
NUM_LISTS: ערךINT64שמציין את מספר הרשימות שאינדקס ה-IVF מקבץ ואז מחלק אליהן את נתוני הווקטורים. הערך חייב להיות 5,000 או פחות. במהלך יצירת האינדקס, וקטורים מוקצים לרשימה שמתאימה למרכז הכובד של האשכול הקרוב ביותר. אם לא מציינים את הארגומנט הזה, BigQuery קובע ערך ברירת מחדל על סמך מאפייני הנתונים. ערך ברירת המחדל מתאים לרוב תרחישי השימוש.
NUM_LISTSקובע את רמת הפירוט של כוונון השאילתה. ערכים גבוהים יותר יוצרים יותר רשימות, כך שתוכלו להגדיר את האפשרותfraction_lists_to_searchשל פונקציית החיפוש לסריקה של אחוז קטן יותר מהאינדקס. לדוגמה, סריקה של 1% מתוך 100 רשימות לעומת סריקה של 10% מתוך 10 רשימות. האפשרות הזו מאפשרת שליטה מדויקת יותר במהירות החיפוש ובאחזור, אבל היא מעלה מעט את עלות האינדוקס. מגדירים את ערך הארגומנט הזה בהתאם למידת הדיוק שבה רוצים לכוונן את היקף השאילתה.
-
בדוגמה הבאה נוצר אינדקס וקטורים בעמודה embedding של הטבלה my_table:
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS(index_type = 'IVF');
בדוגמה הבאה נוצר אינדקס וקטורים בעמודה embedding של הטבלה my_table, ומוגדרים סוג המרחק שבו יש להשתמש ואפשרויות ה-IVF:
CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS(index_type = 'IVF', distance_type = 'COSINE', ivf_options = '{"num_lists": 2500}')
בדוגמה הבאה נוצרת טבלה עם יצירה אוטונומית של הטמעה מופעלת, ונוצר אינדקס וקטורי בטבלה. העמודה description_embedding
embedding נוצרת אוטומטית על סמך העמודה description.
CREATE TABLE mydataset.products ( description STRING, description_embedding STRUCT<result ARRAY<FLOAT64>, status STRING> GENERATED ALWAYS AS ( AI.EMBED(description, connection_id => 'us.example_connection', endpoint => 'text-embedding-005')) STORED OPTIONS( asynchronous = TRUE )); CREATE VECTOR INDEX my_index ON my_dataset.my_table(description_embedding) OPTIONS(index_type = 'IVF');
יצירת אינדקס וקטורי של TreeAH
כדי ליצור אינדקס וקטורי מסוג TreeAH, משתמשים בהצהרת שפת הגדרת הנתונים (DDL) CREATE VECTOR INDEX:
עוברים לדף BigQuery.
בעורך השאילתות, מריצים את הצהרת ה-SQL הבאה:
CREATE [ OR REPLACE ] VECTOR INDEX [ IF NOT EXISTS ] INDEX_NAME ON DATASET_NAME.TABLE_NAME(COLUMN_NAME) STORING(STORED_COLUMN_NAME [, ...]) OPTIONS(index_type = 'TREE_AH', distance_type = 'DISTANCE_TYPE', tree_ah_options = '{"leaf_node_embedding_count":LEAF_NODE_EMBEDDING_COUNT, "normalization_type":"NORMALIZATION_TYPE"}')
מחליפים את מה שכתוב בשדות הבאים:
-
INDEX_NAME: השם של אינדקס הווקטור שאתם יוצרים. מכיוון שהאינדקס תמיד נוצר באותו פרויקט ובאותו מערך נתונים כמו טבלת הבסיס, אין צורך לציין אותם בשם. -
DATASET_NAME: שם מערך הנתונים שמכיל את הטבלה. -
TABLE_NAME: שם הטבלה שמכילה את העמודה עם נתוני ההטמעות.
COLUMN_NAME: השם של עמודה שמכילה את נתוני ההטמעות. הסוג של העמודה חייב להיותARRAY<FLOAT64>, או שאם משתמשים ביצירה אוטונומית של הטמעה, הסוג חייב להיותSTRUCT<result ARRAY<FLOAT64>, status STRING>.בכל המקרים, כל הרכיבים במערך ההטמעה צריכים להיות שונים מ-
NULL, ולכל הערכים בעמודה צריכים להיות אותם ממדים של מערך. המערך חייב להיות לפחות דו-ממדי.אם סוג העמודה הוא
STRUCT<result ARRAY<FLOAT64>, status STRING>, אז הערךSTRUCTיכול להיותNULLאו המערךresultיכול להיותNULL. המערכת מתעלמת מכל השורות שבהן הערכים האלה מופיעים בשדהNULL.
STORED_COLUMN_NAME: השם של עמודה ברמה העליונה בטבלה שרוצים לאחסן באינדקס הווקטורי. סוג העמודה לא יכול להיותRANGE. המערכת לא משתמשת בעמודות מאוחסנות אם לטבלה יש מדיניות גישה ברמת השורה או אם לעמודה יש תג מדיניות. מידע על הפעלת עמודות מאוחסנות מופיע במאמר אחסון עמודות וסינון מראש.
DISTANCE_TYPE: ארגומנט אופציונלי שמציין את סוג המרחק שמוגדר כברירת מחדל לשימוש כשמבצעים חיפוש וקטורי באמצעות האינדקס הזה. הערכים הנתמכים הםEUCLIDEAN,COSINEו-DOT_PRODUCT. ברירת המחדל היאEUCLIDEAN.תהליך יצירת האינדקס תמיד מתבסס על מרחק
EUCLIDEANלאימון, אבל המרחק שמשמש בפונקציית החיפוש יכול להיות שונה.אם מציינים ערך לארגומנט
distance_typeשל הפונקציהVECTOR_SEARCHאוAI.SEARCH, המערכת משתמשת בערך הזה במקום בערךDISTANCE_TYPE.
LEAF_NODE_EMBEDDING_COUNT: ערךINT64שגדול מ-500 או שווה לו, שמציין את המספר המשוער של וקטורים בכל צומת עלה בעץ שנוצר על ידי אלגוריתם TreeAH. אלגוריתם TreeAH מחלק את מרחב הנתונים כולו למספר רשימות, כאשר כל רשימה מכילה בערךLEAF_NODE_EMBEDDING_COUNTנקודות נתונים. ערך נמוך יותר יוצר יותר רשימות עם פחות נקודות נתונים, ואילו ערך גבוה יותר יוצר פחות רשימות עם יותר נקודות נתונים. ברירת המחדל היא 1,000, שמתאימה לרוב מערכי הנתונים.
NORMALIZATION_TYPE: ערך שלSTRING. הערכים הנתמכים הםNONEאוL2. ערך ברירת המחדל הואNONE. הנרמול מתבצע לפני כל עיבוד, גם של נתוני טבלת הבסיס וגם של נתוני השאילתה, אבל הוא לא משנה את עמודת ההטמעהCOLUMN_NAMEב-TABLE_NAME. בהתאם למערך הנתונים, למודל ההטמעה ולסוג המרחק שמשמש במהלך החיפוש, נרמול ההטמעות עשוי לשפר את ההחזרה.
-
בדוגמה הבאה נוצר אינדקס וקטורי בעמודה embedding של my_table, ומוגדרים סוג המרחק לשימוש ואפשרויות TreeAH:
CREATE TABLE my_dataset.my_table(id INT64, embedding ARRAY<FLOAT64>); CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) OPTIONS (index_type = 'TREE_AH', distance_type = 'EUCLIDEAN', tree_ah_options = '{"normalization_type": "L2"}');
סינון
בקטעים הבאים מוסבר איך מסננים מראש ומסננים אחרי משפיעים על תוצאות החיפוש הווקטורי, וגם איך מסננים מראש באמצעות עמודות ומחיצות מאוחסנות באינדקס הווקטורי.
מסננים לפני ומסננים אחרי
בשיחות עם BigQuery VECTOR_SEARCH או AI.SEARCH, סינון מראש וסינון אחרי עוזרים לשפר את תוצאות החיפוש על ידי החלת תנאים שמבוססים על עמודות מטא-נתונים שמשויכות להטמעות וקטוריות. חשוב להבין את ההבדלים בין השיטות, את ההטמעה שלהן ואת ההשפעה שלהן כדי לבצע אופטימיזציה של ביצועי השאילתות, העלות והדיוק.
ההגדרות של סינון מוקדם וסינון מאוחר הן:
- סינון מראש: המערכת מחילה תנאי סינון לפני שהחיפוש של השכן הקרוב המשוער (ANN) מבצע חישובי מרחק על וקטורים מועמדים. כך מצמצמים את מאגר הווקטורים שנלקחים בחשבון במהלך החיפוש. כתוצאה מכך, סינון מראש מוביל לרוב לזמני שאילתה מהירים יותר ולעלות חישובית נמוכה יותר, כי החיפוש ברשת ה-ANN מעריך פחות מועמדים פוטנציאליים.
- סינון אחרי החיפוש: המערכת מחילה את תנאי הסינון אחרי שחיפוש ה-ANN מזהה את
top_kהשכנים הקרובים ביותר. הפעולה הזו משפרת את קבוצת התוצאות הסופית על סמך הקריטריונים שצוינו.
המיקום של סעיף WHERE קובע אם המסנן פועל כמסנן מקדים או כמסנן סופי.
כדי ליצור מסנן מוקדם, סעיף WHERE של השאילתה צריך לחול על ארגומנט טבלת הבסיס של פונקציית החיפוש.
הפרדיקט חייב לחול על עמודה מאוחסנת, אחרת הוא הופך למסנן אחרי.
בדוגמה הבאה אפשר לראות איך יוצרים מסנן מראש:
-- Pre-filter on a stored column. The index speeds up the query. SELECT * FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE type = 'animal'), 'embedding', TABLE my_dataset.my_testdata); SELECT * FROM AI.SEARCH( (SELECT * FROM my_dataset.my_table WHERE type = 'animal'), 'content', 'dog'); -- Filter on a column that isn't stored. The index is used to search the -- entire table, and then the results are post-filtered. You might see fewer -- than 5 matches returned for some embeddings. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE id = 123), 'embedding', TABLE my_dataset.my_testdata, top_k => 5); -- Use pre-filters with brute force. The data is filtered and then searched -- with brute force for exact results. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE id = 123), 'embedding', TABLE my_dataset.my_testdata, options => '{"use_brute_force":true}');
כדי ליצור מסנן אחרי החיפוש, צריך להחיל את פסוקית WHERE של השאילתה מחוץ לפונקציה VECTOR_SEARCH, כדי שהיא תסנן את התוצאות שמוחזרות מהחיפוש.
בדוגמה הבאה אפשר לראות איך יוצרים מסנן אחרי:
-- Use post-filters. The index is used, but the entire table is searched and -- the post-filtering might reduce the number of results. SELECT query.test_id, base.type, distance FROM VECTOR_SEARCH( TABLE my_dataset.my_table, 'embedding', TABLE my_dataset.my_testdata, top_k => 5) WHERE base.type = 'animal'; SELECT base.id, distance FROM VECTOR_SEARCH( TABLE mydataset.base_table, 'embedding', (SELECT embedding FROM mydataset.query_table), top_k => 10 ) WHERE type = 'document' AND year > 2022
כשמשתמשים בסינון אחרי השאילתה, או כשמסנני טבלת הבסיס שצוינו מפנים לעמודות שלא נשמרו ולכן פועלים כמסננים אחרי השאילתה, יכול להיות שקבוצת התוצאות הסופית תכיל פחות מ-top_k שורות, ואפילו אפס שורות, אם התנאי הוא סלקטיבי. אם אתם צריכים מספר מסוים של תוצאות אחרי הסינון, כדאי לציין ערך גדול יותר של top_k או להגדיל את הערך של fraction_lists_to_search בבקשה להפעלת פונקציה של החיפוש.
במקרים מסוימים, במיוחד אם המסנן המקדים הוא סלקטיבי מאוד, סינון מקדים יכול גם להקטין את גודל קבוצת התוצאות. אם זה קורה, כדאי לנסות להגדיל את הערך של fraction_lists_to_search בקריאה לפונקציית החיפוש.
סינון מראש באמצעות עמודות מאוחסנות
כדי לשפר עוד יותר את היעילות של אינדקס הווקטורים, אפשר לציין עמודות מטבלת הבסיס לאחסון באינדקס הווקטורים. שימוש בעמודות מאוחסנות יכול לשפר את השאילתות שמפעילות את הפונקציות VECTOR_SEARCH או AI.SEARCH בדרכים הבאות:
במקום לחפש בטבלה שלמה, אפשר להפעיל פונקציית חיפוש על הצהרת שאילתה שמסננת מראש את טבלת הבסיס באמצעות פסקה
WHERE. אם לטבלה יש אינדקס ואתם מסננים רק עמודות מאוחסנות, BigQuery מבצע אופטימיזציה של השאילתה על ידי סינון הנתונים לפני החיפוש, ואז משתמש באינדקס כדי לחפש במערך התוצאות הקטן יותר. אם מסננים עמודות שלא מאוחסנות, BigQuery מחיל את המסנן אחרי החיפוש בטבלה, או מסננים אחרי.הפונקציות
VECTOR_SEARCHו-AI.SEARCHמחזירות מבנה נתונים שנקראbaseשמכיל את כל העמודות מהטבלה הבסיסית. אם לא מאחסנים עמודות, צריך לבצע פעולת צירוף (join) שעשויה להיות יקרה כדי לאחזר את העמודות שמאוחסנות ב-base. אם משתמשים באינדקס IVF והשאילתה בוחרת רק עמודות מאוחסנות מ-base, BigQuery מבצע אופטימיזציה של השאילתה כדי לבטל את הצירוף הזה. באינדקסים של TreeAH, הצירוף לטבלת הבסיס לא מוסר. העמודות שמאוחסנות באינדקסים של TreeAH משמשות רק לסינון מראש.
כדי לאחסן עמודות, צריך לרשום אותן בסעיף STORING של הצהרת CREATE VECTOR INDEX.
אחסון עמודות מגדיל את הגודל של אינדקס הווקטורים, ולכן מומלץ לאחסן רק את העמודות שבהן משתמשים הכי הרבה או שמסננים הכי הרבה.
בדוגמה הבאה נוצר אינדקס וקטורי עם עמודות מאוחסנות, ואז מופעלת שאילתת חיפוש וקטורי שבוחרת רק עמודות מאוחסנות:
-- Create a table that contains an embedding. CREATE TABLE my_dataset.my_table(embedding ARRAY<FLOAT64>, type STRING, creation_time DATETIME, id INT64); -- Create a query table that contains an embedding. CREATE TABLE my_dataset.my_testdata(embedding ARRAY<FLOAT64>, test_id INT64); -- Create a vector index with stored columns. CREATE VECTOR INDEX my_index ON my_dataset.my_table(embedding) STORING (type, creation_time) OPTIONS (index_type = 'IVF'); -- Select only stored columns from a vector search to avoid an expensive join. SELECT query, base.type, distance FROM VECTOR_SEARCH( TABLE my_dataset.my_table, 'embedding' TABLE my_dataset.my_testdata);
מגבלות על עמודות מאוחסנות
- אם משנים את המצב, הסוג או הסכימה של עמודה בטבלת הבסיס, ואם זו עמודה מאוחסנת באינדקס הווקטורי, יכול להיות שיהיה עיכוב עד שהשינוי ישתקף באינדקס הווקטורי. עד שהעדכונים יוחלו על האינדקס, שאילתות של חיפוש וקטורי ישתמשו בעמודות המאוחסנות שעברו שינוי מטבלת הבסיס.
- אם בוחרים עמודה מהסוג
STRUCTמהפלטqueryשל שאילתת חיפוש בטבלה שיש לה אינדקס עם עמודות מאוחסנות, יכול להיות שהשאילתה כולה תיכשל.
סינון מקדים עם מחיצות
אם הטבלה שעליה אתם יוצרים את אינדקס הווקטורים מחולקת למחיצות, אתם יכולים לבחור לחלק למחיצות גם את אינדקס הווקטורים. לחלוקה למחיצות (partitioning) של אינדקס הווקטורים יש כמה יתרונות:
- הגיזום של המחיצות חל על אינדקסים של וקטורים בנוסף למחיצות של הטבלה. הסרת מחיצות מתרחשת כשחיפוש וקטורי משתמש במסנן שעומד בדרישות של הערך בעמודת החלוקה למחיצות (partitioning). כך BigQuery יכול לסרוק את המחיצות שתואמות למסנן ולדלג על שאר המחיצות. קיצוץ מחיצות יכול להקטין את עלויות הקלט/פלט. מידע נוסף על סינון מחיצות זמין במאמר בנושא שאילתות על טבלאות עם מחיצות.
- אם מסננים מראש לפי עמודת החלוקה, הסיכוי שהחיפוש הווקטורי יפספס תוצאות קטן יותר.
אפשר לבצע חלוקה למחיצות רק באינדקסים של וקטורים מסוג TreeAH. אי אפשר ליצור אינדקס וקטורי עם חלוקה למחיצות בעמודת הטמעה שנוצרה באופן אוטומטי.
מומלץ לחלק את אינדקס הווקטורים רק אם משתמשים בסינון מראש כדי להגביל את רוב חיפושי הווקטורים לכמה מחיצות.
כדי ליצור אינדקס עם חלוקה למחיצות, משתמשים בסעיף PARTITION BY של הצהרת CREATE VECTOR INDEX. הפסקה PARTITION BY שאתם מציינים בהצהרת CREATE VECTOR INDEX חייבת להיות זהה לפסקה PARTITION BY שצוינה בהצהרת CREATE TABLE של הטבלה שעליה אתם יוצרים את אינדקס הווקטור, כמו שמוצג בדוגמה הבאה:
-- Create a date-partitioned table. CREATE TABLE my_dataset.my_table( embeddings ARRAYid INT64, date DATE, ) PARTITION BY date; -- Create a partitioned vector index on the table. CREATE VECTOR INDEX my_index ON my_dataset.my_table(embeddings) PARTITION BY date OPTIONS(index_type='TREE_AH', distance_type='COSINE');
אם הטבלה משתמשת בחלוקת עמודות לפי טווח מספרים שלמים או יחידת זמן, עמודת החלוקה מאוחסנת באינדקס הווקטורי, מה שמגדיל את עלות האחסון.
אם נעשה שימוש בעמודה בטבלה גם בסעיפים STORING וגם בסעיפים PARTITION BY של ההצהרה CREATE VECTOR INDEX, העמודה מאוחסנת רק פעם אחת.
כדי להשתמש בחלוקה למחיצות (partitioning) של אינדקס הווקטורים, מסננים את עמודת החלוקה למחיצות (partitioning) בשאילתת המשנה של טבלת הבסיס בקריאה VECTOR_SEARCH או AI.SEARCH.
בדוגמה הבאה, הטבלה samples.items מחולקת למחיצות לפי העמודה produced_date, ולכן שאילתת המשנה של טבלת הבסיס בהצהרה VECTOR_SEARCH מסננת לפי העמודה produced_date:
SELECT query.id, base.id, distance FROM VECTOR_SEARCH( (SELECT * FROM my_dataset.my_table WHERE produced_date = '2025-01-01'), 'embedding', TABLE samples.test, distance_type => 'COSINE', top_k => 10 );
דוגמאות
יוצרים אינדקס וקטורי מחולק למחיצות בטבלה שמחולקת למחיצות לפי תאריך ושעה:
-- Create a datetime-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, produced_date DATETIME, embeddings ARRAY) PARTITION BY produced_date; -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY produced_date OPTIONS(index_type='TREE_AH', distance_type='COSINE');
יצירת אינדקס וקטורי מחולק למחיצות בטבלה מחולקת למחיצות לפי חותמת זמן:
-- Create a timestamp-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, produced_time TIMESTAMP, embeddings ARRAY) PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY TIMESTAMP_TRUNC(produced_time, HOUR) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
יצירת אינדקס וקטורי עם חלוקה למחיצות בטבלה עם חלוקה למחיצות לפי טווח של מספרים שלמים:
-- Create a integer range-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, embeddings ARRAY) PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20)); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY RANGE_BUCKET(id, GENERATE_ARRAY(-100, 100, 20)) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
יצירת אינדקס וקטורי מחולק למחיצות בטבלה מחולקת למחיצות לפי זמני כתיבת הנתונים:
-- Create a ingestion time-partitioned table. CREATE TABLE my_dataset.my_table( id INT64, embeddings ARRAY) PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY); -- Create a partitioned vector index on the table. CREATE VECTOR INDEX index0 ON my_dataset.my_table(embeddings) PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, DAY) OPTIONS(index_type='TREE_AH', distance_type='COSINE');
מגבלות של סינון מקדים
- אי אפשר להשתמש בתצוגות לוגיות במסנן המקדים.
- אם המסנן המקדים מכיל שאילתת משנה, יכול להיות שהוא יפריע לשימוש באינדקס.
הסבר על המועד שבו הנתונים נוספים לאינדקס
האינדקסים של הווקטורים מנוהלים באופן מלא על ידי BigQuery, והם מתעדכנים אוטומטית כשמתבצעים שינויים בטבלה המאונדקסת.
ההוספה לאינדקס היא אסינכרונית. יש עיכוב בין הוספת שורות חדשות לטבלת הבסיס לבין הזמן שבו השורות החדשות משתקפות באינדקס. עם זאת, הפונקציות VECTOR_SEARCH ו-AI.SEARCH עדיין לוקחות בחשבון את כל השורות ולא מפספסות שורות שלא נוספו לאינדקס. הפונקציות מחפשות באמצעות האינדקס רשומות שנוספו לאינדקס, ומבצעות חיפוש בכוח רשומות שעדיין לא נוספו לאינדקס.
אם יוצרים אינדקס וקטורי בעמודת הטמעה שנוצרה באופן אוטומטי, האימון של האינדקס מתחיל ברגע שלפחות 80% מהשורות יצרו הטמעות.
אם יוצרים אינדקס וקטורי בטבלה שגודלה קטן מ-10MB, האינדקס הווקטורי לא יאוכלס. באופן דומה, אם מוחקים נתונים מטבלה עם אינדקס והגודל של הטבלה יורד מתחת ל-10MB, האינדקס הווקטורי מושבת באופן זמני. במקרה כזה, שאילתות חיפוש וקטורי לא משתמשות באינדקס, והקוד indexUnusedReasons בקטע vectorSearchStatistics של משאב Job הוא BASE_TABLE_TOO_SMALL. בלי האינדקס, פונקציית החיפוש שלכם תשתמש אוטומטית בשיטת הכוח הגס כדי למצוא את השכנים הקרובים ביותר של ההטמעות.
אם מוחקים את העמודה עם האינדקס בטבלה, או משנים את השם של הטבלה עצמה, האינדקס הווקטורי נמחק אוטומטית.
מעקב אחרי הסטטוס של אינדקסים של וקטורים
אפשר לעקוב אחרי התקינות של אינדקסים של וקטורים באמצעות שאילתות של תצוגות INFORMATION_SCHEMA. התצוגות הבאות מכילות מטא-נתונים על אינדקסים של וקטורים:
INFORMATION_SCHEMA.VECTOR_INDEXESהתצוגה כוללת מידע על אינדקסים של וקטורים במערך נתונים.אחרי שההצהרה
CREATE VECTOR INDEXמסתיימת, עדיין צריך לאכלס את האינדקס לפני שאפשר להשתמש בו. אפשר להשתמש בעמודותlast_refresh_timeו-coverage_percentageכדי לוודא שמדד הווקטור מוכן. אם אינדקס הווקטורים לא מוכן, עדיין אפשר להשתמש בפונקציותVECTOR_SEARCHו-AI.SEARCHבטבלה, אבל יכול להיות שהן יפעלו לאט יותר בלי האינדקס.בתצוגה
INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNSיש מידע על העמודות עם אינדקס וקטורי לכל הטבלאות בקבוצת נתונים.בתצוגה
INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONSיש מידע על האפשרויות שבהן נעשה שימוש באינדקסים של וקטורים במערך נתונים.
דוגמאות לאינדקסים של וקטורים
בדוגמה הבאה מוצגים כל האינדקסים הפעילים של וקטורים בטבלאות במערך הנתונים my_dataset, שנמצא בפרויקט my_project. הוא כולל את השמות שלהם, את הצהרות ה-DDL ששימשו ליצירתם ואת אחוז הכיסוי שלהם. אם טבלת בסיס עם אינדקס קטנה מ-10MB, האינדקס שלה לא יאוכלס, ובמקרה כזה הערך של coverage_percentage יהיה 0.
SELECT table_name, index_name, ddl, coverage_percentage FROM my_project.my_dataset.INFORMATION_SCHEMA.VECTOR_INDEXES WHERE index_status = 'ACTIVE';
התוצאה אמורה להיראות כך:
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table_name | index_name | ddl | coverage_percentage |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table1 | indexa | CREATE VECTOR INDEX `indexa` ON `my_project.my_dataset.table1`(embeddings) | 100 |
| | | OPTIONS (distance_type = 'EUCLIDEAN', index_type = 'IVF', ivf_options = '{"num_lists": 100}') | |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table2 | indexb | CREATE VECTOR INDEX `indexb` ON `my_project.my_dataset.table2`(vectors) | 42 |
| | | OPTIONS (distance_type = 'COSINE', index_type = 'IVF', ivf_options = '{"num_lists": 500}') | |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
| table3 | indexc | CREATE VECTOR INDEX `indexc` ON `my_project.my_dataset.table3`(vectors) | 98 |
| | | OPTIONS (distance_type = 'DOT_PRODUCT', index_type = 'TREE_AH', | |
| | | tree_ah_options = '{"leaf_node_embedding_count": 1000, "normalization_type": "NONE"}') | |
+------------+------------+-------------------------------------------------------------------------------------------------+---------------------+
דוגמאות לעמודות של אינדקס וקטורים
השאילתה הבאה שולפת מידע על עמודות עם אינדקסים של וקטורים:
SELECT table_name, index_name, index_column_name, index_field_path FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_COLUMNS;
התוצאה אמורה להיראות כך:
+------------+------------+-------------------+------------------+ | table_name | index_name | index_column_name | index_field_path | +------------+------------+-------------------+------------------+ | table1 | indexa | embeddings | embeddings | | table2 | indexb | vectors | vectors | | table3 | indexc | vectors | vectors | +------------+------------+-------------------+------------------+
דוגמאות לאפשרויות של אינדקס וקטורים
השאילתה הבאה מחלצת מידע על אפשרויות של אינדקס וקטורי:
SELECT table_name, index_name, option_name, option_type, option_value FROM my_project.dataset.INFORMATION_SCHEMA.VECTOR_INDEX_OPTIONS;
התוצאה אמורה להיראות כך:
+------------+------------+------------------+------------------+-------------------------------------------------------------------+
| table_name | index_name | option_name | option_type | option_value |
+------------+------------+------------------+------------------+-------------------------------------------------------------------+
| table1 | indexa | index_type | STRING | IVF |
| table1 | indexa | distance_type | STRING | EUCLIDEAN |
| table1 | indexa | ivf_options | STRING | {"num_lists": 100} |
| table2 | indexb | index_type | STRING | IVF |
| table2 | indexb | distance_type | STRING | COSINE |
| table2 | indexb | ivf_options | STRING | {"num_lists": 500} |
| table3 | indexc | index_type | STRING | TREE_AH |
| table3 | indexc | distance_type | STRING | DOT_PRODUCT |
| table3 | indexc | tree_ah_options | STRING | {"leaf_node_embedding_count": 1000, "normalization_type": "NONE"} |
+------------+------------+------------------+------------------+-------------------------------------------------------------------+
אימות השימוש באינדקס וקטורי
מידע על השימוש באינדקס הווקטורי זמין במטא-נתונים של הג'וב שבו הופעלה שאילתת חיפוש הווקטורים. אפשר לראות את המטא-נתונים של העבודות באמצעות Google Cloud המסוף, כלי שורת הפקודה של BigQuery, BigQuery API או ספריות הלקוח.
כשמשתמשים במסוף Google Cloud , אפשר למצוא מידע על השימוש באינדקס וקטורי בשדות Vector Index Usage Mode ו-Vector Index Unused Reasons.
כשמשתמשים בכלי bq או ב-BigQuery API, אפשר למצוא מידע על השימוש באינדקס וקטורי בקטע VectorSearchStatistics במשאב Job.
מצב השימוש באינדקס מציין אם נעשה שימוש באינדקס וקטורי. הערכים האפשריים הם:
-
UNUSED: לא נעשה שימוש באינדקס וקטורי. -
PARTIALLY_USED: חלק מפונקציות החיפוש בשאילתה השתמשו באינדקסים של וקטורים וחלק לא. -
FULLY_USED: כל פונקציית חיפוש בשאילתה השתמשה באינדקס וקטורי.
כשהערך של מצב השימוש באינדקס הוא UNUSED או PARTIALLY_USED, הסיבות לאי-השימוש באינדקס מציינות למה לא נעשה שימוש באינדקסים וקטוריים בשאילתה.
לדוגמה, התוצאות הבאות שמוחזרות על ידי bq show --format=prettyjson -j my_job_id מראות שלא נעשה שימוש באינדקס כי האפשרות use_brute_force צוינה בפונקציה VECTOR_SEARCH:
"vectorSearchStatistics": {
"indexUnusedReasons": [
{
"baseTable": {
"datasetId": "my_dataset",
"projectId": "my_project",
"tableId": "my_table"
},
"code": "INDEX_SUPPRESSED_BY_FUNCTION_OPTION",
"message": "No vector index was used for the base table `my_project:my_dataset.my_table` because use_brute_force option has been specified."
}
],
"indexUsageMode": "UNUSED"
}
בעיה מוכרת: יכול להיות שהשימוש באינדקס הווקטורי לא מדויק כשהשאילתה פועלת, מבוטלת או נכשלת.
אפשרויות לניהול האינדקס
כדי ליצור אינדקסים ולגרום ל-BigQuery לתחזק אותם, יש שתי אפשרויות:
- שימוש במאגר ברירת המחדל של משבצות זמן משותפות: אם כמות הנתונים שאתם מתכננים ליצור להם אינדקס קטנה מהמגבלה לכל ארגון, אתם יכולים להשתמש במאגר ברירת המחדל של משבצות זמן משותפות לניהול האינדקס.
- שימוש בהזמנה משלכם: כדי להשיג התקדמות צפויה ועקבית יותר ביצירת אינדקסים בעומסי עבודה גדולים יותר של ייצור, אתם יכולים להשתמש בהזמנות משלכם לניהול אינדקסים.
שימוש במשבצות משותפות
אם לא הגדרתם בפרויקט הזמנה ייעודית לאינדוקס, ניהול האינדקס מתבצע במאגר החינמי של משבצות זמן משותפות, בכפוף לאילוצים הבאים.
אם מוסיפים נתונים לטבלה שגורמים לגודל הכולל של הטבלאות המאונדקסות לחרוג מהמגבלה של הארגון, BigQuery משהה את ניהול האינדקסים של הטבלה הזו. במקרה כזה, בשדה index_status בתצוגה INFORMATION_SCHEMA.VECTOR_INDEXES מופיע הערך PENDING DISABLEMENT והאינדקס מתווסף לתור למחיקה. בזמן שהאינדקס ממתין להשבתה, הוא עדיין משמש בשאילתות ואתם מחויבים על אחסון האינדקס.
אחרי שהאינדקס נמחק, בשדה index_status האינדקס מוצג כ-TEMPORARILY DISABLED. במצב הזה, השאילתות לא משתמשות באינדקס, ולא תחויבו על אחסון האינדקס. במקרה הזה, הקוד IndexUnusedReason הוא BASE_TABLE_TOO_LARGE.
אם מוחקים נתונים מהטבלה והגודל הכולל של הטבלאות המאונדקסות קטן מהמגבלה לכל ארגון, ניהול האינדקסים יתחדש. השדה index_status בתצוגה INFORMATION_SCHEMA.VECTOR_INDEXES הוא ACTIVE, אפשר להשתמש באינדקס בשאילתות, ויש חיוב על האחסון של האינדקס.
אפשר להשתמש בתצוגה INFORMATION_SCHEMA.SEARCH_INDEXES_BY_ORGANIZATION כדי להבין את הצריכה הנוכחית שלכם ביחס למגבלה לכל ארגון באזור מסוים, עם פירוט לפי פרויקטים וטבלאות.
BigQuery לא מתחייב לגבי הקיבולת הזמינה של המאגר המשותף או לגבי קצב העברת הנתונים של יצירת האינדקס שאתם רואים. באפליקציות ייצור, כדאי להשתמש במשבצות ייעודיות לעיבוד האינדקס.
שימוש בהזמנה שלכם
במקום להשתמש במאגר ברירת המחדל של משבצות משותפות, אתם יכולים להקצות משבצת משלכם כדי להוסיף את הטבלאות לאינדקס. שימוש בהזמנה משלכם מבטיח ביצועים צפויים ועקביים של משימות ניהול אינדקסים, כמו יצירה, רענון ואופטימיזציות ברקע.
- אין הגבלות על גודל הטבלה כשמריצים עבודת אינדוקס בהזמנה.
- שימוש בהזמנה משלכם מאפשר לכם גמישות בניהול האינדקס. אם אתם צריכים ליצור אינדקס גדול מאוד או לבצע עדכון משמעותי בטבלה עם אינדקס, אתם יכולים להוסיף זמנית עוד משבצות להקצאה.
כדי ליצור אינדקס לטבלאות בפרויקט עם הזמנה ייעודית, צריך ליצור הזמנה באזור שבו הטבלאות נמצאות. לאחר מכן, מקצים את הפרויקט להזמנה עם הערך job_type שמוגדר ל-BACKGROUND, שמשתף משאבים בין משימות אופטימיזציה ברקע:
SQL
משתמשים בהצהרת ה-DDL CREATE ASSIGNMENT.
במסוף Google Cloud , עוברים לדף BigQuery.
מזינים את ההצהרה הבאה בעורך השאילתות:
CREATE ASSIGNMENT `ADMIN_PROJECT_ID.region-LOCATION.RESERVATION_NAME.ASSIGNMENT_ID` OPTIONS ( assignee = 'projects/PROJECT_ID', job_type = 'BACKGROUND');
מחליפים את מה שכתוב בשדות הבאים:
-
ADMIN_PROJECT_ID: מזהה הפרויקט של פרויקט הניהול שבבעלותו משאב המקום השמור -
LOCATION: המיקום של ההזמנה -
RESERVATION_NAME: השם של ההזמנה
ASSIGNMENT_ID: מזהה ההקצאההמזהה צריך להיות ייחודי לפרויקט ולמיקום, להתחיל ולהסתיים באות קטנה או במספר, ולהכיל רק אותיות קטנות, מספרים ומקפים.
-
PROJECT_ID: מזהה הפרויקט שמכיל את הטבלאות לאינדקס. הפרויקט הזה משויך להזמנה.
-
לוחצים על הפעלה.
מידע נוסף על הרצת שאילתות זמין במאמר הרצת שאילתה אינטראקטיבית.
BQ
משתמשים בפקודה bq mk:
bq mk \
--project_id=ADMIN_PROJECT_ID \
--location=LOCATION \
--reservation_assignment \
--reservation_id=RESERVATION_NAME \
--assignee_id=PROJECT_ID \
--job_type=BACKGROUND \
--assignee_type=PROJECT
מחליפים את מה שכתוב בשדות הבאים:
-
ADMIN_PROJECT_ID: מזהה הפרויקט של פרויקט הניהול שבבעלותו משאב המקום השמור -
LOCATION: המיקום של ההזמנה -
RESERVATION_NAME: השם של ההזמנה -
PROJECT_ID: המזהה של הפרויקט להקצאה להזמנה הזו
הצגת משימות האינדוקס
משימת אינדוקס חדשה נוצרת בכל פעם שנוצר או מתעדכן אינדקס בטבלה יחידה. כדי לראות מידע על המשימה, מריצים שאילתה על תצוגות INFORMATION_SCHEMA.JOBS*. אפשר לסנן משימות אינדוקס על ידי הגדרת job_type IS NULL AND SEARCH(job_id, '`search_index`') בסעיף WHERE של השאילתה. בדוגמה הבאה מוצגת רשימה של חמשת תהליכי הוספת האינדקס האחרונים בפרויקט my_project:
SELECT * FROM region-us.INFORMATION_SCHEMA.JOBS WHERE project_id = 'my_project' AND job_type IS NULL AND SEARCH(job_id, '`search_index`') ORDER BY creation_time DESC LIMIT 5;
בחירת גודל ההזמנה
כדי לבחור את מספר המשבצות המתאים להזמנה, צריך לקחת בחשבון מתי מופעלים תהליכי ניהול האינדקס, כמה משבצות הם צורכים ואיך נראה השימוש לאורך זמן. מערכת BigQuery מפעילה משימה לניהול אינדקסים במצבים הבאים:
- יוצרים אינדקס בטבלה.
- הנתונים משתנים בטבלה עם אינדקס.
- הסכימה של טבלה משתנה, וזה משפיע על העמודות שמתווספות לאינדקס.
- נתוני האינדקס והמטא-נתונים עוברים אופטימיזציה או עדכון מדי פעם.
מספר המשבצות שדרושות לעבודת ניהול אינדקס בטבלה תלוי בגורמים הבאים:
- גודל הטבלה
- קצב הטמעת הנתונים בטבלה
- שיעור פקודות ה-DML שהוחלו על הטבלה
- העיכוב המקסימלי המותר ביצירה ובתחזוקה של האינדקס
- מורכבות האינדקס, שנקבעת בדרך כלל לפי מאפייני הנתונים, כמו מספר המונחים הכפולים
מעקב אחרי השימוש וההתקדמות
הדרך הכי טובה להעריך כמה משבצות צריך כדי להריץ ביעילות את משימות ניהול האינדקס היא לעקוב אחרי השימוש במשבצות ולהתאים את גודל ההזמנה בהתאם. השאילתה הבאה מפיקה את נתוני השימוש היומי במשבצות זמן למשימות של ניהול אינדקסים. הנתונים שמוצגים באזור us-west1 כוללים רק את 30 הימים האחרונים:
SELECT TIMESTAMP_TRUNC(job.creation_time, DAY) AS usage_date, -- Aggregate total_slots_ms used for index-management jobs in a day and divide -- by the number of milliseconds in a day. This value is most accurate for -- days with consistent slot usage. SAFE_DIVIDE(SUM(job.total_slot_ms), (1000 * 60 * 60 * 24)) AS average_daily_slot_usage FROM `region-us-west1`.INFORMATION_SCHEMA.JOBS job WHERE project_id = 'my_project' AND job_type IS NULL AND SEARCH(job_id, '`search_index`') GROUP BY usage_date ORDER BY usage_date DESC limit 30;
אם אין מספיק משבצות להרצת משימות של ניהול אינדקסים, יכול להיות שהאינדקס לא יסונכרן עם הטבלה, והמשימות של יצירת האינדקס ייכשלו. במקרה הזה, BigQuery בונה מחדש את האינדקס מאפס. כדי למנוע מצב שבו האינדקס לא מסונכרן, צריך לוודא שיש מספיק משבצות כדי לתמוך בעדכוני אינדקס מהטמעת נתונים ומאופטימיזציה. מידע נוסף על מעקב אחרי השימוש במשבצות זמין במאמר תרשימי משאבים לאדמינים.
בנייה מחדש של אינדקס וקטורי
אם הנתונים בטבלה משתנים באופן משמעותי אחרי שיוצרים אינדקס וקטורי, היעילות של האינדקס הווקטורי עשויה לרדת. כשאינדקס הווקטורים פחות יעיל, שאילתת חיפוש וקטורים שהייתה לה החזרה גבוהה בהתחלה כשנעשה שימוש באינדקס, תחזיר החזרה נמוכה יותר, כי שינוי חלוקת הנתונים בטבלת הבסיס לא מיוצג באינדקס הווקטורים.
אם רוצים לשפר את ההחזרה בלי להגדיל את זמן האחזור של שאילתות החיפוש, צריך לבנות מחדש את אינדקס הווקטורים. לחלופין, אפשר להגדיל את הערך של האפשרות fraction_lists_to_search של חיפוש הווקטור כדי לשפר את ההחזרה, אבל בדרך כלל זה מאט את שאילתת החיפוש. כדי לגלות מתי נוצר האינדקס בפעם האחרונה, מריצים את השאילתה הבאה:
SELECT last_model_build_time FROM DATASET_NAME.INFORMATION_SCHEMA.VECTOR_INDEXES WHERE table_name = TABLE_NAME;
אתם יכולים להשתמש בפונקציה VECTOR_INDEX.STATISTICS כדי לחשב את מידת הסחף של נתוני טבלה עם אינדקס בין מועד היצירה של אינדקס וקטורי לבין ההווה. אם הנתונים בטבלה השתנו מספיק כדי לדרוש בנייה מחדש של אינדקס הווקטורים, אפשר להשתמש בהצהרת ALTER VECTOR INDEX REBUILD כדי לבנות מחדש את אינדקס הווקטורים.
כדי לבנות מחדש אינדקס וקטורי:
עוברים לדף BigQuery.
בעורך השאילתות, מריצים את הצהרת ה-SQL הבאה כדי לבדוק את סחף הנתונים בטבלה שנוספה לאינדקס:
SELECT * FROM VECTOR_INDEX.STATISTICS(TABLE DATASET_NAME.TABLE_NAME);
מחליפים את מה שכתוב בשדות הבאים:
-
DATASET_NAME: השם של מערך הנתונים שמכיל את הטבלה המאונדקסת. -
TABLE_NAME: השם של הטבלה שמכילה את אינדקס הווקטור.
הפונקציה מחזירה ערך
FLOAT64בטווח[0,1). ערך נמוך יותר מצביע על סחף נמוך יותר. בדרך כלל, ערך של0.3ומעלה נחשב לשינוי משמעותי מספיק שמצביע על כך ששחזור של אינדקס הווקטור עשוי להועיל.-
אם הפונקציה
VECTOR_INDEX.STATISTICSמציינת שסחף נתוני הטבלה משמעותי, מריצים את הצהרת ה-SQL הבאה כדי לבנות מחדש את אינדקס הווקטור:ALTER VECTOR INDEX IF EXISTS INDEX_NAME ON DATASET_NAME.TABLE_NAME REBUILD;
מחליפים את מה שכתוב בשדות הבאים:
-
INDEX_NAME: השם של אינדקס הווקטור שאתם בונים מחדש. -
DATASET_NAME: השם של מערך הנתונים שמכיל את הטבלה המאונדקסת. -
TABLE_NAME: השם של הטבלה שמכילה את אינדקס הווקטור.
-
מעקב אחר בנייה מחדש
כדי לעקוב אחר הבנייה מחדש של האינדקס, מריצים שאילתה בתצוגה INFORMATION_SCHEMA.VECTOR_INDEXES.
לדוגמה, השאילתה הבאה מציגה את סטטוס הבנייה מחדש של כל האינדקסים בטבלאות בקבוצת הנתונים my_dataset בפרויקט my_project. אם לא מתבצעת בנייה מחדש של אינדקס, הערך של last_index_alteration_info הוא NULL.
SELECT
table_name,
index_name,
last_index_alteration_info.status AS status,
last_index_alteration_info.new_coverage_percentage AS coverage
FROM my_project.my_dataset.INFORMATION_SCHEMA.VECTOR_INDEXES
התוצאה אמורה להיראות כך:
+------------+------------+-------------+----------+
| table_name | index_name | status | coverage |
+------------+------------+-------------+----------+
| table1 | index_a | IN_PROGRESS | 50 |
| table2 | index_b | null | null |
+------------+------------+-------------+----------+
ביטול בנייה מחדש
כדי לבטל בנייה מחדש של אינדקס וקטורי, משתמשים בהליך המערכת BQ.CANCEL_INDEX_ALTERATION.
יכול להיות שפעולת שינוי באינדקס תושלם לפני שהבקשה לביטול תעובד. כדי לוודא שהפעולה בוטלה בהצלחה, שולחים שאילתה לתצוגה INFORMATION_SCHEMA.VECTOR_INDEXES.
אם הביטול הצליח, השדה last_model_build_time לא מתעדכן והשדה last_index_alteration_info לא מופיע באינדקס הזה.
מחיקת אינדקס וקטורי
אם כבר לא צריך אינדקס וקטורי או שרוצים לשנות את העמודה שמתווספת לאינדקס בטבלה, אפשר למחוק את האינדקס בטבלה באמצעות הצהרת DDL DROP VECTOR INDEX:
עוברים לדף BigQuery.
בעורך השאילתות, מריצים את הצהרת ה-SQL הבאה:
DROP VECTOR INDEX INDEX_NAME ON DATASET_NAME.TABLE_NAME;
מחליפים את מה שכתוב בשדות הבאים:
-
INDEX_NAME: השם של אינדקס הווקטור שרוצים למחוק. -
DATASET_NAME: השם של מערך הנתונים שמכיל את הטבלה המאונדקסת. -
TABLE_NAME: השם של הטבלה שמכילה את אינדקס הווקטור.
-
אם מוחקים טבלה עם אינדקס, האינדקס שלה נמחק אוטומטית.
ייצוא הטמעות ל-Vertex AI Vector Search
כדי להפעיל אפליקציות אונליין עם זמן טעינה קצר במיוחד, אפשר להשתמש בשילוב של BigQuery עם חיפוש וקטורים ב-Vertex AI כדי לייבא את ההטמעות שלכם ב-BigQuery לחיפוש וקטורים ולפרוס נקודות קצה עם זמן אחזור נמוך. למידע נוסף, אפשר לקרוא את המאמר ייבוא נתוני אינדקס מ-BigQuery.
המאמרים הבאים
- סקירה כללית של תרחישי שימוש, תמחור ומגבלות של אינדקס וקטורי זמינה במאמר מבוא לחיפוש וקטורי.
- כאן מוסבר איך לבצע חיפוש וקטורי באמצעות הפונקציה
VECTOR_SEARCH. - איך מבצעים חיפוש סמנטי באמצעות הפונקציה
AI.SEARCH - מידע נוסף על דוח
CREATE VECTOR INDEX - אפשר לנסות את המדריך בנושא Search embeddings with vector search.