AppSearch

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

דיאגרמה שממחישה את תהליך ההוספה לאינדקס והחיפוש ב-AppSearch

התכונות של AppSearch:

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

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

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

הגדרה

כדי להשתמש ב-AppSearch באפליקציה, מוסיפים את יחסי התלות הבאים לקובץ build.gradle של האפליקציה:

מגניב

dependencies {
    def appsearch_version = "1.2.0-alpha02"

    implementation "androidx.appsearch:appsearch:$appsearch_version"
    // Use kapt instead of annotationProcessor if writing Kotlin classes
    annotationProcessor "androidx.appsearch:appsearch-compiler:$appsearch_version"

    implementation "androidx.appsearch:appsearch-local-storage:$appsearch_version"
    // PlatformStorage is compatible with Android 12+ devices and supports sharing data
    // with other apps. Feature support varies by device. Before calling an API that
    // requires a feature, check Features.isFeatureSupported().
    implementation "androidx.appsearch:appsearch-platform-storage:$appsearch_version"

    // PlayServicesStorage is compatible with all devices that support Google Play Services on
    // all API levels. It offers similar capabilities to PlatformStorage and is the
    // recommended solution for lower API levels on which PlatformStorage is not supported.
    implementation "androidx.appsearch:appsearch-play-services-storage:$appsearch_version"
}

Kotlin

dependencies {
    val appsearch_version = "1.2.0-alpha02"

    implementation("androidx.appsearch:appsearch:$appsearch_version")
    // Use annotationProcessor instead of kapt if writing Java classes
    kapt("androidx.appsearch:appsearch-compiler:$appsearch_version")

    implementation("androidx.appsearch:appsearch-local-storage:$appsearch_version")
    // PlatformStorage is compatible with Android 12+ devices and supports sharing data
    // with other apps. Feature support varies by device. Before calling an API that
    // requires a feature, check Features.isFeatureSupported().
    implementation("androidx.appsearch:appsearch-platform-storage:$appsearch_version")

    // PlayServicesStorage is compatible with all devices that support Google Play Services on
    // all API levels. It offers similar capabilities to PlatformStorage and is the
    // recommended solution for lower API levels on which PlatformStorage is not supported.
    implementation("androidx.appsearch:appsearch-play-services-storage:$appsearch_version")

}

מושגים ב-AppSearch

התרשים הבא ממחיש את המושגים של AppSearch ואת האינטראקציות שלהם.

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

מסד נתונים וסשן

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

סכימה וסוגי סכימות

סכימה מייצגת את המבנה הארגוני של הנתונים במסד נתונים של AppSearch.

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

מסמכים

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

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

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

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

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

אחסון בפלטפורמה, אחסון מקומי או אחסון ב-Play Services

ב-AppSearch יש שלושה פתרונות אחסון: LocalStorage, ‏ PlatformStorage ו-PlayServicesStorage. באמצעות LocalStorage, האפליקציה מנהלת אינדקס ספציפי לאפליקציה שנמצא בספריית הנתונים של האפליקציה. גם ב-PlatformStorage וגם ב-PlayServicesStorage, האפליקציה תורמת לאינדקס מרכזי ברמת המערכת. האינדקס של PlatformStorage מתארח בשרת המערכת והאינדקס של PlayServicesStorage מתארח באחסון של Google Play Services. הגישה לנתונים באינדקסים המרכזיים האלה מוגבלת לנתונים שהאפליקציה שלכם תרמה, ולנתונים שאפליקציה אחרת שיתפה איתכם באופן מפורש. כל אפשרויות האחסון האלה משתמשות באותו API, ואפשר להחליף ביניהן בהתאם לגרסת המכשיר.

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

הקוד הבא יוצר סשן PlatformStorage ב-Android מגרסה 12 (רמת API ‏31) ומעלה, וסשן PlayServicesStorage או LocalStorage בגרסאות קודמות:

