Bir yazım denetleyicide hangi algoritma önerilerde bulunur?


114

Kelime önerileriyle birlikte bir yazım denetleyicisi uygularken genellikle hangi algoritma kullanılır?

İlk başta, yazılan her yeni kelimeyi (sözlükte yoksa) sözlükteki diğer her kelimeden Levenshtein mesafesine göre kontrol etmenin ve en iyi sonuçları döndürmenin mantıklı olacağını düşündüm . Ancak bu, tüm sözlüğü tekrar tekrar değerlendirmek zorunda kaldığı için oldukça verimsiz gibi görünüyor.

Bu genellikle nasıl yapılır?

Yanıtlar:


203

Yazım düzelticisinin nasıl uygulanacağı Peter Norvig tarafından yazılmış güzel bir makale var . Temel olarak, belirli bir düzenleme mesafesi ile aday dizeleri deneyen bir kaba kuvvet yaklaşımıdır. ( Bloom Filtresi ve daha hızlı aday karması kullanarak yazım düzeltici performansını nasıl iyileştirebileceğinize dair bazı ipuçlarını burada bulabilirsiniz .)

Yazım denetleyicisinin gereksinimleri daha zayıftır. Sadece sözlükte bir kelimenin olmadığını öğrenmen gerekiyor. Daha az bellek tüketen bir yazım denetleyici oluşturmak için Bloom Filtresi kullanabilirsiniz . Eski bir sürüm, İngilizce sözlük için 64kb kullanan Jon Bentley tarafından Programming Pearls'de açıklanmıştır.

Bir BK-Ağacı alternatif bir yaklaşımdır. Güzel bir makale burada .

Levenshstein mesafesi, bir yazım denetleyicisi için tam olarak doğru düzenleme mesafesi değildir. Yalnızca yerleştirmeyi, çıkarmayı ve değiştirmeyi bilir. Transpozisyon eksik ve 1 karakterlik transpozisyon için 2 üretiyor (1 silme ve 1 ekleme). Damerau-Levenshtein mesafesi doğru düzenleme mesafesidir.


2
Nispeten bilinmeyen BK-Ağacı referansı için +1. Gerçek Dünya [TM] veri miktarı ile çalışan Google gibi şirketler bunu böyle yapıyor.
NoozNooz42

2
Burada BK-Ağaçlarının çok daha iyi bir açıklaması var .
Ian Boyd

17

Başarılı bir şekilde kullandığım ancak hiçbir yerde açıklanmayan öneriler üretmeye yönelik bir yaklaşım, "kötü" hash işlevlerini kullanarak önerileri önceden hesaplamaktır (sözlüğü oluştururken).

Buradaki fikir, insanların yaptığı yazım hatası türlerine bakmak ve doğru yazımla aynı kovaya yanlış yazım atayacak hash fonksiyonları tasarlamaktır.

Örneğin, yaygın bir hatadır gibi yanlış bir sesli kullanmaktır definate yerine kesin . Böylece tüm ünlüleri aynı harf olarak değerlendiren bir hash işlevi tasarlarsınız. Bunu yapmanın kolay bir yolu, önce giriş sözcüğünü "normalleştirmek" ve ardından normalleştirilmiş sonucu normal bir hash işlevi aracılığıyla koymaktır. Bu örnekte, normalleştirme işlevi tüm sesli harfleri bırakabilir, yani definiteolur dfnt. "Normalleştirilmiş" kelime daha sonra tipik bir hash fonksiyonu ile hash edilir.

Bu özel hash fonksiyonunu kullanarak tüm sözlük kelimelerinizi bir yardımcı dizine (karma tablo) ekleyin. Bu tablodaki paketler uzun çarpışma listelerine sahip olacaktır çünkü hash işlevi "kötüdür", ancak bu çarpışma listeleri esasen önceden hesaplanmış önerilerdir.

