Ricerca con facet

La ricerca con facet ti consente di allegare informazioni categoriche ai documenti. Un facet è una coppia attributo/valore. Ad esempio, il facet denominato "size" potrebbe avere i valori "small", "medium" e "large".

Utilizzando i facet con la ricerca, puoi recuperare informazioni di riepilogo per perfezionare una query e "visualizzare in dettaglio" i risultati in una serie di passaggi.

Questa funzionalità è utile per applicazioni come i siti di shopping, in cui intendi offrire un insieme di filtri per consentire ai clienti di restringere i prodotti che vogliono vedere.

I dati aggregati di un facet mostrano la distribuzione dei valori di un facet. Ad esempio, il facet "size" potrebbe essere presente in molti documenti del set di risultati. I dati aggregati di questo facet potrebbero mostrare che il valore "small" è stato visualizzato 100 volte, "medium" 300 volte e "large" 250 volte. Ogni coppia facet/valore rappresenta un sottoinsieme di documenti nel risultato della query. A ogni coppia è associata una chiave, chiamata affinamento. Puoi includere gli affinamenti in una query per recuperare i documenti che corrispondono alla stringa di query e che hanno i valori dei facet corrispondenti a uno o più affinamenti.

Quando esegui una ricerca, puoi scegliere quali facet raccogliere e mostrare con i risultati oppure puoi attivare il rilevamento dei facet per selezionare automaticamente i facet che appaiono più spesso nei documenti.

Aggiungere facet a un documento

Aggiungi i facet a un documento prima di aggiungerlo a un indice. Esegui questa operazione contemporaneamente alla specifica dei campi del documento:

package app

import (
    "google.golang.org/appengine/v2"
    "google.golang.org/appengine/v2/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.
}

Un facet è simile a un campo del documento: ha un nome e accetta un valore.

I nomi dei facet seguono le stesse regole dei campi dei documenti: i nomi fanno distinzione tra maiuscole e minuscole e possono contenere solo caratteri ASCII. Devono iniziare con una lettera e possono contenere lettere, cifre o trattini bassi. Un nome non può superare i 500 caratteri.

Il valore di un facet può essere una stringa atomica (non più lunga di 500 caratteri) o un numero (un valore a virgola mobile a doppia precisione compreso tra -2.147.483.647 e 2.147.483.647).

Puoi assegnare più valori a un facet in un documento aggiungendo un facet con lo stesso nome e tipo più volte, utilizzando ogni volta un valore diverso.

Non esiste un limite al numero di valori che un facet può avere. Non esiste inoltre un limite al numero di facet che puoi aggiungere a un documento o al numero di facet con nomi univoci in un indice.

Tieni presente che ogni volta che utilizzi un facet, può assumere un valore atomico o numerico. Un facet con il nome "size" può essere collegato a un documento con il valore stringa "small" e a un altro documento con il valore numerico 8. Infatti, lo stesso facet può essere visualizzato più volte nello stesso documento con entrambi i tipi di valori. Anche se è consentito, non consigliamo di utilizzare valori atomici e numerici per lo stesso facet.

Anche se un facet ha un tipo specifico quando lo aggiungi a un documento, i risultati di ricerca raccolgono tutti i suoi valori. Ad esempio, i risultati del facet "size" potrebbero mostrare che sono state trovate 100 istanze del valore "small", 150 istanze di "medium" e 135 istanze di valori numerici nell'intervallo [4, 8). I valori numerici esatti e la relativa distribuzione di frequenza non vengono mostrati.

Quando recuperi un documento utilizzando una query, non puoi accedere direttamente ai relativi facet e valori. Devi richiedere che le informazioni sui facet vengano restituite con la query, come spiegato nella sezione successiva.

Utilizzare una ricerca con facet per recuperare le informazioni sui facet

Puoi chiedere al backend di ricerca di rilevare i facet utilizzati più di frequente. Questa operazione è chiamata rilevamento automatico dei facet. Puoi anche recuperare le informazioni sui facet in modo esplicito selezionando un facet per nome o per nome e valore. Puoi combinare tutti e tre i tipi di recupero dei facet in una singola query.

La richiesta di informazioni sui facet non influirà sui documenti restituiti dalla query. Può influire sul rendimento. L'esecuzione di una ricerca con facet con la profondità predefinita di 1000 ha lo stesso effetto dell'impostazione del limite di punteggio delle opzioni di ordinamento su 1000.

Rilevamento automatico dei facet

