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” podría tener los valores “pequeño”, “mediano” y “grande”.

Mediante el uso de facetas con la búsqueda, puedes recuperar información de resumen a fin de precisar las consultas y “desglosar” los resultados en una serie de pasos.

Esto es útil para aplicaciones tales como los sitios de compras, en los que se quiere ofrecer 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 podrían 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. A cada par se asocia una clave denominada perfeccionamiento. Puedes incluir perfeccionamientos en una consulta para recuperar documentos que coincidan con la string de consulta y que tengan valores de faceta que se correspondan con uno o más perfeccionamientos.

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

Agregado de 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 app

import (
    "appengine"
    "appengine/search"
    "net/http"
)

type ComputerDoc struct {
    Name      search.Atom
    Type      search.Atom `search:",facet"`
    RAMSizeGB float64     `search:",facet"`
}

func handlePut(w http.ResponseWriter, r *http.Request) {
    c := appengine.NewContext(r)
    index, err := search.Open("products")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    _, err = index.Put(c, "doc1", &ComputerDoc{
        Name:      "x86",
        Type:      "computer",
        RAMSizeGB: 8.0,
    })
    // Handle err and write HTTP response.
}

La faceta es similar a un campo de un documento; tiene un nombre y recibe 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 incluir letras, dígitos o guiones bajos. El nombre no puede tener más de 500 caracteres.

