Búsqueda por facetas

La búsqueda por facetas te permite adjuntar información categórica a tus documentos. Una faceta es un par de atributo y valor. Por ejemplo, la faceta llamada “tamaño” puede tener los valores “pequeño”, “mediano” y “grande”.

Mediante el uso de las facetas con la búsqueda, puedes recuperar información de resumen para ayudarte a definir mejor una consulta y a “desglosar” tus resultados en una serie de pasos.

Esto es útil para las aplicaciones que funcionan como un sitio de compras en el que quieres ofrecerles a los clientes un conjunto de filtros para acotar la selección de productos que desean ver.

Los datos agregados de una faceta muestran cómo se distribuyen sus valores. Por ejemplo, la faceta “tamaño” puede aparecer en muchos de los documentos de tu conjunto de resultados. Los datos agregados de esta faceta pueden mostrar que el valor “pequeño” aparece 100 veces, “mediano” 300 veces y “grande” 250 veces. Cada par de faceta y valor representa un subconjunto de documentos en el resultado de la consulta. Una clave denominada perfeccionamiento se asocia con cada par. Puedes incluir perfeccionamientos en una consulta para recuperar documentos que coincidan con la string de consulta y que tengan los valores de la faceta correspondientes con uno o más perfeccionamientos.

Cuando llevas a cabo una búsqueda, puedes elegir qué facetas recopilar y mostrar con los resultados, o puedes habilitar la detección de facetas para que se seleccionen de forma automática las que aparecen con mayor frecuencia en tus documentos.

Agrega facetas a un documento

Agrega facetas a un documento antes de agregar el documento a un índice. Hazlo al mismo tiempo que especificas los campos del documento:

package com.google.test.facet;

import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.search.*;

public class FacetsearchjavaServlet extends HttpServlet {
  public void doPut(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    Document doc1 = Document.newBuilder()
      .setId("doc1")
      .addField(Field.newBuilder().setName("name").setAtom("x86"))
      .addFacet(Facet.withAtom("type", "computer"))
      .addFacet(Facet.withNumber("ram_size_gb", 8.0))
      .build();
    IndexSpec indexSpec = IndexSpec.newBuilder().setName("products").build();
      Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec);
    index.put(doc1);
  }
}

Una faceta es similar a un campo del documento; ambos tienen un nombre y reciben un valor.

Los nombres de las facetas siguen las mismas reglas que los campos de los documentos: los nombres distinguen entre mayúscula y minúscula, y solo pueden contener caracteres ASCII. Deben empezar con una letra y pueden contener letras, dígitos o guiones bajos. Un nombre no puede tener más de 500 caracteres.

El valor de una faceta puede ser una string atómica (no más de 500 caracteres) o un número (valor de coma flotante de doble precisión entre -2,147,483,647 y 2,147,483,647).

Para asignar varios valores a una faceta de un documento, puedes agregar una faceta con el mismo nombre y tipo muchas veces, pero con un valor diferente en cada una.

Una faceta puede tener una cantidad ilimitada de valores. Tampoco hay restricciones en cuanto a la cantidad de facetas que puedes agregar a un documento o la cantidad de facetas con nombre único que puede tener un índice.

Ten en cuenta que cada vez que uses una faceta, puede recibir un valor atómico o numérico. Una faceta con el nombre “tamaño” puede adjuntarse a un documento con el valor de string “pequeño” y a otro documento con el valor numérico 8. De hecho, la misma faceta puede aparecer varias veces en el mismo documento con ambos tipos de valores. No recomendamos que uses valores atómicos y numéricos para la misma faceta, a pesar de que esté permitido.

Si bien una faceta tiene un tipo específico cuando la agregas a un documento, los resultados de la búsqueda reúnen todos sus valores. Por ejemplo, los resultados para la faceta “tamaño” pueden mostrar que existen 100 instancias del valor “pequeño”, 150 instancias de “mediano” y 135 instancias de valores numéricos en el rango [4, 8). No se muestran los valores numéricos exactos ni su distribución de frecuencia.

Cuando recuperas un documento mediante una consulta, no puedes acceder directamente a sus facetas y valores. Debes solicitar que se muestre la información de esa faceta con la consulta, como se explica en la siguiente sección.

Usa una búsqueda por facetas para recuperar información sobre ellas

Puedes pedirle al backend de la búsqueda que detecte las facetas que se usan con más frecuencia. Esto se denomina "detección automática de facetas". También puedes recuperar información de la faceta de manera explícita si seleccionas una faceta por su nombre o por su nombre y valor. Puedes combinar los tres tipos de recuperación de facetas en una única consulta.

Consultar la información de las facetas no afectará a los documentos que muestre la consulta, aunque sí puede afectar el rendimiento. La realización de una búsqueda por facetas con la profundidad predeterminada de 1000 tiene el mismo efecto que la configuración del límite del marcador de opciones de ordenamiento en 1000.

Detección automática de facetas

