AppSearch

AppSearch เป็นโซลูชันการค้นหาในอุปกรณ์ที่มีประสิทธิภาพสูงสำหรับการจัดการข้อมูลที่มีโครงสร้างซึ่งจัดเก็บไว้ในเครื่อง ซึ่งมี API สำหรับจัดทำดัชนีข้อมูลและดึงข้อมูลโดยใช้การค้นหาข้อความแบบเต็ม แอปพลิเคชันสามารถใช้ AppSearch เพื่อเสนอความสามารถในการค้นหาในแอปที่กำหนดเอง ซึ่งช่วยให้ผู้ใช้ค้นหาเนื้อหาได้แม้ในขณะออฟไลน์

แผนภาพแสดงการจัดทำดัชนีและการค้นหาภายใน AppSearch

AppSearch มีฟีเจอร์ต่อไปนี้

  • การติดตั้งใช้งานพื้นที่เก็บข้อมูลที่รวดเร็วและเน้นอุปกรณ์เคลื่อนที่เป็นหลักซึ่งมีการใช้ I/O ต่ำ
  • การจัดทำดัชนีและการค้นหาชุดข้อมูลขนาดใหญ่ที่มีประสิทธิภาพสูง
  • การรองรับหลายภาษา เช่น ภาษาอังกฤษและภาษาสเปน
  • การจัดอันดับความเกี่ยวข้องและการให้คะแนนการใช้งาน

เนื่องจากมีการใช้ I/O น้อยกว่า AppSearch จึงมีเวลาในการตอบสนองที่ต่ำกว่าสำหรับการจัดทำดัชนีและการค้นหาในชุดข้อมูลขนาดใหญ่เมื่อเทียบกับ SQLite AppSearch ช่วยให้การค้นหาข้ามประเภทง่ายขึ้นด้วยการรองรับการค้นหาแบบเดี่ยว ในขณะที่ SQLite จะผสานผลลัพธ์จากหลายตาราง

เพื่อแสดงให้เห็นฟีเจอร์ของ AppSearch ลองดูตัวอย่างแอปพลิเคชันเพลงที่จัดการเพลงโปรดของผู้ใช้และช่วยให้ผู้ใช้ค้นหาเพลงได้อย่างง่ายดาย ผู้ใช้เพลิดเพลินกับเพลงจากทั่วโลกที่มีชื่อเพลงเป็นภาษาต่างๆ ซึ่ง AppSearch รองรับการจัดทำดัชนีและการค้นหาในภาษาต่างๆ อยู่แล้ว เมื่อผู้ใช้ค้นหาเพลงตามชื่อหรือชื่อศิลปิน แอปพลิเคชันจะส่งคำขอไปยัง AppSearch เพื่อดึงข้อมูลเพลงที่ตรงกันอย่างรวดเร็วและมีประสิทธิภาพ แอปพลิเคชันจะแสดงผลลัพธ์ ซึ่งช่วยให้ผู้ใช้เริ่มเล่นเพลงโปรดได้อย่างรวดเร็ว

ตั้งค่า

หากต้องการใช้ AppSearch ในแอปพลิเคชัน ให้เพิ่มทรัพยากร Dependency ต่อไปนี้ลงในไฟล์ 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 คือคอลเล็กชันเอกสารที่สอดคล้องกับสคีมาฐานข้อมูล แอปพลิเคชันไคลเอ็นต์จะสร้างฐานข้อมูลโดยระบุบริบทของแอปพลิเคชันและชื่อฐานข้อมูล ฐานข้อมูลจะเปิดได้โดยแอปพลิเคชันที่สร้างฐานข้อมูลนั้นเท่านั้น เมื่อเปิดฐานข้อมูล ระบบจะแสดงผลเซสชันเพื่อโต้ตอบกับฐานข้อมูล เซสชันคือจุดแรกเข้าสำหรับการเรียกใช้ AppSearch API และจะยังคงเปิดอยู่จนกว่าแอปพลิเคชันไคลเอ็นต์จะปิด

สคีมาและประเภทสคีมา

สคีมาแสดงโครงสร้างองค์กรของข้อมูลภายในฐานข้อมูล AppSearch

สคีมาประกอบด้วยประเภทสคีมาที่แสดงประเภทข้อมูลที่ไม่ซ้ำกัน ประเภทสคีมาประกอบด้วยพร็อพเพอร์ตี้ที่มีชื่อ ประเภทข้อมูล และจำนวนสมาชิกในเซ็ต เมื่อเพิ่มประเภทสคีมาลงในสคีมาฐานข้อมูลแล้ว คุณจะสร้างและเพิ่มเอกสารของประเภทสคีมานั้นลงในฐานข้อมูลได้

