יצירת מחבר של תוכן

מחבר תוכן הוא תוכנת תוכנה שמשמשת לסריקה של הנתונים במאגר של הארגון ולאכלוס של מקור נתונים. Google מספקת את האפשרויות הבאות לפיתוח מחברים לתוכן:

  • ה-SDK של Content Connector. האפשרות הזו מתאימה אם אתם מתכנתים ב-Java. Content Connector SDK הוא מעטפת של API ל-REST שמאפשרת ליצור מחברים במהירות. במאמר יצירת מחבר תוכן באמצעות ה-SDK של Content Connector מוסבר איך יוצרים מחבר תוכן באמצעות ה-SDK.

  • API ל-REST ברמה נמוכה או ספריות API. אפשר להשתמש באפשרויות האלה אם אתם לא מתכנתים ב-Java, או אם קוד הבסיס שלכם מתאים יותר ל-API ל-REST או לספרייה. במאמר יצירת מחבר תוכן באמצעות ה-API ל-REST מוסבר איך יוצרים מחבר תוכן באמצעות ה-API ל-REST.

מחבר תוכן רגיל מבצע את הפעולות הבאות:

  1. קריאה ועיבוד של פרמטרים של הגדרות אישיות.
  2. משיכת קטעי נתונים נפרדים שניתנים להוספה לאינדקס, שנקראים פריטים, ממאגר התוכן של הצד השלישי.
  3. שילוב של רשימות ACL, מטא-נתונים ונתוני תוכן בפריטים שאפשר להוסיף לאינדקס.
  4. הוספת פריטים לאינדקס של מקור הנתונים של Cloud Search.
  5. (אופציונלי) האזנה להתראות על שינויים במאגר התוכן של הצד השלישי. התראות על שינויים מומרות לבקשות להוספת נתונים לאינדקס כדי לשמור על סנכרון בין מקור הנתונים של Cloud Search לבין המאגר של הצד השלישי. המחבר מבצע את המשימה הזו רק אם המאגר תומך בזיהוי שינויים.

יצירת מחבר תוכן באמצעות Content Connector SDK

בקטעים הבאים מוסבר איך ליצור מחבר תוכן באמצעות Content Connector SDK.

הגדרת יחסי תלות

כדי להשתמש ב-SDK, צריך לכלול יחסי תלות מסוימים בקובץ ה-build. לוחצים על אחת מהכרטיסיות הבאות כדי להציג את יחסי התלות של סביבת ה-build:

Maven

<dependency>
<groupId>com.google.enterprise.cloudsearch</groupId>
<artifactId>google-cloudsearch-indexing-connector-sdk</artifactId>
<version>v1-0.0.3</version>
</dependency>

Gradle

compile group: 'com.google.enterprise.cloudsearch',
        name: 'google-cloudsearch-indexing-connector-sdk',
        version: 'v1-0.0.3'

יצירת הגדרות המחבר

לכל מחבר יש קובץ תצורה שמכיל פרמטרים שבהם המחבר משתמש, כמו המזהה של המאגר. הפרמטרים מוגדרים כצמדים של מפתח-ערך, כמו api.sourceId=1234567890abcdef.

‏Google Cloud Search SDK מכיל כמה פרמטרים של הגדרות שסופקו על ידי Google, שבהם משתמשים כל המחברים. צריך להצהיר על הפרמטרים הבאים שסופקו על ידי Google בקובץ התצורה:

  • במחבר תוכן, צריך להצהיר על api.sourceId ו-api.serviceAccountPrivateKeyFile כי הפרמטרים האלה מזהים את המיקום של המאגר ואת המפתח הפרטי שנדרש כדי לגשת למאגר.
  • במחבר זהויות, צריך להצהיר על api.identitySourceId כי הפרמטר הזה מזהה את המיקום של מקור הזהויות החיצוני. אם אתם מסנכרנים משתמשים, עליכם גם להצהיר על api.customerId כמזהה הייחודי של חשבון Google Workspace של הארגון.

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

אפשר גם להגדיר פרמטרים משלכם ספציפיים למאגר לשימוש בקובץ התצורה.

העברת קובץ התצורה למחבר

מגדירים את מאפיין המערכת config כדי להעביר את קובץ התצורה למחבר. אפשר להגדיר את הנכס באמצעות הארגומנט -D כשמפעילים את המחבר. לדוגמה, הפקודה הבאה מפעילה את המחבר עם קובץ התצורה MyConfig.properties:

java -classpath myconnector.jar;... -Dconfig=MyConfig.properties MyConnector

אם הארגומנט הזה חסר, ה-SDK ינסה לגשת לקובץ ההגדרות שמוגדר כברירת מחדל בשם connector-config.properties.

הגדרת אסטרטגיית סריקה

התפקיד העיקרי של מחבר תוכן הוא לעבור מאגר ולסמן את הנתונים שלו ב-index. צריך להטמיע אסטרטגיית סריקה על סמך הגודל והפריסה של הנתונים במאגר. אתם יכולים לתכנן אסטרטגיה משלכם או לבחור באחת מהאסטרטגיות הבאות שמוטמעות ב-SDK:

אסטרטגיית סריקה מלאה

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

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

