Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: similar_text w MySQL
Forum PHP.pl > Forum > Bazy danych > MySQL
#luq
Potrzebuje na poziomie bazy wyciągnąć rekordy w których jedno z pól jest zbliżone w 90% do podanego ciągu. Tak w PHP jest funckja similar_text jednak to powinno się robić na poziomie bazy. Chodzi o coś takiego:

  1. SELECT foo.id FROM foo WHERE SIMILAR( foo.name, 'jakis string' ) > 0.9


tyle, że takiej funkcji w MySQL nie ma winksmiley.jpg Da się to w ogóle zrobić na MySQL`u?

Na forum znalazłem identyczny temat http://forum.php.pl/index.php?showtopic=70797 jednak nie rozwiązany...
wookieb
W mysql jest wyszukiwanie pełnotekstowe (FULLTEXT) dla tabel na silniku MyIsam. Na silniku InnoDb powinieneś użyć sphinxa.
Zapomnij o soundex, służy do czegoś innego. Levensthein jest czymś podobnym ale potrzebuje funkcji składowanej http://codejanitor.com/wp/2007/02/10/leven...tored-function/

Podpowiedź aby zainstalować procedurę.
  1. DELIMITER |;
  2. [KOD PROCEDURY]
  3.  
  4. DELIMITER ;
#luq
Super. Dzięki!

Btw. rozumiem, że to inne algorytmy są, bo dla
  1. similar_text( 'abrakadabra', 'kadabra', $procent );
  2. echo $procent;


dostaje: 77,(7)

natomiast dla:
  1. SELECT LEVENSHTEIN_RATIO( 'abrakadabra', 'kadabra' );


dostaje: 64
wookieb
Jest to różnica algorytmów.
similar_text korzysta z algorytma Olivera , drugi Levenshteina
Wyniki, które podałeś są oczywiste.

Może powiedz co chcesz uzyskać to dobierzemy coś dla Ciebie.
#luq
W sumie to dla mnie chyba bez różnicy który algorytm, wystarczy skalibrować przy ilu % otrzymuje dane które są na tyle podobne, że możliwe, że to literówka.
wookieb
Przy prostych literówkach lepiej nie porównywać procentowo tylko po prostu liczbowo.
Odległość levenstheina mówi ile zmian musisz dokonać aby jedno słowo zamienić w drugie. Więc myślę że 3 (max 4) są w zupełności zadowalające.
#luq
Sprawdzę. Na pewno będzie to szybsze smile.gif

Nie będę zakładać nowego tematu, ale mam kolejne zapytanie:
  1. SELECT id, name, LEVENSHTEIN_RATIO( name, '/*tu mam zmienna*/' ) AS similar FROM foo WHERE LEVENSHTEIN_RATIO( name, '/*tu mam zmienna*/' ) >= 90 GROUP BY id ORDER BY similar DESC


i ogólnie chodzi mi o to, że hm... funkcja LEVENSHTEIN_RATIO jest wykonywana 2 razy tak? Czy nie wiem jest ten wynik jakoś cachowany w bazie? Jeśli nie to jak zrobić tak aby nie liczyć tego 2 razy bo przy kilku tys. rekordów to troszkę trwa. Nie sprawdzałem (jest późno a mnie się oczy kleją) ale podzapytanie dało by chyba radę. Jakieś inne rozwiązanie?
wookieb
Szczerze to nie chce mi się teraz kombinować ale wystarczy użyć having albo zmiennej. Co lepiej, niestety za późno by testować smile.gif
#luq
Okej to tak, zwykła odległość Levenstheina przy małych stringach powinna być mała.
  1. SELECT authorName FROM `msh_name_author` WHERE LEVENSHTEIN( authorName, 'kant' ) < 4


Dostaje:
Kod
Ray
TEST
kant
kant.


Dla warunku < 3 wyniki są jak dla mnie zadowalające
Kod
kant
kant.


Ale przy długich stringach max 2 zmieny to imho mało, więc chyba zostanę jednak na procentowej wersji.

Użyłem zmiennej i HAVING i nie zauważam zmniejszenia czasu wykonani, może jednak to nie jest liczone 2 razy?
  1. SELECT authorId, authorName, (
  2. @t := LEVENSHTEIN_RATIO( authorName, 'kant' )
  3. ) AS similar
  4. FROM msh_name_author
  5. HAVING similar > 70


Jeszcze jedna sprawa - dla tabelki w której mam ~1200 rekordów to jest strasznie wolne (~7 sec) więc pomyślałem, żeby nie mielić całej tabelki tylko rekordy o inentycznej pierwszej literze, wygląda to tak:
  1. SELECT authorId, authorName, (
  2. @t := LEVENSHTEIN_RATIO( authorName, 'kant' )
  3. ) AS similar
  4.  
  5. FROM (
  6. SELECT authorId, authorName
  7. FROM msh_name_author
  8. WHERE SUBSTRING( authorName, 1, 1 ) = 'k'
  9. ) AS foo
  10. HAVING similar >70

Prawie przy 'k' wykonuje się ~0.2 sec więc jest okej. Przy szukaniu literówek to chyba dobry pomysł bo raczej rzadko robi się literówkę w pierwszym znaku, chyba że ma ktoś inny pomysł?
wookieb
Ten pomysł jest ok, ale stworzyłbym dodatkową kolumne przedstawiajaca ilosc znakow w słowie.
Dzięki temu np jak szukasz słowo "test" to założysz warunek
  1. dlugosc_slowa BETWEEN 2 AND 6
co jeszcze lepiej ograniczy wyniki

Jeżeli chcesz szukać jeszcze inaczej zainteresuj się n-gramami.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.