• Publicidad

Búsqueda inteligente

Todo lo relacionado con el desarrollo Web con Perl: desde CGI hasta Mojolicious

Búsqueda inteligente

Notapor seafree » 2015-04-08 14:25 @642

Hola, ¿alguien sabe si desde Perl puedo realizar búsquedas inteligentes? El panorama es el siguiente:

Tengo una base de datos almacenando una tabla con registros identificados por el campo fechas, ubicación, usuario, equipo, etc. Los usuarios quieren realizar la búsqueda de registros de acuerdo al campo que ellos conozcan. Una solución es identificar los parámetros seleccionados y crear el SQL. Sin embargo, he visto maneras más automatizadas para realizar las búsquedas.

Pregunta: ¿Existe en Perl alguna librería para realizar búsquedas o la única forma es manual?

Gracias.
seafree
Perlero nuevo
Perlero nuevo
 
Mensajes: 296
Registrado: 2012-08-10 11:26 @518

Publicidad

Re: Búsqueda inteligente

Notapor explorer » 2015-04-08 19:45 @865

Hay un módulo (no tiene por qué ser el único) llamado Search::QueryParser::SQL, que convierte las búsquedas de 'texto libre' en cláusulas WHERE.

Por ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. use Search::QueryParser::SQL;
  2.  
  3. my $parser = Search::QueryParser::SQL->new(                             # crea el objeto S::Q::S
  4.                  columns => [qw( fechas ubicacion usuario equipo )]
  5. );
  6.        
  7. my $query = $parser->parse('sea free', 1);                              # 1 indica un 'AND'
  8. print $query;                                   # sale:
  9.                                                 # (fechas='sea'  OR ubicacion='sea'  OR usuario='sea'  OR equipo='sea' ) AND \
  10.                                                 # (fechas='free' OR ubicacion='free' OR usuario='free' OR equipo='free')
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4

pero nada más. Habría luego que agregar este trozo de consulta al final de una sentencia 'SQL .... WHERE' o cualquier otro módulo que admita cláusulas SQL WHERE.

La ventaja que tiene es que si el usuario quiere buscar por 'sea*', crea la sentencia con cláusulas ILIKE:

fechas ILIKE 'sea%' OR ubicacion ILIKE 'sea%' OR ...

Otra solución... sería mirar si el propio motor de base de datos tiene esa facilidad. En MySQL tiene el concepto de 'full-text search' pero se refiere a la indexación de los contenidos de una determinada columna, para acelerar las búsquedas. Pero solo en esa columna.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Búsqueda inteligente

Notapor seafree » 2015-04-09 08:51 @410

Gracias, explorer, investigaré acerca del módulo llamado Search::QueryParser::SQL.

Saludos.
seafree
Perlero nuevo
Perlero nuevo
 
Mensajes: 296
Registrado: 2012-08-10 11:26 @518

Re: Búsqueda inteligente

Notapor Superdri » 2017-10-14 05:27 @269

Hola, estoy intentando crear un buscador para los datos que tengo en mi base de datos y quiero usar este módulo, pero tengo una duda porque veo que si le añades campos vacíos no crea la consulta.

Entonces supongo que tengo que comprobar cada campo que llega al cgi por GET antes de crear la consulta ¿o hay alguna otra forma de hacerlo?

Gracias y saludos.
Superdri
Perlero nuevo
Perlero nuevo
 
Mensajes: 21
Registrado: 2017-10-06 22:11 @966

Re: Búsqueda inteligente

Notapor Superdri » 2017-10-15 01:19 @096

Hola de nuevo.