La detección automática de facetas busca las facetas que aparecen con mayor frecuencia en la totalidad de tus documentos. Por ejemplo, imagina que los documentos que coinciden con tu consulta incluyen una faceta de “color” que aparece 5 veces con el valor “rojo”, 5 veces con el valor “blanco” y 5 veces con el color “azul”. Esta faceta tiene un recuento total de 15. Para los fines de detección, se clasificaría en una posición superior a otra faceta de “tono” que aparece en los mismos documentos correspondientes 6 veces con el valor “oscuro” y 7 veces con el valor “claro”.

Para habilitar la detección de facetas, debes configurarla en tu consulta:

package com.google.test.facet;

import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.search.*;

public class FacetsearchjavaServlet extends HttpServlet {
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    IndexSpec indexSpec = IndexSpec.newBuilder().setName("products").build();
      Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec);
      Results<ScoredDocument> result = index.search(
          Query.newBuilder().setEnableFacetDiscovery(true) // enable discovery
          .build("name:x86"));
      for(FacetResult facetResult : result.getFacets()) {
        resp.getWriter().printf("Facet %s:\n", facetResult.getName());
        for (FacetResultValue facetValue : facetResult.getValues()) {
          resp.getWriter().printf("   %s: Count=%s, RefinementKey=%s\n",
              facetValue.getLabel(),
              facetValue.getCount(),
              facetValue.getRefinementToken());
        }
      }
  }
}

Cuando recuperas facetas con la detección, en la configuración predeterminada, solo se muestran los 10 valores que aparecen con mayor frecuencia para una faceta. Puedes aumentar este límite hasta un valor máximo de 100 con FacetOptions.Builder.setDiscoveryValueLimit().

Ten en cuenta que el objetivo de la detección automática de facetas no es mostrar todas las facetas posibles y sus valores. Las facetas que se muestran a partir de la detección pueden variar entre distintas ejecuciones. Si deseas un conjunto fijo de facetas, usa un parámetro return_facets en tu consulta.

Los valores de string se mostrarán de manera individual. Los valores numéricos de una faceta detectada se muestran en un único rango [mín. máx.). Puedes analizar este rango y crear un subrango más pequeño para una consulta posterior.

Selecciona facetas por nombre

Para recuperar información acerca de una faceta solo por su nombre, agrega un objeto ReturnFacet a tu consulta y especifica el nombre de la faceta:

package com.google.test.facet;

import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.search.*;

public class FacetsearchjavaServlet extends HttpServlet {
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    IndexSpec indexSpec = IndexSpec.newBuilder().setName("products").build();
      Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec);
      Results<ScoredDocument> result = index.search(Query.newBuilder()
        .addReturnFacet("type")
        .addReturnFacet("ram_size_gb")
        .build("name:x86"));
      for(FacetResult facetResult : result.getFacets()) {
        resp.getWriter().printf("Facet %s:\n", facetResult.getName());
        for (FacetResultValue facetValue : facetResult.getValues()) {
          resp.getWriter().printf("   %s: Count=%s, RefinementKey=%s\n",
              facetValue.getLabel(),
              facetValue.getCount(),
              facetValue.getRefinementToken());
        }
      }
  }
}

Cuando recuperas facetas por nombre, en la configuración predeterminada, solo se muestran los 10 valores que aparecen con mayor frecuencia para una faceta. Puedes aumentar este límite hasta un valor máximo de 20 con FacetOptions.Builder.setDiscoveryValueLimit().

Selecciona facetas por nombre y valor

Para recuperar una faceta con un valor particular, agrega un objeto ReturnFacet que incluya una FacetRequest:

package com.google.test.facet;

import java.io.IOException;
import javax.servlet.http.*;
import com.google.appengine.api.search.*;

public class FacetsearchjavaServlet extends HttpServlet {
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        IndexSpec indexSpec = IndexSpec.newBuilder().setName("products").build();
        Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec);
        // Fetch the "type" facet with values "computer and "printer"
        // along with the "ram_size_gb" facet with values in the ranges [0,4), [4, 8), and [8, max]
        Results<ScoredDocument> result = index.search(Query.newBuilder()
            .addReturnFacet(FacetRequest.newBuilder()
                .setName("type")
                .addValueConstraint("computer")
                .addValueConstraint("printer"))
            .addReturnFacet(FacetRequest.newBuilder()
                .setName("ram_size_gb")
                .addRange(FacetRange.withEnd(4.0))
                .addRange(FacetRange.withStartEnd(4.0, 8.0))
                .addRange(FacetRange.withStart(8.0)))
            .build("name:x86"));
        for(FacetResult facetResult : result.getFacets()) {
            resp.getWriter().printf("Facet %s:\n", facetResult.getName());
            for (FacetResultValue facetValue : facetResult.getValues()) {
                resp.getWriter().printf("   %s: Count=%s, RefinementKey=%s\n",
                        facetValue.getLabel(),
                        facetValue.getCount(),
                        facetValue.getRefinementToken());
            }
        }
    }
}