אסטרטגיית סריקה של רשימה

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

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

מעבר בתרשים

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

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

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

יצירת מחבר סריקה מלא באמצעות כיתה תבנית

הקטע הזה במסמכים מתייחס לקטעי קוד מהדוגמה FullTraversalSample.

הטמעת נקודת הכניסה של המחבר

נקודת הכניסה למחבר היא השיטה main(). המשימה העיקרית של השיטה הזו היא ליצור מופע של הכיתה Application ולהפעיל את השיטה start() שלה כדי להריץ את המחבר.

לפני שמפעילים את application.start(), משתמשים בכיתה IndexingApplication.Builder כדי ליצור מופע של התבנית FullTraversalConnector. הפונקציה FullTraversalConnector מקבלת אובייקט Repository שהשיטות שלו מטמיעים. קטע הקוד הבא מראה איך מטמיעים את השיטה main():

FullTraversalSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a full
 * traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new FullTraversalConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

מאחורי הקלעים, ה-SDK קורא ל-method‏ initConfig() אחרי ש-method‏ main() של המחבר קורא ל-Application.build. השיטה initConfig() מבצעת את הפעולות הבאות:

  1. קריאה ל-method‏ Configuation.isInitialized() כדי לוודא ש-Configuration לא הותחל.
  2. הפונקציה מפעילה אובייקט Configuration עם זוגות המפתח-ערך ש-Google מספקת. כל צמד מפתח/ערך מאוחסן באובייקט ConfigValue בתוך האובייקט Configuration.

הטמעת הממשק Repository

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

  • השיטה init(). כדי לבצע הגדרה ואתחול של מאגר נתונים, צריך לשנות את השיטה init().

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

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

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

כל אחת מהשיטות של האובייקט Repository מחזירה אובייקט מסוג כלשהו של ApiOperation. אובייקט ApiOperation מבצע פעולה בצורת קריאה אחת או כמה קריאות ל-IndexingService.indexItem() כדי לבצע את ההוספה בפועל לאינדקס של המאגר.

אחזור של פרמטרים מותאמים אישית של תצורה

כחלק מהטיפול בהגדרות המחבר, תצטרכו לקבל את כל הפרמטרים המותאמים אישית מהאובייקט Configuration. בדרך כלל, המשימה הזו מתבצעת בשיטה init() של הכיתה Repository.

לכיתה Configuration יש כמה שיטות לאחזור סוגי נתונים שונים מהגדרה. כל method מחזיר אובייקט ConfigValue. לאחר מכן, משתמשים ב-method‏ get() של האובייקט ConfigValue כדי לאחזר את הערך בפועל. קטע הקוד הבא, מ-FullTraversalSample, מראה איך לאחזר ערך שלם מותאם אישית יחיד מאובייקט Configuration:

FullTraversalSample.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

כדי לקבל ולנתח פרמטר שמכיל כמה ערכים, משתמשים באחד ממנתחי הסוגים של הכיתה Configuration כדי לנתח את הנתונים למקטעים נפרדים. קטע הקוד הבא, מהמחבר במדריך, משתמש ב-method‏ getMultiValue כדי לקבל רשימה של שמות המאגרים ב-GitHub:

GithubRepository.java
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

ביצוע טרנספורמציה מלאה

משנים את הערך של getAllDocs() כדי לבצע סריקה מלאה ולהוסיף את המאגר לאינדקס. השיטה getAllDocs() מקבלת נקודת עצירה. נקודת הבדיקה משמשת להמשך ההוספה לאינדקס בפריט ספציפי, אם התהליך מופרע. לכל פריט במאגר, מבצעים את השלבים הבאים ב-method‏ getAllDocs():

  1. מגדירים הרשאות.
  2. מגדירים את המטא-נתונים של הפריט שרוצים להוסיף לאינדקס.
  3. משלבים את המטא-נתונים והפריט לRepositoryDoc אחד שאפשר להוסיף לאינדקס.
  4. צריך לארוז כל פריט שאפשר להוסיף לאינדקס ב-iterator שמוחזר על ידי השיטה getAllDocs(). שימו לב ש-getAllDocs() מחזירה למעשה CheckpointCloseableIterable, שהיא חזרה על אובייקטים מסוג ApiOperation, כאשר כל אובייקט מייצג בקשת API שבוצעה על RepositoryDoc, למשל הוספה לאינדקס.

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

הגדרת ההרשאות לפריט

המאגר משתמש ברשימה של בקרת גישה (ACL) כדי לזהות את המשתמשים או הקבוצות שיש להם גישה לפריט. רשימת ACL היא רשימה של מזהי קבוצות או משתמשים שיש להם גישה לפריט.

צריך להעתיק את רשימת ה-ACL שבה משתמש המאגר כדי לוודא שרק משתמשים שיש להם גישה לפריט יכולים לראות אותו בתוצאת חיפוש. צריך לכלול את ה-ACL של פריט כשמוסיפים אותו לאינדקס, כדי של-Google Cloud Search יהיה את המידע הדרוש כדי לספק את רמת הגישה הנכונה לפריט.