Şimdi, yanlış yazılmış bir kelime bulduğunuzda, yanlış yazımın yardımcı indekslerde eşlendiği kovanın çarpışma listelerine bakarsınız. Ta da: Bir öneri listeniz var! Tek yapmanız gereken, üzerindeki kelimeleri sıralamak.

Pratikte, çevrilmiş harfler, tek / çift harf ve hatta fonetik yazım hatalarını yakalamak için basit bir Soundex benzeri gibi diğer hata türlerini işlemek için diğer hash işlevlerine sahip birkaç yardımcı dizine ihtiyacınız olacak. Pratikte, basit telaffuzların uzun bir yol kat ettiğini ve aslında önemsiz yazım hatalarını bulmak için tasarlananların bazılarını geçersiz kıldığını buldum.

Artık yardımcı dizinlerdeki yanlış yazımlara bakarsınız ve sıralamadan önce çakışma listelerini birleştirirsiniz.

Çarpışma listelerinin yalnızca sözlükte bulunan sözcükleri içerdiğini unutmayın. Alternatif yazımlar üretmeye çalışan yaklaşımlarla (Peter Norvig makalesinde olduğu gibi), ilk önce sözlüğe göre filtrelemeniz gereken (on binlerce) adayı elde edebilirsiniz. Önceden hesaplanmış yaklaşımla, belki birkaç yüz aday elde edersiniz ve bunların hepsinin doğru yazıldığını bilirsiniz, böylece doğrudan sıralamaya geçebilirsiniz.

Güncelleme : O zamandan beri buna benzer bir algoritma açıklaması buldum, FAROO Dağıtılmış Arama . Bu hala düzenleme mesafesi sınırlı bir aramadır, ancak çok hızlıdır çünkü ön hesaplama adımı benim "kötü hash fonksiyonları" fikrim gibi çalışır. FAROO sadece sınırlı bir kötü hash işlevi kavramı kullanır.


Faroos'un SymSpell algoritmasına başvurduğunuz için teşekkür ederiz. Her iki algoritma da olası yazım hatalarını önceden hesaplarken ve hızlı arama için bir karma tablosu kullanırken, asıl fark, SymSpell'in belirli bir düzenleme mesafesine kadar olası tüm yazım hatalarını tespit etmeyi garanti etmesidir (bu açıdan SymSpell, Peter Norvig'in algoritmasına eşdeğerdir, sadece 3..6 büyüklük sıralaması daha hızlı), algoritmanız teorik olarak olası tüm yazım hatalarının yalnızca sınırlı bir alt kümesini algılayan sezgisel bir yaklaşım kullanırken (bu nedenle ön hesaplama maliyetiniz daha düşük olabilir).
Wolf Garbe

SymSpell algoritması olası yazım hatalarını önceden hesaplar ve saklar, benim "bozuk hash" şemam bunu yapmaz. İngilizce için, çok fazla zemini kapsayan tek bir basit fonetik karma eklemek önemsizdir (örneğin, düzenleme mesafesi 6 olan "terradacktle" -> "pterodactyl"). Verilmiş, eğer çok dilli aramalara ihtiyacınız varsa, o zaman çok daha zor olabilir.
Adrian McCarthy

Kesinlikle, olası yazım hatalarıyla ilgili deneysel bilgileri kullanarak (ve bunlarla sınırlandırarak) hesaplama öncesi zamandan ve yerden tasarruf edersiniz. Ancak tüm olası yazım hatalarını kapsamak için SymSpell'in bunların yalnızca küçük bir kısmını önceden hesaplaması gerekir. 5 harfli bir kelimede maksimum 3 düzenleme mesafesi içinde yaklaşık 3 milyon olası yazım hatası vardır, ancak SymSpell ile yalnızca 25 silinmeyi önceden hesaplamanız ve saklamanız gerekir. Bu, ampirik bilginin bulunmadığı yazım düzeltmesinin ötesinde bulanık / benzerlik araştırması için önemlidir.
Kurt Garbe

7

Algoritma

  1. Yanlış yazılmış bir kelimeyi girdi olarak alın.
  2. İngilizce kelimelerin listesini frekanslarıyla birlikte bir metin dosyasında saklayın.
  3. Mevcut tüm İngilizce kelimeleri (metin dosyasında saklanan) frekanslarıyla birlikte (bir kelimenin İngilizce dilinde ne sıklıkla kullanıldığının ölçüsü) Üçlü Arama Ağacına ekleyin.
  4. Şimdi Üçlü Arama Ağacı boyunca ilerleyin -
    • Üçlü Arama Ağacında karşılaşılan her kelime için, yanlış yazılmış kelimeden Levensthein Mesafesini hesaplayın.
    • Levensthein Distance <= 3 ise, kelimeyi bir Öncelik Kuyruğunda saklayın.
    • İki kelime aynı düzenleme mesafesine sahipse, frekansı daha yüksek olan daha büyüktür. Priority Queue'dan ilk 10 öğeyi yazdırın.

Optimizasyon

  1. Giriş kelimesinin alt dizesinin mevcut kelimeden düzenleme mesafesi 3'ten daha büyükse, mevcut düğümün alt ağacındaki kelimeleri kaldırabilirsiniz.
    Daha detaylı açıklama ve kaynak kodunu github projesinde bulabilirsiniz .

Hmm, bu durumda Levenshtein 'daha büyük' ​​ile 'daha büyük' ​​arasındaki mesafe yeterli olmazdı, çünkü 'rende' aynı zamanda bir sözlük kelimesi. ;-)
Tony Brasunas