El valor de una faceta puede ser una string atómica (de no más de 500 caracteres) o un número (valor de punto 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 varias veces una faceta del mismo nombre y tipo, pero con un valor diferente en cada caso.

Las facetas pueden 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 incluir un índice.

Ten en cuenta que cada vez que uses una faceta, puede recibir un valor atómico o numérico. Es posible agregar una faceta con el nombre “tamaño” 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 usar valores atómicos y numéricos para la misma faceta aunque esté permitido.

Si bien cada 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” podrían 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 la faceta con la consulta, como se explica en la sección siguiente.

Búsqueda por facetas para recuperar información sobre facetas

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 facetas de manera explícita seleccionando una faceta por nombre o por nombre y valor. Puedes combinar las tres clases de recuperación de facetas en una misma consulta.

El pedido de información de las facetas no afectará los documentos que muestre la consulta. Sí puede afectar el rendimiento. Realizar una búsqueda por facetas con la profundidad predeterminada de 1,000 tiene el mismo efecto que configurar el límite del marcador de opciones de ordenamiento en 1,000.

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 “color” que aparece 5 veces con el valor “rojo”, 5 veces con el valor “blanco” y 5 veces con el color “azul”. El recuento total de la faceta es 15. Para los fines de detección, se clasificaría en una posición superior a la de otra faceta “tono” que apareciera en los mismos documentos 6 veces con el valor “oscuro” y 7 veces con el valor “claro”.

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

func handleSearch(w http.ResponseWriter, r *http.Request) {
    index, err := search.Open("products")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    it := index.Search(c, "name:x86", &search.SearchOptions{
        Facets: {
            search.AutoFacetDiscovery(0, 0),
        },
    })
    facets, err := it.Facets()
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    for _, results := range facets {
        for i, facet := range result {
            // The facet results are grouped by facet name.
            // Print the name of each group before its values.
            if i == 0 {
                fmt.Fprintf(w, "Facet %s:\n", facet.Name)
            }
            fmt.Fprintf(w, "    %v: count=%d", facet.Value, facet.Count)
        }
    }
}

Cuando recuperas facetas con la detección, de forma predeterminada, solo se muestran los 10 valores que aparecen con mayor frecuencia para una faceta. Puedes aumentar este límite hasta 100 con el primer parámetro en AutoFacetDiscovery.

Ten en cuenta que la detección automática de facetas no tiene por objeto 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 consultar por un conjunto fijo de facetas, usa un parámetro return_facets en la consulta.

Los valores 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 ese rango y crear un subrango más pequeño para una consulta posterior.

Selección de facetas por nombre

Para recuperar información acerca de una faceta solo por su nombre, agrega FacetDiscovery con el nombre de la faceta a las opciones de búsqueda de tu consulta:

it := index.Search(c, "name:x86", &search.SearchOptions{
    Facets: {
        FacetDiscovery("Type"),
        FacetDiscovery("RAMSizeGB"),
    },
})

Cuando recuperas facetas por nombre, solo se muestran los 10 valores que aparecen con mayor frecuencia en una faceta.

Selecciona facetas por nombre y valor

Para solo recuperar información acerca de los valores de una faceta en particular, agrega FacetDiscovery con el nombre de la faceta y los valores de interés:

it := index.Search(c, "name:x86", &search.SearchOptions{
    Facets: {
        // Fetch the "Type" facet with Values "computer" and "printer"
        FacetDiscovery("Type",
            search.Atom("computer"),
            search.Atom("printer"),
        ),
        // Fetch the "RAMSizeGB" facet with values in the ranges [0, 4), [4, 8), and [8, max]
        FacetDiscovery("RAMSizeGB",
            search.Range{Start: 0, End: 4},
            search.Range{Start: 4, End: 8},
            search.AtLeast(8),
        ),
    },
})

Todos los valores en una sola FacetDiscovery deben ser del mismo tipo, ya sea una lista de valores de search.Atom o, si se trata de números, una lista de search.Range, que son intervalos cerrados a la izquierda (inicio) y abiertos a la derecha (fin). Si tu faceta tiene una combinación de valores numéricos y de strings, agrega opciones de FacetDisovery independientes para cada uno.

Opciones

Puedes controlar la cantidad mínima de documentos que se evaluarán a fin de recopilar la información de las facetas. Para ello, agrega la opción FacetDocumentDepth al SearchOptions de tu consulta. Si no especificas una cantidad, la profundidad se establece de forma predeterminada en 1,000.

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 como mínimo para el valor de profundidad de los documentos. Si configuraste el límite del marcador de opciones de ordenamiento en un valor superior al de la profundidad, se usará el límite del marcador.

Recuperación de 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 muestra junto con el resultado de la consulta.

La búsqueda Iterator tiene un método Facets, que muestra la agregación de información de la faceta como [][]FacetResult. Los resultados se organizan de modo tal que haya una porción de resultados de cada faceta que aparezca en un documento que coincidió con tu consulta. Para cada resultado, obtendrás lo siguiente:

  • El nombre de la faceta
  • Un valor de la faceta tomado de la lista de valores más frecuentes
  • Una cantidad aproximada de cuántas veces apareció ese valor

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 en la consulta solicitaste de forma explícita una faceta numérica con uno o más rangos, la lista mostrará un intervalo cerrado-abierto [inicio, fin) por 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 del iterador:

it := index.Search(...)
facets, err := it.Facets()  // And check err != nil.
for _, results := range facets {
    for _, facet := range results {
        ...
    }
}

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

[][]search.FacetResult{
    {
        {Name: "size", Value: search.Range{Start: 8, End: 10}, Count: 22},
        {Name: "size", Value: search.Atom("small"), Count: 100},
        {Name: "size", Value: search.Atom("medium"), Count: 300},
        {Name: "size", Value: search.Atom("large"), Count: 250},
    },
}

Usa facetas para definir mejor o filtrar una consulta

Cada FacetResult se puede usar para reducir aún más los resultados y solo incluir los documentos que tengan esos valores de faceta. A fin de definir mejor las consultas con una o más de estas claves, pásalas como opciones de búsqueda:

it := index.Search(c, "...", &search.SearchOptions{
    Refinements: []search.Facet{
        facetResult1.Facet,
        facetResult2.Facet,
    },
})

Puedes combinar 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 Facet personalizada de forma manual para usarla como un perfeccionamiento. Consulta la referencia para obtener más información.