Bu, şu anda yaşadığım araştırma projelerinden biri. Gereksinim neredeyse tam olarak sizinkiyle aynı ve sorunu çözmek için güzel algoritmalar geliştirdik.
Girdi
Giriş, sonsuz bir İngilizce kelime veya kelime öbeği akışıdır (bunlara şu şekilde değiniyoruz tokens).
Çıktı
- Şimdiye kadar gördüğümüz en iyi N jetonu çıkarın (gördüğümüz tüm jetonlardan!)
- Geçmiş bir pencerede, örneğin son gün veya geçen hafta ilk N jetonu çıkarın.
Bu araştırmanın bir uygulaması, Twitter veya Facebook'ta sıcak konu veya konu trendlerini bulmaktır. Web sitesinde gezinen ve sisteme beslenecek bir kelime akışı oluşturan bir tarayıcımız var. Sistem daha sonra genel veya tarihsel olarak en yüksek frekanslı kelimeleri veya cümleleri çıkaracaktır. Son birkaç hafta içinde "Dünya Kupası" ifadesinin Twitter'da birçok kez görüneceğini düşünün. "Ahtapot Paul" da öyle. :)
Tamsayılara Dize
Sistemin her kelime için bir tamsayı kimliği vardır. İnternette neredeyse sonsuz olası kelime olmasına rağmen, çok sayıda kelime biriktirdikten sonra, yeni kelimeler bulma olasılığı gittikçe azalır. Şimdiden 4 milyon farklı kelime bulduk ve her birine benzersiz bir kimlik verdik. Tüm bu veri seti, kabaca 300MB bellek tüketen bir karma tablo olarak belleğe yüklenebilir. (Kendi hash tablomuzu uyguladık. Java'nın uygulaması büyük bellek yükü gerektirir)
Her cümle daha sonra bir tamsayı dizisi olarak tanımlanabilir.
Bu önemlidir, çünkü tam sayılarda sıralama ve karşılaştırmalar çok daha hızlıdır dizelerden .
Verileri Arşivle
Sistem, her belirteç için arşiv verilerini tutar. Temelde çiftleri(Token, Frequency) . Ancak, verileri depolayan tablo o kadar büyük olur ki, tabloyu fiziksel olarak bölümlere ayırmamız gerekir. Bölme şeması, jetonun ngramlarına dayandığında. Jeton tek bir kelimeyse, 1 gramdır. Belirteç iki kelimeli bir ifade ise, 2 gramdır. Ve bu devam ediyor. Kabaca 4 gramda 1 milyar kaydımız var ve tablo boyutu 60 GB civarında.
Gelen Akışları İşleme
Sistem, bellek tamamen kullanılıncaya kadar gelen cümleleri absorbe edecektir (Ya, bir MemoryManager'a ihtiyacımız var). N cümleyi alıp belleğe kaydettikten sonra, sistem duraklar ve her cümleyi sözcüklere ve cümlelere dönüştürmeye başlar. Her simge (kelime veya kelime öbeği) sayılır.
Çok sık kullanılan belirteçler için her zaman bellekte tutulurlar. Daha az sıklıkta belirteçler için, kimliklere göre sıralanırlar (Dizeyi bir tamsayı dizisine çevirdiğimizi unutmayın) ve bir disk dosyasına serileştirilir.
(Bununla birlikte, probleminiz için, sadece kelimeleri saydığınız için, tüm kelime-frekans haritasını sadece hafızaya koyabilirsiniz. Dikkatlice tasarlanmış bir veri yapısı, 4 milyon farklı kelime için sadece 300MB hafıza kullanır. Bazı ipucu: ASCII karakterini kullanarak Dizeleri temsil eder) ve bu çok kabul edilebilir.
Bu arada, sistem tarafından oluşturulan herhangi bir disk dosyasını bulduğunda etkinleştirilen ve ardından onu birleştirmeye başlayan başka bir işlem olacaktır. Disk dosyası sıralandığından, birleştirme, birleştirme sıralaması gibi benzer bir işlem alacaktır. Çok fazla rastgele disk aramasından kaçınmak istediğimiz için burada da bazı tasarımlara dikkat edilmesi gerekiyor. Buradaki fikir, aynı anda okumayı (birleştirme işlemi) / yazmayı (sistem çıktısı) önlemek ve birleştirme işleminin farklı bir diske yazarken bir diskten okumasına izin vermektir. Bu, bir kilitleme uygulamaya benzer.
Günün sonu
Günün sonunda, sistem, bellekte depolanmış frekansı olan birçok sık simgeye ve birkaç disk dosyasında depolanan (ve her dosya sıralanır) diğer daha az sıklıkta belirteçlere sahip olacaktır.
Sistem, bellek içi haritayı bir disk dosyasına temizler (sıralayın). Şimdi, sorun bir dizi sıralı disk dosyasını birleştirmeye dönüşüyor. Benzer işlemi kullanarak, sonunda bir sıralı disk dosyası alırdık.
Ardından, son görev, sıralanan disk dosyasını arşiv veritabanına birleştirmektir. Arşiv veritabanının boyutuna bağlı olarak, algoritma yeterince büyükse aşağıdaki gibi çalışır:
for each record in sorted disk file
update archive database by increasing frequency
if rowcount == 0 then put the record into a list
end for
for each record in the list of having rowcount == 0
insert into archive database
end for
Önsezi, bir süre sonra ekleme sayısının daha da azalacağıdır. Giderek daha fazla işlem yalnızca güncelleme ile ilgili olacaktır. Ve bu güncelleme endeks tarafından cezalandırılmayacaktır.
Umarım tüm bu açıklama yardımcı olur. :)
what is the most frequent item in the subsequence [2; 2; 3; 3; 3; 4; 4; 4; 4; 5; 5] of your sequence?