AppSearch は、ローカルで管理するための高性能なオンデバイス検索ソリューションです 構造化データです。データのインデックス登録とデータの取得を行うための API が含まれています。 全文検索を利用できます。アプリは AppSearch を使用してカスタムのアプリ内を提示できる 検索機能により、ユーザーはオフラインでもコンテンツを検索できます。
![AppSearch 内でのインデックス登録と検索の図](https://developer.android.com/static/images/guide/topics/search/appsearch.png?authuser=0&hl=ja)
AppSearch には次の機能があります。
- I/O 使用率の低い、高速かつモバイル ファーストなストレージの実装
- 大規模なデータセットに対する効率性に優れたインデックス登録とクエリ
- 複数言語のサポート(英語やスペイン語など)
- 関連性ランキングと使用状況スコア
I/O の使用が少ないため、AppSearch はインデックス登録と検索のレイテンシを短縮 SQLite と比較して大規模なデータセットに対するパフォーマンスが優れています。AppSearch で複数タイプのクエリを簡素化 SQLite は複数のテーブルからの結果を結合しますが、SQLite は単一クエリをサポートします。
AppSearch の機能を説明するために、音楽アプリの ユーザーのお気に入りの曲を管理し、簡単に検索できるようにするアプリケーション できます。ユーザーは世界中のさまざまな曲をさまざまなタイトルで楽しむ AppSearch がインデックスとクエリをネイティブにサポートしている言語です。Google ユーザーがタイトルやアーティスト名で曲を検索すると、アプリケーションは リクエストを AppSearch に送信して、一致する曲を迅速かつ効率的に取得します。「 結果が表示され、ユーザーはすぐにゲームを開始できる おすすめします。
設定
アプリケーションで AppSearch を使用するには、
アプリケーションの build.gradle
ファイルを次のように変更します。
Groovy
dependencies { def appsearch_version = "1.1.0-alpha04" 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-alpha04" 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 のコンセプト
次の図は、AppSearch のコンセプトと相互作用を示しています。
図 1. AppSearch のコンセプトの図: AppSearch データベース、スキーマ、
各スキーマタイプ、ドキュメント、セッション
検索があります
データベースとセッション
AppSearch データベースは、データベースに準拠するドキュメントのコレクション 説明します。クライアント アプリケーションは、アプリケーションを提供してデータベースを作成します。 コンテキストとデータベース名の組み合わせです。データベースはアプリケーションによってのみ開くことができる 作成しました。データベースが開かれると、セッションが返され 関連付けられていますセッションは AppSearch API を呼び出すためのエントリ ポイントです。 クライアント アプリケーションによって閉じられるまで開いたままになります。
スキーマとスキーマタイプ
スキーマは AppSearch 内のデータの組織構造を表す データベースです
スキーマは、一意のデータタイプを表すスキーマタイプで構成されます。 スキーマタイプはプロパティで構成され、名前、データ型、 基づいています。データベース スキーマにスキーマタイプを追加すると、 スキーマタイプを作成してデータベースに追加できます。
ドキュメント
AppSearch では、データの単位はドキュメントとして表されます。1 つのドキュメントに含まれる AppSearch データベースは名前空間と ID によって一意に識別されます。名前空間 1 つのソースのみが必要な場合に、データを異なるソースから分離するために使用する (ユーザー アカウントなど)を指定します。
ドキュメントには、作成時のタイムスタンプ、有効期間(TTL)、スコアが記載されます。 取得時のランキングに使用できます。ドキュメントにはスキーマも割り当てられる ドキュメントが持つ必要がある追加のデータ プロパティを記述する型。
ドキュメント クラスはドキュメントを抽象化したものです。アノテーション付きのフィールドが含まれています。 オブジェクトを表す名前です。デフォルトでは、ドキュメントの名前は クラスはスキーマタイプの名前を設定します。
検索
ドキュメントはインデックスに登録され、クエリを指定して検索できます。ドキュメントとは 一致したもの(クエリ内の語句を含む場合)が検索結果に含まれる 一致します。結果は、 スコアとランキング戦略が含まれます。検索結果はページで表示されます。 取得する必要があります。
AppSearch のカスタマイズ (フィルタ、ページサイズの設定、スニペットなど)をカスタマイズできます。
プラットフォーム ストレージとローカル ストレージ
AppSearch には、LocalStorage と PlatformStorage の 2 つのストレージ ソリューションがあります。 LocalStorage を使用すると、アプリケーションは、 アプリケーションのデータ ディレクトリに配置します。PlatformStorage では、 システム全体の中央インデックスに寄与します。中央インデックス内のデータアクセス 使用できるデータは、アプリケーションによって提供されたデータと、 明示的に共有することもできます。LocalStorage と PlatformStorage は同じ API を共有し、デバイスの version:
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())); }
PlatformStorage を使用すると、アプリケーションは他のクラウド プロバイダと安全にデータを アプリのデータを検索することもできます。読み取り専用 アプリケーションのデータ共有は証明書ハンドシェイクを介して許可され、 相手側アプリはデータの読み取り権限を持っています。この API の詳細 setSchemaTypeVisibilityForPackage() のドキュメントをご覧ください。
また、インデックスに登録されたデータは、システム UI サーフェスに表示できます。 アプリはシステム上に表示されるデータの一部または全部をオプトアウトできます UI サーフェス。この API の詳細については、setSchemaTypeDisplayedBySystem() のドキュメントをご覧ください。
機能 | 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 を選択する際には、追加のトレードオフを考慮する必要があります。 PlatformStorage をご覧ください。PlatformStorage は、すべてのコンテナで Jetpack API をラップするため、 AppSearch システム サービスを使用するため、APK サイズへの影響は、 LocalStorage。ただし、この場合、AppSearch オペレーションによって追加の AppSearch システム サービスを呼び出すときのバインダー レイテンシ。PlatformStorage を使用すると AppSearch は、アプリケーションに含まれるドキュメントの数とサイズを制限する インデックスを作成して、効率的な中央インデックスを確保できます。
AppSearch を使ってみる
このセクションの例では、AppSearch API を使用して アプリケーションの例を見てみましょう。
ドキュメント クラスを作成する
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
、
これはデータベースへの接続を表し、データベースへの接続を
サポートしています。
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
を削除することを明示的にリクエストします。
ID でデータベースから抽出できます。
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 サンプル(Kotlin) AppSearch を使用してユーザーのメモをインデックスに登録し、ユーザーが メモを検索できます。
フィードバックを送信
以下のリソースを通じてフィードバックやアイデアをお寄せください。
Google が修正できるようにバグを報告してください。