เอกสาร

ใน AppSearch หน่วยข้อมูลจะแสดงเป็นเอกสาร เอกสารแต่ละรายการในฐานข้อมูล AppSearch จะได้รับการระบุโดยเนมสเปซและรหัสที่ไม่ซ้ำกัน เนมสเปซใช้เพื่อแยกข้อมูลจากแหล่งที่มาต่างๆ เมื่อต้องการค้นหาแหล่งที่มาเพียงแหล่งเดียว เช่น บัญชีผู้ใช้

เอกสารประกอบด้วยการประทับเวลาที่สร้าง, ระยะเวลาที่คงอยู่ (TTL) และคะแนนที่สามารถใช้สำหรับการจัดอันดับระหว่างการดึงข้อมูล นอกจากนี้ เอกสารยังได้รับการกำหนดประเภทสคีมาที่อธิบายพร็อพเพอร์ตี้ข้อมูลเพิ่มเติมที่เอกสารต้องมี

คลาสเอกสารคือข้อมูลสรุปของเอกสาร ซึ่งมีช่องที่มีคำอธิบายประกอบ ที่แสดงเนื้อหาของเอกสาร โดยค่าเริ่มต้น ชื่อของคลาสเอกสารจะกำหนดชื่อของประเภทสคีมา

เอกสารจะได้รับการจัดทำดัชนีและค้นหาได้โดยการระบุคำค้นหา ระบบจะจับคู่เอกสารและรวมไว้ในผลการค้นหาหากเอกสารมีคำในคำค้นหาหรือตรงกับข้อกำหนดการค้นหาอื่นๆ ระบบจะจัดเรียงผลลัพธ์ตามคะแนนและกลยุทธ์การจัดอันดับ ผลการค้นหาจะแสดงเป็นหน้าเว็บที่คุณสามารถเรียกดูตามลำดับได้

AppSearch มีการปรับแต่งสำหรับการค้นหา เช่น ตัวกรอง การกำหนดค่าขนาดหน้า และตัวอย่างข้อมูล

พื้นที่เก็บข้อมูลของแพลตฟอร์ม พื้นที่เก็บข้อมูลในเครื่อง หรือพื้นที่เก็บข้อมูลของบริการ Google Play

AppSearch มีโซลูชันพื้นที่เก็บข้อมูล 3 แบบ ได้แก่ LocalStorage, PlatformStorage และ PlayServicesStorage เมื่อใช้ LocalStorage แอปพลิเคชันของคุณจะจัดการดัชนีเฉพาะแอปที่อยู่ในไดเรกทอรีข้อมูลแอปพลิเคชัน ทั้ง PlatformStorage และ PlayServicesStorage จะทำให้แอปพลิเคชันของคุณมีส่วนร่วมในดัชนีส่วนกลางทั่วทั้งระบบ ดัชนีของ PlatformStorage โฮสต์อยู่ในเซิร์ฟเวอร์ระบบ และดัชนีของ PlayServicesStorage โฮสต์อยู่ในพื้นที่เก็บข้อมูลของบริการ Google Play การเข้าถึงข้อมูลภายในดัชนีส่วนกลางเหล่านี้จำกัดเฉพาะข้อมูลที่แอปพลิเคชันของคุณมีส่วนร่วมและข้อมูลที่แอปพลิเคชันอื่นแชร์กับคุณอย่างชัดแจ้ง ตัวเลือกพื้นที่เก็บข้อมูลทั้งหมดนี้ใช้ 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 แอปพลิเคชันของคุณจะแชร์ข้อมูลกับแอปพลิเคชันอื่นๆ ได้อย่างปลอดภัย เพื่อให้แอปพลิเคชันเหล่านั้นค้นหาข้อมูลที่แชร์ของแอปคุณได้ด้วย การแชร์ข้อมูลแอปพลิเคชันแบบอ่านอย่างเดียวจะได้รับสิทธิ์โดยใช้แฮนด์เชคใบรับรองเพื่อให้แน่ใจว่าแอปพลิเคชันอื่นมีสิทธิ์อ่านข้อมูล อ่านข้อมูลเพิ่มเติมเกี่ยวกับ API นี้ได้ในเอกสารประกอบสำหรับ setSchemaTypeVisibilityForPackage()