Creo que construir la consulta sql conforme lo que ha enviado el formulario es lo correcto, así que me puse manos a la obra:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #empezamos a construir el query
  2. my $query = "select * from wow_eu_leadder_rbg";
  3. #caso en que no hay filtros
  4. if ((!$player) && (!$spec) && (!$realm) && (!$faction)) {
  5.   #quiero devolver 100 entradas por pagina(hay un pagination en la web)
  6.   $query .= " LIMIT 100 OFFSET $pagina";
  7.   my $sth = $db->prepare($query);
  8.   $sth->execute() or die "imposible ejecutar la consulta $query";
  9.   my @players;
  10.   while(my $data = $sth->fetchrow_hashref()){
  11.     push @players, $data;
  12.   }
  13.   $sth->finish;
  14.   $players->{'rbg'} = \@players;
  15.  
  16.   #este bloque sirve para calcular las entradas totales y devolver el numero para crear el pagination
  17.   $query =~ s/LIMIT 100 OFFSET $pagina//;
  18.   my $sth = $db->prepare($query);
  19.   $sth->execute() or die "imposible ejecutar la consulta";
  20.   my $count = $sth->rows;
  21.   $sth->finish;
  22.                
  23.   return ($players, $count);
  24. }
  25. #aquí empieza lo interesante, cuando hay filtros vamos añadiendo campos al query para realizar la busqueda
  26. else {
  27.   $query .= " where";
  28.   if ($player) {
  29.     $query .= " name like '$player' AND";
  30.   }
  31.   if ($spec) {
  32.     #esta el parte que no me acaba de funcionar
  33.     #se envían las specs por el formulario en método GET
  34.     #ejemplo: rbg?player=&spec=102_&spec=103_&spec=104_&spec=105_
  35.     #die Dumper($spec);
  36.     my @specs = split(/_/, $spec);
  37.     #die Dumper(@specs);
  38.     my $longitud = @specs;
  39.     if ($longitud > 1) {
  40.       #el bucle recorre todos las posibles specs enviadas para crear el IN(spec1, spec2..) en el query
  41.       for (my $i = 0; $i < $longitud; $i++) {
  42.         if ($i == 0) {
  43.           $query .= " spec_id IN ($specs[$i],";
  44.         }
  45.         if (($i != 0) && ($i != $longitud-1)) {
  46.           $query .= " $specs[$i],";
  47.         }
  48.         if ($i == $longitud-1) {
  49.           $query .= " $specs[$i]) AND";
  50.         }
  51.       }
  52.     }
  53.     else {
  54.       $query .= " spec_id = $specs[0] AND";
  55.     }
  56.   }
  57.   #comprobamos otros filtros (servidor y facción)
  58.   if ($realm) {
  59.     $query .= " realm_name = '$realm' AND";
  60.   }
  61.   if ($faction eq 'Horde') {
  62.     $query .= " faction_id = 1 AND";
  63.   }
  64.   if ($faction eq 'Alliance') {
  65.     $query .= " faction_id = 0 AND";
  66.   }
  67.   #quitamos el ultimo AND si existe
  68.   $query =~ s/AND$//;
  69.   $query .= " LIMIT 100 OFFSET $pagina";
  70.   #die "Consulta ejecutada: $query";
  71.   my $sth = $db->prepare($query);
  72.   $sth->execute() or die "imposible ejecutar la consulta $query";
  73.   my @players;
  74.   while(my $data = $sth->fetchrow_hashref()){
  75.     push @players, $data;
  76.   }
  77.   $sth->finish;
  78.   $players->{'rbg'} = \@players;
  79.  
  80.   #este bloque es para calcual las entradas totales para el pagination         
  81.   $query =~ s/LIMIT 100 OFFSET $pagina//;
  82.   my $sth = $db->prepare($query);
  83.   $sth->execute() or die "imposible ejecutar la consulta";
  84.   my $count = $sth->rows;
  85.   $sth->finish;
  86.                
  87.   return ($players, $count);
  88. }
  89.  
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Ejecuto la búsqueda con filtros de facción, nombre jugador o servidor (realm) y funciona perfecto pero cuando añado 'specs' me dice que la sentencia sql no es correcta:
Error executing run mode 'wow': imposible ejecutar la consulta select * from wow_eu_leadder_rbg where spec_id IN (102, 103, 104, 105) LIMIT 100 OFFSET 0 at BlizzardRankings.pm line 547.
at C:/xampp/htdocs/index.cgi line 25

