Ver Mensaje Individual
  #7 (permalink)  
Antiguo 24/10/2013, 08:03
nksn
 
Fecha de Ingreso: mayo-2009
Ubicación: Japon
Mensajes: 60
Antigüedad: 14 años, 9 meses
Puntos: 12
Respuesta: Buscador interno y "mother of orthography" ( php + mysql )

Cita:
Iniciado por ocp001a Ver Mensaje
Podrías intentar probando la distancia levenshtin, o con las funciones soundex o similar text. [url]http://php.net/manual/es/function.levenshtein.php[/url]
nose si alguien habrá seguido el post pero bueh...

comenzamos con el código

gracias a ocp001a y su aporte me puse a investigar un poco, la verdad no esperaba tan buenos resultados (toca filtrar un poco) ya que en cierta forma otorga bastantes resultados basuras...

en si el código esta "vivo" y lo he testeado "un poco", no se rían de mi forma de programar, comenten de forma constructiva!

basta de blablas... a ver un poco de source!


la librería "class.php", es algo un poco "primitiva" aunque indexa correctamente (en varios casos mejor que like y against), decidí meterlo todo dentro de una clase para que fuese un poco mas ordenada, la función "install" la puse simplemente porque existe quienes no saben como subir un .sql


nota: la librería mysql "tradicional" fue declarada deprecada, creo que algunos no están muy familiarizados con las librerías mysqli o PDO por tal causa decidí usar la librería tradicional, simplemente para que todos puedan seguir el hilo


Código PHP:
<?php

class index
{
    private 
$mysqlr;
    
//la clase constructora
    
public function __construct($host$user$pass$db)
    {
        
//creamos una conexion y almacenamos el identificador
        
$this->mysqlr mysql_connect($host$user$pass) or die(mysql_error());
        
        
//cambiamos la encodificacion a utf8
        
mysql_query('SET NAMES utf8') or die(mysql_error());
        
        
//seleccionamos la base de datos
        
mysql_select_db($db) or die(mysql_error());
    }
    
    
    public function 
__desctruct()
    {
        
//desconectamos el mysql
        
mysql_close($this->mysqlr);
    }
    
    
    public function 
save($txt$minLen 2)
    {
        
// prevenir las llamadas sin conexion
        
if(!isset($this)){ return false; }
        
        
//multibite en utf8
        
mb_internal_encoding("UTF-8");

        
//remplasar delimitadores por un espacio
        
$txt str_replace(array("."'"'"'"','':'';''@''/''\\'"\n""\r""\t""[""]""("")") , ' '$txt);
        
        
//convertir la cadena de texto en una matris
        
$txt explode(' '$txt);
        
        
$values '';
        
//recorrer cada palabra y agregarla al index
        
foreach($txt as $keyword)
        {
            
//comprobar que supera la longitud minina
            
if(mb_strlen($keyword) >= $minLen)
            {
                
$values .= ($values != '' ', ' '')."('$keyword')";
            }
        }
        
        
//echo "INSERT IGNORE INTO `lib_post_index` (`key`) VALUES $values";
        
if($values != '')
        {
            
mysql_query("INSERT IGNORE INTO `lib_post_index` (`key`) VALUES $values"$this->mysqlr) or die(mysql_error());
        }
    }
    
    
    public function 
check($key$sens 2)
    {
        
// prevenir las llamadas sin conexion
        
if(!isset($this)){ return false; }
        
        if(
$query mysql_query("SELECT *, levenshtein('$key', `key`) AS `lvs` FROM `lib_post_index` WHERE levenshtein('$key', `key`) BETWEEN 0 AND $sens ORDER BY `lvs`, `key` ASC"))
        {
            return 
$query;
        }
    }
    
    
    public function 
install()
    {
        
// prevenir las llamadas sin conexion
        
if(!isset($this)){ return false; }
        
        
//comprobar que la funcion no exista y luego instalar;
        
$result mysql_query("SHOW FUNCTION STATUS LIKE 'levenshtein'") or die(mysql_error());
        
        if(
mysql_num_rows($result) == 0)
        {
            
mysql_query("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;"
) or die(mysql_error());
             
              
mysql_query("CREATE FUNCTION levenshtein_ratio( s1 VARCHAR(255), s2 VARCHAR(255) )
              RETURNS INT
              DETERMINISTIC
              BEGIN
                DECLARE s1_len, s2_len, max_len INT;
                SET s1_len = LENGTH(s1), s2_len = LENGTH(s2);
                IF s1_len > s2_len THEN 
                  SET max_len = s1_len; 
                ELSE 
                  SET max_len = s2_len; 
                END IF;
                RETURN ROUND((1 - LEVENSHTEIN(s1, s2) / max_len) * 100);
              END;"
) or die(mysql_error());
              
              
              
mysql_query("CREATE TABLE IF NOT EXISTS `lib_post_index` (
              `id` bigint(20) NOT NULL AUTO_INCREMENT,
              `key` varchar(255) DEFAULT NULL,
              `parents` text CHARACTER SET ascii,
              PRIMARY KEY (`id`),
              UNIQUE KEY `key` (`key`)
            ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1"
) or die(mysql_error());
        }
    }
}
?>
fuente "function levenshtein" -> http://stackoverflow.com/questions/4671378/levenshtein-mysql-php

dentro de todo allí esta lo mas importante, la función levenshtein ella retornara los elementos que contengan mas cercanía a la palabra clave

la función save "parsea" el texto según los delimitadores indicados y retorna un array, el loop genera la query y el mysql_query los guarda en la tabla "lib_post_index"

en si es todo esta bastante fácil de entender creo...


index.php esta es una interface muy precaria pero para testear sobra

Código PHP:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

<?php
//incluimos la clase principal
include 'class.php';

//creamos el objeto
$index = new index('localhost''usuario mysql''password mysql''base de datos');

//comprobamos que alla datos suficientes como para guardar el string
if(isset($_POST['string']) && strlen($_POST['string']) > 2)
{
    
//creamos el index
    
$index->save($_POST['string']);
}

// comprobamos si hay una keyword
if(isset($_POST['keyword']))
{
    
//generamos una consulta
    
$query $index->check($_POST['keyword'], 2);
    
    
//imprimimos el/los resultado(s)
    
while($_result mysql_fetch_assoc($query))
    {
        
print_r($_result);
        echo 
'<br />';
    }
}

?>

<body>

<form method="post" enctype="multipart/form-data">
    buscar en el index<br />
    <input name="keyword" type="text" value="<?php echo $_POST['keyword']; ?>" /><br /><br />
    
    indexar texto<br />
    <textarea name="string"></textarea><br />
    <input type="submit" />
</form>

</body>
</html>
comenten cualquier idea o algo que se les ocurra para optimizar el codigo, "maten a los que den copy&past" haha

Última edición por nksn; 24/10/2013 a las 08:09 Razón: error de redaccion