ערכת ה-SDK של Content Connector מספקת קבוצה עשירה של שיטות וסוגים של רשימות ACL ליצירת מודל של רשימות ה-ACL ברוב המאגרים. כשאתם מוסיפים פריט לאינדקס, עליכם לנתח את רשימת ה-ACL של כל פריט במאגר וליצור רשימת ACL תואמת עבור חיפוש Google Cloud. אם רשימת ה-ACL של המאגר כוללת מושגים כמו ירושה של ACL, יכול להיות שיהיה קשה ליצור מודל של רשימת ה-ACL הזו. למידע נוסף על רשימות ACL של Google Cloud Search, אפשר לעיין במאמר רשימות ACL של Google Cloud Search.

הערה: Cloud Search Indexing API תומך ברשימות ACL של דומיין יחיד. הוא לא תומך ברשימות ACL בכמה דומיינים. משתמשים בכיתה Acl.Builder כדי להגדיר את הגישה לכל פריט באמצעות רשימת ACL. קטע הקוד הבא, שנלקח מהדוגמה המלאה לסריקה, מאפשר לכל המשתמשים או 'חשבונות המשתמשים' (getCustomerPrincipal()) להיות 'קוראים' של כל הפריטים (.setReaders()) כשהם מבצעים חיפוש.

FullTraversalSample.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

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

הגדרת המטא-נתונים של פריט

המטא-נתונים מאוחסנים באובייקט Item. כדי ליצור Item, צריך לפחות מזהה מחרוזת ייחודי, סוג פריט, ACL, כתובת URL וגרסה של הפריט. קטע הקוד הבא מראה איך ליצור Item באמצעות ה-helper class‏ IndexingItemBuilder.

FullTraversalSample.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Using the SDK item builder class to create the document with appropriate attributes
// (this can be expanded to include metadata fields etc.)
Item item = IndexingItemBuilder.fromConfiguration(Integer.toString(id))
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .build();

יצירת הפריט שאפשר להוסיף לאינדקס

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

FullTraversalSample.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %d", id);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

// Create the fully formed document
RepositoryDoc doc = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT)
    .build();

RepositoryDoc הוא סוג של ApiOperation שמבצע את הבקשה בפועל של IndexingService.indexItem().

אפשר גם להשתמש ב-method‏ setRequestMode() של הכיתה RepositoryDoc.Builder כדי לזהות את הבקשה להוספה לאינדקס בתור ASYNCHRONOUS או SYNCHRONOUS:

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

אריזה של כל פריט שאפשר להוסיף לאינדקס ב-iterator

השיטה getAllDocs() מחזירה Iterator, ובפרט CheckpointCloseableIterable, של אובייקטים מסוג RepositoryDoc. אפשר להשתמש בכיתה CheckpointClosableIterableImpl.Builder כדי ליצור מעבד חזרה ולהחזיר אותו. בקטע הקוד הבא מוסבר איך ליצור מעבד ומחזירים אותו.

FullTraversalSample.java
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(allDocs).build();

ה-SDK מבצע כל קריאה להוספה לאינדקס שמקיפה את המאיץ.

השלבים הבאים

הנה כמה שלבים אפשריים:

יצירת מחבר לסריקה של רשימה באמצעות כיתה של תבנית

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

הקטע הזה במסמכים מתייחס לקטעי קוד מהדוגמה ListTraversalSample.

הטמעת נקודת הכניסה של המחבר

נקודת הכניסה למחבר היא השיטה main(). המשימה העיקרית של השיטה הזו היא ליצור מופע של הכיתה Application ולהפעיל את השיטה start() שלה כדי להריץ את המחבר.

לפני שמפעילים את application.start(), משתמשים בכיתה IndexingApplication.Builder כדי ליצור מופע של התבנית ListingConnector. הפרמטר ListingConnector מקבל אובייקט Repository, שמטמיעים את השיטות שלו. קטע הקוד הבא מראה איך ליצור מופע של ListingConnector ושל Repository המשויך אליו:

ListTraversalSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a
 * list traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new ListingConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

מאחורי הקלעים, ה-SDK קורא ל-method‏ initConfig() אחרי ש-method‏ main() של המחבר קורא ל-Application.build. השיטה initConfig():

  1. קריאה ל-method‏ Configuation.isInitialized() כדי לוודא ש-Configuration לא הותחל.
  2. הפונקציה מפעילה אובייקט Configuration עם זוגות המפתח-ערך ש-Google מספקת. כל צמד מפתח/ערך מאוחסן באובייקט ConfigValue בתוך האובייקט Configuration.

הטמעת הממשק Repository

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

  • השיטה init(). כדי לבצע הגדרה ואתחול של מאגר נתונים, צריך לשנות את השיטה init().

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

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

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

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

כל אחת מהשיטות של האובייקט Repository מחזירה אובייקט מסוג כלשהו של ApiOperation. אובייקט ApiOperation מבצע פעולה בצורת קריאה אחת או כמה קריאות ל-IndexingService.indexItem() כדי לבצע את ההוספה בפועל לאינדקס של המאגר.

אחזור של פרמטרים מותאמים אישית של תצורה

כחלק מהטיפול בהגדרות המחבר, תצטרכו לקבל את כל הפרמטרים המותאמים אישית מהאובייקט Configuration. בדרך כלל, המשימה הזו מתבצעת בשיטה init() של הכיתה Repository.