นอกจากนี้ PlatformStorage ยังช่วยให้ข้อมูลที่จัดทำดัชนีแสดงบนแพลตฟอร์ม UI ของระบบได้ด้วย แอปพลิเคชันสามารถเลือกไม่ให้แสดงข้อมูลบางส่วนหรือทั้งหมดในแพลตฟอร์ม UI ของระบบได้ อ่านข้อมูลเพิ่มเติมเกี่ยวกับ API นี้ในเอกสารประกอบสำหรับ setSchemaTypeDisplayedBySystem()

ฟีเจอร์ LocalStorage (ใช้ได้กับ Android 5.0 ขึ้นไป) PlatformStorage (ใช้ได้กับ Android 12 ขึ้นไป) PlayServicesStorage (ใช้ได้กับ Android 5.0 ขึ้นไป)
การค้นหาข้อความแบบเต็มที่มีประสิทธิภาพ
การสนับสนุนหลายภาษา
ขนาดไบนารีที่ลดลง
การแชร์ข้อมูลระหว่างแอปพลิเคชัน
ความสามารถในการแสดงข้อมูลบนแพลตฟอร์ม UI ของระบบ
จัดทำดัชนีเอกสารได้ไม่จำกัดขนาดและจำนวน
การดำเนินการที่รวดเร็วขึ้นโดยไม่มีเวลาในการตอบสนองของ Binder เพิ่มเติม

ยังมีข้อดีข้อเสียอื่นๆ ที่ควรพิจารณาเมื่อเลือกระหว่าง LocalStorage กับ PlatformStorage เนื่องจาก PlatformStorage รวม Jetpack API ไว้ในบริการระบบ AppSearch ผลกระทบต่อขนาด APK จึงน้อยมากเมื่อเทียบกับการใช้ LocalStorage อย่างไรก็ตาม การดำเนินการนี้ยังหมายความว่าการดำเนินการ AppSearch จะทำให้เกิดเวลาในการตอบสนองของ Binder เพิ่มเติมเมื่อเรียกใช้บริการระบบ AppSearch PlatformStorage AppSearch จะจำกัดจำนวนและขนาดของเอกสารที่แอปพลิเคชันสามารถจัดทำดัชนีได้ เพื่อให้มั่นใจว่าดัชนีส่วนกลางมีประสิทธิภาพ PlayServicesStorage ยังมีข้อจำกัดเดียวกันกับ PlatformStorage และรองรับเฉพาะในอุปกรณ์ที่มีบริการ Google Play เท่านั้น

ตรวจสอบความพร้อมใช้งานของฟีเจอร์

แม้ว่าตัวเลือกพื้นที่เก็บข้อมูลทั้งหมดจะใช้ 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

ตัวอย่างในส่วนนี้แสดงวิธีใช้ AppSearch API เพื่อผสานรวมกับแอปพลิเคชันจดบันทึกสมมติ

เขียนคลาสเอกสาร

ขั้นตอนแรกในการผสานรวมกับ AppSearch คือการเขียนคลาสเอกสารเพื่ออธิบายข้อมูลที่จะแทรกลงในฐานข้อมูล ทำเครื่องหมายคลาสเป็นคลาสเอกสารโดยใช้คำอธิบายประกอบ @Document คุณสามารถใช้อินสแตนซ์ของคลาสเอกสารเพื่อใส่เอกสารและดึงข้อมูลเอกสารจากฐานข้อมูลได้

โค้ดต่อไปนี้กำหนดคลาสเอกสาร Note ที่มีช่องที่มีคำอธิบายประกอบ @Document.StringProperty สำหรับจัดทำดัชนีข้อความของออบเจ็กต์ Note

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 เพื่อแสดงผู้ใช้ที่กำหนดเองของตัวอย่างนี้ จากนั้นระบบจะแทรกเอกสารลงในฐานข้อมูลและแนบ Listener เพื่อประมวลผลผลลัพธ์ของการดำเนินการใส่

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() พร้อม Listener เพื่อระบุว่าการเรียกสำเร็จหรือไม่

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 ได้ที่แหล่งข้อมูลเพิ่มเติมต่อไปนี้

ตัวอย่าง

  • ตัวอย่าง AppSearch ของ Android (Kotlin) แอปจดโน้ตที่ใช้ AppSearch เพื่อจัดทำดัชนีโน้ตของผู้ใช้และอนุญาตให้ผู้ใช้ค้นหาโน้ตของตนเองได้

แสดงความคิดเห็น

แชร์ความคิดเห็นและไอเดียกับเราผ่านแหล่งข้อมูลต่อไปนี้

Issue Tracker

รายงานข้อบกพร่องเพื่อให้เราแก้ไขได้