AppSearch هو حلّ عالي الأداء للبحث على الجهاز فقط لإدارة عمليات البحث على الجهاز والمخزنة والمهيكلة. يحتوي على واجهات برمجة تطبيقات لفهرسة البيانات واسترداد البيانات باستخدام البحث في النص الكامل. يمكن للتطبيقات استخدام AppSearch لتقديم تجربة مخصَّصة داخل التطبيق إمكانات البحث، ما يسمح للمستخدمين بالبحث عن المحتوى حتى في وضع عدم الاتصال.
![مخطّط بياني يوضّح الفهرسة والبحث ضمن AppSearch](https://developer.android.com/static/images/guide/topics/search/appsearch.png?hl=ar)
ويوفّر AppSearch الميزات التالية:
- تنفيذ سريع للتخزين أولاً على الأجهزة الجوّالة مع انخفاض في استخدام وحدات الإدخال والإخراج
- فهرسة وإجراء طلبات بحث بكفاءة عالية على مجموعات كبيرة من البيانات
- التوافق مع لغات متعددة، مثل الإنجليزية والإسبانية
- تصنيف مدى الصلة بموضوع البحث ونتيجة الاستخدام
بسبب انخفاض استخدام وحدات الإدخال والإخراج، يوفّر AppSearch وقت استجابة أقل للفهرسة والبحث على مجموعات البيانات الكبيرة مقارنة بـ SQLite. خدمة AppSearch تبسّط طلبات البحث المتعددة الأنواع من خلال دعم الاستعلامات المفردة بينما تدمج SQLite النتائج من جداول متعددة.
لتوضيح ميزات AppSearch، لنلقِ نظرة على محتوى موسيقي تطبيق يدير الأغاني المفضلة للمستخدمين ويتيح للمستخدمين البحث بسهولة لهم. يستمتع المستخدمون بموسيقى من جميع أنحاء العالم مع عناوين أغاني مختلفة التي تتيح خدمة AppSearch في الأصل الفهرسة وطلب البحث. عندما يبحث المستخدم عن أغنية حسب العنوان أو اسم الفنان، يجتاز التطبيق طلب البحث إلى 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 هي مجموعة من المستندات التي تتوافق مع قاعدة البيانات Google. تنشئ تطبيقات العميل قاعدة بيانات من خلال تقديم تطبيقاتها والسياق واسم قاعدة البيانات. لا يمكن فتح قواعد البيانات إلا بواسطة التطبيق التي أنشأتها. عند فتح قاعدة بيانات، يتم إرجاع جلسة للتفاعل مع قاعدة البيانات. الجلسة هي نقطة الدخول لاستدعاء واجهات برمجة تطبيقات AppSearch ويظل مفتوحًا إلى أن يغلقه تطبيق العميل.
أنواع المخططات والمخططات
يمثِّل المخطط البنية التنظيمية للبيانات ضمن عملية بحث التطبيقات. قاعدة البيانات.
يتألف المخطط من أنواع مخططات تمثل أنواعًا فريدة من البيانات. تتكون أنواع المخططات من الخصائص التي تحتوي على اسم ونوع بيانات عدد القيم الفريدة للسمة. وبمجرد إضافة نوع المخطط إلى مخطط قاعدة البيانات، فإن مستندات نوع المخطط هذا وإضافته إلى قاعدة البيانات.
المستندات
في AppSearch، يتم تمثيل وحدة من البيانات كمستند. كل مستند في يتم تحديد قاعدة بيانات AppSearch بشكلٍ فريد من خلال مساحة الاسم ورقم التعريف. مساحات الاسم تُستخدم لفصل البيانات من مصادر مختلفة عندما يحتاج مصدر واحد فقط المطلوب البحث عنها، مثل حسابات المستخدمين.
تشتمل المستندات على طابع زمني للإنشاء ومدة البقاء (TTL) ونقاط ويمكن استخدامها للترتيب أثناء الاسترجاع. يتم أيضًا تعيين مخطط للمستند يصف خصائص البيانات الإضافية التي يجب أن يحتوي عليها المستند.
فئة المستند هي تجريد لمستند. تحتوي النتيجة على حقول تتضمن تعليقات توضيحية. التي تمثّل محتوى المستند. بشكل افتراضي، يكون اسم المستند تحدد الفئة اسم نوع المخطط.
بحث
تتم فهرسة المستندات ويمكن البحث عنها من خلال تقديم طلب بحث. الوثيقة عبارة عن بمطابقتها وتضمينها في نتائج البحث إذا كانت تحتوي على العبارات في طلب البحث أو تتطابق مع مواصفات بحث أخرى يتم ترتيب النتائج استنادًا إلى استراتيجية النتائج والترتيب. يتم تمثيل نتائج البحث بالصفحات التي يمكنك استردادها بشكل تسلسلي.
يوفّر AppSearch تخصيصات لشبكة البحث، مثل الفلاتر وإعدادات حجم الصفحة والمقتطفات
مقارنة بين مساحة تخزين النظام الأساسي والتخزين المحلي
تقدّم AppSearch حلَي تخزين هما LocalStorage وPlatformStorage. باستخدام LocalStorage، يمكن للتطبيق إدارة فهرس خاص بالتطبيق موجود في دليل بيانات التطبيق. باستخدام PlatformStorage، يمكن لتطبيقك في فهرس مركزي على مستوى النظام. الوصول إلى البيانات في الفهرس المركزي فقط على البيانات التي ساهم بها تطبيقك والبيانات التي تمت مشاركتها معك صراحةً بواسطة تطبيق آخر. كل من LocalStorage و تشترك PlatformStorage في واجهة برمجة التطبيقات نفسها ويمكن تبادلها استنادًا إلى إعدادات :الإصدار:
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، يمكن لتطبيقك مشاركة البيانات بشكل آمن مع التطبيقات للسماح لها بالبحث في بيانات تطبيقك أيضًا. للقراءة فقط يتم منح مشاركة بيانات التطبيق عن طريق تأكيد اتصال الشهادة لضمان فإن التطبيق الآخر لديه إذن لقراءة البيانات. مزيد من المعلومات حول واجهة برمجة التطبيقات هذه في مستندات setSchemaType visibilityForPackage().
بالإضافة إلى ذلك، يمكن عرض البيانات المفهرَسة على مساحات عرض واجهة مستخدِم النظام. يمكن للتطبيقات إيقاف عرض بعض أو كل بياناتها على النظام مساحات عرض واجهة المستخدم يمكنك الاطّلاع على مزيد من المعلومات عن واجهة برمجة التطبيقات هذه في مستندات 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 على خدمة نظام 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
لتمثيل
المستخدم العشوائي لهذه العينة. ويتم بعد ذلك إدراج المستند في قاعدة البيانات
ويتم ربط أداة استماع لمعالجة نتيجة عملية add.
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);
بحث
يمكنك البحث في المستندات التي تمت فهرستها باستخدام عمليات البحث التي يتم تناولها في
هذا القسم. تقوم التعليمة البرمجية التالية بإجراء استعلامات عن مصطلح "فاكهة" خلال
قاعدة البيانات للمستندات التي تنتمي إلى مساحة الاسم 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
الذي يمنح إمكانية الوصول إلى صفحات عناصر 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 (Kotlin)، تطبيق لتدوين الملاحظات يستخدم AppSearch لفهرسة ملاحظات المستخدم ويسمح للمستخدمين للبحث في ملاحظاتهم.
تقديم تعليقات
يمكنك مشاركة ملاحظاتك وأفكارك معنا من خلال هذه المراجع:
يُرجى الإبلاغ عن الأخطاء لنتمكّن من إصلاحها.