Ricerca con facet

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

L'utilizzo dei facet con la ricerca ti consente di recuperare informazioni riepilogative che ti consentono di perfezionare una query e visualizzare in dettaglio i risultati in una serie di passaggi.

Questo è utile per applicazioni come i siti di shopping, in cui intendi offrire ai clienti una serie di filtri per limitare i prodotti che vogliono vedere.

I dati aggregati di un facet mostrano come vengono distribuiti i relativi valori. Ad esempio, le "dimensioni" dei facet possono essere visualizzate in molti documenti nel set di risultati. I dati aggregati per quel facet potrebbero mostrare che il valore "small" è apparso 100 volte, "medium" 300 volte e "large" 250 volte. Ogni coppia di facet/valore rappresenta un sottoinsieme di documenti nel risultato della query. A ogni coppia è associata una chiave, chiamata perfezionamento. Puoi includere perfezionamenti in una query per recuperare documenti che corrispondono alla stringa di query e i cui valori dei facet corrispondono a uno o più perfezionamenti.

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

Aggiunta di facet a un documento

Aggiungi facet a un documento prima di aggiungerlo a un indice. Esegui questa operazione nello stesso momento in cui specifichi i campi 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);
  }
}

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

I nomi dei facet seguono le stesse regole dei campi dei documenti: i nomi sono sensibili alle maiuscole e possono contenere solo caratteri ASCII. Devono iniziare con una lettera e possono contenere lettere, numeri o trattini bassi. Il 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 in virgola mobile a precisione doppia compresa tra -2.147.483.647 e 2.147.483.647).

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

Non è previsto alcun limite al numero di valori che un facet può avere. Inoltre, non esiste alcun 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ò essere utilizzato un valore atomico o numerico. Un facet con nome "size" può essere allegato a un documento con il valore stringa "small" e a un altro documento con valore numerico 8. Infatti, lo stesso facet può apparire più volte nello stesso documento con entrambi i tipi di valori. Sconsigliamo di utilizzare valori atomici e numerici per lo stesso facet, anche se è consentito.

Mentre 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 relativi a "size" dei facet potrebbero indicare che ci sono state 100 istanze del valore "small", 150 di "medium" e 135 istanze di valori numerici nell'intervallo [4, 8). Non vengono mostrati i valori numerici esatti e la relativa distribuzione di frequenza.

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

Utilizzo di una ricerca con facet per recuperare informazioni sui facet

Puoi chiedere al backend di ricerca di scoprire i facet che utilizzi più di frequente per te, ovvero il cosiddetto rilevamento automatico dei facet. Puoi anche recuperare esplicitamente le informazioni sui facet selezionando un facet in base al nome o al nome e al valore. Puoi combinare tutti e tre i tipi di recupero dei facet in un'unica query.

La richiesta di informazioni sui facet non influisce sui documenti restituiti dalla query. Può influire sulle prestazioni. Eseguire una ricerca con facet con la profondità predefinita di 1000 equivale a impostare il 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 nell'aggregato dei tuoi documenti. Ad esempio, supponiamo che i documenti corrispondenti alla query includano un facet "colore" che viene visualizzato 5 volte con il valore "rosso", 5 volte con il valore "bianco" e 5 volte con il colore "blu". che ha un conteggio totale di 15. Ai fini della scoperta, verrebbe classificato più in alto rispetto a un'altra "ombra" dei facet che compare negli stessi documenti corrispondenti sei volte con il valore "scuro" e sette volte con il valore "chiaro".

Devi abilitare il rilevamento dei facet impostandolo nella query:

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

Quando recuperi i facet per rilevamento, per impostazione predefinita verranno restituiti solo i 10 valori più frequenti per un facet. Puoi aumentare questo limite fino a 100 utenti utilizzando FacetOptions.Builder.setDiscoveryValueLimit().

Tieni presente che il rilevamento automatico dei facet non restituisce 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 verranno restituiti singolarmente. I valori numerici di un facet rilevato vengono restituiti in un singolo intervallo [min max). Puoi esaminare questo intervallo e creare un sottointervallo più piccolo per una query successiva.

