Uygulama Arama

AppSearch, yerel olarak depolanan, yapılandırılmış verileri yönetmek için kullanılan yüksek performanslı bir cihaz üzerinde arama çözümüdür. Verileri dizine eklemeye ve tam metin araması kullanarak veri almaya yönelik API'ler içerir. Uygulamalar, kullanıcıların çevrimdışıyken bile içerik aramasına olanak tanıyarak özel uygulama içi arama özellikleri sunmak için AppSearch'ü kullanabilir.

AppSearch'te dizine ekleme ve arama yapmayı gösteren şema

AppSearch aşağıdaki özellikleri sağlar:

  • Düşük G/Ç kullanımı ile hızlı, mobil öncelikli depolama uygulaması
  • Büyük veri kümelerinde son derece verimli dizine ekleme ve sorgulama
  • İngilizce ve İspanyolca gibi çoklu dil desteği
  • Alaka düzeyi sıralaması ve kullanım puanı

Daha düşük G/Ç kullanımı nedeniyle AppSearch, dizine ekleme ve büyük veri kümelerinde arama için SQLite'a kıyasla daha düşük gecikme sunar. AppSearch, tek sorguları destekleyerek türler arası sorguları basitleştirirken SQLite, birden fazla tablodaki sonuçları birleştirir.

AppSearch'ün özelliklerini göstermek için kullanıcıların favori şarkılarını yöneten ve bu şarkıları kolayca arayabilmelerini sağlayan bir müzik uygulaması örneğini ele alalım. Kullanıcılar farklı dillerdeki şarkı başlıklarıyla dünyanın dört bir yanından müziklerin keyfini çıkarır. AppSearch yerel olarak dizine eklemeyi ve sorgulamayı destekler. Kullanıcı bir şarkıyı başlığa veya sanatçı adına göre aradığında uygulama, eşleşen şarkıları hızlı ve etkili bir şekilde almak için isteği AppSearch'e iletir. Uygulama sonuçları göstererek kullanıcılarının en sevdikleri şarkıları hızlıca çalmaya başlamalarını sağlar.

Kurulum

AppSearch'ü uygulamanızda kullanmak için uygulamanızın build.gradle dosyasına aşağıdaki bağımlılıkları ekleyin:

Modern

dependencies {
    def appsearch_version = "1.1.0-alpha03"

    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 offers additional features
    // to LocalStorage.
    implementation "androidx.appsearch:appsearch-platform-storage:$appsearch_version"
}

Kotlin

dependencies {
    val appsearch_version = "1.1.0-alpha03"

    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 offers additional features
    // to LocalStorage.
    implementation("androidx.appsearch:appsearch-platform-storage:$appsearch_version")
}

AppSearch kavramları

Aşağıdaki şemada AppSearch kavramları ve etkileşimleri gösterilmektedir.

Bir istemci uygulamasını ve bu uygulamanın şu AppSearch kavramlarıyla olan etkileşimlerini gösteren şema: AppSearch veritabanı, şema, şema türleri, belgeler, oturum ve arama. Şekil 1. AppSearch kavramlarının şeması: AppSearch veritabanı, şema, şema türleri, belgeler, oturum ve arama.

Veritabanı ve oturum

AppSearch veritabanı, veritabanı şemasına uygun olan belge koleksiyonudur. İstemci uygulamaları, uygulama bağlamını ve veritabanı adını sağlayarak veritabanı oluşturur. Veritabanları yalnızca onları oluşturan uygulama tarafından açılabilir. Bir veritabanı açıldığında, veritabanıyla etkileşimde bulunmak için bir oturum döndürülür. Oturum, AppSearch API'lerini çağırmak için kullanılan giriş noktasıdır ve istemci uygulaması tarafından kapatılana kadar açık kalır.

Şema ve şema türleri

Şema, bir AppSearch veritabanındaki verilerin kuruluş yapısını temsil eder.

Şema, benzersiz veri türlerini temsil eden şema türlerinden oluşur. Şema türleri; ad, veri türü ve kardinaliteyi içeren mülklerden oluşur. Veritabanı şemasına bir şema türü eklendikten sonra, bu şema türünde belgeler oluşturulabilir ve veritabanına eklenebilir.

Dokümanlar

AppSearch'te, bir veri birimi doküman olarak temsil edilir. AppSearch veritabanındaki her belge, ad alanı ve kimliği ile benzersiz şekilde tanımlanır. Ad alanları, kullanıcı hesapları gibi yalnızca tek bir kaynağın sorgulanması gerektiğinde farklı kaynaklardan verileri ayırmak için kullanılır.