לכיתה Configuration יש כמה שיטות לאחזור סוגי נתונים שונים מהגדרה. כל method מחזיר אובייקט ConfigValue. לאחר מכן, משתמשים ב-method‏ get() של האובייקט ConfigValue כדי לאחזר את הערך בפועל. קטע הקוד הבא, מ-FullTraversalSample, מראה איך לאחזר ערך שלם מותאם אישית יחיד מאובייקט Configuration:

FullTraversalSample.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

כדי לקבל ולנתח פרמטר שמכיל כמה ערכים, משתמשים באחד ממנתחי הסוגים של הכיתה Configuration כדי לנתח את הנתונים למקטעים נפרדים. קטע הקוד הבא, מהמחבר במדריך, משתמש ב-method‏ getMultiValue כדי לקבל רשימה של שמות המאגרים ב-GitHub:

GithubRepository.java
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

ביצוע סריקה של הרשימה

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

בשלב הבא, משנים את השיטה getDoc() כדי לטפל בכל פריט בתור ההוספה לאינדקס של Cloud Search.

דחיפת מזהי פריטים וערכים של גיבוב

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

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

  • אחזור של כל מזהה פריט וערך הגיבוב המשויך מהמאגר.
  • צריך לארוז כל זוג מזהה וערך גיבוב ב-PushItems.
  • משלבים כל PushItems ב-iterator שמוחזר על ידי השיטה getIds(). שימו לב ש-getIds() מחזירה למעשה CheckpointCloseableIterable, שהיא חזרה על אובייקטים מסוג ApiOperation, כאשר כל אובייקט מייצג בקשת API שבוצעה ב-RepositoryDoc, למשל דחיפת הפריטים לתור.

קטע הקוד הבא מראה איך לקבל כל מזהה פריט וערך גיבוב ולהוסיף אותם ל-PushItems. PushItems היא בקשה של ApiOperation להעברת פריט לתור ההוספה לאינדקס של Cloud Search.

ListTraversalSample.java
PushItems.Builder allIds = new PushItems.Builder();
for (Map.Entry<Integer, Long> entry : this.documents.entrySet()) {
  String documentId = Integer.toString(entry.getKey());
  String hash = this.calculateMetadataHash(entry.getKey());
  PushItem item = new PushItem().setMetadataHash(hash);
  log.info("Pushing " + documentId);
  allIds.addPushItem(documentId, item);
}

קטע הקוד הבא מראה איך להשתמש בכיתה PushItems.Builder כדי לארוז את המזהים ואת ערכי הגיבוב ב-push יחיד ApiOperation.

ListTraversalSample.java
ApiOperation pushOperation = allIds.build();
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(
      Collections.singletonList(pushOperation))
  .build();
return iterator;

הפריטים מועברים לתור ההוספה לאינדקס של Cloud Search לצורך עיבוד נוסף.

אחזור וטיפול בכל פריט

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

השיטה getDoc() מקבלת פריט מתור ההוספה לאינדקס של Google Cloud Search. לכל פריט בתור, מבצעים את השלבים הבאים ב-method‏ getDoc():

  1. בודקים אם המזהה של הפריט נמצא במאגר, בתוך התור להוספה לאינדקס של Cloud Search. אם לא, מוחקים את הפריט מהאינדקס.

  2. בודקים את סטטוס הפריט באינדקס. אם הפריט לא השתנה (ACCEPTED), לא עושים דבר.

  3. פריטים חדשים או פריטים שהשתנו באינדקס:

    1. מגדירים את ההרשאות.
    2. מגדירים את המטא-נתונים של הפריט שרוצים להוסיף לאינדקס.
    3. משלבים את המטא-נתונים והפריט לRepositoryDoc אחד שאפשר להוסיף לאינדקס.
    4. מחזירים את RepositoryDoc.

הערה: התבנית ListingConnector לא תומכת בהחזרת null בשיטה getDoc(). החזרת הערך null גורמת ליצירת NullPointerException.

טיפול בפריטים שנמחקו

בקטע הקוד הבא מוצג איך לקבוע אם פריט קיים במאגר, ואם לא, למחוק אותו.

ListTraversalSample.java
String resourceName = item.getName();
int documentId = Integer.parseInt(resourceName);

if (!documents.containsKey(documentId)) {
  // Document no longer exists -- delete it
  log.info(() -> String.format("Deleting document %s", item.getName()));
  return ApiOperations.deleteItem(resourceName);
}

חשוב לזכור ש-documents הוא מבנה נתונים שמייצג את המאגר. אם הערך documentID לא נמצא ב-documents, מחזירים את הערך APIOperations.deleteItem(resourceName) כדי למחוק את הפריט מהאינדקס.

טיפול בפריטים שלא השתנו

בקטע הקוד הבא מוצג איך לבדוק את סטטוס הפריט בתור ההוספה לאינדקס של Cloud Search ולטפל בפריט שלא השתנה.

