Isar Plus
Tarifler

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:

message.dart
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:

  1. Sadece tam kelimeleri arayabiliriz
  2. Noktalama işaretlerini dikkate almıyoruz
  3. 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:

post.dart
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:

post_with_suffix.dart
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
connecting

Popü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