Jonny 5: Ähnliche Ergebnisse finden (soundex, similar_text, levenshtein)

Hallo liebes Forum,

Arbeite an einer 'Meinten Sie'-Funktion.

Sie soll aus einer mysql/innodb Datenbank mit ca 200.000 Keywords (index) ähnliche Treffer finden. Leider ist die soundex/sounds like funktion für deutsch unbrauchbar.

Habe es bisher etwas umständlich gelöst (siehe unten). Erzeugt einen Ergebnispool (langsam / query=ca 2-4 sek) Die Ergebnisse werden dann mittels php-funktionen dann nach Ahnlichkeit sortiert. Liefert auch recht gute Ergebnisse.

Hat vielleicht jemand einen flotten sql-query für mich, der gute ähnliche Ergebnisse liefert? Bisher sieht es so aus:

-------------------------------------

# relevante teile aus string
  $like_string1=substr($temp_string,1,3);
  $like_string2=substr($temp_string,0,2)."%".$temp_string{strlen($temp_string)-1};
  $like_string3=substr($temp_string,(strlen($temp_string)-3),(strlen($temp_string)-1));
  $like_string4=$temp_string{0}."%".$temp_string{(floor(strlen($temp_string)/2))}."%".$temp_string{strlen($temp_string)-2};
  $like_string5=$temp_string{1}."%".$temp_string{(ceil(strlen($temp_string)/2))}."%".$temp_string{strlen($temp_string)-1};
  $like_string6=$temp_string{0}."%".$temp_string{(floor(strlen($temp_string)/2))}."%".$temp_string{strlen($temp_string)-1};

# escape string
  $temp_string=dbIn($temp_string);

# get similar
  $sql="SELECT keyword,search_count FROM keywords WHERE
         (
         (keyword LIKE '%test%') OR
         (keyword LIKE '%".dbIn($like_string2)."%') OR
         (keyword LIKE '%".dbIn($like_string3)."%') OR
       (keyword LIKE '%".dbIn($like_string4)."%') OR
         (keyword LIKE '%".dbIn($like_string5)."%') OR
         (keyword LIKE '%".dbIn($like_string6)."%')
         )
       AND (keyword <> '".$temp_string."')
       ORDER BY
         search_count DESC,
         ((from_dict = '1') AND (search_count > '0')) DESC,
         ((CHAR_LENGTH(keyword)<'".(strlen($temp_string)+3)."') AND (CHAR_LENGTH(keyword)>'".(strlen($temp_string)-3)."')) DESC,
         (keyword LIKE '%".dbIn($like_string1)."%') DESC,
         (keyword LIKE '%".dbIn($like_string2)."%') DESC,
         (keyword LIKE '%".dbIn($like_string3)."%') DESC,
         (keyword LIKE '%".dbIn($like_string4)."%') DESC,
         (keyword LIKE '%".dbIn($like_string5)."%') DESC,
         (keyword LIKE '%".dbIn($like_string6)."%') DESC
       LIMIT 0,200";

-------------------------------------

besten Dank für jeden Tip!

  1. Hi nochmal!

    Nach einigem rumexperimentiern mit REGEXP und INSTR ist doch LIKE die effizientere Variante.

    Habe den Query überarbeitet, so dass er jetzt deutlich schneller läuft.

    Ein Kriterium dafür dürfte sein, dass Mysql bei Vorkommen von mindestens 3 Zeichen in einer %-LIKE-SUCHE den schnellen 'Turbo-Boyer-Moore-Algorithmus' verwendet.

    Weiters sollten (wie vorher auch schon) über die relevanten Spalten der WHERE-Klausel ein Index liegen.

    Der neue Query liefert zwar etwas weniger, aber recht gute Ergebnisse:

    ------------------------->

    # relevante teile aus string
      $like_string1=substr($temp_string,1,3);
      $like_string2=substr($temp_string,0,2)."%".$temp_string{strlen($temp_string)-1};
      $like_string3=substr($temp_string,(strlen($temp_string)-3),(strlen($temp_string)-1));
      $like_string4=$temp_string{0}."%".$temp_string{(floor(strlen($temp_string)/2))}."%".$temp_string{strlen($temp_string)-1};

    # get similar
      $sql="SELECT keyword,search_count FROM keywords WHERE
             (
            (keyword LIKE '%".dbIn($like_string1)."%') OR
            (keyword LIKE '".dbIn($like_string2)."%') OR
            (keyword LIKE '%".dbIn($like_string3)."%') OR
          (keyword LIKE '".dbIn($like_string4)."%')
             )
           ORDER BY
             search_count DESC,
             ((from_dict = '1') AND (search_count > '0')) DESC,
             ((CHAR_LENGTH(keyword)<'".(strlen($temp_string)+3)."') AND (CHAR_LENGTH(keyword)>'".(strlen($temp_string)-3)."')) DESC,
             (keyword LIKE '%".dbIn($like_string1)."%') DESC,
             (keyword LIKE '".dbIn($like_string2)."%') DESC,
             (keyword LIKE '%".dbIn($like_string3)."%') DESC,
             (keyword LIKE '".dbIn($like_string4)."%') DESC
           LIMIT 0,100";