Tam Metin Arama
Kelime indeksleme ve gelişmiş eşleştirme ile güçlü tam metin araması uygulayın
Tam Metin Arama
Tam metin arama, veritabanındaki metinleri aramanın güçlü bir yoludur. İndekslerin nasıl çalıştığını zaten biliyor olmalısınız, ancak hızlıca üzerinden geçelim.
Bir indeks, sorgu motorunun belirli değere sahip kayıtları hızlıca bulmasını sağlayan bir lookup tablosu gibi çalışır. Örneğin nesnenizde bir title alanınız varsa, bu alanı indeksleyerek belirli bir başlığa sahip kayıtları daha hızlı bulabilirsiniz.
Neden tam metin araması?
Filtreler kullanarak metin aramak kolaydır. .startsWith(), .contains() ve .matches() gibi çeşitli string işlemleri vardır. Sorun, filtrelerin çalışma süresinin koleksiyondaki kayıt sayısı n olduğunda O(n) olmasıdır. .matches() gibi string işlemleri özellikle pahalıdır.
Performans Avantajı
Tam metin araması filtrelere göre çok daha hızlıdır, ancak indekslerin bazı kısıtlamaları vardır. Bu tarifte bu kısıtları nasıl aşabileceğimizi inceleyeceğiz.
Basit örnek
Fikir her zaman aynıdır: Tüm metni indekslemek yerine metindeki kelimeleri indeksleriz ve böylece tek tek arayabiliriz.
En temel tam metin indeksini oluşturalım:
class Message {
Id? id;
late String content;
@Index()
List<String> get contentWords => content.split(' ');
}Artık içerikte belirli kelimeler geçen mesajları arayabiliriz:
final posts = await isar.messages
.where()
.contentWordsAnyEqualTo('hello')
.findAll();Bu sorgu çok hızlıdır, ancak bazı sorunlar var:
- Sadece tam kelimeleri arayabiliriz
- Noktalama işaretlerini dikkate almıyoruz
- Diğer boşluk karakterlerini desteklemiyoruz
Metni doğru şekilde bölmek
Önceki örneği geliştirmeye çalışalım. Kelime bölmeyi düzeltmek için karmaşık bir regex yazabiliriz, ancak muhtemelen yavaş olur ve köşetaşlarında bozulur.
Unicode Annex #29 neredeyse tüm diller için metnin kelimelere nasıl bölüneceğini tanımlar. Oldukça karmaşıktır ama neyse ki Isar bizim için işi yapar:
Isar.splitWords('hello world');
// -> ['hello', 'world']Isar.splitWords('The quick ("brown") fox can't jump 32.3 feet, right?');
// -> ['The', 'quick', 'brown', 'fox', 'can't', 'jump', '32.3', 'feet', 'right']Gelişmiş eşleştirme kontrolü
Çok kolay! İndeksi prefix eşleşmesini ve büyük/küçük harf duyarsız aramayı destekleyecek şekilde değiştirebiliriz:
class Post {
Id? id;
late String title;
@Index(type: IndexType.value, caseSensitive: false)
List<String> get titleWords => title.split(' ');
}Varsayılan olarak Isar kelimeleri hash'lenmiş şekilde saklar; bu hızlı ve yer açısından verimlidir. Ancak hash'ler prefix eşleşmesinde kullanılamaz. IndexType.value kullanarak indeksin kelimeleri doğrudan kullanmasını sağlayabiliriz. Böylece .titleWordsAnyStartsWith() where cümlesi elde ederiz:
final posts = await isar.posts
.where()
.titleWordsAnyStartsWith('hel')
.or()
.titleWordsAnyStartsWith('welco')
.or()
.titleWordsAnyStartsWith('howd')
.findAll();.endsWith() ile soneki eşleştirme
Elbette! .endsWith() eşleşmesi için küçük bir numara kullanacağız:
class Post {
Id? id;
late String title;
@Index(type: IndexType.value, caseSensitive: false)
List<String> get revTitleWords {
return Isar.splitWords(title).map(
(word) => word.reversed).toList()
);
}
}Aramak istediğiniz son ekin tersini almayı unutmayın:
final posts = await isar.posts
.where()
.revTitleWordsAnyStartsWith('lcome'.reversed)
.findAll();Stemmer algoritmaları
Ne yazık ki indeksler .contains() eşleşmesini desteklemez (bu diğer veritabanları için de geçerlidir). Ancak keşfetmeye değer birkaç alternatif vardır. Seçim kullanım senaryonuza göre değişir. Bir örnek, kelimenin tamamı yerine kökünü indekslemektir.
Stemmer algoritması, bir kelimenin farklı varyantlarını ortak bir forma indirgeme sürecidir:
connection
connections
connective ---> connect
connected
connectingPopüler stemmer algoritmaları:
- Porter stemming algorithm: Klasik İngilizce stemmer
- Snowball stemming algorithms: Çoklu dil desteği
- Lemmatization: Daha gelişmiş dilsel normalizasyon
Popüler algoritmalar Porter stemming algorithm ve Snowball stemming algorithms'tur.
Lemmatization gibi daha gelişmiş yöntemler de vardır.
Fonetik algoritmalar
Fonetik algoritma, kelimeleri telaffuzlarına göre indeksleyen bir algoritmadır. Başka bir deyişle, aradığınız kelimelere benzer şekilde söylenen kelimeleri bulmanızı sağlar.
Dil Kısıtı
Çoğu fonetik algoritma yalnızca tek bir dili destekler.
Soundex
Soundex, adları İngilizce telaffuzlarına göre indeksleyen bir fonetik algoritmadır. Amaç, homofonların aynı temsil ile kodlanması ve yazım farklarına rağmen eşleştirilebilmesidir.
"Robert" -> "R163"
"Rupert" -> "R163"
"Rubin" -> "R150"
"Ashcraft" -> "A261"
"Ashcroft" -> "A261"Bu algoritma, homofonların aynı temsile kodlanmasını sağlar; böylece küçük yazım farklarına rağmen eşleştirilebilirler. Oldukça basit bir algoritmadır ve geliştirilmiş sürümleri mevcuttur.
Double Metaphone
Double Metaphone fonetik kodlama algoritması, bu algoritmanın ikinci neslidir. İlk Metaphone algoritmasına göre temel tasarım iyileştirmeleri içerir.
Double Metaphone; Slav, Germen, Kelt, Yunanca, Fransızca, İtalyanca, İspanyolca, Çince ve diğer kökenli İngilizce düzensizliklerini dikkate alır.
Son Güncelleme