ListTraversalSample.java
String currentHash = this.calculateMetadataHash(documentId);
if (this.canSkipIndexing(item, currentHash)) {
  // Document neither modified nor deleted, ack the push
  log.info(() -> String.format("Document %s not modified", item.getName()));
  PushItem pushItem = new PushItem().setType("NOT_MODIFIED");
  return new PushItems.Builder().addPushItem(resourceName, pushItem).build();
}

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

ListTraversalSample.java
/**
 * Checks to see if an item is already up to date
 *
 * @param previousItem Polled item
 * @param currentHash  Metadata hash of the current github object
 * @return PushItem operation
 */
private boolean canSkipIndexing(Item previousItem, String currentHash) {
  if (previousItem.getStatus() == null || previousItem.getMetadata() == null) {
    return false;
  }
  String status = previousItem.getStatus().getCode();
  String previousHash = previousItem.getMetadata().getHash();
  return "ACCEPTED".equals(status)
      && previousHash != null
      && previousHash.equals(currentHash);
}

הגדרת ההרשאות לפריט

המאגר משתמש ברשימה של בקרת גישה (ACL) כדי לזהות את המשתמשים או הקבוצות שיש להם גישה לפריט. רשימת ACL היא רשימה של מזהי קבוצות או משתמשים שיש להם גישה לפריט.

צריך להעתיק את רשימת ה-ACL שבה משתמש המאגר כדי לוודא שרק משתמשים שיש להם גישה לפריט יכולים לראות אותו בתוצאת חיפוש. צריך לכלול את ה-ACL של פריט כשמוסיפים אותו לאינדקס, כדי של-Google Cloud Search יהיה את המידע הדרוש כדי לספק את רמת הגישה הנכונה לפריט.

ערכת ה-SDK של Content Connector מספקת קבוצה עשירה של שיטות וסוגים של רשימות ACL ליצירת מודל של רשימות ה-ACL ברוב המאגרים. כשאתם מוסיפים פריט לאינדקס, עליכם לנתח את רשימת ה-ACL של כל פריט במאגר וליצור רשימת ACL תואמת עבור חיפוש Google Cloud. אם רשימת ה-ACL של המאגר כוללת מושגים כמו ירושה של ACL, יכול להיות שיהיה קשה ליצור מודל של רשימת ה-ACL הזו. למידע נוסף על רשימות ACL של Google Cloud Search, אפשר לעיין במאמר רשימות ACL של Google Cloud Search.

הערה: Cloud Search Indexing API תומך ברשימות ACL של דומיין יחיד. הוא לא תומך ברשימות ACL בכמה דומיינים. משתמשים בכיתה Acl.Builder כדי להגדיר את הגישה לכל פריט באמצעות רשימת ACL. קטע הקוד הבא, שנלקח מהדוגמה המלאה לסריקה, מאפשר לכל המשתמשים או 'חשבונות המשתמשים' (getCustomerPrincipal()) להיות 'קוראים' של כל הפריטים (.setReaders()) כשהם מבצעים חיפוש.

FullTraversalSample.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

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

הגדרת המטא-נתונים של פריט

המטא-נתונים מאוחסנים באובייקט Item. כדי ליצור Item, צריך לפחות מזהה מחרוזת ייחודי, סוג פריט, ACL, כתובת URL וגרסה של הפריט. קטע הקוד הבא מראה איך ליצור Item באמצעות ה-helper class‏ IndexingItemBuilder.

ListTraversalSample.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Set metadata hash so queue can detect changes
String metadataHash = this.calculateMetadataHash(documentId);

// Using the SDK item builder class to create the document with
// appropriate attributes. This can be expanded to include metadata
// fields etc.
Item item = IndexingItemBuilder.fromConfiguration(Integer.toString(documentId))
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .setHash(metadataHash)
    .build();

יצירת פריט שאפשר להוסיף לאינדקס

אחרי שמגדירים את המטא-נתונים של הפריט, אפשר ליצור את הפריט שאפשר להוסיף לאינדקס באמצעות הפקודה RepositoryDoc.Builder. בדוגמה הבאה מוסבר איך ליצור פריט יחיד שאפשר להוסיף לאינדקס.

ListTraversalSample.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %d", documentId);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

// Create the fully formed document
RepositoryDoc doc = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT)
    .build();

RepositoryDoc הוא סוג של ApiOperation שמבצע את הבקשה בפועל של IndexingService.indexItem().

אפשר גם להשתמש ב-method‏ setRequestMode() של הכיתה RepositoryDoc.Builder כדי לזהות את הבקשה להוספה לאינדקס בתור ASYNCHRONOUS או SYNCHRONOUS:

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

השלבים הבאים

הנה כמה שלבים אפשריים:

  • (אופציונלי) מטמיעים את השיטה close() כדי לשחרר את המשאבים לפני ההשבתה.
  • (אופציונלי) יוצרים מחבר זהויות באמצעות Content Connector SDK.

יצירת מחבר לסריקה של גרף באמצעות כיתה של תבנית

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

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

הקטע הזה במסמכים מתייחס לקטעי קוד מהדוגמה GraphTraversalSample.

הטמעת נקודת הכניסה של המחבר

נקודת הכניסה למחבר היא השיטה main(). המשימה העיקרית של השיטה הזו היא ליצור מופע של הכיתה Application ולהפעיל את השיטה start() שלה כדי להריץ את המחבר.

