Consultas en Solr

Consultas en Solr
Como ya hemos visto en anteriores entradas, Solr nos ofrece un interfaz de administración que nos permite hacer consultas contra los indices y analizarlas. En esta ocasión, vamos a hacer un repaso de las funciones de consulta en Solr.

Veremos como indicar los campos sobre los que buscar, condiciones, filtros, ordenación, depuración, y cómo cambiar el tipo de respuesta y procesarla.

 

Administrador de Solr

Una vez seleccionado, entramos en la pantalla principal del administrador de Solr, desde aquí, podemos cambiar de core, revisar su configuración y el esquema; pero sobre todo podemos hacer consultas y analizarlas. La pantalla principal incorpora un formulario rápido de consulta, pero es más útil el formulario avanzado.

  • Administración de Solr
  • Consultas Avanzadas

 

Todas las opciones que podemos utilizar desde la pantalla de consultas se traducen en parámetros en la url de consulta.

http://localhost:8983/solr/test/select?indent=on&version=2.2
&q=tronos&fq=-category1%3ALibros&start=0&rows=10
&fl=id%2Cname%2Ccategory1%2Cscore&wt=json
&explainOther=&hl=on&hl.fl=name%2C+description

 

Respuesta

Por defecto Solr devuelve los resultados en forma de XML, pero permite seleccionar diferentes tipos usando el parámetro wt.

Como ejemplo, veamos los resultados devueltos para los siguientes valores de wt:xml,json,php,ruby:

 

  • xml

  • json

  • php

  • ruby


<?xml version="1.0" encoding="UTF-8"?>
<response>

<lst name="responseHeader">
  <int name="status">0</int>
  <int name="QTime">1</int>
  <lst name="params">
    <str name="explainOther"/>
    <str name="fl">id,name,category1,score</str>
    <str name="indent">on</str>
    <str name="start">0</str>
    <str name="q">tronos</str>
    <str name="hl.fl"/>
    <str name="wt">java</str>
    <str name="fq"/>
    <str name="version">2.2</str>
    <str name="rows">10</str>
  </lst>
</lst>
<result name="response" numFound="2" start="0" maxScore="0.72428">
  <doc>
    <float name="score">0.72428</float>
    <str name="category1">Videojuegos</str>
    <str name="id">14</str>
    <str name="name">Juego de Tronos</str>
  </doc>
  <doc>
    <float name="score">0.72428</float>
    <str name="category1">Libros</str>
    <str name="id">16</str>
    <str name="name">Juego de tronos: Canción de Hielo y Fuego 1</str>
  </doc>
</result>
</response>

{
  "responseHeader":{
    "status":0,
    "QTime":0,
    "params":{
      "explainOther":"",
      "fl":"id,name,category1,score",
      "indent":"on",
      "start":"0",
      "q":"tronos",
      "hl.fl":"",
      "wt":"json",
      "fq":"",
      "version":"2.2",
      "rows":"10"}},
  "response":{"numFound":2,"start":0,"maxScore":0.72428,"docs":[
      {
        "id":"14",
        "name":"Juego de Tronos",
        "category1":"Videojuegos",
        "score":0.72428},
      {
        "id":"16",
        "name":"Juego de tronos: Canción de Hielo y Fuego 1",
        "category1":"Libros",
        "score":0.72428}]
  }}

array(
  'responseHeader'=>array(
    'status'=>0,
    'QTime'=>1,
    'params'=>array(
      'explainOther'=>'',
      'fl'=>'id,name,category1,score',
      'indent'=>'on',
      'start'=>'0',
      'q'=>'tronos',
      'hl.fl'=>'',
      'wt'=>'php',
      'fq'=>'',
      'version'=>'2.2',
      'rows'=>'10')),
  'response'=>array('numFound'=>2,'start'=>0,'maxScore'=>0.72428,'docs'=>array(
      array(
        'id'=>'14',
        'name'=>'Juego de Tronos',
        'category1'=>'Videojuegos',
        'score'=>0.72428),
      array(
        'id'=>'16',
        'name'=>'Juego de tronos: Canción de Hielo y Fuego 1',
        'category1'=>'Libros',
        'score'=>0.72428))
  ))