Il rilevamento automatico dei facet cerca i facet che appaiono più spesso in aggregato nei documenti. Ad esempio, supponiamo che i documenti che corrispondono alla query includano un facet "color" che appare 5 volte con il valore "red", 5 volte con il valore "white" e 5 volte con il colore "blue". Questo facet ha un conteggio totale di 15. Ai fini del rilevamento, avrebbe una classificazione più alta rispetto a un altro facet "shade" che appare negli stessi documenti corrispondenti 6 volte con il valore "dark" e 7 volte con il valore "light".

Devi attivare il rilevamento dei facet impostandolo nella query:

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)
        }
    }
}

Quando recuperi i facet tramite il rilevamento, per impostazione predefinita vengono restituiti solo i 10 valori più frequenti per un facet. Puoi aumentare questo limite fino a 100 utilizzando il primo parametro di AutoFacetDiscovery.

Tieni presente che il rilevamento automatico dei facet non ha lo scopo di restituire tutti i facet possibili e i relativi valori. I facet restituiti dal rilevamento possono variare da un'esecuzione all'altra. Se vuoi un insieme fisso di facet, utilizza un parametro return_facets nella query.

I valori stringa vengono restituiti singolarmente. I valori numerici di un facet rilevato vengono restituiti in un singolo intervallo [min max). Puoi esaminare questo intervallo e creare un intervallo secondario più piccolo per una query successiva.

Selezionare i facet per nome

Per recuperare le informazioni su un facet solo in base al nome, aggiungi un FacetDiscovery con il nome del facet alle opzioni di ricerca per la query:

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

Quando recuperi i facet per nome, vengono restituiti solo i 10 valori più frequenti per un facet.

Selezionare i facet per nome e valore

Per recuperare informazioni solo su valori specifici di un facet, aggiungi un FacetDiscovery con il nome del facet e i valori di interesse:

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),
        ),
    },
})

I valori in un singolo FacetDiscovery devono essere tutti dello stesso tipo, ovvero un elenco di valori search.Atom o, per i numeri, un elenco di search.Range, che sono intervalli chiusi a sinistra (inizio) e aperti a destra (fine). Se il facet ha un mix di valori stringa e numerici, aggiungi opzioni FacetDisovery separate per ciascuno.

Opzioni

Puoi controllare il numero minimo di documenti da valutare per raccogliere informazioni sui facet aggiungendo l'opzione FacetDocumentDepth in SearchOptions per la query. Se non specificata, questa profondità è impostata per impostazione predefinita su 1000.

Tieni presente che la profondità dei facet è in genere molto maggiore del limite della query. I risultati dei facet vengono calcolati per almeno il numero di documenti di profondità.

Se hai impostato il limite di punteggio delle opzioni di ordinamento su un valore superiore alla profondità, verrà utilizzato il limite di punteggio.

Recuperare i risultati dei facet

Quando utilizzi i parametri di ricerca con facet in una query, le informazioni aggregate sui facet vengono fornite con il risultato della query stesso.

L'oggetto Iterator di ricerca ha un metodo Facets, che restituisce le informazioni aggregate sui facet come [][]FacetResult. I risultati sono organizzati in modo che ci sia una sezione di risultati dei facet per ogni facet visualizzato in un documento che corrisponde alla query. Per ogni risultato, riceverai:

  • Il nome del facet
  • Un valore per il facet dall'elenco dei valori più frequenti
  • Un conteggio approssimativo del numero di volte in cui è apparso il valore

Tieni presente che l'elenco dei valori includerà i valori stringa e numerici di un facet. Se il facet è stato rilevato automaticamente, i relativi valori numerici vengono restituiti come un singolo intervallo [min max). Se hai richiesto in modo esplicito un facet numerico con uno o più intervalli nella query, l'elenco conterrà un intervallo chiuso-aperto [start end) per ogni intervallo.

L'elenco dei valori dei facet potrebbe non includere tutti i valori trovati nei documenti, poiché le opzioni della query determinano il numero di documenti da esaminare e il numero di valori da restituire.

Le informazioni aggregate per ogni facet possono essere lette dall'iteratore:

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

Ad esempio, una query potrebbe aver trovato documenti che includono un facet "size" con i valori stringa e numerici. I risultati di questo facet verranno creati nel seguente modo:

[][]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},
    },
}

Utilizzare i facet per perfezionare/filtrare una query

Ogni FacetResult può essere utilizzato per restringere ulteriormente i risultati in modo da includere solo i documenti che hanno questi valori dei facet. Per perfezionare le query con una o più di queste chiavi, trasmettile come opzioni di ricerca:

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

Puoi combinare gli affinamenti per uno o più facet diversi nella stessa richiesta. Tutti gli affinamenti appartenenti allo stesso facet vengono uniti con un OR. Gli affinamenti per facet diversi vengono combinati con AND.

È anche possibile creare manualmente un Facet personalizzato da utilizzare come affinamento. Per ulteriori informazioni, consulta il riferimento.