בדף הזה מוסבר איך להשתמש בחיפוש משוער כחלק מחיפוש טקסט מלא.
בנוסף לביצוע חיפושים מדויקים של טוקנים באמצעות הפונקציות SEARCH ו-SEARCH_SUBSTRING, Spanner תומך גם בחיפושים משוערים (או לא מדויקים). חיפושים משוערים מוצאים מסמכים תואמים למרות הבדלים קטנים בין השאילתה לבין המסמך.
Spanner תומך בסוגים הבאים של חיפוש משוער:
- חיפוש משוער מבוסס N-grams
- חיפוש פונטי באמצעות Soundex
שימוש בחיפוש משוער שמבוסס על n-גרמות
חיפוש משוער שמבוסס על N-גרמים מסתמך על אותו תהליך של טוקניזציה של מחרוזות משנה שנדרש בחיפוש מחרוזות משנה. ההגדרה של הטוקנייזר חשובה כי היא משפיעה על איכות החיפוש ועל הביצועים. בדוגמה הבאה מוצג איך ליצור שאילתה עם מילים שמאויתות בצורה שונה או עם שגיאות איות, כדי למצוא התאמות משוערות באינדקס החיפוש.
סכימה
GoogleSQL
CREATE TABLE Albums (
AlbumId STRING(MAX) NOT NULL,
AlbumTitle STRING(MAX),
AlbumTitle_Tokens TOKENLIST AS (
TOKENIZE_SUBSTRING(AlbumTitle, ngram_size_min=>2, ngram_size_max=>3,
relative_search_types=>["word_prefix", "word_suffix"])) HIDDEN
) PRIMARY KEY(AlbumId);
CREATE SEARCH INDEX AlbumsIndex
ON Albums(AlbumTitle_Tokens)
STORING (AlbumTitle);
PostgreSQL
בדוגמה הזו נעשה שימוש ב-spanner.tokenize_substring.
CREATE TABLE albums (
albumid character varying NOT NULL,
albumtitle character varying,
albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (
spanner.tokenize_substring(albumtitle, ngram_size_min=>2, ngram_size_max=>3,
relative_search_types=>'{word_prefix, word_suffix}'::text[])) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));
CREATE SEARCH INDEX albumsindex
ON albums(albumtitle_tokens)
INCLUDE (albumtitle);
שאילתה
השאילתה הבאה מוצאת את האלבומים שהשמות שלהם הכי קרובים ל-"Hatel Kaliphorn", כמו "Hotel California".
GoogleSQL
SELECT AlbumId
FROM Albums
WHERE SEARCH_NGRAMS(AlbumTitle_Tokens, "Hatel Kaliphorn")
ORDER BY SCORE_NGRAMS(AlbumTitle_Tokens, "Hatel Kaliphorn") DESC
LIMIT 10
PostgreSQL
בדוגמה הזו נעשה שימוש ב-spanner.score_ngrams וב-spanner.search_ngrams.
SELECT albumid
FROM albums
WHERE spanner.search_ngrams(albumtitle_tokens, 'Hatel Kaliphorn')
ORDER BY spanner.score_ngrams(albumtitle_tokens, 'Hatel Kaliphorn') DESC
LIMIT 10
אופטימיזציה של הביצועים וההחזרה של חיפוש משוער שמבוסס על n-גרמים
השאילתה לדוגמה בקטע הקודם מחפשת בשני שלבים, באמצעות שתי פונקציות שונות:
-
SEARCH_NGRAMSמציאת כל האלבומים הפוטנציאליים שכוללים n-גרמים משותפים עם שאילתת החיפוש. לדוגמה, n-גרמות של שלושה תווים עבור המילה California כוללות את[cal, ali, lif, ifo, for, orn, rni, nia]ועבור המילה Kaliphorn כוללות את[kal, ali, lip, iph, pho, hor, orn]. ה-n-grams המשותפים במערכי הנתונים האלה הם[ali, orn]. כברירת מחדל,SEARCH_NGRAMSמתאים לכל המסמכים עם לפחות שני n-גרמים משותפים, ולכן 'Kaliphorn' מתאים ל-'California'. -
SCORE_NGRAMSמדרג את ההתאמות לפי מידת הדמיון. הדמיון בין שתי מחרוזות מוגדר כיחס בין n-גרמים משותפים ייחודיים לבין n-גרמים לא משותפים ייחודיים:
בדרך כלל שאילתת החיפוש זהה בפונקציות SEARCH_NGRAMS ו-SCORE_NGRAMS. הדרך המומלצת לעשות זאת היא להשתמש בארגומנט עם פרמטרים של שאילתה ולא עם מחרוזות מילוליות, ולציין את אותו פרמטר של שאילתה בפונקציות SEARCH_NGRAMS ו-SCORE_NGRAMS.
ל-Spanner יש שלושה ארגומנטים להגדרה שאפשר להשתמש בהם עם SEARCH_NGRAMS:
- הגודל המינימלי והמקסימלי של n-גרם מצוין באמצעות הפונקציות
TOKENIZE_SUBSTRINGאוTOKENIZE_NGRAMS. אנחנו לא ממליצים על n-גרמים של תו אחד כי הם יכולים להתאים למספר גדול מאוד של מסמכים. מצד שני, n-grams ארוכים גורמים ל-SEARCH_NGRAMSלפספס מילים קצרות עם איות שגוי. - מספר ה-n-grams המינימלי שצריך להיות זהה (מוגדר באמצעות הארגומנטים
min_ngramsו-min_ngrams_percentבפונקציהSEARCH_NGRAMS). בדרך כלל, מספרים גבוהים יותר מזרזים את השאילתה, אבל מקטינים את ההחזרה.SEARCH_NGRAMS
כדי להשיג איזון טוב בין ביצועים לבין היכולת לאחזר מידע, אפשר להגדיר את הארגומנטים האלה כך שיתאימו לשאילתה ולעומס העבודה הספציפיים.
מומלץ גם להוסיף LIMIT פנימי כדי להימנע מיצירת שאילתות יקרות מאוד כשנתקלים בשילוב של n-גרמות פופולריות.
GoogleSQL
SELECT AlbumId
FROM (
SELECT AlbumId,
SCORE_NGRAMS(AlbumTitle_Tokens, @p) AS score
FROM Albums
WHERE SEARCH_NGRAMS(AlbumTitle_Tokens, @p)
LIMIT 10000 # inner limit
)
ORDER BY score DESC
LIMIT 10 # outer limit
PostgreSQL
בדוגמה הזו נעשה שימוש ב-spanner.score_ngrams וב-spanner.search_ngrams.
פרמטר השאילתה $1 קשור ל-'Hatel Kaliphorn'.
SELECT albumid
FROM
(
SELECT albumid, spanner.score_ngrams(albumtitle_tokens, $1) AS score
FROM albums
WHERE spanner.search_ngrams(albumtitle_tokens, $1)
LIMIT 10000
) AS inner_query
ORDER BY inner_query.score DESC
LIMIT 10
חיפוש משוער מבוסס N-grams לעומת מצב שאילתה משופר
בנוסף לחיפוש משוער שמבוסס על n-grams, מצב השאילתה המשופר מטפל גם במילים מסוימות עם שגיאות איות. לכן יש חפיפה מסוימת בין שתי התכונות. בטבלה הבאה מפורטים ההבדלים:
| חיפוש משוער שמבוסס על n-גרמים | מצב שאילתה משופר | |
| עלות | נדרשת טוקניזציה יקרה יותר של מחרוזת משנה שמבוססת על n-גרמים | נדרשת טוקניזציה מלאה של הטקסט בעלות נמוכה יותר |
| סוגי שאילתות חיפוש | היא מתאימה במיוחד למסמכים קצרים עם כמה מילים, למשל שם של אדם, שם של עיר או שם של מוצר | הוא פועל בצורה טובה באותה מידה עם מסמכים בכל הגדלים ועם שאילתות חיפוש בכל הגדלים |
| חיפוש מילים חלקיות | מבצע חיפוש של מחרוזת משנה שמאפשרת שגיאות איות | תומך רק בחיפוש של מילים שלמות (SEARCH_SUBSTRING
לא תומך בארגומנט enhance_query)
|
| מילים עם שגיאות איות | תמיכה במילים עם שגיאות איות באינדקס או בשאילתה | התכונה תומכת רק במילים עם שגיאות איות בשאילתה |
| תיקונים | חיפוש של התאמות עם שגיאות כתיב, גם אם ההתאמה היא לא מילה אמיתית | תיקון שגיאות איות במילים נפוצות ומוכרות |
ביצוע חיפוש פונטי באמצעות Soundex
ב-Spanner יש פונקציה SOUNDEX שמאפשרת למצוא מילים שמאויתות בצורה שונה אבל נשמעות אותו דבר. לדוגמה, SOUNDEX("steven"), SOUNDEX("stephen") ו-SOUNDEX("stefan") הם כולם s315, ואילו SOUNDEX("stella") הוא s340. הפונקציה SOUNDEX היא תלוית אותיות רישיות, והיא פועלת רק באלפבית שמבוסס על לטינית.
אפשר להטמיע חיפוש פונטי עם SOUNDEX באמצעות עמודה שנוצרה ואינדקס חיפוש, כמו בדוגמה הבאה:
GoogleSQL
CREATE TABLE Singers (
SingerId INT64,
AlbumTitle STRING(MAX),
AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
Name STRING(MAX),
NameSoundex STRING(MAX) AS (LOWER(SOUNDEX(Name))),
NameSoundex_Tokens TOKENLIST AS (TOKEN(NameSoundex)) HIDDEN
) PRIMARY KEY(SingerId);
CREATE SEARCH INDEX SingersPhoneticIndex ON Singers(AlbumTitle_Tokens, NameSoundex_Tokens);
PostgreSQL
בדוגמה הזו נעשה שימוש ב-spanner.soundex.
CREATE TABLE singers (
singerid bigint,
albumtitle character varying,
albumtitle_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(albumtitle)) VIRTUAL HIDDEN,
name character varying,
namesoundex character varying GENERATED ALWAYS AS (lower(spanner.soundex(name))) VIRTUAL,
namesoundex_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.token(lower(spanner.soundex(name))) VIRTUAL HIDDEN,
PRIMARY KEY(singerid));
CREATE SEARCH INDEX singersphoneticindex ON singers(albumtitle_tokens, namesoundex_tokens);
השאילתה הבאה מתאימה ל-"stefan" ל-"Steven" ב-SOUNDEX, יחד עם
AlbumTitle שמכיל "cat":
GoogleSQL
SELECT SingerId
FROM Singers
WHERE NameSoundex = LOWER(SOUNDEX("stefan")) AND SEARCH(AlbumTitle_Tokens, "cat")
PostgreSQL
SELECT singerid
FROM singers
WHERE namesoundex = lower(spanner.soundex('stefan')) AND spanner.search(albumtitle_tokens, 'cat')
המאמרים הבאים
- מידע על יצירת טוקנים ועל כלי ליצירת טוקנים ב-Spanner
- מידע נוסף על אינדקסים של חיפושים
- מידע נוסף על שאילתות חיפוש בטקסט מלא