Todos los valores en una sola FacetRequest deben ser del mismo tipo, ya sea una lista de valores de string o, si se trata de números, una lista de FacetRanges, que son intervalos cerrados a la izquierda (inicio) y abiertos a la derecha (fin). Si tu faceta posee una combinación de valores numéricos y de string, agrega distintas FacetRequests para cada uno.

Opciones

Puedes controlar la búsqueda por facetas si agregas un parámetro FacetOptions a una llamada de consulta. Este parámetro toma una sola instancia de FacetOptions. Usa este parámetro para anular el comportamiento predeterminado de la búsqueda por facetas.

Results<ScoredDocument> results = index.search(Query.newBuilder()
  .addReturnFacet(FacetRequest.newBuilder()
    .setName("type")
    .addValueConstraint("computer")
    .addValueConstraint("printer"))
  .addReturnFacet(FacetRequest.newBuilder()
    .setName("ram_size_gb")
    .addRange(FacetRange.withEnd(4.0))
    .addRange(FacetRange.withStartEnd(4.0, 8.0))
    .addRange(FacetRange.withStart(8.0)))
  .setFacetOptions(FacetOptions.newBuilder()
    .setDiscoveryLimit(5)
    .setDiscoveryValueLimit(10)
    .setDepth(6000).build());
  .build(“some_query”);
Parámetro Descripción Valor predeterminado
DiscoveryLimit Cantidad de facetas a descubrir si la detección de facetas está activada. Si el valor es 0, la detección de facetas se inhabilitará. 10
DiscoveryValueLimit Cantidad de valores que se muestran para cada una de las facetas descubiertas más importantes. 10
Depth La cantidad mínima de documentos en los resultados de la consulta a evaluarse para recopilar información de la faceta. 1000

La opción Depth se aplica a los tres tipos de agregación de facetas: por nombre, por nombre y valor, y autodetección. Las otras opciones son solo para la autodetección.

Ten en cuenta que la profundidad de las facetas suele mucho mayor que el límite de la consulta. Los resultados de las facetas se calculan, al menos, para el valor de profundidad de los documentos. Si configuraste el límite del marcador de las opciones de ordenamiento en un valor superior a la profundidad, se usará el límite del marcador.

Recupera los resultados de facetas

Cuando usas parámetros de búsqueda por facetas en una consulta, la agregación de la información de las facetas se mostrará junto con el resultado de la consulta.

Una consulta tendrá una lista de FacetResult. Habrá un resultado en la lista para cada faceta que apareció en un documento que coincidió con tu consulta. Para cada resultado, obtendrás lo siguiente:

  • El nombre de la faceta
  • Una lista de los valores más frecuentes para la faceta. A cada valor le corresponde un conteo de cuántas veces apareció y una clave de perfeccionamiento que puede usarse para recuperar los documentos que coinciden con esta consulta y con el valor de la faceta.

Ten en cuenta que la lista de valores incluirá los valores numéricos y las strings de la faceta. Si la faceta se detectó de forma automática, sus valores numéricos se mostrarán como un único intervalo [mín., máx.). Si solicitaste de forma explícita una faceta numérica con uno o más rangos en tu consulta, la lista mostrará un intervalo cerrado-abierto [inicio, fin) para cada rango.

La lista de los valores de la faceta puede no incluir todos los valores encontrados en tus documentos, ya que las opciones de la consulta determinan cuántos documentos se examinan y cuántos valores se muestran.

La agregación de la información de cada faceta puede leerse desde los resultados de la búsqueda:

Results<ScoredDocument> results = index.search(...);
for (FacetResult facetInfo : results.getFacets()) {
  ...
}

Por ejemplo, una consulta podría encontrar documentos que incluyen una faceta de “tamaño” con valores de string y valores numéricos. Los FacetResult de esta faceta tendrían el siguiente formato:

FacetResult.newBuilder()
        .setName("size")
        .addValue(FacetResultValue.create("[8, 10)", 22, refinement_key)
        .addValue(FacetResultValue.create("small", 100, refinement_key)
        .addValue(FacetResultValue.create("medium", 300, refinement_key)
        .addValue(FacetResultValue.create("large", 250, refinement_key).build());

La etiqueta FacetResultValue se construye con un valor de faceta. Los valores numéricos se muestran como una representación "en forma de string" de un rango.

refinement_key es una string segura de web o URL que puede usarse en una consulta posterior para recuperar los documentos que coinciden con el nombre o el valor de la faceta del resultado.

Usa facetas para definir mejor o filtrar una consulta

Query query = Query.newBuilder()
  .addFacetRefinementFromToken(refinement_key1)
  .addFacetRefinementFromToken(refinement_key2)
  .addFacetRefinementFromToken(refinement_key3)
  .build(“some_query”);

Puedes combinar los perfeccionamientos para una o más facetas diferentes en la misma solicitud. Todos los perfeccionamientos que pertenezcan a la misma faceta se unirán con OR. Los perfeccionamientos de facetas diferentes se combinarán con AND.

También es posible crear una clave FacetRefinement personalizada de forma manual. Consulta la documentación de la clase para obtener más información.

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Entorno estándar de App Engine para Java