{
  'responseHeader'=>{
    'status'=>0,
    'QTime'=>1,
    'params'=>{
      'explainOther'=>'',
      'fl'=>'id,name,category1,score',
      'indent'=>'on',
      'start'=>'0',
      'q'=>'tronos',
      'hl.fl'=>'',
      'wt'=>'ruby',
      'fq'=>'',
      'version'=>'2.2',
      'rows'=>'10'}},
  'response'=>{'numFound'=>2,'start'=>0,'maxScore'=>0.72428,'docs'=>[
      {
        'id'=>'14',
        'name'=>'Juego de Tronos',
        'category1'=>'Videojuegos',
        'score'=>0.72428},
      {
        'id'=>'16',
        'name'=>'Juego de tronos: Canción de Hielo y Fuego 1',
        'category1'=>'Libros',
        'score'=>0.72428}]
  }}

 

 

En todos los casos la estructura es la misma, una sección header en la que nos devuelve los parámetros de configuración que le hemos pasado y response con los documentos. Más adelante veremos que a estas estructuras básicas se le van añadiendo otras colecciones como resultado de operaciones de facetación, highlighting y otros.

Se pueden encontrar librerías para facilitar la tarea de consulta y procesado de la respuesta desde distintos lenguajes de programación: java, php, .net, ruby, python, perl, etc. Antes de decantarse por la adopción de una librería, es importante comprobar que es capaz de usar todas las funcionalidades de Solr, y de que realmente ayuda; ya que a veces sólo introducen una capa más que aprender, debes aprender a usar Solr y además a hacer que la librería transmita al buscador lo que quieres. También podemos encontrar componentes ya creados para integrar Solr con aplicaciones conocidas.

 

Párametros básicos

Antes de nada debemos saber los parámetros básicos para la búsqueda en Solr:

q (query)
Especifica la consulta de búsqueda.
fq (filter query)
Permite filtrar los resultados de la búsqueda según criterios.
sort (ordenación)
Ordena de forma ascendente o descendente.
fl (fields)
Permite especificar los campos que va a devolver Solr. Por defecto *, score
wt (writer type)
Indica a Solr cual va a ser el procesador de salida que componga la cadena de respuesta. por defecto wt=xml.
start
Indica la primera fila a devolver del conjunto de elementos resultantes (comienzo de página).
rows
Número máximo de elementos a devover del resultado (elementos por página).
omitHeader
Permite obviar el elemento header en la respuesta.

 

Cómo hacer búsquedas

Los resultados de una búsqueda dependen, tanto de la consulta que hagamos, como de la forma en que hemos indexado los datos. Por ejemplo, cuando buscamos sobre un campo de tipo string o uno numérico, no se hace ningún tipo de búsqueda por aproximación. En el caso de un número parece obvio, pero en los campos de texto el resultado depende mucho de cómo se esté analizando el texto en el momento de la indexación.

Los campos String sólo admiten búsquedas literales, no harán búsquedas parciales ni cambiarán el “case” de un texto para encontrarlo; por otro lado un campo de texto que esté toquenizando el contenido, no servirá para hacer filtros ya que aplicará búsquedas por aproximación. Esto no debe ser un problema, podemos usar copyfields y mantener el contenido en campos con diferentes tipos de indexación.

Solr tiene dos tipos de sintaxis de consulta que se indican el el parámetro defType. Hoy vamos a ver el tipo por defecto: LuceneQParser (Búsqueda de Lucene), en otro post veremos a fondo el edismax (Extended Dismax).

Las búsquedas se definen con los parámetros q y fq, veamos unos ejemplos:

 

  • q=tronos
    fq=category1:Libros
    Documentos que contengan “tronos” en el campo por defecto y cuya categoría sea “Libros”.
  • q=tronos
    fq=-category1:Libros
    Documentos que contengan “tronos” en el campo por defecto y cuya categoria NO sea “Libros”.
  • q=*:*
    fq=category1:Electrónica
    Todos los documentos de la categoría Electrónica.

 

Aquellas consultas que incluyan cualquiera de los caracteres reservados de Lucene: + - && || ! ( ) { } [ ] ^ " ~ * ? : \ deberán escaparse utilizando o entrecomillando la consulta.

