इस गाइड में, उपयोगकर्ता के डिवाइस पर सिमैंटिक सर्च की सुविधा लागू करने का तरीका बताया गया है. यह खोज की एक ऐसी तकनीक है जो सिर्फ़ कीवर्ड के बजाय, क्वेरी के मतलब के आधार पर काम का कॉन्टेंट ढूंढती है. सिमैंटिक सर्च की सुविधा की मदद से, समानार्थी शब्दों की कस्टम टेबल या टैगिंग टैक्सोनॉमी को मैन्युअल तरीके से बनाने और मैनेज करने की ज़रूरत नहीं पड़ती. उपयोगकर्ता के डिवाइस पर सिमैंटिक सर्च की सुविधा लागू करने के लिए, इन लाइब्रेरी का इस्तेमाल करें:
- वेक्टर एंबेडिंग जनरेट करने के लिए, ML Kit SDK टूल, खास तौर पर एंबेडिंग एपीआई
- AndroidX AppSearch, ताकि वेक्टर एंबेडिंग को सेव किया जा सके. साथ ही, कोसाइन डिस्टेंस मेट्रिक का इस्तेमाल करके स्ट्रक्चर्ड डेटा को खोजा जा सके, ताकि कॉन्टेंट को उसके सिमैंटिक के हिसाब से ढूंढा जा सके
ज़रूरी शर्तें
उपयोगकर्ता के डिवाइस पर सेमैंटिक सर्च की सुविधा का इस्तेमाल करने के लिए, आपको डिवाइस और खाते से जुड़ी ये ज़रूरी शर्तें पूरी करनी होंगी:
- आपके डिवाइस पर Android AICore काम करता हो. AICore की सुविधा वाले ज़्यादातर डिवाइसों में, एनपीयू की मदद से तेज़ी से काम करने वाले मॉडल इस्तेमाल किए जाते हैं. वहीं, इस सुविधा वाले बाकी डिवाइसों में सीपीयू मॉडल (XNNPACK की मदद से तेज़ी से काम करने वाले मॉडल) का इस्तेमाल किया जाता है.
- आपके डिवाइस पर मौजूद Google खाता, AICore Developer Preview program का हिस्सा है.
- आपके डिवाइस पर, AICore डेवलपर के लिए झलक APK का नया वर्शन मौजूद हो: अपने डिवाइस पर, Android AICore Play Store पेज खोलें और APK का नया वर्शन इंस्टॉल करने के लिए, अपडेट करें पर टैप करें. इसके अलावा, अपने डिवाइस की सेटिंग में जाकर, सिस्टम की सेवाएं या Google की सेवाएं खोजें. इसके बाद, Android AICore (बीटा वर्शन) पर टैप करें. अगर कोई अपडेट उपलब्ध है, तो अपडेट करें पर टैप करें.
- आपके डिवाइस पर Private Compute Services ऐप्लिकेशन का नया वर्शन मौजूद हो: अपने डिवाइस पर, Private Compute Services का Play Store पेज खोलें और ऐप्लिकेशन का नया वर्शन इंस्टॉल करने के लिए, अपडेट करें पर टैप करें. इसके अलावा, Play Store > ऐप्लिकेशन और डिवाइस मैनेज करें > मैनेज करें > Private Compute Services पर जाएं. अगर कोई अपडेट उपलब्ध है, तो अपडेट करें पर टैप करें.
इस्तेमाल किए जा सकने वाले मॉडल और कॉन्फ़िगरेशन
ML Kit Embedding API, Google के EmbeddingGemma मॉडल फ़ैमिली का इस्तेमाल करता है. इसे Android AICore मैनेज करता है. खास तौर पर, Embedding API, टेक्स्ट और इमेज इनपुट के लिए एंबेडिंग जनरेट करने के लिए, EmbeddingGemma 2 (embedding_gemma_v2) का इस्तेमाल करता है.
इनपुट की खास जानकारी और सीमाएं यहां दी गई हैं:
| इनपुट प्रॉपर्टी | EmbeddingGemma 2 | इस्तेमाल की जानकारी |
|---|---|---|
| इस्तेमाल किए जा सकने वाले मोड | टेक्स्ट और इमेज (Modality.TEXT, Modality.IMAGE) |
इमेज इनपुट की सुविधा काम करती है या नहीं, इसकी पुष्टि करने के लिए रनटाइम के दौरान देखें कि model.getMetadata()?.supportedModalities.contains(Modality.IMAGE), true दिखाता है या नहीं. |
| टोकन की सीमा | 256 टोकन | model.getTokenLimit() तरीके का इस्तेमाल करके जांच करें. हर इमेज को 70 टोकन में एन्कोड किया जाता है. इससे, इमेज के साथ मौजूद टेक्स्ट के लिए 186 टोकन बचते हैं. |
| इमेज रिज़ॉल्यूशन | छोटी साइड पर 768 पिक्सल तक | ImagePart क्लास के लिए कंस्ट्रक्टर, Bitmap, Uri या ByteArray आर्ग्युमेंट टाइप स्वीकार करता है. अगर किसी इमेज का छोटा डाइमेंशन 768 पिक्सल से ज़्यादा है, तो एसडीके उसका साइज़ अपने-आप छोटा कर देता है. हालांकि, इससे इमेज के आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) पर कोई असर नहीं पड़ता. बेहतर परफ़ॉर्मेंस और मेमोरी के इस्तेमाल के लिए, बहुत ज़्यादा आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) इस्तेमाल करने से बचें. |
आउटपुट वेक्टर डाइमेंशन 768 है (32-बिट फ़्लोट का FloatArray ऑब्जेक्ट). model.getMetadata()?.dimension तरीके का इस्तेमाल करके, रनटाइम के दौरान आउटपुट वेक्टर डाइमेंशन की जांच की जा सकती है.
अपनी प्रोफ़ाइल बनाना शुरू करें
सेमैंटिक सर्च का इस्तेमाल करने के लिए, अपने प्रोजेक्ट को कॉन्फ़िगर करें. इसके लिए, मॉड्यूल-लेवल की build.gradle.kts (या build.gradle) फ़ाइल में ये डिपेंडेंसी जोड़ें.
Kotlin
dependencies {
// ...
implementation("com.google.mlkit:genai-embedding:1.0.0-alpha1")
implementation("androidx.appsearch:appsearch:1.2.0-alpha01")
implementation("androidx.appsearch:appsearch-local-storage:1.2.0-alpha01")
implementation("androidx.concurrent:concurrent-futures-ktx:1.3.0")
// ...
}
ग्रूवी
dependencies {
// ...
implementation 'com.google.mlkit:genai-embedding:1.0.0-alpha1'
implementation 'androidx.appsearch:appsearch:1.2.0-alpha01'
implementation 'androidx.appsearch:appsearch-local-storage:1.2.0-alpha01'
implementation 'androidx.concurrent:concurrent-futures-ktx:1.3.0'
// ...
}
उपलब्ध मॉडल की जानकारी पाने के लिए, EmbeddingGeneration.getEmbeddingModels(EmbeddingOptions()) तरीके का इस्तेमाल करें.
AppSearch स्कीमा तय करना
सेमैंटिक सिमिलैरिटी सर्चिंग की सुविधा चालू करने के लिए, आपको AppSearch स्कीमा तय करना होगा. इसमें वेक्टर प्रॉपर्टी को साफ़ तौर पर सिमिलैरिटी इंडेक्सिंग के लिए कॉन्फ़िगर किया गया हो.
// Define the document schema
val documentSchema = AppSearchSchema.Builder("my_schema_type")
.addProperty(
AppSearchSchema.StringPropertyConfig.Builder("text")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_PREFIXES)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_PLAIN)
.build()
)
.addProperty(
AppSearchSchema.StringPropertyConfig.Builder("imageUri")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(AppSearchSchema.StringPropertyConfig.INDEXING_TYPE_NONE)
.setTokenizerType(AppSearchSchema.StringPropertyConfig.TOKENIZER_TYPE_NONE)
.build()
)
.addProperty(
AppSearchSchema.EmbeddingPropertyConfig.Builder("embedding")
.setCardinality(AppSearchSchema.PropertyConfig.CARDINALITY_OPTIONAL)
.setIndexingType(
AppSearchSchema.EmbeddingPropertyConfig.INDEXING_TYPE_SIMILARITY)
.setQuantizationType(
AppSearchSchema.EmbeddingPropertyConfig.QUANTIZATION_TYPE_8_BIT)
.build()
)
.build()
दस्तावेज़ के कॉन्टेंट को इंडेक्स करना
दस्तावेज़ के कॉन्टेंट को इंडेक्स करने के लिए, आपको हर Content ऑब्जेक्ट के लिए एक वेक्टर एंबेडिंग जनरेट करनी होगी. इसके बाद, उसे GenericDocument इंस्टेंस में रैप करना होगा और अपने AppSearch डेटाबेस में सेव करना होगा.
EmbeddingVector ऑब्जेक्ट बनाते समय, आपको चालू modelSignature वैल्यू भी पास करनी होगी. AppSearch, इस modelSignature स्ट्रिंग का इस्तेमाल करके, सर्च क्वेरी को गलत तरीके से इस्तेमाल होने से रोकता है.
suspend fun syncDatabase(documents: List<Pair<String, Uri?>>) {
val modelSignature = model?.getModelSignature() ?: return
val docsWithEmbedding = mutableListOf<GenericDocument>()
for ((index, item) in documents.withIndex()) {
val (content, imageUri) = item
// 1. Generate embedding (text and/or image)
val parts = mutableListOf<Part>()
if (content.isNotBlank()) {
parts.add(TextPart(content))
}
var imagePart: ImagePart? = null
val vector = try {
if (imageUri != null && isImageSupported) {
imagePart = ImagePart(imageUri)
parts.add(imagePart)
}
if (parts.isEmpty()) continue
val request = EmbeddingRequest(
Content(parts)
)
model?.generateEmbedding(request)?.embedding?.vector
?: continue
} finally {
imagePart?.close()
}
// 2. Build the AppSearch document
val docBuilder = GenericDocument.Builder<GenericDocument.Builder<*>>(
"my_namespace",
"doc_$index",
"my_schema_type"
)
.setPropertyString("text", content)
// Associate the vector with the signature that generated it
.setPropertyEmbedding("embedding", EmbeddingVector(vector, modelSignature))
if (imageUri != null) {
docBuilder.setPropertyString("imageUri", imageUri.toString())
}
docsWithEmbedding.add(docBuilder.build())
}
// 3. Clear the old database by force-overriding the schema
val clearRequest = SetSchemaRequest.Builder().setForceOverride(true).build()
session?.setSchemaAsync(clearRequest)?.await()
val schemaRequest = SetSchemaRequest.Builder().addSchemas(documentSchema).build()
session?.setSchemaAsync(schemaRequest)?.await()
// 4. Index documents
val putRequest = PutDocumentsRequest.Builder().addGenericDocuments(docsWithEmbedding).build()
session?.putAsync(putRequest)?.await()
}
सिमैंटिक सर्च की सुविधा का इस्तेमाल करना
सिमैंटिक क्वेरी करने के लिए, सर्च क्वेरी (टेक्स्ट और/या इमेज) को एंबेडिंग वेक्टर में बदलें. इसके बाद, वेक्टर-सर्च पैरामीटर कॉन्फ़िगर करें और अपने AppSearch डेटाबेस से क्वेरी करें.
सुझाव:
- डिफ़ॉल्ट मेट्रिक को
SearchSpec.EMBEDDING_SEARCH_METRIC_TYPE_COSINEकॉन्सटेंट पर सेट करें. "sum(this.matchedSemanticScores(getEmbeddingParameter(0)))"फ़ॉर्मूला के हिसाब से नतीजों को रैंक करें.- नतीजों को फ़िल्टर करने के लिए, लॉजिकल
"semanticSearch(getEmbeddingParameter(0), $threshold)"स्ट्रिंग का इस्तेमाल करें. इससे आपको ऐसे नतीजे मिलेंगे जो आपकी थ्रेशोल्ड वैल्यू (आम तौर पर 0.5 या इससे ज़्यादा) से मिलते-जुलते हों.
suspend fun search(
queryText: String,
imageUri: Uri? = null,
threshold: Double = 0.5
): List<Triple<String, Uri?, Double>> {
val modelSignature = model?.getModelSignature() ?: return emptyList()
// 1. Generate query embedding (text and/or image)
val parts = mutableListOf<Part>()
if (queryText.isNotBlank()) {
parts.add(TextPart(queryText))
}
var imagePart: ImagePart? = null
val queryVector = try {
if (imageUri != null && isImageSupported) {
imagePart = ImagePart(imageUri)
parts.add(imagePart)
}
if (parts.isEmpty()) return emptyList()
val request = EmbeddingRequest(
content = Content(parts)
)
model?.generateEmbedding(request)?.embedding?.vector
?: return emptyList()
} finally {
imagePart?.close()
}
// 2. Configure search specifications
val searchSpec = SearchSpec.Builder()
.addFilterSchemas("my_schema_type")
.setDefaultEmbeddingSearchMetricType(SearchSpec.EMBEDDING_SEARCH_METRIC_TYPE_COSINE)
.setRankingStrategy("sum(this.matchedSemanticScores(getEmbeddingParameter(0)))")
.setListFilterQueryLanguageEnabled(true)
.setResultCountPerPage(5)
// Add the query vector as parameter 0
.addEmbeddingParameters(EmbeddingVector(queryVector, modelSignature))
.build()
// 3. Execute search
val queryExpression = "semanticSearch(getEmbeddingParameter(0), $threshold)"
val results = session?.search(queryExpression, searchSpec) ?: return emptyList()
return try {
val page = results.nextPageAsync.await()
page.map {
val text = it.genericDocument.getPropertyString("text") ?: ""
val matchedImageUri = it.genericDocument.getPropertyString("imageUri")?.let(Uri::parse)
// rankingSignal contains the computed similarity score
Triple(text, matchedImageUri, it.rankingSignal)
}
} finally {
results.close()
}
}
हाइब्रिड सर्च इंडेक्स का इस्तेमाल करना
उपयोगकर्ता को बेहतर अनुभव देने के लिए, हमारा सुझाव है कि आप हाइब्रिड रणनीति का इस्तेमाल करें. इसमें सिमैंटिक और कीवर्ड सर्च, दोनों शामिल हैं. जब उपयोगकर्ता खोज बार में कुछ टाइप कर रहा हो, तब कीवर्ड सर्च का इस्तेमाल करके, उसे तुरंत टाइप-अहेड सुझाव दिखाएं. जब वह पूरी क्वेरी डाल दे या शब्दों के बीच में स्पेस दे, तब सिमैंटिक सर्च का इस्तेमाल करके, क्वेरी को पढ़ें, समझें, और सबसे सही मैच दिखाएं.
अपने वेक्टर डेटाबेस को फिर से इंडेक्स करना
मॉडल के अलग-अलग वर्शन से जनरेट किए गए एंबेडिंग, अलग-अलग वेक्टर स्पेस में मौजूद होते हैं. इसलिए, उनकी तुलना सीधे तौर पर नहीं की जा सकती. जब भी एम्बेडिंग मॉडल को अपडेट किया जाए, तब आपको AppSearch डेटाबेस को फिर से इंडेक्स करना होगा.
हमारा सुझाव है कि इस्तेमाल किए जा रहे मॉडल के बंद होने की अवधि शुरू होते ही, एंबेडिंग को फिर से इंडेक्स करना शुरू कर दें. Embedding API का इस्तेमाल करके, किसी मॉडल के बंद होने का शेड्यूल देखा जा सकता है. EmbeddingMetadata ऑब्जेक्ट को वापस पाने के लिए, model.getMetadata() तरीके को कॉल करें. साथ ही, लाइफ़साइकल की तारीख की इन प्रॉपर्टी को देखें. ये प्रॉपर्टी, यूटीसी में LocalDate ऑब्जेक्ट के तौर पर दिखती हैं:
deprecationDateवैल्यू से, मॉडल के बंद होने की अवधि की शुरुआत का पता चलता है. आपको मॉडल के बंद होने से पहले, फिर से इंडेक्स करने की प्रोसेस शुरू कर देनी चाहिए. साथ ही, मॉडल के आधिकारिक तौर पर बंद होने से पहले, फिर से इंडेक्स करने की प्रोसेस पूरी कर लेनी चाहिए.shutdownDateकी वैल्यू से पता चलता है कि मॉडल को कब बंद किया जाएगा और कब इसका इस्तेमाल नहीं किया जा सकेगा. इस तारीख के बाद, अनुमान लगाने के लिए मॉडल को ऐक्सेस नहीं किया जा सकेगा. साथ ही, इस मॉडल की मौजूदा एम्बेडिंग को उपलब्ध नए मॉडल के साथ फिर से इंडेक्स करना होगा.
हम ML Kit के प्रॉडक्ट की जानकारी और डेवलपर के दस्तावेज़ के अपडेट के ज़रिए, मॉडल के बंद होने, माइग्रेशन की टाइमलाइन, और बंद होने की तारीखों के बारे में भी बताते हैं.
सबसे सही तरीके
उपयोगकर्ता को बेहतर अनुभव देने के लिए, अपने Android ऐप्लिकेशन में वेक्टर एंबेडिंग को इंटिग्रेट करते समय इन तरीकों को अपनाएं:
- इंडेक्स करने के वर्कलोड शेड्यूल करना: बैकग्राउंड में इंडेक्स करने के वर्कलोड को हमेशा WorkManager लाइब्रेरी का इस्तेमाल करके शेड्यूल करें. बैकग्राउंड में चलने वाले टास्क को इस तरह कॉन्फ़िगर करें कि वे सिर्फ़ तब चलें, जब डिवाइस चार्ज हो रहा हो और इस्तेमाल में न हो. एलएलएम एपीआई की तरह ही, एमएल किट भी मॉडल के इस्तेमाल के लिए कोटा तय करती है. हालांकि, डिवाइस के चार्ज होने के दौरान, कोटा की सीमाएं ज़्यादा उदार होती हैं. डेवलपर के लिए झलक मोड में, टेस्टिंग के लिए कोटा की सीमाओं को बायपास किया जा सकता है.
- स्टोरेज और क्वेरी ऑप्टिमाइज़ेशन: क्वांटाइज़ेशन और डाइमेंशन ट्रंकेशन का इस्तेमाल करके, अपने डेटाबेस फ़ुटप्रिंट और क्वेरी के इंतज़ार के समय को ऑप्टिमाइज़ करें:
QUANTIZATION_TYPE_8_BITकॉन्सटैंट का इस्तेमाल करने के लिए, अपनेAppSearchSchemaस्कीमा को कॉन्फ़िगर करें. इसके बारे में AppSearch स्कीमा तय करें में बताया गया है. इससे मेमोरी का इस्तेमाल कम होता है. साथ ही, हर कोऑर्डिनेट की सटीक जानकारी को 8-बिट के पूर्णांक में छोटा करके, क्वालिटी पर कम से कम असर पड़ता है.- एम्बेडिंग वेक्टर को छोटा करने के लिए, Matryoshka Representation Learning (MRL) का इस्तेमाल करें. यह EmbeddingGemma 2 मॉडल के साथ काम करता है. ज़्यादा जानने के लिए, HuggingFace पर EmbeddingGemma 2 देखें.
- सिग्नेचर की एकरूपता: किसी वेक्टर स्पेस को क्वेरी करने के लिए, ऐसे सिग्नेचर का इस्तेमाल न करें जो मेल न खाता हो. अगर आपने एंबेडिंग मॉडल के वर्शन को अपग्रेड किया है, तो आपको AppSearch डेटाबेस को वाइप करना होगा. साथ ही, नए मॉडल सिग्नेचर का इस्तेमाल करके, सभी दस्तावेज़ों के लिए एंबेडिंग को फिर से जनरेट करना होगा.
- सुरक्षा और कॉन्टेंट मॉडरेट करना: अपने ऐप्लिकेशन में कॉन्टेंट मॉडरेट करने और सुरक्षा फ़िल्टर लागू करने की ज़िम्मेदारी आपकी है. जनरेटिव टेक्स्ट या इमेज एपीआई के उलट, ML Kit Embedding API में सुरक्षा फ़िल्टर पहले से मौजूद नहीं होते. मॉडल, कॉलर से मिले इनपुट के लिए नया टेक्स्ट या मीडिया जनरेट करने के बजाय, संख्या वाले वेक्टर प्रज़ेंटेशन (
FloatArrayकोऑर्डिनेट) आउटपुट करता है. इसलिए, संख्या वाले वेक्टर से जनरेटिव कॉन्टेंट की सुरक्षा को कोई खतरा नहीं होता. उपयोगकर्ता के डिवाइस पर सुरक्षा से जुड़ी फ़िल्टरिंग की सुविधा को हटाने से, कम इंतज़ार के समय वाली इंडेक्सिंग और खोज की परफ़ॉर्मेंस भी बेहतर बनी रहती है. ऐसा इसलिए होता है, क्योंकि हाई-थ्रूपुट वाले दस्तावेज़ की इंडेक्सिंग और रीयल-टाइम क्वेरी के दौरान, सीपीयू के लिए संसाधनों की कमी नहीं होती. सुरक्षा को बेहतर बनाने के लिए, इन दिशा-निर्देशों का पालन करें:- गैर-भरोसेमंद इनपुट और इंडेक्स किए गए कॉन्टेंट को मॉडरेट करें: अगर आपका ऐप्लिकेशन, यूज़र जनरेटेड कॉन्टेंट या बाहरी डेटा को इंडेक्स करता है या खोजता है, तो इंडेक्स करने या खोज के नतीजे दिखाने से पहले, सोर्स टेक्स्ट या इमेज पर कॉन्टेंट मॉडरेट करने और नीति से जुड़े फ़िल्टर लागू करें.
- डाउनस्ट्रीम जनरेटिव एआई पाइपलाइन को सुरक्षित रखना: अगर खोजे गए दस्तावेज़ों या पैसेज को डाउनस्ट्रीम जनरेटिव एआई मॉडल के लिए कॉन्टेक्स्ट के तौर पर पास किया जाता है, तो पुष्टि करें कि उस डाउनस्ट्रीम मॉडल और उसके इस्तेमाल करने वाले लोगों के लिए उपलब्ध आउटपुट पर, सुरक्षा फ़िल्टर और कॉन्टेंट से जुड़ी नीतियां चालू हों.