Kotlin

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    appSearchSessionFuture.setFuture(
        PlatformStorage.createSearchSession(
            PlatformStorage.SearchContext.Builder(mContext, DATABASE_NAME)
               .build()
        )
    )
} else {
    if (usePlayServicesStorageBelowS) {
        appSearchSessionFuture.setFuture(
            PlayServicesStorage.createSearchSession(
                PlayServicesStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                    .build()
            )
        )
    } else {
        appSearchSessionFuture.setFuture(
            LocalStorage.createSearchSession(
                LocalStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                    .build()
            )
        )
    }
}

Java

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    mAppSearchSessionFuture.setFuture(PlatformStorage.createSearchSession(
            new PlatformStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                    .build()));
} else {
    if (usePlayServicesStorageBelowS) {
        mAppSearchSessionFuture.setFuture(PlayServicesStorage.createSearchSession(
                new PlayServicesStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                        .build()));
    } else {
        mAppSearchSessionFuture.setFuture(LocalStorage.createSearchSession(
                new LocalStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                        .build()));
    }
}

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

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

תכונות LocalStorage (תואם ל-Android מגרסה 5.0 ואילך) PlatformStorage (תואם ל-Android מגרסה 12 ואילך) PlayServicesStorage (תואם ל-Android מגרסה 5.0 ואילך)
חיפוש יעיל של טקסט מלא
תמיכה בכמה שפות
גודל קובץ בינארי מוקטן
שיתוף נתונים בין אפליקציות
יכולת להציג נתונים בממשק המשתמש של המערכת
אפשר להוסיף לאינדקס מספר בלתי מוגבל של מסמכים בכל גודל
פעולות מהירות יותר בלי זמן אחזור נוסף של ה-binder

יש עוד שיקולים שצריך להביא בחשבון כשבוחרים בין LocalStorage לבין PlatformStorage. מכיוון ש-PlatformStorage עוטף את ממשקי ה-API של Jetpack מעל שירות המערכת של AppSearch, ההשפעה על גודל ה-APK היא מינימלית בהשוואה לשימוש ב-LocalStorage. עם זאת, המשמעות היא גם שפעולות AppSearch גורמות לזמן אחזור נוסף של ה-binder כשמתבצעת קריאה לשירות המערכת של AppSearch. ב-PlatformStorage, ‫AppSearch מגביל את מספר המסמכים ואת גודל המסמכים שאפליקציה יכולה להוסיף לאינדקס כדי להבטיח אינדקס מרכזי יעיל. גם ל-PlayServicesStorage יש את אותן מגבלות כמו ל-PlatformStorage, והוא נתמך רק במכשירים עם Google Play Services.

בדיקת זמינות של תכונות

למרות שכל אפשרויות האחסון משתמשות באותו API, חלק מהתכונות לא זמינות בכל אפשרות אחסון או בכל מכשיר. במאמרי העזרה של ה-API, ההערה @RequiresFeature מזהה ממשקי API שדורשים אחת מהתכונות האלה, והמחלקה Features מגדירה קבוע לכל תכונה. לדוגמה, INDEXING_TYPE_RANGE דורש את Features.NUMERIC_SEARCH.

ב-PlatformStorage, התמיכה בתכונות תלויה בגרסת Android של המכשיר. החל מ-Android 13 (רמת API‏ 33), התמיכה בתכונות תלויה גם בעדכוני המערכת של Google Play שהמכשיר קיבל. לדוגמה, PlatformStorage תומך בחיפוש מספרי (Features.NUMERIC_SEARCH), בחיפוש מילה במילה (Features.VERBATIM_SEARCH) ובצירופים (Features.JOIN_SPEC_AND_QUALIFIED_ID) רק במכשירים הבאים:

  • מכשירים עם Android מגרסה 14 (רמת API‏ 34) ואילך.
  • מכשירים עם Android 13 (רמת API‏ 33) שקיבלו את עדכון המערכת הנדרש של Google Play.

התכונות האלה לא נתמכות במכשירים עם Android 12 או Android 12L (רמות API ‏31 ו-32).

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