cuando yo creo que es correcta (lo he comprobado pasándola por sql en phpmyadmin). Lo único que observo es un espacio extra entre el paréntesis del IN y el LIMIT que probé a eliminar con chop() pero tampoco funcionó. Por supuesto el valor spec_id en la tabla sql es un INT.

Saludos y gracias.
Superdri
Perlero nuevo
Perlero nuevo
 
Mensajes: 21
Registrado: 2017-10-06 22:11 @966

Re: Búsqueda inteligente

Notapor explorer » 2017-10-15 12:05 @545

Modifica la línea 83 para que el programa saque el texto del error, y así tendrás más información de lo que pasa:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1.   $sth->execute() or die "Imposible ejecutar la consulta. ERROR: " . $sth->errstr);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Repasa la página de este tutorial, para que veas en qué más sitios se puede poner errstr().
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Búsqueda inteligente

Notapor Superdri » 2017-10-15 14:53 @662

Hola, gracias por la respuesta.

El error me lo da en la línea 72, he puesto el errstr() y dice lo siguiente
Error executing run mode 'rbg': imposible ejecutar la consulta select * from wow_eu_leadder_rbg where spec_id IN (102, 105) LIMIT 100 OFFSET 0 sth error: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1 at MojoMate.pm line 504.
at C:/xampp/htdocs/index.cgi line 25.
Superdri
Perlero nuevo
Perlero nuevo
 
Mensajes: 21
Registrado: 2017-10-06 22:11 @966

Re: Búsqueda inteligente

Notapor explorer » 2017-10-15 19:04 @836

¿Has probado esa consulta en MariaDB? Yo creí que te referías a MySQL porque comentaste que la probaste en phpmyadmin.

Pero aunque MariaBD sea una versión derivada de MySQL, no sé qué tal será de compatible su SQL.

Yo la consulta la veo bien, pero al no saber nada de MariaDB, no tengo idea de si, incluso, la mezcla de mayúsculas y minúsculas influye en la consulta.

Yo ejecutaría

select * from wow_eu_leadder_rbg where spec_id IN (102, 105) LIMIT 100 OFFSET 0

en la línea de comandos de MariaDB, para que me diga exactamente dónde está el error.

Consejo: A la hora de sacar valores de variables, mételas entre corchetes, para que no tengas ninguna duda de qué es lo que contienen. Es decir, usa esto:

die "Imposible preparar la consulta [$query]"

De esa manera, si en la salida ves esto

[select * from wow_eu_leadder_rbg where spec_id IN (102, 105) LIMIT 100 OFFSET 0]

pues vemos la consulta entera, pero, si en lugar de eso, vemos

[select * from wow_eu_leadder_rbg where spec_id IN (102, 105) LIMIT 100 OFFSET 0
]


hay algo raro: fíjate que el corchete de cierre está en la línea siguiente, así que eso significa que hay un carácter de nueva línea al final de la consulta.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Búsqueda inteligente

Notapor Superdri » 2017-10-16 01:06 @087

Buenas, gracias por la respuesta.

