2011-06-11 30 views
6

Mysql'de 1000000 addan fazla ad depoladığım bir veritabanım var. Şimdi benim uygulamamın görevi biraz tipik. Sadece veritabanındaki isimleri araştırmakla kalmaz, aynı zamanda benzer isimler bulur. adı christian olarak girilir varsayalım, o zaman uygulama like maddesini kullanmadan, christine, chris vb Bunu yapmanın en uygun yolu nedir gibi önerilen isimler gösterecektir. Öneriler, sadece ismin son kısmındaki değişikliklere ait olacaktır.Büyük bir tablodan benzer değer bulmanın en iyi yolu

+0

Neden 'like' deyimini kullanmak istemiyorsunuz? – Geoffroy

+0

Postgres'e geçmeyi düşünün. Bunu [metin arama sözlükleri] kullanarak yapmaya izin verir (http://www.postgresql.org/docs/9.0/static/textsearch-dictionaries.html) –

+0

Yeni bir alan ekleyebilir misiniz? eğer öyleyse cevabım altında ek yorumumu kontrol et. –

cevap

5

: http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_soundex

Aksi … LIKE 'chri%' kötü bir fikir değil benim için görünüyor?

LIKE olmadan sadece ilk karakterleri gerçekten istiyorsanız, SUBSTRING()'u kullanabilirsiniz.

+0

Keşke bunu iki defa daha fazla yapabilirim. Tabii ki sadece ilk karakterleri karşılaştırmak için SUBSTRING() kullanıyorsanız,% xyz% aynı şeyi yapıyor gibi görünüyor. Ama SOUNDEX() ... bu harika bir öneri ve bana bir çeşit Perua için Lingua :: EN :: SimilarNames, Text :: Soundex ve Lingua :: EN :: NameLookup CPAN modüllerini hatırlatıyor. önce veri kümesinin içe aktarılmasını gerektirir). SUBSTRING() kullanılarak – DavidO

+1

, tam bir tablo taraması gerektirir. Bu durumda daha hızlı olacak. SOUNDEX() iyi bir öneridir, ancak arama hızlı olduğu için ayrı bir dizinlenmiş alan olarak depolanmalıdır. –

0

Sanırım normal bir genisleme kullanabilirsin. Ben şu anda gitmiyorum ama bir WHERE maddesine koyabileceğiniz REGEXP adlı bir fonksiyon var. Bakın here

+0

'REGEXP' daha karmaşık sorgular için kullanışlıdır, ancak' LIKE'dan çok daha yavaş olacaktır. – glortho

+0

Ben (hiç kullanmadım) sadece "LIKE" dan farklı bir şey teklif etmek olduğunu hayal ettim! –

1

Like genellikle iyi bir çözümdür, ancak bunun performansını artırmak için başka bir yol kısmi bir sütun dizini oluşturmak ve sonra öneki ile aynı uzunlukta sorguları göndermek olabilir. col_name(length) ile ilgili MySQL documentation'a bakın. Eğer (sesiyle) benzer isimler SOUNDEX() gibi bir şey yardımcı olabilir ayrıca istiyorsanız

0

SOUNDS LIKE kullanabilirsiniz, bence oldukça hızlı olmalı.

http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#operator_sounds-like

+1

kalyoncu, bu muhtemelen iyi bir iş yapacak, ancak SOUNDEX() gibi tam bir tablo taraması gerektirecektir. –

+0

Başka bir alan oluşturabilirseniz, bundan kaçınabilirsiniz. Her ekleme ile soundex'i bu alana eklersiniz ve arama süresinde oldukça hızlı olacaktır. Ayrıca bu alanda bir dizin oluşturabilirsiniz. Hmm Sanırım bu öncekinden daha iyi bir cevap. –

+0

Ayrıca bir soundex dizesini de doğru olarak hatırlarsam C#### biçimindeki bir sayıya dönüştürebilirsiniz. C, 1-26 arasında en fazla 6 basamaklı bir sayıdır. –

0

sol taraftaki bir tablo taraması gerektirmez sabittir nerede GİBİ kullanma. LIKE kullanmak istememenizin nedeni budur: SELECT * FROM table WHERE name LIKE CONCAT(?, "%") hızlıdır ve satırları bulmak için bir tablo taraması gerektirmez. CONCAT, hazırlanmış sözdizimini% sözdizimi ile kullanmanızı sağlar. sıralanmış listede komşular bulmak için

SELECT * from table WHERE name < 'christian' LIMIT 20

ve

SELECT * FROM table WHERE name > 'christian' LIMIT 20

:

Ayrıca böyle bir şey yapabilirdi.

2

Her isme metafon-kodu oluşturup adlarıyla birlikte bunları saklamak için php'nin metafon() işlevini kullanabilirsiniz.

<?php 
print "chris" . "\t" . metaphone("chris") . "\n"; 
print "christian" . "\t" . metaphone("christian") . "\n"; 
print "christine" . "\t" . metaphone("christine") . "\n"; 

# prints: 
# chris  XRS 
# christine XRSTN 
# christian XRSXN 

sonra bir levenshtein mesafesi algoritma kullanabilir (ya php [http://php.net/manual/en/function.levenshtein.php] veya MySQL [http://www.artfulsoftware.com /infotree/queries.php#552]) meta kodlar arasındaki mesafeyi hesaplamak için. Benim testimde, 2 veya daha az bir mesafe, aradığınız benzerlik düzeyini belirtiyor gibiydi.

<?php 
$names = array(
     array('mike',metaphone('mike')), 
     array('chris',metaphone('chris')), 
     array('chrstian',metaphone('christian')), 
     array('christine',metaphone('christine')), 
     array('michelle',metaphone('chris')), 
     array('mick',metaphone('mick')), 
     array('john',metaphone('john')), 
     array('joseph',metaphone('joseph')) 
); 

foreach ($names as $name) { 
     _compare($name); 
} 

function _compare($n) { 
     global $names; 
     $name = $n[0]; 
     $meta = $n[1]; 

     foreach ($names as $cname) { 
       printf("The distance between $name and {$cname[0]} is %d\n",       
        levenshtein($meta, $cname[1])); 
     } 
} 
İlgili konular