1
@TonyBrasunas, Evet haklısın. Fakat program aslında girdi olarak 'daha büyük' ​​olması durumunda 10 kelimelik bir liste döndürecektir ve 0 düzenleme mesafesi ile 'daha büyük' ​​ve ayrıca 1 düzenleme mesafesi ile 'daha büyük' ​​önerecektir. Bu biraz yardımcı olabilir. ;)
amarjeetAnand

Bir adayın uzaklığı 2 olmasına rağmen çok sıksa ve başka bir adayın uzaklığı 1 ise ancak son derece nadirse, ikisini nasıl sıralarsınız? Yukarıdaki yaklaşımda, nadir öğe her zaman kazanırdı, bu doğru sonuç mu?
sürat uçağı

@speedplane Evet. nadir olan kazanacak. Ve bunun doğru sonuç olduğunu düşünüyorum. Çünkü, giriş sözcüğünün yazılışına bağlı olarak en yakın sözcük olmasını bekliyoruz. Hala şüpheniz varsa, şu şekilde düşünün --- kullanıcının nadiren doğru yazdığı bir kelime olduğunu varsayalım. Şimdi mesafesi 0, ancak frekansı çok düşük. Şimdi önerilerde, bu nadir kelimeyi (0 mesafesi ile) en üstte (çünkü en az düzenleme mesafesi kazanır) ve diğer kelimeleri 1-2-3 mesafe ile aşağıda listelemeliyiz.
amarjeetAnand

3

Sözlükteki her kelime için tam düzenleme mesafesini bilmenize gerek yoktur. Algoritmayı bir limit değere ulaştıktan sonra durdurabilir ve kelimeyi hariç tutabilirsiniz. Bu size çok fazla bilgi işlem süresi kazandıracak.


1

Yazım denetleyicisinin uygulanması, Unix yazım programında olduğu gibi çok kolaydır. Kaynak kodu halka açık olarak mevcuttur. Düzeltme dahil edilebilir, bir teknik düzenleme yapmak ve bu yeni kelimenin sözlükte olup olmadığını tekrar kontrol etmektir. Bu tür yeni düzenlemeler gruplanabilir ve kullanıcıya gösterilebilir.

Unix sistemi Mc IllRoy tarafından yazılmış bir program kullanır. Alternatif bir yol, çok büyük dosyalar söz konusu olduğunda faydalı olabilecek bir Trie kullanmaktır.

Unix yaklaşımı, dağılım hash algoritması kullandığından, büyük bir sözlük için çok daha az alana ihtiyaç duyar.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.