Bu kılavuzda, cihaz üzerinde semantik arama özelliğinin nasıl uygulanacağı açıklanmaktadır. Bu arama tekniği, yalnızca anahtar kelimelere göre değil, sorgu anlamına göre alakalı içerikleri bulur. Semantik arama, özel eş anlamlı tabloları veya etiketleme taksonomilerini manuel olarak oluşturma ve sürdürme ihtiyacını ortadan kaldırır. Cihaz üzerinde semantik arama uygulamak için aşağıdaki kitaplıkları kullanın:
- Vektör yerleştirmeleri oluşturmak için ML Kit SDK'sı, özellikle de Embedding API
- Vektör yerleştirmelerini depolamak ve kosinüs uzaklığı metriklerini kullanarak yapılandırılmış verileri arayıp içeriği semantiğine göre bulmak için AndroidX AppSearch
Ön koşullar
Cihaz üzerinde anlamsal aramayı kullanmak için aşağıdaki cihaz ve hesap koşullarını karşılamanız gerekir:
- Cihazınız Android AICore'u destekliyor. AICore destekli cihazların çoğu NPU hızlandırmalı modeller kullanırken, desteklenen diğer cihazlar CPU modeline (XNNPACK hızlandırmalı) geri döner.
- Cihazınızdaki Google Hesabı, AICore Geliştirici Önizleme Programı'na dahildir.
- Cihazınızda AICore Geliştirici Önizlemesi APK'sının en yeni sürümü yüklü: Cihazınızda Android AICore Play Store sayfasını açın ve APK'nın en yeni sürümünü yüklemek için Güncelle'ye dokunun. Alternatif olarak cihazınızın Ayarlar bölümüne gidip Sistem hizmetleri veya Google hizmetleri'ni arayın, Android AICore (Beta) seçeneğine dokunun ve güncelleme varsa Güncelle'ye dokunun.
- Cihazınızda Private Compute Services uygulamasının en yeni sürümü yüklü olmalıdır: Cihazınızda Private Compute Services Play Store sayfasını açıp Güncelle'ye dokunarak uygulamanın en yeni sürümünü yükleyin. Alternatif olarak Play Store > Uygulamaları ve cihazı yönetin > Yönet > Private Compute Services'e gidip güncelleme varsa Güncelle'ye dokunun.
Desteklenen modeller ve yapılandırma
ML Kit Embedding API, Android AICore tarafından yönetilen Google'ın EmbeddingGemma model ailesini kullanır. Embedding API, metin ve resim girişleri için yerleştirme oluşturmak üzere özellikle EmbeddingGemma 2'yi (embedding_gemma_v2) kullanır.
Giriş spesifikasyonları ve sınırları şunlardır:
| Giriş özelliği | EmbeddingGemma 2 | Kullanım notları |
|---|---|---|
| Desteklenen modaliteler | Metin ve resim (Modality.TEXT, Modality.IMAGE) |
Resim girişinin desteklendiğini doğrulamak için çalışma zamanında model.getMetadata()?.supportedModalities.contains(Modality.IMAGE) değerinin true döndürdüğünü kontrol edin. |
| Jeton sınırı | 256 jeton | model.getTokenLimit() yöntemini kullanarak inceleyin. Her resim 70 jeton olarak kodlanır ve eşlik eden metin için 186 jeton kalır. |
| Resim çözünürlüğü | Kısa kenarda en fazla 768 piksel | ImagePart sınıfının oluşturucusu Bitmap, Uri veya ByteArray bağımsız değişken türlerini kabul eder. Kısa boyutu 768 pikselden büyük olan resimler, en boy oranı korunarak SDK tarafından otomatik olarak küçültülür. En iyi performans ve bellek kullanımı için aşırı en-boy oranlarından kaçının. |
Çıkış vektörü boyutu 768'dir (32 bit kayan noktalı sayılardan oluşan bir FloatArray nesnesi). Çıkış vektörü boyutunu, çalışma zamanında model.getMetadata()?.dimension yöntemini kullanarak inceleyebilirsiniz.
Başlayın
Projenizi semantik aramayı kullanacak şekilde yapılandırmak için modül düzeyindeki build.gradle.kts (veya build.gradle) dosyanıza aşağıdaki bağımlılıkları ekleyin.
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")
// ...
}
Modern
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'
// ...
}
Kullanılabilir modelleri almak için EmbeddingGeneration.getEmbeddingModels(EmbeddingOptions()) yöntemini kullanın.
AppSearch şeması tanımlama
Semantik benzerlik aramasını etkinleştirmek için vektör özelliğinin benzerlik dizine ekleme için açıkça yapılandırıldığı bir AppSearch şeması tanımlamanız gerekir.
// 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()
Doküman içeriğini dizine ekleme
Doküman içeriğini dizine eklemek için her Content nesnesi için bir vektör yerleştirme oluşturmanız, bunu bir GenericDocument örneğine sarmalamanız ve AppSearch veritabanınıza kaydetmeniz gerekir.
EmbeddingVector nesnesi oluştururken etkin modelSignature değerini de iletmeniz gerekir. AppSearch, uyumsuz arama sorgularını önlemek için bu modelSignature dizesini kullanır.
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()
}
Semantik arama yapma
Semantik sorgu gerçekleştirmek için arama sorgusunu (metin ve/veya resim) yerleştirme vektörüne dönüştürün, vektör arama parametrelerini yapılandırın ve AppSearch veritabanınızı sorgulayın.
Öneriler:
- Varsayılan metriği
SearchSpec.EMBEDDING_SEARCH_METRIC_TYPE_COSINEsabitine ayarlayın. - Sonuçları
"sum(this.matchedSemanticScores(getEmbeddingParameter(0)))"formülüne göre sıralayın. - Benzerliğin eşik değerinizi (genellikle 0,5 veya daha yüksek) karşıladığı sonuçları filtrelemek için mantıksal
"semanticSearch(getEmbeddingParameter(0), $threshold)"dizesini kullanın.
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()
}
}
Karma arama dizini kullanma
En iyi kullanıcı deneyimi için hem semantik hem de anahtar kelime aramasını içeren karma bir strateji kullanmanızı öneririz. Kullanıcı arama çubuğuna aktif olarak yazarken anında yazarken tamamlama önerileri göstermek için anahtar kelime aramayı kullanın. Kullanıcı tamamlanmış sorguyu girdiğinde veya kelime aralarında bile en iyi kavramsal eşleşmeleri okumak, anlamak ve getirmek için semantik aramayı kullanın.
Vektör veritabanınızı yeniden dizine ekleme
Farklı model sürümleri tarafından oluşturulan yerleştirmeler, uyumsuz vektör uzaylarında bulunur ve doğrudan karşılaştırılamaz. Yerleştirme modelini her güncellediğinizde AppSearch veritabanınızı yeniden dizine eklemeniz gerekir.
Kullandığınız modelin desteği sonlandırılma dönemine girer girmez yerleştirmeleri yeniden dizine eklemeye başlamanızı öneririz. Embedding API'yi kullanarak bir modelin desteğinin sonlandırılma planını kontrol edebilirsiniz. EmbeddingMetadata nesnesini almak için model.getMetadata() yöntemini çağırın ve şu yaşam döngüsü tarih özelliklerini kontrol edin (UTC'de LocalDate nesneleri olarak döndürülür):
deprecationDatedeğeri, modelin desteğinin sonlandırılma döneminin başlangıcını gösterir. Yeniden dizine ekleme işlemini model çalışmaya devam ederken başlatmanız ve resmi olarak kapatılmadan önce tamamlamanız gerekir.shutdownDatedeğeri, modelin kullanımdan kaldırılacağı ve artık sunulmayacağı zamanı gösterir. Bu tarihten sonra model, çıkarım için kullanılamaz ve bu modelin mevcut yerleştirmeleri, mevcut en yeni modelle yeniden dizine eklenmeye zorlanır.
Ayrıca, yakında kullanımdan kaldırılacak modeller, taşıma zaman çizelgeleri ve hedef kapatma tarihleri hakkında ML Kiti sürüm notları ve geliştirici belgeleri güncellemeleri aracılığıyla bilgi veriyoruz.
En iyi uygulamalar
İyi bir kullanıcı deneyimi için vektör yerleştirmeleri Android uygulamanıza entegre ederken aşağıdaki uygulamaları takip edin:
- Dizine ekleme iş yüklerini planlama: Arka planda dizine ekleme iş yüklerini her zaman WorkManager kitaplığını kullanarak planlayın. Arka plan görevlerinizi yalnızca cihaz şarj olurken ve boştayken çalışacak şekilde yapılandırın. ML Kit, LLM API'lerine benzer şekilde model kullanımı için kota sınırları uygular. Cihaz şarj olurken bu sınırlar daha esnektir. Geliştirici Önizlemesi modunda, test amacıyla kota sınırlamalarını atlayabilirsiniz.
- Depolama ve sorgu optimizasyonu: Niceleme ve boyut kısaltma yöntemlerini kullanarak veritabanı ayak izinizi ve sorgu gecikmesini optimize edin:
AppSearchSchemaşemanızı, AppSearch şeması tanımlama bölümünde gösterildiği gibiQUANTIZATION_TYPE_8_BITsabitini kullanacak şekilde yapılandırın. Bu, her koordinatın hassasiyetini 8 bitlik bir tam sayıya küçülterek kalite üzerinde minimum etkiyle bellek kullanımını azaltır.- Yerleştirme vektörünü kısaltmak için EmbeddingGemma 2 modeli tarafından desteklenen Matryoshka Gösterim Öğrenimi (MRL) yöntemini kullanın. Daha fazla bilgi için HuggingFace'te EmbeddingGemma 2 sayfasına bakın.
- İmza tutarlılığı: Eşleşmeyen bir imza kullanarak vektör uzayını sorgulamayın. Yerleştirme modeli sürümünü yükseltirseniz AppSearch veritabanını temizlemeniz ve yeni model imzasını kullanarak tüm dokümanlar için yerleştirmeleri yeniden oluşturmanız gerekir.
- Güvenlik ve içerik moderasyonu: Uygulamanızda içerik moderasyonu ve güvenlik filtrelemesi uygulamak sizin sorumluluğunuzdadır. Üretken metin veya görüntü API'lerinin aksine, ML Kit Embedding API'de yerleşik güvenlik filtreleri yoktur. Model, yeni metin veya medya oluşturmak yerine arayanın sağladığı girişin sayısal vektör temsillerini (
FloatArraykoordinatları) çıkardığından sayısal vektörler, doğası gereği üretken içerik güvenliği riskleri oluşturmaz. Cihaz üzerinde güvenlik filtrelemesini atlamak, yüksek gönderim hacimli belge dizine ekleme ve anlık sorgular sırasında CPU çekişmesini önleyerek düşük gecikmeli dizine ekleme ve arama performansını da korur. Güvenliği artırmak için aşağıdaki yönergeleri uygulayın:- Güvenilmeyen girişleri ve dizine eklenen içerikleri denetleyin: Uygulamanız, güvenilmeyen kullanıcı tarafından oluşturulan içerikleri veya harici verileri dizine ekliyor ya da arıyorsa dizine eklemeden veya arama sonuçlarını göstermeden önce kaynak metne ya da resimlere içerik denetimi ve politika filtreleri uygulayın.
- Alt akış üretken yapay zeka ardışık düzenlerini koruma: Alınan belgeler veya pasajlar, alt akış üretken yapay zeka modeline bağlam olarak iletiliyorsa bu alt akış modelinde ve kullanıcıya yönelik çıkışında güvenlik filtrelerinin ve içerik politikalarının etkinleştirildiğini doğrulayın.