Belgelerde oluşturma zaman damgası, geçerlilik süresi (TTL) ve alma sırasında sıralamada kullanılabilecek bir puan bulunur. Ayrıca belgeye, dokümanın sahip olması gereken ek veri özelliklerini açıklayan bir şema türü de atanır.

Doküman sınıfı, dokümanın soyutlanmasıdır. Bir belgenin içeriğini temsil eden ek açıklamalı alanlar içerir. Varsayılan olarak, şema türünün adı belge sınıfının adı tarafından belirlenir.

Dokümanlar dizine eklenir ve sorgu sağlanarak aranabilir. Bir doküman, sorgudaki terimleri içeriyorsa veya başka bir arama spesifikasyonuyla eşleşirse eşleştirilir ve arama sonuçlarına dahil edilir. Sonuçlar, puanlarına ve sıralama stratejilerine göre sıralanır. Arama sonuçları, sıralı olarak alabileceğiniz sayfalarla gösterilir.

AppSearch, arama için filtreler, sayfa boyutu yapılandırması ve snippet oluşturma gibi özelleştirmeler sunar.

Platform Depolama Alanı - Yerel Depolama Alanı

AppSearch iki depolama çözümü sunar: LocalStorage ve PlatformStorage. LocalStorage sayesinde uygulamanız, uygulama veri dizininizde bulunan uygulamaya özel bir dizini yönetir. PlatformStorage sayesinde uygulamanız sistem genelinde bir merkezi dizine katkıda bulunur. Merkezi dizindeki veri erişimi, uygulamanızın katkıda bulunduğu ve başka bir uygulamanın sizinle açıkça paylaştığı verilerle sınırlıdır. Hem LocalStorage hem de PlatformStorage aynı API'yi paylaşır ve cihazın sürümüne bağlı olarak birbirinin yerine kullanılabilir:

Kotlin

if (BuildCompat.isAtLeastS()) {
    appSearchSessionFuture.setFuture(
        PlatformStorage.createSearchSession(
            PlatformStorage.SearchContext.Builder(mContext, DATABASE_NAME)
               .build()
        )
    )
} else {
    appSearchSessionFuture.setFuture(
        LocalStorage.createSearchSession(
            LocalStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                .build()
        )
    )
}

Java

if (BuildCompat.isAtLeastS()) {
    mAppSearchSessionFuture.setFuture(PlatformStorage.createSearchSession(
            new PlatformStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                    .build()));
} else {
    mAppSearchSessionFuture.setFuture(LocalStorage.createSearchSession(
            new LocalStorage.SearchContext.Builder(mContext, DATABASE_NAME)
                    .build()));
}

Uygulamanız, PlatformStorage kullanarak verileri diğer uygulamalarla güvenli bir şekilde paylaşarak uygulamaların verilerinde de arama yapmalarına olanak tanıyabilir. Salt okunur uygulama veri paylaşımı, diğer uygulamanın verileri okuma iznine sahip olduğundan emin olmak için sertifika el sıkışması ile verilir. setSchemaTypeVisibilityForPackage() belgelerinde bu API hakkında daha fazla bilgi edinebilirsiniz.

Ayrıca, dizine eklenen veriler sistem arayüzü yüzeylerinde görüntülenebilir. Uygulamalar, verilerinin bir kısmının veya tamamının Sistem kullanıcı arayüzü yüzeylerinde görüntülenmesini devre dışı bırakabilir. setSchemaTypeDisplayedBySystem() belgelerinde bu API hakkında daha fazla bilgi edinebilirsiniz.

Özellikler LocalStorage (compatible with Android 4.0+) PlatformStorage (compatible with Android 12+)
Efficient full-text search
Multi-language support
Reduced binary size
Application-to-application data sharing
Capability to display data on System UI surfaces
Unlimited document size and count can be indexed
Faster operations without additional binder latency

LocalStorage ve PlatformStorage arasında seçim yaparken göz önünde bulundurulması gereken ek dengelemeler vardır. PlatformStorage, Jetpack API'lerini AppSearch sistem hizmeti üzerinden sarmaladığından LocalStorage kullanımına kıyasla APK boyutu etkisi minimum düzeydedir. Ancak bu aynı zamanda AppSearch işlemlerinin, AppSearch sistem hizmeti çağrılırken ek bağlayıcı gecikmesine neden olacağı anlamına da gelir. PlatformStorage sayesinde AppSearch, verimli bir merkezi dizin sağlamak için bir uygulamanın dizine ekleyebileceği doküman sayısını ve doküman boyutunu sınırlandırır.