לפני שמפעילים את application.start(), צריך להשתמש בכיתה IndexingApplication.Builder כדי ליצור מופע של התבנית ListingConnector. הפונקציה ListingConnector מקבלת אובייקט Repository שהשיטות שלו מטמיעים.

קטע הקוד הבא מראה איך ליצור מופע של ListingConnector ושל Repository המשויך אליו:

GraphTraversalSample.java
/**
 * This sample connector uses the Cloud Search SDK template class for a graph
 * traversal connector.
 *
 * @param args program command line arguments
 * @throws InterruptedException thrown if an abort is issued during initialization
 */
public static void main(String[] args) throws InterruptedException {
  Repository repository = new SampleRepository();
  IndexingConnector connector = new ListingConnector(repository);
  IndexingApplication application = new IndexingApplication.Builder(connector, args).build();
  application.start();
}

מאחורי הקלעים, ה-SDK קורא ל-method‏ initConfig() אחרי ש-method‏ main() של המחבר קורא ל-Application.build. השיטה initConfig():

  1. קריאה ל-method‏ Configuation.isInitialized() כדי לוודא ש-Configuration לא הותחל.
  2. הפונקציה מפעילה אובייקט Configuration עם זוגות המפתח-ערך ש-Google מספקת. כל צמד מפתח/ערך מאוחסן באובייקט ConfigValue בתוך האובייקט Configuration.

הטמעת הממשק Repository

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

  • השיטה init(). כדי לבצע הגדרה ואתחול של מאגר נתונים, צריך לשנות את השיטה init().

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

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

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

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

כל אחת מהשיטות של האובייקט Repository מחזירה אובייקט מסוג ApiOperation. אובייקט ApiOperation מבצע פעולה בצורת קריאה אחת או כמה קריאות ל-IndexingService.indexItem() כדי לבצע את ההוספה בפועל לאינדקס של המאגר.

אחזור של פרמטרים מותאמים אישית של תצורה

כחלק מהטיפול בהגדרות המחבר, תצטרכו לקבל את כל הפרמטרים המותאמים אישית מהאובייקט Configuration. בדרך כלל, המשימה הזו מתבצעת בשיטה init() של הכיתה Repository.

לכיתה Configuration יש כמה שיטות לאחזור סוגי נתונים שונים מהגדרה. כל method מחזיר אובייקט ConfigValue. לאחר מכן, משתמשים ב-method‏ get() של האובייקט ConfigValue כדי לאחזר את הערך בפועל. קטע הקוד הבא, מ-FullTraversalSample, מראה איך לאחזר ערך שלם מותאם אישית יחיד מאובייקט Configuration:

FullTraversalSample.java
@Override
public void init(RepositoryContext context) {
  log.info("Initializing repository");
  numberOfDocuments = Configuration.getInteger("sample.documentCount", 10).get();
}

כדי לקבל ולנתח פרמטר שמכיל כמה ערכים, משתמשים באחד ממנתחי הסוגים של הכיתה Configuration כדי לנתח את הנתונים למקטעים נפרדים. קטע הקוד הבא, מהמחבר במדריך, משתמש ב-method‏ getMultiValue כדי לקבל רשימה של שמות המאגרים ב-GitHub:

GithubRepository.java
ConfigValue<List<String>> repos = Configuration.getMultiValue(
    "github.repos",
    Collections.emptyList(),
    Configuration.STRING_PARSER);

ביצוע סריקה של הגרף

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

בשלב הבא, משנים את השיטה getDoc() כדי לטפל בכל פריט בתור ההוספה לאינדקס של Cloud Search.

דחיפת מזהי פריטים וערכים של גיבוב

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

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

  • אחזור של כל מזהה פריט וערך הגיבוב המשויך מהמאגר.
  • צריך לארוז כל זוג מזהה וערך גיבוב ב-PushItems.
  • משלבים כל PushItems ב-iterator שמוחזר על ידי השיטה getIds(). שימו לב ש-getIds() מחזירה למעשה CheckpointCloseableIterable, שהיא חזרה על אובייקטים מסוג ApiOperation, כאשר כל אובייקט מייצג בקשת API שבוצעה ב-RepositoryDoc, למשל דחיפת הפריטים לתור.

קטע הקוד הבא מראה איך לקבל כל מזהה פריט וערך גיבוב ולהוסיף אותם ל-PushItems. PushItems היא בקשה של ApiOperation להעברת פריט לתור ההוספה לאינדקס של Cloud Search.

GraphTraversalSample.java
PushItems.Builder allIds = new PushItems.Builder();
PushItem item = new PushItem();
allIds.addPushItem("root", item);

קטע הקוד הבא מראה איך להשתמש בכיתה PushItems.Builder כדי לארוז את המזהים ואת ערכי הגיבוב ב-push אחד ApiOperation.

GraphTraversalSample.java
ApiOperation pushOperation = allIds.build();
CheckpointCloseableIterable<ApiOperation> iterator =
  new CheckpointCloseableIterableImpl.Builder<>(
      Collections.singletonList(pushOperation))
  .build();

הפריטים מועברים לתור ההוספה לאינדקס של Cloud Search לצורך עיבוד נוסף.

