validar - soundex php
Levenshtein: MySQL+PHP (8)
Esa es una consulta. Si preguntas si puedes mover la funcionalidad levenshtein a mysql, no puedes.
Ok, bueno puedes, pero no es más fácil que solo hacerlo en php.
http://www.artfulsoftware.com/infotree/queries.php?&bw=1280#552
$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''];
}
}
¿Cómo puedo mover todo eso en una sola consulta? No quiero tener que consultar todos los términos y hacer el filtrado en PHP.
Hago esto en Oracle implementando el algoritmo en PL / SQL dentro de una función que se puede llamar.
Hay dos formas de implementar una función de Levenshtein en MySQL. El primero es crear una FUNCIÓN ALMACENADA que funciona de forma muy parecida a una TRANSACCIÓN ALMACENADA, excepto que tiene entradas distintas y una salida. Esto está bien para pequeños conjuntos de datos, pero un poco lento en cualquier cosa que se acerque a varios miles de filas.
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//
Almacene el código anterior en un archivo .sql e impórtelo en su base de datos de la siguiente manera:
source /tmp/mysql_udf.sql
El segundo método es implementar una Función definida por el usuario en C / C ++ y vincularla a MySQL como una biblioteca compartida (archivo * .so). Este método también usa una FUNCIÓN ALMACENADA para llamar a la biblioteca, lo que significa que la consulta real para este o el primer método puede ser idéntica (siempre que las entradas a ambas funciones sean las mismas). Puede encontrar más información sobre este método aquí: http://samjlevy.com/mysql-levenshtein-and-damerau-levenshtein-udfs/
Con cualquiera de estos métodos, su consulta sería algo así como:
SELECT term FROM words WHERE levenshtein(term, ''term'') < 5;
Además, recuerde que el valor ''umbral'' debe cambiar en relación con la longitud original de la palabra. Es mejor pensarlo en términos de un valor porcentual, es decir, la mitad de tu palabra = 50%, la mitad de ''término'' = 2.
Le sugiero que incluya la llamada de levenshtein (enlace: http://www.artfulsoftware.com/infotree/queries.php#552 ) en su consulta.
Debes usar mysqli_query ($ q) porque mysql_query ($ q) está en desuso y puede ser eliminado en futuras versiones de php.
$word = mysql_real_escape_string($word);
$query = "SELECT `term` FROM `words` WHERE levenshtein(''$word'', `term`) BETWEEN 0 AND 4";
mysqli_qery($query);
Necesita una función levenshtein en MySQL y consultar como
$word = mysql_real_escape_string($word);
mysql_qery("SELECT `term` FROM `words` WHERE levenshtein(''$word'', `term`) BETWEEN 0 AND 4");
Puede hacer que este código se vea un poco más ordenado, pero @profitphp es correcto, no puede hacerlo en MySQL sin una biblioteca levenstein.
$word = strtolower($_GET[''term'']); $q = mysql_uqery("SELECT LOWER(`term`) FROM `words`"); while($r = mysql_fetch_assoc($q)) { $lev = levenshtein($word, $r[''term'']); .... }
Si se trata de conjuntos de datos muy grandes, he descubierto que es mucho más eficiente manejar las operaciones de Levenshtein y clasificarlas en PHP que en MySQL. por ejemplo, consulta de alrededor de 1000 registros:
MySQL (~ 0.0050s) -> PHP Levenshtein (~ 1.300s)
vs.
MySQL Levenshtein (> = 5.000s) -> PHP (~ 0.250s)
También hay muchas otras opciones para optimizar los motores de búsqueda, pero si desea utilizar Levenshtein, tenga en cuenta los datos que manejará y las latencias que desea.
Si tiene una gran base de datos, puede filtrar las palabras primero usando 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'']);
....
}
Si tiene tiempo suficiente para jugar con una extensión C o un procedimiento, puede lograr un mejor rendimiento, pero filtrar los registros en mysql antes de aplicar realnshtein hará las cosas más rápidas sin apenas esfuerzo.