AppSearch'ü kullanmaya başlayın

Bu bölümdeki örnekte, varsayıma dayalı not tutma uygulaması ile entegrasyon sağlamak için AppSearch API'lerinin nasıl kullanılacağı gösterilmektedir.

Belge sınıfı yazın

AppSearch ile entegrasyon için ilk adım, veritabanına eklenecek verileri tanımlamak üzere bir belge sınıfı yazmaktır. @Document notasyonunu kullanarak bir sınıfı belge sınıfı olarak işaretleyin.Veritabanına belge eklemek ve almak için belge sınıfının örneklerini kullanabilirsiniz.

Aşağıdaki kod, bir Note nesnesinin metnini dizine eklemek için @Document.StringProperty ek açıklamalı alanı içeren bir Note dokümanı sınıfı tanımlar.

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;
  }
}

Bir veritabanı açın

Dokümanlarla çalışmaya başlamadan önce bir veritabanı oluşturmanız gerekir. Aşağıdaki kod notes_app adında yeni bir veritabanı oluşturur ve AppSearchSession için bir ListenableFuture alır. Bu da veritabanı ile olan bağlantıyı temsil eder ve veritabanı işlemleri için API'ler sağlar.

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()
);

Şema ayarlama

Dokümanları veritabanına yerleştirip almak için öncelikle bir şema ayarlamanız gerekir. Veritabanı şeması, "şema türleri" olarak adlandırılan farklı yapılandırılmış veri türlerinden oluşur. Aşağıdaki kod, belge sınıfını bir şema türü olarak sağlayarak şemayı ayarlar.

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);

Veritabanına bir belge ekleyin

Bir şema türü eklendikten sonra, bu türdeki dokümanları veritabanına ekleyebilirsiniz. Aşağıdaki kod, Note doküman sınıfı oluşturucuyu kullanarak Note şema türünde bir belge oluşturur. user1 belge ad alanını, bu örneğin rastgele bir kullanıcısını temsil edecek şekilde ayarlar. Belge, daha sonra veritabanına eklenir ve koyma işleminin sonucunu işlemek için bir işleyici iliştirilir.

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);

Bu bölümde ele alınan arama işlemlerini kullanarak dizine eklenen dokümanları arayabilirsiniz. Aşağıdaki kod, user1 ad alanına ait belgeler için veritabanı üzerinde "meyve" terimi için sorgular gerçekleştirir.

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);

Arama Sonuçları ile yineleyin

Aramalar, SearchResult nesnelerinin sayfalarına erişim sağlayan bir SearchResults örneği döndürür. Her SearchResult, eşleşen GenericDocument öğesini (tüm dokümanların dönüştürüldüğü genel biçim) barındırır. Aşağıdaki kod, arama sonuçlarının ilk sayfasını alır ve sonucu tekrar bir Note dokümanına dönüştürür.

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);

Dokümanı kaldırma

Kullanıcı bir notu sildiğinde uygulama, ilgili Note dokümanını veritabanından siler. Bu, notun artık sorgularda gösterilmemesini sağlar. Aşağıdaki kod, Note belgesini kimliğe göre veritabanından kaldırmak için açık bir istekte bulunur.

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);

Diske devam et

Bir veritabanında yapılan güncellemeler, requestFlush() çağrısı yapılarak düzenli aralıklarla diskte sürdürülmelidir. Aşağıdaki kod, çağrının başarılı olup olmadığını belirlemek için bir işleyici ile requestFlush() çağırır.

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);

Oturum kapatma

Bir uygulama artık veritabanı işlemi çağırmayacaksa AppSearchSession kapatılmalıdır. Aşağıdaki kod, daha önce açılmış olan AppSearch oturumunu kapatır ve diskte yapılan tüm güncellemeleri devam ettirir.

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);

Ek kaynaklar

AppSearch hakkında daha fazla bilgi edinmek için aşağıdaki ek kaynaklara bakın:

Sana Özel

  • Android AppSearch Örneği (Kotlin), bir kullanıcının notlarını dizine eklemek için AppSearch'ü kullanan ve kullanıcıların notlarında arama yapmasına olanak tanıyan bir not alma uygulamasıdır.

Geri bildirim gönderme

Aşağıdaki kaynakları kullanarak geri bildirimlerinizi ve fikirlerinizi bizimle paylaşabilirsiniz:

Sorun izleyici

Düzeltebilmemiz için hataları bildirin.