אל תסתמכו רק על גרסת Android כדי לקבוע אם יש תמיכה בתכונה. לפני ששולחים קריאה ל-API שדורש תכונה מסוימת, צריך לוודא שהתכונה נתמכת על ידי שליחת קריאה ל-isFeatureSupported() באובייקט Features שמוחזר על ידי AppSearchSession.getFeatures(). אם תכונה נדרשת לא נתמכת, הפעולה נכשלת ומופיעה הודעת חריגה. דוגמה למקרה של כשל: הגדרת סכימה שכוללת מאפיין INDEXING_TYPE_RANGE נכשלת במכשירים שלא תומכים ב-Features.NUMERIC_SEARCH.

הקוד הבא בודק אם AppSearchSession פתוח תומך בחיפוש מספרי:

Kotlin

val features = session.features
if (features.isFeatureSupported(Features.NUMERIC_SEARCH)) {
    // Numeric search is supported. You can index properties with
    // LongPropertyConfig.INDEXING_TYPE_RANGE and enable numeric search with
    // SearchSpec.Builder.setNumericSearchEnabled(true).
} else {
    // Numeric search isn't supported. Set a schema without range-indexed
    // properties, or switch to a different storage option.
}

Java

Features features = session.getFeatures();
if (features.isFeatureSupported(Features.NUMERIC_SEARCH)) {
    // Numeric search is supported. You can index properties with
    // LongPropertyConfig.INDEXING_TYPE_RANGE and enable numeric search with
    // SearchSpec.Builder.setNumericSearchEnabled(true).
} else {
    // Numeric search isn't supported. Set a schema without range-indexed
    // properties, or switch to a different storage option.
}

איך מתחילים להשתמש ב-AppSearch

הדוגמה בקטע הזה ממחישה איך להשתמש בממשקי ה-API של AppSearch כדי לשלב אפליקציה היפותטית לניהול הערות.

כתיבת מחלקת מסמכים

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

הקוד הבא מגדיר מחלקת מסמך של הערה עם שדה עם הערה @Document.StringProperty להוספה לאינדקס של טקסט של אובייקט הערה.

Kotlin

