31
$word = strtolower($_GET['term']); 

$lev = 0;

$q = mysql_query("SELECT `term` FROM `words`"); 
while($r = mysql_fetch_assoc($q)) 
{ 
    $r['term'] = strtolower($r['term']); 

    $lev = levenshtein($word, $r['term']);

    if($lev >= 0 && $lev < 5)
    {
        $word = $r['term'];
    }
}

これらすべてを 1 つのクエリに移動するにはどうすればよいでしょうか? すべての用語を照会して、PHP でフィルタリングを行う必要はありません。

4

8 に答える 8

59

MySQLのレーベンシュタイン関数と次のようなクエリが必要です

$word = mysql_real_escape_string($word);
mysql_qery("SELECT `term` FROM `words` WHERE levenshtein('$word', `term`) BETWEEN 0 AND 4");
于 2011-01-12T16:57:38.850 に答える
11

MySQL でレーベンシュタイン関数を実装するには、2 つの方法があります。1 つ目は、入力と出力が異なることを除いて、STORED TRANSACTION とほぼ同じように動作する STORED FUNCTION を作成することです。これは小さなデータセットでは問題ありませんが、数千行に近づくと少し遅くなります。

CREATE FUNCTION levenshtein( s1 VARCHAR(255), s2 VARCHAR(255) )
RETURNS INT
DETERMINISTIC

BEGIN
DECLARE s1_len, s2_len, i, j, c, c_temp, cost INT;
DECLARE s1_char CHAR;
-- max strlen=255
DECLARE cv0, cv1 VARBINARY(256);
SET s1_len = CHAR_LENGTH(s1), s2_len = CHAR_LENGTH(s2), cv1 = 0x00, j = 1, i = 1, c = 0;
IF s1 = s2 THEN
  RETURN 0;
ELSEIF s1_len = 0 THEN
  RETURN s2_len;
ELSEIF s2_len = 0 THEN
  RETURN s1_len;
ELSE
  WHILE j <= s2_len DO
    SET cv1 = CONCAT(cv1, UNHEX(HEX(j))), j = j + 1;
  END WHILE;
  WHILE i <= s1_len DO
    SET s1_char = SUBSTRING(s1, i, 1), c = i, cv0 = UNHEX(HEX(i)), j = 1;
    WHILE j <= s2_len DO
    SET c = c + 1;
    IF s1_char = SUBSTRING(s2, j, 1) THEN
      SET cost = 0; ELSE SET cost = 1;
    END IF;
    SET c_temp = CONV(HEX(SUBSTRING(cv1, j, 1)), 16, 10) + cost;
    IF c > c_temp THEN SET c = c_temp; END IF;
      SET c_temp = CONV(HEX(SUBSTRING(cv1, j+1, 1)), 16, 10) + 1;
      IF c > c_temp THEN
        SET c = c_temp;
      END IF;
      SET cv0 = CONCAT(cv0, UNHEX(HEX(c))), j = j + 1;
    END WHILE;
    SET cv1 = cv0, i = i + 1;
  END WHILE;
END IF;

RETURN c;

END//

上記のコードを .sql ファイルに保存し、次のようにデータベースにインポートします。

source /tmp/mysql_udf.sql

2 番目の方法は、C/C++ でユーザー定義関数を実装し、それを共有ライブラリ (*.so ファイル) として MySQL にリンクすることです。このメソッドは、STORED FUNCTION を使用してライブラリを呼び出します。つまり、このメソッドまたは最初のメソッドの実際のクエリは同じである可能性があります (両方の関数への入力が同じである場合)。この方法の詳細については、http ://samjlevy.com/mysql-levenshtein-and-damerau-levenshtein-udfs/ を参照してください。

これらの方法のいずれかを使用すると、クエリは次のようになります。

SELECT term FROM words WHERE levenshtein(term, 'term') < 5;

また、'threshold' 値は元の語長に関連して変化する必要があることに注意してください。パーセンテージ値で考えたほうがよいでしょう。つまり、単語の半分 = 50%、「期間」の半分 = 2 です。

于 2012-04-29T09:47:39.353 に答える
8

巨大なデータベースがある場合は、まず SOUNDEX を使用して単語をフィルタリングできます。

$word = strtolower(mysql_real_escape_string($_GET['term']));

$rs = mysql_query("SELECT LOWER(`term`) FROM `words` WHERE SOUNDEX(term) = SOUNDEX(" . $word . ")");

while ($row = mysql_fetch_assoc($rs)) { 

    $lev = levenshtein($word, $row['term']);

    ....

}

C の拡張機能や手順を試す時間が十分にある場合は、パフォーマンスが向上する可能性がありますが、実際のレーベンシュタインを適用する前に mysql でレコードをフィルタリングすると、ほとんど労力をかけずに処理が高速化されます。

于 2013-04-25T18:15:32.060 に答える
1

レーベンシュタイン (リンク: http://www.artfulsoftware.com/infotree/queries.php#552 )の呼び出しを クエリに含めることをお勧めします。

mysql_query($q) は推奨されておらず、将来の PHP バージョンで削除される可能性があるため、mysqli_query($q) を使用する必要があります。

$word = mysql_real_escape_string($word);
$query = "SELECT `term` FROM `words` WHERE levenshtein('$word', `term`)   BETWEEN 0 AND 4";
mysqli_qery($query);
于 2015-06-28T22:16:05.900 に答える
1

このコードを少しきれいに見せることはできますが、@profitphp は正しく、levenstein ライブラリがなければ MySQL では実行できません。

$word = strtolower($_GET['term']);

$q = mysql_uqery("SELECT LOWER(`term`) FROM `words`");

while($r = mysql_fetch_assoc($q)) {

    $lev = levenshtein($word, $r['term']);

    ....

}
于 2011-01-12T16:59:24.073 に答える
0

これは、呼び出し可能な関数内の PL/SQL でアルゴリズムを実装することにより、Oracle で行います。

于 2011-01-12T16:51:43.143 に答える
-3

それが1つのクエリです。レーベンシュタインの機能を mysql に移行できるかどうか尋ねている場合は、できません。

わかりました、できますが、php で行うよりも簡単ではありません。

http://www.artfulsoftware.com/infotree/queries.php?&bw=1280#552

于 2011-01-12T16:49:23.473 に答える