Selezione dei facet per nome

Per recuperare le informazioni su un facet solo in base al nome, aggiungi un oggetto ReturnFacet alla query, specificando il nome del facet:

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

Quando recuperi i facet per nome, per impostazione predefinita vengono restituiti solo i 10 valori più frequenti per un facet. Puoi aumentare questo limite fino a 20 utilizzando FacetOptions.Builder.setDiscoveryValueLimit().

Selezione dei facet per nome e valore

Per recuperare un facet con un determinato valore, aggiungi un oggetto ReturnFacet che includa un 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());
            }
        }
    }
}

I valori in un singolo elemento FacetRequest devono essere tutti dello stesso tipo, ovvero un elenco di valori stringa oppure, per i numeri, un elenco di FacetRanges, ovvero intervalli chiusi a sinistra (start) e aperti a destra (fine). Se il facet ha una combinazione di valori di stringa e numeri, aggiungi FacetRequests distinti per ognuno.

Opzioni

Puoi controllare la ricerca con facet aggiungendo un parametro FacetOptions a una chiamata alla query. Questo parametro accetta una singola istanza di FacetOptions. Utilizza questo parametro per eseguire l'override del comportamento predefinito della ricerca con facet.

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");
Parametro Descrizione Predefinito
DiscoveryLimit Numero di facet per scoprire se il rilevamento facet è attivo. Se il valore è pari a 0, i facet di rilevamento verranno disattivati. 10
DiscoveryValueLimit Numero di valori da restituire per ciascuno dei principali facet rilevati. 10
Depth Il numero minimo di documenti nei risultati della query da valutare per raccogliere informazioni sui facet. 1000

L'opzione Depth si applica a tutti e tre i tipi di aggregazione dei facet: per nome, nome e valore e rilevamento automatico. Le altre opzioni riguardano solo il rilevamento automatico.

Tieni presente che la profondità dei facet è di solito molto maggiore del limite di query. I risultati dei facet vengono calcolati almeno in base al numero di documenti di profondità. Se hai impostato un limite di punteggio delle opzioni di ordinamento superiore alla profondità, verrà utilizzato il limite di punteggio.

Recupero dei risultati dei facet

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

Una query avrà un elenco di FacetResult. Ci sarà un risultato nell'elenco per ogni facet visualizzato in un documento che corrisponde alla tua query. Per ogni risultato otterrai:

  • Il nome del facet
  • Un elenco dei valori più frequenti per il facet. Per ogni valore esiste un conteggio approssimativo del numero di volte in cui è stato visualizzato e una chiave di perfezionamento che può essere utilizzata per recuperare i documenti che corrispondono a questa query e al valore del facet.

Tieni presente che l'elenco dei valori includerà la stringa di un facet e i valori numerici. Se il facet è stato rilevato automaticamente, i relativi valori numerici vengono restituiti come un singolo intervallo [min max). Se hai richiesto esplicitamente 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 di query determinano quanti documenti da esaminare e quanti valori restituire.

Dai risultati di ricerca è possibile leggere le informazioni aggregate relative a ogni facet:

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

Ad esempio, una query potrebbe aver trovato documenti che includevano un facet "size" con valori stringa e valori numerici. Il FacetResult per questo facet verrà creato in questo modo:

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());

FacetResultValue.label viene creato a partire da un valore facet. I valori numerici vengono restituiti come rappresentazione "stringizzata" di un intervallo.

refinement_key è una stringa sicura per l'URL/web che può essere utilizzata in una query successiva per recuperare i documenti che corrispondono al nome e al valore del facet del risultato.

Utilizzo dei facet per perfezionare/filtrare una query

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

Puoi combinare i perfezionamenti per uno o più facet diversi nella stessa richiesta. Tutti i perfezionamenti appartenenti allo stesso facet sono uniti con un operatore OR. I perfezionamenti per facet diversi vengono combinati con AND.

È anche possibile creare manualmente una chiave FacetRefinement personalizzata. Per ulteriori informazioni, consulta la documentazione del corso.