MariaDB es la que viene con xampp, yo diría que la sintaxis es la misma que Mysql, estado probando por consola y no me devuelve error :z
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
MariaDB [blizzardrankings]> select * from wow_eu_leadder_rbg where spec_id IN (259, 260, 261, 102, 103, 104, 105) LIMIT 100 OFFSET 0;
+---------+--------+--------------+----------+------------------------+------------------------+---------+----------+---------+------------+-----------+-------------+---------------+-------------+---------------+
| ranking | rating | name         | realm_id | realm_name             | realm_slug             | race_id | class_id | spec_id | faction_id | gender_id | season_wins | season_losses | weekly_wins | weekly_losses |
+---------+--------+--------------+----------+------------------------+------------------------+---------+----------+---------+------------+-----------+-------------+---------------+-------------+---------------+
|       2 |   2751 | Sångsvan     |     1306 | Tarren Mill            | tarren-mill            |       4 |       11 |     105 |          0 |         1 |         247 |             0 |           0 |             0 |
|       5 |   2741 | Precezeswusu |     1388 | Lightbringer           | lightbringer           |       4 |       11 |     102 |          0 |         1 |         233 |             0 |           0 |             0 |
|       8 |   2592 | Imbajohni    |     1301 | Outland                | outland                |       4 |        4 |     261 |          0 |         1 |         140 |             0 |           0 |             0 |
|       9 |   2583 | Imbajohni    |     1303 | Grim Batol             | grim-batol             |       7 |        4 |     261 |          0 |         0 |         127 |             0 |           0 |             0 |
|      24 |   2478 | ??????????   |     1922 | Azuregos               | azuregos               |       4 |       11 |     103 |          0 |         1 |         150 |            31 |           0 |             0 |
|      26 |   2464 | Meoowth      |     1306 | Tarren Mill            | tarren-mill            |       6 |       11 |     105 |          1 |         1 |         166 |          
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


También he probado lo de los corchetes y no hay saltos ni nada parecido, al menos que se vea en el navegador
Error executing run mode 'rbg': imposible ejecutar la consulta [select * from wow_eu_leadder_rbg where spec_id IN (259, 260, 261, 102, 103, 104, 105) LIMIT 100 OFFSET 0] sth error: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1 at MojoMate.pm line 504.
at C:/xampp/htdocs/index.cgi line 25.


Igual ejecutando esa parte del cgi por consola vería algún carácter que esté por hay metido, pero no sé cómo hacerlo en Windows.

Es muy extraño porque cuando ejecuto una búsqueda para un campo que no sea el de spec funciona correctamente, así que el fallo tiene que estar por:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. if ($spec) {
  2.   my @specs = split(/_/, $spec); #el idspec llega delimitado por _ ejemplo: 102_103_104_105_
  3.   my $longitud = @specs;
  4.   if ($longitud > 1) {
  5.     for (my $i = 0; $i < $longitud; $i++) {
  6.       if ($i == 0) {
  7.         $query .= " spec_id IN ($specs[$i],";
  8.       }
  9.       if (($i != 0) && ($i != $longitud-1)) {
  10.         $query .= " $specs[$i],";
  11.       }
  12.       if ($i == $longitud-1) {
  13.         $query .= " $specs[$i]) AND";
  14.       }
  15.     }
  16.   }
  17.   else {
  18.     $query .= " spec_id = $specs[0] AND";
  19.   }
  20. }
  21.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


¡Hasta luego!
Superdri
Perlero nuevo
Perlero nuevo
 
Mensajes: 21
Registrado: 2017-10-06 22:11 @966

Re: Búsqueda inteligente

Notapor Superdri » 2017-10-16 04:07 @213

Ya lo logré solucionar, pero ha sido curioso.

Ejecuté el cgi desde la consola con un die() para ver lo que llegaba a la variable $spec y salía lo siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
C:\xampp\htdocs>perl index.cgi action=rbg lang=en spec=102_ spec=103_ spec=104_ spec=105_ spec=71_ spec=72_
102_ 103_ 104_ 105_ 71_ 72_
 
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Unos espacios (o eso parece) pero en realidad no son espacios.

Entonces le metí la típica regxp para quitar espacios pero no quitaba nada, así que probé con
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $spec =~ s/\W//g;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

lo cual elimina caracteres no alfanuméricos y '_' y todo empezó a funcionar :D

Me gustaría entender de dónde salen esos caracteres no palabra. Puede ser algo del funcionamiento del módulo CGI al enviar los params repetidos.

¡Saludos!
Superdri
Perlero nuevo
Perlero nuevo
 
Mensajes: 21
Registrado: 2017-10-06 22:11 @966

Siguiente

Volver a Web

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 2 invitados