$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でフィルタリングする必要はありません。
MySQLのレベンシュタイン関数 が必要で、
$Word = mysql_real_escape_string($Word);
mysql_qery("SELECT `term` FROM `words` WHERE levenshtein('$Word', `term`) BETWEEN 0 AND 4");
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;
また、「しきい値」の値は、元の単語の長さに対して変更する必要があることも覚えておいてください。パーセント値で考えるとよいでしょう。つまり、単語の半分= 50%、「用語」の半分= 2です。
巨大なデータベースがある場合は、最初に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でレコードをフィルタリングすると、ほとんど労力をかけずに処理が速くなります。
非常に大きなデータセットを処理している場合、Levenshteinの操作を処理し、PHPでソートする方が、MySQLの場合よりもはるかに効率的です。たとえば、約1000レコードのクエリ:
MySQL(〜0.0050秒)-> PHPレーベンシュタイン(〜1.300秒)
vs.
MySQL Levenshtein(> = 5.000s)-> PHP(〜0.250s)
検索エンジンを最適化する他の多くのオプションもありますが、レーベンシュタインを使用する場合は、処理するデータと必要なレイテンシに注意してください。
クエリにlevenshtein(link: 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);
このコードを少しすっきりと見せることはできますが、@ profitphpは正しいです。MySQLでは、レベンシュタインライブラリなしではそれを行うことはできません。
$ Word = strtolower($ _ GET ['term']); $ q = mysql_uqery( "SELECT LOWER(` term`)FROM `words`"); while($ r = mysql_fetch_assoc($ q)){ $ lev = levenshtein($ Word、$ r ['term']); .... }
Oracleでは、呼び出すことができる関数内のPL/SQLにアルゴリズムを実装することでこれを行っています。