אחזור וטיפול בכל פריט

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

השיטה getDoc() מקבלת פריט מהתור להוספה לאינדקס של Cloud Search. לכל פריט בתור, מבצעים את השלבים הבאים ב-method‏ getDoc():

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

  2. פריטים חדשים או פריטים שהשתנו באינדקס:

    1. מגדירים את ההרשאות.
    2. מגדירים את המטא-נתונים של הפריט שרוצים להוסיף לאינדקס.
    3. משלבים את המטא-נתונים והפריט לRepositoryDoc אחד שאפשר להוסיף לאינדקס.
    4. מוסיפים את מזהי הצאצאים לתור של ניהול האינדקס ב-Cloud Search לצורך עיבוד נוסף.
    5. מחזירים את RepositoryDoc.

טיפול בפריטים שנמחקו

קטע הקוד הבא מראה איך לקבוע אם פריט קיים באינדקס, ואם לא, למחוק אותו.

GraphTraversalSample.java
String resourceName = item.getName();
if (documentExists(resourceName)) {
  return buildDocumentAndChildren(resourceName);
}
// Document doesn't exist, delete it
log.info(() -> String.format("Deleting document %s", resourceName));
return ApiOperations.deleteItem(resourceName);

הגדרת ההרשאות לפריט

המאגר משתמש ברשימה של בקרת גישה (ACL) כדי לזהות את המשתמשים או הקבוצות שיש להם גישה לפריט. רשימת ACL היא רשימה של מזהי קבוצות או משתמשים שיש להם גישה לפריט.

צריך להעתיק את רשימת ה-ACL שבה משתמש המאגר כדי לוודא שרק משתמשים שיש להם גישה לפריט יכולים לראות אותו בתוצאת חיפוש. צריך לכלול את ה-ACL של פריט כשמוסיפים אותו לאינדקס, כדי של-Google Cloud Search יהיה את המידע הדרוש כדי לספק את רמת הגישה הנכונה לפריט.

ערכת ה-SDK של Content Connector מספקת קבוצה עשירה של שיטות וסוגים של רשימות ACL ליצירת מודל של רשימות ה-ACL ברוב המאגרים. כשאתם מוסיפים פריט לאינדקס, עליכם לנתח את רשימת ה-ACL של כל פריט במאגר וליצור רשימת ACL תואמת עבור חיפוש Google Cloud. אם רשימת ה-ACL של המאגר כוללת מושגים כמו ירושה של ACL, יכול להיות שיהיה קשה ליצור מודל של רשימת ה-ACL הזו. למידע נוסף על רשימות ACL של Google Cloud Search, אפשר לעיין במאמר רשימות ACL של Google Cloud Search.

הערה: Cloud Search Indexing API תומך ברשימות ACL של דומיין יחיד. הוא לא תומך ברשימות ACL בכמה דומיינים. משתמשים בכיתה Acl.Builder כדי להגדיר את הגישה לכל פריט באמצעות רשימת ACL. קטע הקוד הבא, שנלקח מהדוגמה המלאה לסריקה, מאפשר לכל המשתמשים או 'חשבונות המשתמשים' (getCustomerPrincipal()) להיות 'קוראים' של כל הפריטים (.setReaders()) כשהם מבצעים חיפוש.

FullTraversalSample.java
// Make the document publicly readable within the domain
Acl acl = new Acl.Builder()
    .setReaders(Collections.singletonList(Acl.getCustomerPrincipal()))
    .build();

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

הגדרת המטא-נתונים של פריט

המטא-נתונים מאוחסנים באובייקט Item. כדי ליצור Item, צריך לפחות מזהה מחרוזת ייחודי, סוג פריט, ACL, כתובת URL וגרסה של הפריט. קטע הקוד הבא מראה איך ליצור Item באמצעות ה-helper class‏ IndexingItemBuilder.

GraphTraversalSample.java
// Url is required. Use google.com as a placeholder for this sample.
String viewUrl = "https://www.google.com";

// Version is required, set to current timestamp.
byte[] version = Longs.toByteArray(System.currentTimeMillis());

// Using the SDK item builder class to create the document with
// appropriate attributes. This can be expanded to include metadata
// fields etc.
Item item = IndexingItemBuilder.fromConfiguration(documentId)
    .setItemType(IndexingItemBuilder.ItemType.CONTENT_ITEM)
    .setAcl(acl)
    .setSourceRepositoryUrl(IndexingItemBuilder.FieldOrValue.withValue(viewUrl))
    .setVersion(version)
    .build();

יצירת הפריט שאפשר להוסיף לאינדקס

אחרי שמגדירים את המטא-נתונים של הפריט, אפשר ליצור את הפריט שאפשר להוסיף לאינדקס באמצעות הפקודה RepositoryDoc.Builder. בדוגמה הבאה מוסבר איך ליצור פריט יחיד שאפשר להוסיף לאינדקס.

GraphTraversalSample.java
// For this sample, content is just plain text
String content = String.format("Hello world from sample doc %s", documentId);
ByteArrayContent byteContent = ByteArrayContent.fromString("text/plain", content);