q=\[opcional\]
q="Atencion!"

 

Cuando hacemos una consulta al índice, si no decimos los contrario, se utilizarán los valores por defecto definidos en el fichero schema.xml en los campos defaultSearchField y defaultOperator.

Podemos indicar varios campos sobre los que hacer la búsqueda, e indicar el operador lógico si es distinto al configurado por defecto en el esquema. Veamos de nuevo varios ejemplos:

 

  • q=name:mp3 OR categoryBreadcrumb: mp3 OR description:mp3
    fq=category1:Electrónica
    Documentos pertenecientes a la categoría electrónica que contengan “mp3″ en cualquiera de los campos: name, categoryBreadcrumb o description.

 

  • q=*:*
    fq=+stock:[12 TO *] -price:[* TO 65]
    Cualquier documento (producto) que tenga un stock superior 11 y con un precio mínimo de 65€.

 

  • q=name:tronos AND name:juego AND -name:hielo
    fq=
    Documentos que contenga en el campo nombre “tronos” y “juego” pero que no contengan “hielo”

 

Depuración

Es importante saber cómo evalúa Solr las consultas para entender los resultados. Podemos activar la depuración de consulta añadiendo el parámetro debugQuery=on; esto nos devuelve una estructura como esta al final de la respuesta normal de la consulta:

<lst name="debug">
  <str name="rawquerystring">name:hielo OR description:hielo</str>
  <str name="querystring">name:hielo OR description:hielo</str>
  <str name="parsedquery">name:hielo description:hielo</str>
  <str name="parsedquery_toString">name:hielo description:hielo</str>
  <lst name="explain">
    <str name="16">
0.43786508 = (MATCH) product of:
  0.87573016 = (MATCH) sum of:
    0.87573016 = (MATCH) weight(name:hielo in 15), product of:
      0.7071068 = queryWeight(name:hielo), product of:
        3.3025851 = idf(docFreq=1, maxDocs=20)
        0.21410707 = queryNorm
      1.2384694 = (MATCH) fieldWeight(name:hielo in 15), product of:
        1.0 = tf(termFreq(name:hielo)=1)
        3.3025851 = idf(docFreq=1, maxDocs=20)
        0.375 = fieldNorm(field=name, doc=15)
  0.5 = coord(1/2)
</str>
    <str name="14">
0.3648876 = (MATCH) product of:
  0.7297752 = (MATCH) sum of:
    0.7297752 = (MATCH) weight(description:hielo in 13), product of:
      0.7071068 = queryWeight(description:hielo), product of:
        3.3025851 = idf(docFreq=1, maxDocs=20)
        0.21410707 = queryNorm
      1.0320579 = (MATCH) fieldWeight(description:hielo in 13), product of:
        1.0 = tf(termFreq(description:hielo)=1)
        3.3025851 = idf(docFreq=1, maxDocs=20)
        0.3125 = fieldNorm(field=description, doc=13)
  0.5 = coord(1/2)
</str>
  </lst>
  <str name="QParser">LuceneQParser</str>
  <lst name="timing">
    <double name="time">2.0</double>
    <lst name="prepare">
      <double name="time">1.0</double>
      <lst name="org.apache.solr.handler.component.QueryComponent">
        <double name="time">1.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.FacetComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.MoreLikeThisComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.HighlightComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.StatsComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.DebugComponent">
        <double name="time">0.0</double>
      </lst>
    </lst>
    <lst name="process">
      <double name="time">1.0</double>
      <lst name="org.apache.solr.handler.component.QueryComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.FacetComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.MoreLikeThisComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.HighlightComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.StatsComponent">
        <double name="time">0.0</double>
      </lst>
      <lst name="org.apache.solr.handler.component.DebugComponent">
        <double name="time">1.0</double>
      </lst>
    </lst>
  </lst>
</lst>

Incluye los datos de tiempos de respuesta de cada módulo de Solr implicado, el query parser, en este caso LuceneQParser, la query real que ha ejecutado y la explicación del cálculo de score para cada documento devuelto.

 

Ordenación

