AppSearch, yerel olarak depolanan yapılandırılmış verileri yönetmek için yüksek performanslı bir cihaz üzerinde arama çözümüdür. Verileri dizine ekleme ve tam metin aramayı kullanarak verileri alma API'lerini içerir. Uygulamalar, özel uygulama içi arama özellikleri sunmak için AppSearch'i kullanabilir. Bu sayede kullanıcılar çevrimdışıyken bile içerik arayabilir.
![AppSearch'ta dizine ekleme ve arama işlemini gösteren şema](https://developer.android.google.cn/static/images/guide/topics/search/appsearch.png?authuser=0&hl=tr)
AppSearch aşağıdaki özellikleri sağlar:
- Düşük G/Ç kullanımıyla hızlı ve mobil öncelikli bir depolama alanı uygulaması
- Büyük veri kümelerinde yüksek verimlilikte dizine ekleme ve sorgu oluşturma
- İngilizce ve İspanyolca gibi çok dilli destek
- Alaka düzeyi sıralaması ve kullanım puanlaması
Daha düşük G/Ç kullanımı nedeniyle AppSearch, büyük veri kümelerinde dizine ekleme ve arama için SQLite'e kıyasla daha düşük gecikme süresi sunar. AppSearch, tek sorguları destekleyerek türler arası sorguları basitleştirirken SQLite, birden fazla tablodaki sonuçları birleştirir.
AppSearch'in özelliklerini açıklamak için kullanıcıların favori şarkılarını yöneten ve kullanıcıların bu şarkıları kolayca aramasına olanak tanıyan bir müzik uygulaması örneğini ele alalım. Kullanıcılar, dünyanın dört bir yanından farklı dillerdeki şarkı başlıklarıyla müzik dinleyebilir. AppSearch, bu şarkıların dizine eklenmesini ve sorgulanması için doğal olarak destek sunar. Kullanıcı, şarkıyı başlığa veya sanatçı adına göre aradığında uygulama, eşleşen şarkıları hızlı ve verimli bir şekilde almak için isteği AppSearch'e iletir. Uygulama, sonuçları gösterir ve kullanıcıların en sevdikleri şarkıları hızlı bir şekilde çalmaya başlamasına olanak tanır.
Kurulum
Uygulamanızda AppSearch'i kullanmak için uygulamanızın build.gradle
dosyasına aşağıdaki bağımlılıkları ekleyin:
Groovy
dependencies { def appsearch_version = "1.1.0-alpha05" 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-alpha05" 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") }
Uygulama Araması kavramları
Aşağıdaki diyagramda AppSearch kavramları ve bunların etkileşimleri gösterilmektedir.
Şekil 1. AppSearch kavramlarının şeması: AppSearch veritabanı, şema, şema türleri, dokümanlar, oturum ve arama.
Veritabanı ve oturum
AppSearch veritabanı, veritabanı şemasına uygun bir doküman koleksiyonudur. İstemci uygulamaları, uygulama bağlamlarını ve bir veritabanı adı sağlayarak veritabanı oluşturur. Veritabanları yalnızca onları oluşturan uygulama tarafından açılabilir. Bir veritabanı açıldığında, veritabanıyla etkileşim kurmak için bir oturum döndürülür. Oturum, AppSearch API'lerini çağırmanın 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ı içindeki verilerin organizasyon 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 kardinalite içeren özelliklerden oluşur. Bir şema türü veritabanı şemasına eklendikten sonra, bu şema türünde dokümanlar oluşturulup veritabanına eklenebilir.
Dokümanlar
AppSearch'te veri birimleri doküman olarak temsil edilir. AppSearch veritabanındaki her doküman, ad alanı ve kimliğiyle benzersiz şekilde tanımlanır. Alan adları, yalnızca bir kaynağın (ör. kullanıcı hesapları) sorgulanması gerektiğinde farklı kaynaklardan gelen verileri ayırmak için kullanılır.
Dokümanlar, oluşturma zaman damgası, geçerlilik süresi (TTL) ve getirme sırasında sıralama için kullanılabilecek bir puan içerir. Belgelere, sahip olması gereken ek veri özelliklerini açıklayan bir şema türü de atanır.
Belge sınıfı, bir belgenin soyut bir temsilidir. Bir dokümanın içeriğini temsil eden ek açıklamalı alanlar içerir. Varsayılan olarak, şema türü adı, belge sınıfının adıyla belirlenir.
Arat
Dizine eklenen dokümanlar, sorgu sağlanarak aranabilir. Sorgudaki terimleri içeren veya başka bir arama özelliğiyle eşleşen dokümanlar 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ırayla alabileceğiniz sayfalarla temsil edilir.
AppSearch, arama için filtreler, sayfa boyutu yapılandırması ve snippet oluşturma gibi özelleştirmeler sunar.
Platform Depolama, Yerel Depolama veya Play Hizmetleri Depolama
AppSearch üç depolama çözümü sunar: LocalStorage
, PlatformStorage
ve PlayServicesStorage
. LocalStorage
ile uygulamanız, uygulama veri dizininde bulunan uygulamaya özel bir dizini yönetir. Hem PlatformStorage
hem de PlayServicesStorage
ile uygulamanız, sistem genelindeki merkezi bir dizin oluşturmaya katkıda bulunur. PlatformStorage
dizini sistem sunucusunda, PlayServicesStorage
dizini ise Google Play Hizmetleri'nin depolama alanında barındırılır. Bu merkezi dizinlerdeki veri erişimi, uygulamanızın katkıda bulunduğu veriler ve başka bir uygulama tarafından sizinle açıkça paylaşılan verilerle sınırlıdır. Bu depolama alanı seçeneklerinin tümü aynı API'yi kullanır ve cihazın sürümüne göre değiştirilebilir:
Kotlin
if (BuildCompat.isAtLeastS()) { 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 (BuildCompat.isAtLeastS()) { 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
ve PlayServicesStorage
'ü kullanarak uygulamanız, diğer uygulamaların da uygulamanızın verilerinde arama yapmasına izin vermek için verileri güvenli bir şekilde paylaşabilir. Salt okunur uygulama verisi paylaşımı, diğer uygulamanın verileri okuma izni olduğundan emin olmak için sertifika el sıkışması kullanılarak verilir. Bu API hakkında daha fazla bilgiyi setSchemaTypeVisibilityForPackage()
dokümanlarında bulabilirsiniz.
Ayrıca PlatformStorage
ile dizine eklenen veriler sistem kullanıcı arayüzü platformlarında görüntülenebilir. Uygulamalar, verilerinin bir kısmının veya tamamının sistem kullanıcı arayüzü yüzeylerinde gösterilmesini devre dışı bırakabilir. Bu API hakkında daha fazla bilgiyi setSchemaTypeDisplayedBySystem()
dokümanlarında bulabilirsiniz.
Özellikler | LocalStorage (Android 5.0 ve sonraki sürümlerle uyumlu) |
PlatformStorage (Android 12 ve sonraki sürümlerle uyumlu) |
PlayServicesStorage (Android 5.0 ve sonraki sürümlerle uyumlu) |
---|---|---|---|
Etkili tam metin arama | |||
Çok dilli destek | |||
Azaltılmış ikili dosya boyutu | |||
Uygulamalar arası veri paylaşımı | |||
Sistem kullanıcı arayüzü yüzeylerinde veri görüntüleme yeteneği | |||
Sınırsız sayıda ve boyuttaki doküman dizine eklenebilir | |||
Ek bağlayıcı gecikmesi olmadan daha hızlı işlemler |
LocalStorage
ile PlatformStorage
arasında seçim yaparken dikkate almanız gereken başka değişkenler de vardır. PlatformStorage
, Jetpack API'lerini AppSearch sistem hizmetinin üzerine sarmaladığından APK boyutu üzerindeki etkisi, LocalStorage'ı kullanmaya kıyasla çok azdır. Ancak bu, AppSearch sistem hizmetini çağırırken AppSearch işlemlerinin ek bağlayıcı gecikmesi yaşaması anlamına da gelir. AppSearch, PlatformStorage
ile verimli bir merkezi dizin sağlamak için bir uygulamanın dizine ekleyebildiği doküman sayısını ve doküman boyutunu sınırlandırır. PlayServicesStorage
, PlatformStorage
ile aynı sınırlamalara sahiptir ve yalnızca Google Play Hizmetleri'nin yüklü olduğu cihazlarda desteklenir.
AppSearch'i kullanmaya başlama
Bu bölümdeki örnekte, varsayımsal bir not tutma uygulamasıyla entegrasyon için AppSearch API'lerinin nasıl kullanılacağı gösterilmektedir.
Doküman sınıfı yazma
AppSearch ile entegrasyona ilk adım, veritabanına eklenecek verileri tanımlayacak bir doküman sınıfı yazmaktır. @Document
ek açıklamasını kullanarak bir sınıfı doküman sınıfı olarak işaretleyin.Doküman sınıfının örneklerini kullanarak veritabanına doküman ekleyebilir ve veritabanından doküman alabilirsiniz.
Aşağıdaki kod, bir Not nesnesinin metnini dizine eklemek için @Document.StringProperty
ek açıklamalı bir alan içeren bir Not belgesi 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; } }
Veritabanı açma
Dokümanlarla çalışmaya başlamadan önce bir veritabanı oluşturmanız gerekir. Aşağıdaki kod, notes_app
adlı yeni bir veritabanı oluşturur ve veritabanı bağlantısını temsil eden ve veritabanı işlemleri için API'leri sağlayan bir AppSearchSession
için ListenableFuture
alır.
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
Veri tabanına belge eklemeden ve veritabanından belge almadan önce bir şema ayarlamanız gerekir. Veritabanı şeması, "şema türleri" olarak adlandırılan farklı türde yapılandırılmış verilerden oluşur. Aşağıdaki kod, belge sınıfını ş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 doküman ekleme
Eklenen bir şema türüne ait dokümanları veritabanına ekleyebilirsiniz.
Aşağıdaki kod, Note
doküman sınıfı oluşturucusunu kullanarak Note
şeması türüne sahip bir doküman oluşturur. Bu örnekteki rastgele bir kullanıcıyı temsil edecek şekilde doküman ad alanını user1
ayarlar. Ardından, belge veritabanına eklenir ve ekleme işleminin sonucunu işlemek için bir dinleyici eklenir.
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);
Arat
Bu bölümde açıklanan arama işlemlerini kullanarak dizine eklenen dokümanları arayabilirsiniz. Aşağıdaki kod, user1
ad alanına ait belgeler için veritabanında "fruit" terimiyle ilgili 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);
SearchResults öğesini iterasyonla gezme
Aramalar, SearchResult
nesnelerinin sayfalarına erişim sağlayan bir SearchResults
örneği döndürür. Her SearchResult
, eşleşen GenericDocument
'yi (tüm dokümanların dönüştürüldüğü belgenin genel biçimi) içerir. Aşağıdaki kod, arama sonuçlarının ilk sayfasını alır ve sonucu tekrar Note
belgesine 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
belgeyi veritabanından siler. Bu işlem, notun artık sorgularda gösterilmemesini sağlar. Aşağıdaki kod, Note
belgesinin kimliğe göre veritabanından kaldırılması için açık bir istek gönderir.
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 kalıcı olarak kaydetme
Bir veritabanındaki güncellemeler, requestFlush()
çağrılarak düzenli olarak diske kaydedilmelidir. Aşağıdaki kod, aramanın başarılı olup olmadığını belirlemek için requestFlush()
'ü bir dinleyiciyle ç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);
Oturumları kapatma
Bir uygulama artık veritabanı işlemi çağırmayacaksa AppSearchSession
kapatılmalıdır. Aşağıdaki kod, daha önce açılan AppSearch oturumunu kapatır ve tüm güncellemeleri diske kaydeder.
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 göz atın:
Örnekler
- Android AppSearch Örneği (Kotlin): Kullanıcı notlarını dizine eklemek için AppSearch'i kullanan ve kullanıcıların notlarında arama yapmasına olanak tanıyan bir not alma uygulaması.
Geri bildirim gönder
Geri bildirimlerinizi ve fikirlerinizi aşağıdaki kaynaklar üzerinden bizimle paylaşın:
Düzeltmemiz için hataları bildirin.