RepositoryDoc.Builder docBuilder = new RepositoryDoc.Builder()
    .setItem(item)
    .setContent(byteContent, IndexingService.ContentFormat.TEXT);

RepositoryDoc הוא סוג של ApiOperation שמבצע את הבקשה בפועל של IndexingService.indexItem().

אפשר גם להשתמש ב-method‏ setRequestMode() של הכיתה RepositoryDoc.Builder כדי לזהות את הבקשה להוספה לאינדקס בתור ASYNCHRONOUS או SYNCHRONOUS:

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

הוספת מזהי הצאצאים לתור של ניהול האינדקס ב-Cloud Search

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

GraphTraversalSample.java
// Queue the child nodes to visit after indexing this document
Set<String> childIds = getChildItemNames(documentId);
for (String id : childIds) {
  log.info(() -> String.format("Pushing child node %s", id));
  PushItem pushItem = new PushItem();
  docBuilder.addChildId(id, pushItem);
}

RepositoryDoc doc = docBuilder.build();

השלבים הבאים

הנה כמה שלבים אפשריים:

  • (אופציונלי) מטמיעים את השיטה close() כדי לשחרר את המשאבים לפני ההשבתה.
  • (אופציונלי) יוצרים מחבר זהויות באמצעות Identity Connector SDK.

יצירת מחבר תוכן באמצעות ה-API ל-REST

בקטעים הבאים מוסבר איך ליצור מחבר תוכן באמצעות ה-API ל-REST.

הגדרת אסטרטגיית סריקה

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

אסטרטגיית סריקה מלאה

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

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

אסטרטגיית סריקה של רשימה

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

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

מעבר בתרשים

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

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

הטמעת שיטת הניווט והוספת פריטים לאינדקס

כל רכיב שאפשר להוסיף לאינדקס של Cloud Search נקרא פריט ב-Cloud Search API. פריט יכול להיות קובץ, תיקייה, שורה בקובץ CSV או רשומה במסד נתונים.

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

  1. (אופציונלי) שימוש ב-items.upload כדי להעלות קבצים גדולים מ-100KiB להוספה לאינדקס. בקבצים קטנים יותר, אפשר להטמיע את התוכן בתור inlineContent באמצעות items.index.

  2. (אופציונלי) שימוש ב-media.upload כדי להעלות קובצי מדיה להוספה לאינדקס.

  3. שימוש ב-items.index כדי להוסיף את הפריט לאינדקס. לדוגמה, אם בסכימה שלכם נעשה שימוש בהגדרת האובייקט בסכימה של סרט, בקשת ההוספה לאינדקס של פריט יחיד תיראה כך:

    {
      "name": "datasource/<data_source_id>/items/titanic",
      "acl": {
        "readers": [
          {
            "gsuitePrincipal": {
              "gsuiteDomain": true
            }
          }
        ]
      },
      "metadata": {
        "title": "Titanic",
        "viewUrl": "http://www.imdb.com/title/tt2234155/?ref_=nv_sr_1",
        "objectType": "movie"
      },
      "structuredData": {
        "object": {
          "properties": [
            {
              "name": "movieTitle",
              "textValues": {
                "values": [
                  "Titanic"
                ]
              }
            },
            {
              "name": "releaseDate",
              "dateValues": {
                "values": [
                  {
                    "year": 1997,
                    "month": 12,
                    "day": 19
                  }
                ]
              }
            },
            {
              "name": "actorName",
              "textValues": {
                "values": [
                  "Leonardo DiCaprio",
                  "Kate Winslet",
                  "Billy Zane"
                ]
              }
            },
            {
              "name": "genre",
              "enumValues": {
                "values": [
                  "Drama",
                  "Action"
                ]
              }
            },
            {
              "name": "userRating",
              "integerValues": {
                "values": [
                  8
                ]
              }
            },
            {
              "name": "mpaaRating",
              "textValues": {
                "values": [
                  "PG-13"
                ]
              }
            },
            {
              "name": "duration",
              "textValues": {
                "values": [
                  "3 h 14 min"
                ]
              }
            }
          ]
        }
      },
      "content": {
        "inlineContent": "A seventeen-year-old aristocrat falls in love with a kind but poor artist aboard the luxurious, ill-fated R.M.S. Titanic.",
        "contentFormat": "TEXT"
      },
      "version": "01",
      "itemType": "CONTENT_ITEM"
    }
    
  4. (אופציונלי) שימוש בקריאות items.get כדי לוודא שפריט נוסף לאינדקס.

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

טיפול בשינויים במאגר

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

במקום להשתמש בקריאות להוספה לאינדקס כדי להוסיף לאינדקס מאגר שלם מדי פעם, אפשר גם להשתמש בתור ההוספה לאינדקס של Google Cloud כמנגנון למעקב אחרי שינויים ולהוספה לאינדקס רק של הפריטים שהשתנו. אפשר להשתמש בבקשות items.push כדי לדחוף פריטים לתור לצורך בדיקה ועדכון מאוחר יותר. למידע נוסף על תור ההוספה לאינדקס של Google Cloud, קראו את המאמר תור ההוספה לאינדקס של Google Cloud.

מידע נוסף על Google Cloud Search API זמין במאמר Cloud Search API.