La ordenación por defecto de Solr es por score en descendente; es decir que muestra primero los elementos que considera más relevantes. Podemos ordenar por otros campos y esto no afecta al subconjunto de datos devueltos por la query (completo, no sólo la página actual); sólo al orden de presentación.

Podemos indicar uno o varios criterios separado por comas:

&sort=category asc,price desc

La ordenación dependerá del modo en que se esté indexando el dato. Un String distingue entre mayúsculas y minúsculas y las trata como caracteres distintos, si queremos una ordenación que encaje con las expectativas del usuario, deberemos hacerlo con un campo de texto que incorpore un LowerCaseFilterFactory al indexar el contenido.

 

Ordenado como string:
  1. Antonio
  2. Bernardo
  3. Miguel
  4. ana
  5. zacarías
Ordenado como texto lcase:
  1. ana
  2. Antonio
  3. Bernardo
  4. Miguel
  5. zacarías

 

De la misma forma, un número almacenado como texto, se ordena “alfabéticamente” y no numéricamente.

 

 

Con esto terminamos con lo básico sobre consultas, en próximas entradas veremos la facetación, request handlers, y otras cosas divertidas.

Hasta pronto.

 

 

 

9 comentarios para “Consultas en Solr”

  • Javier dice:

    Hola, muchas gracias por toda la información publica.

    Una duda, veras he indexado un directoria de documentos en windows y quiero realizar la busqueda de un fichero “filtrando” por un directorio.
    Tengo un campo declarado (he aprovechado todo lo que viene en solr 4) de este modo:
    resourcename:D:\DOCS\FOLDER1\2010\Lista.pdf
    resourcename:D:\DOCS\FOLDER1\2011\Lista.pdf
    resourcename:D:\DOCS\FOLDER1\2012\Lista.pdf

    Para hacer la consulta lo escapo los caracteres y filtro por el mismo metiendo:

    q:id:*lista* OR *LISTA* OR *Lista*
    fq:”resourcename:\”\”DOCS/FOLDER1/2010/”

    Pero me saca todos los ficheros… ¿alguna idea?

    Gracias!

  • Javier dice:

    q:resourcename:*lista* OR *LISTA* OR *Lista*
    fq:resourcename:\”\”DOCS/FOLDER1/2010/”

    En resourcename y id tengo los mismos valores

  • Victor Velez dice:

    Saludos,

    Hace poco empece a trabajar con solr, me gustaria conocer un poco sobre el score que se arroja en el resultado de la busqueda.

    Ahora mismo tengo problemas ya que al buscar un producto, digamos arroz blanco
    y tengo 2 productos diferentes: {arroz integral, arroz roa blanco}, en el campo score me devuelve ambos con el mismo puntaje me interesaria saber como hacer para que el me suba puntos al producto que mas coincidencias tiene.

    Gracias

    • Alberto Pérez dice:

      Tienes una opción para que te devuelva el score explicado, de esta manera puedes ver el score y como llega Solr a esa valoración.

      A partir de ahí yo te aconsejaría que usaras una query concreta que potencie aquellos resultados que contengan todas las palabras de búsqueda.

      Algo así como busca “arroz blanco” y si lo encuentras con una coincidencia literal multiplica el score por 4, busca en modo and y multiplica por 2 aquellas entradas que contengan todos los términos buscados y por último busca en OR y deja el score tal cual.

      Esto te permite unos resultados más fieles, pero primero busca el motivo de que tengan en mismo score.

    • Alberto Pérez dice:

      Me sorprende que devuelva el mismo score. El primer registro no incluye la palabra blanco y por lo tanto su score debe ser inferior. Habría qeu ver el tipo de campo, como se está indexando y sobre cual es la query que se está ejecutando.

  • Cesar dice:

    Hola:

    Alguien sabe como si hay algún equivalente a distinct en solr
    o como podría hacerlos.

    De antemano Gracias
    Saludos

  • C. M. S. dice:

    Hola:

    Hace poco empece a trabajar con solr y me gustaría saber sy existe el equivalente a distinc o si se puede hacer algo parecido en el query.

    Gracias.

  • Walther Wottrich dice:

    se puede ver el URL y el Tamaño de un documento cuando se elije en una interfaz gráfica?

Deja un comentario

Uso de cookies

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.plugin cookies

?>