@Document
public data class Note(

    // Required field for a document class. All documents MUST have a namespace.
    @Document.Namespace
    val namespace: String,

    // Required field for a document class. All documents MUST have an Id.
    @Document.Id
    val id: String,

    // Optional field for a document class, used to set the score of the
    // document. If this is not included in a document class, the score is set
    // to a default of 0.
    @Document.Score
    val score: Int,

    // Optional field for a document class, used to index a note's text for this
    // document class.
    @Document.StringProperty(indexingType = AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
    val text: String
)

Java

@Document
public class Note {

  // Required field for a document class. All documents MUST have a namespace.
  @Document.Namespace
  private final String namespace;

  // Required field for a document class. All documents MUST have an Id.
  @Document.Id
  private final String id;

  // Optional field for a document class, used to set the score of the
  // document. If this is not included in a document class, the score is set
  // to a default of 0.
  @Document.Score
  private final int score;

  // Optional field for a document class, used to index a note's text for this
  // document class.
  @Document.StringProperty(indexingType = StringPropertyConfig.INDEXING_TYPE_PREFIXES)
  private final String text;

  Note(@NonNull String id, @NonNull String namespace, int score, @NonNull String text) {
    this.id = Objects.requireNonNull(id);
    this.namespace = Objects.requireNonNull(namespace);
    this.score = score;
    this.text = Objects.requireNonNull(text);
  }

  @NonNull
  public String getNamespace() {
    return namespace;
  }

  @NonNull
  public String getId() {
    return id;
  }

  public int getScore() {
    return score;
  }

  @NonNull
  public String getText() {
     return text;
  }
}

פתיחת מסד נתונים

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

Kotlin

val context: Context = getApplicationContext()
val sessionFuture = LocalStorage.createSearchSession(
    LocalStorage.SearchContext.Builder(context, /*databaseName=*/"notes_app")
    .build()
)

Java

Context context = getApplicationContext();
ListenableFuture<AppSearchSession> sessionFuture = LocalStorage.createSearchSession(
       new LocalStorage.SearchContext.Builder(context, /*databaseName=*/ "notes_app")
               .build()
);

הגדרת סכימה

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

Kotlin

val setSchemaRequest = SetSchemaRequest.Builder().addDocumentClasses(Note::class.java)
    .build()
val setSchemaFuture = Futures.transformAsync(
    sessionFuture,
    { session ->
        session?.setSchema(setSchemaRequest)
    }, mExecutor
)

Java

SetSchemaRequest setSchemaRequest = new SetSchemaRequest.Builder().addDocumentClasses(Note.class)
       .build();
ListenableFuture<SetSchemaResponse> setSchemaFuture =
       Futures.transformAsync(sessionFuture, session -> session.setSchema(setSchemaRequest), mExecutor);

הוספת מסמך למסד הנתונים

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

Kotlin

val note = Note(
    namespace="user1",
    id="noteId",
    score=10,
    text="Buy fresh fruit"
)

val putRequest = PutDocumentsRequest.Builder().addDocuments(note).build()
val putFuture = Futures.transformAsync(
    sessionFuture,
    { session ->
        session?.put(putRequest)
    }, mExecutor
)

Futures.addCallback(
    putFuture,
    object : FutureCallback<AppSearchBatchResult<String, Void>?> {
        override fun onSuccess(result: AppSearchBatchResult<String, Void>?) {

            // Gets map of successful results from Id to Void
            val successfulResults = result?.successes

            // Gets map of failed results from Id to AppSearchResult
            val failedResults = result?.failures
        }

        override fun onFailure(t: Throwable) {
            Log.e(TAG, "Failed to put documents.", t)
        }
    },
    mExecutor
)

Java

Note note = new Note(/*namespace=*/"user1", /*id=*/
                "noteId", /*score=*/ 10, /*text=*/ "Buy fresh fruit!");

PutDocumentsRequest putRequest = new PutDocumentsRequest.Builder().addDocuments(note)
       .build();
ListenableFuture<AppSearchBatchResult<String, Void>> putFuture =
       Futures.transformAsync(sessionFuture, session -> session.put(putRequest), mExecutor);

Futures.addCallback(putFuture, new FutureCallback<AppSearchBatchResult<String, Void>>() {
   @Override
   public void onSuccess(@Nullable AppSearchBatchResult<String, Void> result) {

     // Gets map of successful results from Id to Void
     Map<String, Void> successfulResults = result.getSuccesses();

     // Gets map of failed results from Id to AppSearchResult
     Map<String, AppSearchResult<Void>> failedResults = result.getFailures();
   }

   @Override
   public void onFailure(@NonNull Throwable t) {
      Log.e(TAG, "Failed to put documents.", t);
   }
}, mExecutor);

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

Kotlin

val searchSpec = SearchSpec.Builder()
    .addFilterNamespaces("user1")
    .build();

val searchFuture = Futures.transform(
    sessionFuture,
    { session ->
        session?.search("fruit", searchSpec)
    },
    mExecutor
)
Futures.addCallback(
    searchFuture,
    object : FutureCallback<SearchResults> {
        override fun onSuccess(searchResults: SearchResults?) {
            iterateSearchResults(searchResults)
        }

        override fun onFailure(t: Throwable?) {
            Log.e("TAG", "Failed to search notes in AppSearch.", t)
        }
    },
    mExecutor
)

Java

SearchSpec searchSpec = new SearchSpec.Builder()
       .addFilterNamespaces("user1")
       .build();

ListenableFuture<SearchResults> searchFuture =
       Futures.transform(sessionFuture, session -> session.search("fruit", searchSpec),
       mExecutor);

Futures.addCallback(searchFuture,
       new FutureCallback<SearchResults>() {
           @Override
           public void onSuccess(@Nullable SearchResults searchResults) {
               iterateSearchResults(searchResults);
           }

           @Override
           public void onFailure(@NonNull Throwable t) {
               Log.e(TAG, "Failed to search notes in AppSearch.", t);
           }
       }, mExecutor);

מעבר על SearchResults

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

Kotlin

Futures.transform(
    searchResults?.nextPage,
    { page: List<SearchResult>? ->
        // Gets GenericDocument from SearchResult.
        val genericDocument: GenericDocument = page!![0].genericDocument
        val schemaType = genericDocument.schemaType
        val note: Note? = try {
            if (schemaType == "Note") {
                // Converts GenericDocument object to Note object.
                genericDocument.toDocumentClass(Note::class.java)
            } else null
        } catch (e: AppSearchException) {
            Log.e(
                TAG,
                "Failed to convert GenericDocument to Note",
                e
            )
            null
        }
        note
    },
    mExecutor
)

Java

Futures.transform(searchResults.getNextPage(), page -> {
  // Gets GenericDocument from SearchResult.
  GenericDocument genericDocument = page.get(0).getGenericDocument();
  String schemaType = genericDocument.getSchemaType();

  Note note = null;

  if (schemaType.equals("Note")) {
    try {
      // Converts GenericDocument object to Note object.
      note = genericDocument.toDocumentClass(Note.class);
    } catch (AppSearchException e) {
      Log.e(TAG, "Failed to convert GenericDocument to Note", e);
    }
  }

  return note;
}, mExecutor);

הסרת מסמך

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

Kotlin

val removeRequest = RemoveByDocumentIdRequest.Builder("user1")
    .addIds("noteId")
    .build()

val removeFuture = Futures.transformAsync(
    sessionFuture, { session ->
        session?.remove(removeRequest)
    },
    mExecutor
)

Java

RemoveByDocumentIdRequest removeRequest = new RemoveByDocumentIdRequest.Builder("user1")
       .addIds("noteId")
       .build();

ListenableFuture<AppSearchBatchResult<String, Void>> removeFuture =
       Futures.transformAsync(sessionFuture, session -> session.remove(removeRequest), mExecutor);

שמירה בדיסק

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

Kotlin

val requestFlushFuture = Futures.transformAsync(
    sessionFuture,
    { session -> session?.requestFlush() }, mExecutor
)

Futures.addCallback(requestFlushFuture, object : FutureCallback<Void?> {
    override fun onSuccess(result: Void?) {
        // Success! Database updates have been persisted to disk.
    }

    override fun onFailure(t: Throwable) {
        Log.e(TAG, "Failed to flush database updates.", t)
    }
}, mExecutor)

Java

ListenableFuture<Void> requestFlushFuture = Futures.transformAsync(sessionFuture,
        session -> session.requestFlush(), mExecutor);

Futures.addCallback(requestFlushFuture, new FutureCallback<Void>() {
    @Override
    public void onSuccess(@Nullable Void result) {
        // Success! Database updates have been persisted to disk.
    }

    @Override
    public void onFailure(@NonNull Throwable t) {
        Log.e(TAG, "Failed to flush database updates.", t);
    }
}, mExecutor);

איך סוגרים סשן

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

Kotlin

val closeFuture = Futures.transform<AppSearchSession, Unit>(sessionFuture,
    { session ->
        session?.close()
        Unit
    }, mExecutor
)

Java

ListenableFuture<Void> closeFuture = Futures.transform(sessionFuture, session -> {
   session.close();
   return null;
}, mExecutor);

מקורות מידע נוספים

איפה אפשר למצוא מידע נוסף על AppSearch?

דוגמאות

  • Android AppSearch Sample (Kotlin), אפליקציה לרישום הערות שמשתמשת ב-AppSearch כדי להוסיף לאינדקס את ההערות של המשתמשים ולאפשר להם לחפש בהן.

שליחת משוב

נשמח לקבל ממך משוב ורעיונות באמצעות המשאבים הבאים:

Issue Tracker

לדווח על באגים כדי שנוכל לתקן אותם.