Condividi tramite


Aggiungere l’esplorazione in base a facet a un'app di ricerca

L'esplorazione in base a facet è usata per il drilldown dei filtri autoindirizzati nei risultati della query in un'applicazione di ricerca, in cui l'applicazione offre i controlli del modulo per limitare l'ambito a gruppi di documenti (ad esempio, categorie o marchi) e Azure AI Search offre le strutture di dati e i dati che supportano l'esperienza.

Questo articolo illustra i passaggi di base per la creazione di una struttura di esplorazione in base a facet in Azure AI Search.

  • Impostare gli attributi del campo nell'indice
  • Strutturare la richiesta e la risposta
  • Aggiungere controlli di spostamento e filtri nel livello di presentazione

Il codice nel livello di presentazione esegue la maggior parte del lavoro in un'esperienza di esplorazione in base a facet. Le demo e gli esempi elencati alla fine di questo articolo forniscono codice funzionante che illustra come riunire tutti gli elementi.

Esplorazione in base a facet in una pagina di ricerca

I facet sono dinamici e vengono restituiti in seguito a una query. Una risposta di ricerca include tutte le categorie di facet usate per esplorare i documenti nel risultato. La query viene eseguita per prima e quindi i facet vengono estrati dai risultati correnti e assemblati in una struttura di esplorazione in base a facet.

In Azure AI Search, i facet sono a un livello di profondità e non possono essere gerarchici. Se non si ha familiarità con le strutture di esplorazione in base a facet, l'esempio seguente ne mostra uno a sinistra. I conteggi indicano il numero di corrispondenze per ogni facet. Lo stesso documento può essere rappresentato in più facet.

Screenshot dei risultati della ricerca in base a facet.

I facet aiutano a trovare ciò che si sta cercando con una percentuale di successo accertata. Per gli sviluppatori, i facet consentono di esporre i criteri di ricerca più utili per l’esplorazione dell’indice di ricerca.

Abilitare i facet nell'indice

Il faceting viene abilitato in base al campo in una definizione di indice quando si imposta l'attributo "con facet" su true.

Anche se non è strettamente richiesto, è necessario impostare anche l'attributo "filtrabile" in modo da poter compilare i filtri necessari che supportino l'esperienza di esplorazione in base a facet nell'applicazione di ricerca.

L'esempio seguente dell'indice di esempio "hotels" mostra "con facet" e "filtrabile" nei campi con cardinalità bassa che contengono singoli valori o frasi brevi: "Categoria", "Tag", "Classificazione".

{
  "name": "hotels",  
  "fields": [
    { "name": "hotelId", "type": "Edm.String", "key": true, "searchable": false, "sortable": false, "facetable": false },
    { "name": "Description", "type": "Edm.String", "filterable": false, "sortable": false, "facetable": false },
    { "name": "HotelName", "type": "Edm.String", "facetable": false },
    { "name": "Category", "type": "Edm.String", "filterable": true, "facetable": true },
    { "name": "Tags", "type": "Collection(Edm.String)", "filterable": true, "facetable": true },
    { "name": "Rating", "type": "Edm.Int32", "filterable": true, "facetable": true },
    { "name": "Location", "type": "Edm.GeographyPoint" }
  ]
}

Scelta dei campi

È possibile calcolare i facet su campi a valore singolo e su raccolte. I campi che funzionano meglio nella esplorazione in base a facet hanno queste caratteristiche:

  • Cardinalità bassa (un numero ridotto di valori distinti che si ripetono in tutti i documenti nel corpus di ricerca)

  • Valori descrittivi brevi (una o due parole) che vengono visualizzati bene in un albero di navigazione

I valori all'interno di un campo e non il nome del campo stesso producono i facet in una struttura di esplorazione in base a facet. Se il facet è un campo stringa denominato Color, i facet sono blu, verde e qualsiasi altro valore per tale campo.

Come procedura consigliata, controllare i campi in cerca di valori null, gli errori di ortografia o le discrepanze tra maiuscole e minuscole e le versioni singole e plurali della stessa parola. Per impostazione predefinita, i filtri e i facet non vengono sottoposti ad analisi lessicali o controllo ortografico, il che significa che tutti i valori di un campo "con facet" sono potenziali facet, anche se le parole differiscono per un carattere. Facoltativamente, è possibile assegnare un normalizzatore a un campo "filtrabile" e "con facet" per uniformare le variazioni di maiuscole, minuscole e caratteri.

Impostazioni predefinite in REST e SDK AZURE

Se si usa uno degli SDK di Azure, il codice deve impostare in modo esplicito gli attributi del campo. Al contrario, l'API REST ha le impostazioni predefinite per gli attributi dei campi in base al tipo di dati. I tipi di dati seguenti sono "filtrabili" e "con facet" per impostazione predefinita:

  • Edm.String
  • Edm.DateTimeOffset
  • Edm.Boolean
  • Edm.Int32, Edm.Int64, Edm.Double
  • Raccolte di uno dei tipi precedenti, ad esempio Collection(Edm.String) o Collection(Edm.Double)

Non è possibile usare i campi Edm.GeographyPoint o Collection(Edm.GeographyPoint) nell'esplorazione in base a facet. I facet funzionano meglio nei campi con cardinalità bassa. A causa della risoluzione delle coordinate geografiche, è raro che due set di coordinate siano uguali in un determinato set di dati. Di conseguenza, i facet non sono supportati nelle coordinate di area geografica. È necessario un campo città o regione per esplorare una posizione in base a facet.

Suggerimento

Disattivare i facet per i campi che non devono essere usati come facet è una procedura consigliata per l'ottimizzazione delle prestazioni e dell'archiviazione. In particolare, i campi stringa per i valori unici, ad esempio un nome di prodotto o ID, devono essere impostati su "facetable": false per impedirne l'uso accidentale (e inefficace) nell'esplorazione in base a facet. Ciò vale soprattutto per l'API REST che abilita i filtri e i facet per impostazione predefinita.

Richiesta e risposta facet

I facet vengono specificati nella query e la struttura di esplorazione in base a facet viene restituita nella parte superiore della risposta. La struttura di una richiesta e di una risposta è piuttosto semplice. In effetti, il lavoro reale dietro l’esplorazione in base a facet si trova nel livello di presentazione, trattato in una sezione successiva.

L'esempio REST seguente è una query non qualificata ("search": "*") con ambito per l'intero indice (vedere l'esempio di hotel predefiniti). I facet sono in genere un elenco di campi, ma questa query ne mostra solo uno per una risposta più leggibile.

POST https://{{service_name}}.search.windows.net/indexes/hotels/docs/search?api-version={{api_version}}
{
    "search": "*",
    "queryType": "simple",
    "select": "",
    "searchFields": "",
    "filter": "",
    "facets": [ "Category"], 
    "orderby": "",
    "count": true
}

È utile inizializzare una pagina di ricerca con una query aperta per compilare completamente la struttura di esplorazione in base a facet. Non appena si passano termini di query nella richiesta, la struttura di esplorazione in base a facet ha come ambito solo le corrispondenze nei risultati, anziché l'intero indice.

La risposta per l'esempio include la struttura di esplorazione in base a facet nella parte superiore. La struttura è costituita da valori "Categoria" e da un conteggio degli hotel per ognuno di essi. È seguita dal resto dei risultati della ricerca, che qui sono tagliati per brevità. Questo esempio funziona bene per diversi motivi. Il numero di facet per questo campo è inferiore al limite (il valore predefinito è 10) in modo che vengano visualizzati tutti gli hotel e che ognuno nell'indice di 50 hotel sia rappresentato in esattamente una di queste categorie.

{
    "@odata.context": "https://demo-search-svc.search.windows.net/indexes('hotels')/$metadata#docs(*)",
    "@odata.count": 50,
    "@search.facets": {
        "Category": [
            {
                "count": 13,
                "value": "Budget"
            },
            {
                "count": 12,
                "value": "Resort and Spa"
            },
            {
                "count": 9,
                "value": "Luxury"
            },
            {
                "count": 7,
                "value": "Boutique"
            },
            {
                "count": 5,
                "value": "Suite"
            },
            {
                "count": 4,
                "value": "Extended-Stay"
            }
        ]
    },
    "value": [
        {
            "@search.score": 1.0,
            "HotelId": "1",
            "HotelName": "Stay-Kay City Hotel",
            "Description": "The hotel is ideally located on the main commercial artery of the city in the heart of New York. A few minutes away is Time's Square and the historic centre of the city, as well as other places of interest that make New York one of America's most attractive and cosmopolitan cities.",
            "Category": "Boutique",
            "Tags": [
                "pool",
                "air conditioning",
                "concierge"
            ],
            "ParkingIncluded": false,
        }
    ]
}

Sintassi facet

Un parametro di query facet è impostato su un elenco delimitato da virgole di campi "con facet" e, a seconda del tipo di dati, può essere ulteriormente parametrizzato per impostare conteggi, ordinamenti e intervalli: count:<integer>, sort:<> interval:<integer>, e values:<list>. Per altri dettagli sui parametri di facet, vedere Parametri di query nell'API REST.

POST https://{{service_name}}.search.windows.net/indexes/hotels/docs/search?api-version={{api_version}}
{
    "search": "*",
    "facets": [ "Category", "Tags,count:5", "Rating,values:1|2|3|4|5"],
    "count": true
}

Per ogni albero di esplorazione in base a facet esiste un limite predefinito dei primi dieci facet. Questa impostazione predefinita risulta utile per le strutture di navigazione perché mantiene l'elenco di valori a un livello gestibile. È possibile sostituire il valore predefinito assegnando un valore per il conteggio. Ad esempio, "Tags,count:5" riduce il numero di tag nella sezione Tag ai primi cinque.

Solo per i valori Numeric e DateTime, è possibile impostare in modo esplicito i valori nel campo facet (ad esempio, facet=Rating,values:1|2|3|4|5) per separare i risultati in intervalli contigui (intervalli basati su valori numerici o periodi di tempo). In alternativa, è possibile aggiungere "interval", come in facet=Rating,interval:1.

Ogni intervallo viene compilato usando 0 come punto di partenza e un valore dall'elenco come endpoint e quindi privato dell'intervallo precedente per creare intervalli discreti.

Discrepanze nei conteggi dei facet

In determinate circostanze, è possibile che i conteggi dei facet non siano completamente accurati a causa dell'architettura di partizionamento orizzontale. Ogni indice di ricerca è suddiviso in più partizioni e ciascuna di esse segnala i principali N facet per numero di documenti, combinando poi i dati in un singolo risultato. Poiché si tratta solo dei primi N facet per ogni shard, è possibile perdere o contare meno documenti corrispondenti nella risposta facet.

Per garantire l'accuratezza, è possibile aumentare artificialmente il conteggio:<numero> a un numero elevato per forzare la creazione di report completi da ogni shard. È possibile specificare "count": "0" per facet illimitati. In alternativa, è possibile impostare "count" su un valore maggiore o uguale al numero di valori univoci del campo in base a facet. Ad esempio, se si esegue il facet in base a un campo "size" con cinque valori univoci, è possibile impostare "count:5" per assicurarsi che tutte le corrispondenze siano rappresentate nella risposta facet.

Il compromesso di questa soluzione alternativa consiste nella maggiore la latenza delle query, quindi usarla solo quando necessario.

Livello di presentazione

Nel codice dell'applicazione, il modello consiste nell'usare parametri di query di facet per restituire la struttura di navigazione in base a facet con i risultati di facet, oltre a un'espressione $filter. L'espressione filtro gestisce l'evento click e restringe ulteriormente il risultato della ricerca in base alla selezione del facet.

Combinazione di facet e filtro

Il frammento di codice seguente del file JobsSearch.cs nella demo NYCJobs aggiunge il Business Title selezionato al filtro se si seleziona un valore dal facet Business Title.

if (businessTitleFacet != "")
  filter = "business_title eq '" + businessTitleFacet + "'";

Ecco un altro esempio dell'esempio di hotel. Il frammento di codice seguente aggiunge categoryFacet al filtro, se un utente seleziona un valore del facet di categoria.

if (!String.IsNullOrEmpty(categoryFacet))
    filter = $"category eq '{categoryFacet}'";

HTML per l’esplorazione in base a facet

L'esempio seguente, tratto dal file index.cshtml dell'applicazione di esempio NYCJobs, mostra la struttura HTML dinamica per la visualizzazione dell'esplorazione in base a facet nella pagina dei risultati di ricerca. L'elenco di facet viene compilato o ricompilato in modo dinamico quando si invia un termine di ricerca oppure si seleziona o deseleziona un facet.

<div class="widget sidebar-widget jobs-filter-widget">
  <h5 class="widget-title">Filter Results</h5>
    <p id="filterReset"></p>
    <div class="widget-content">

      <h6 id="businessTitleFacetTitle">Business Title</h6>
      <ul class="filter-list" id="business_title_facets">
      </ul>

      <h6>Location</h6>
      <ul class="filter-list" id="posting_type_facets">
      </ul>

      <h6>Posting Type</h6>
      <ul class="filter-list" id="posting_type_facets"></ul>

      <h6>Minimum Salary</h6>
      <ul class="filter-list" id="salary_range_facets">
      </ul>

  </div>
</div>

Compilare codice HTML in modo dinamico

Il frammento di codice seguente, tratto dalla pagina index.cshtml (sempre dalla demo NYCJobs), crea in modo dinamico il codice HTML per visualizzare il primo facet, Business Title. Funzioni simili compilano in modo dinamico il codice HTML per gli altri facet. Ogni facet contiene un'etichetta e un conteggio, che visualizza il numero di elementi trovati per questo risultato di facet.

function UpdateBusinessTitleFacets(data) {
  var facetResultsHTML = '';
  for (var i = 0; i < data.length; i++) {
    facetResultsHTML += '<li><a href="javascript:void(0)" onclick="ChooseBusinessTitleFacet(\'' + data[i].Value + '\');">' + data[i].Value + ' (' + data[i].Count + ')</span></a></li>';
  }

  $("#business_title_facets").html(facetResultsHTML);
}

Suggerimenti per l'uso di facet

Questa sezione è una raccolta di suggerimenti e soluzioni alternative che potrebbero essere utili.

Mantenere una struttura di esplorazione in base a facet in modo asincrono per i risultati filtrati

Uno dei problemi dell'esplorazione in base a facet in Azure AI Search è che i facet esistono solo per i risultati correnti. Nella pratica, si conserva in genere un set statico di facet in modo che l'utente possa spostarsi in ordine inverso, ripercorrendo i passaggi per esplorare percorsi alternativi nel contenuto della ricerca.

Sebbene sia un caso d'uso comune, non è un servizio che la struttura di esplorazione in base a facet fornisce in modo predefinito. Gli sviluppatori che intendono usare i facet statici aggirandone i limiti eseguono due query filtrate: una limitata ai risultati, l'altra usata per creare un elenco statico di facet per l'esplorazione.

Cancellare i facet

Quando si progetta la pagina dei risultati di ricerca, ricordarsi di aggiungere un meccanismo per la cancellazione dei facet. Se si aggiungono caselle di controllo, gli utenti possono facilmente intuire come cancellare i filtri. Per altri layout potrebbe essere necessario un modello di navigazione o un altro approccio creativo. Nell'esempio di hotel C# è possibile inviare una ricerca vuota per reimpostare la pagina. Al contrario, l'applicazione di esempio NYCJobs fornisce un [X] cliccabile dopo un facet selezionato per cancellare il facet, ovvero un’indicazione visiva più forte per l'utente.

Ridurre i risultati di facet con altri filtri

I risultati facet sono documenti trovati nei risultati della ricerca che corrispondono a un termine di facet. Nell'esempio seguente, nei risultati della ricerca per il cloud computing, i 254 elementi dispongono inoltre di una specifica interna come tipo di contenuto. Gli elementi non si escludono necessariamente a vicenda. Se un elemento soddisfa i criteri di entrambi i filtri, viene conteggiato in ognuno di essi. Questa duplicazione è possibile quando si esegue l'esplorazione in base a facet su campi Collection(Edm.String) che vengono spesso usati per implementare l'aggiunta di tag nel documento.

Search term: "cloud computing"
Content type
   Internal specification (254)
   Video (10)

In generale, se si ritiene che i risultati dei facet siano costantemente troppo elevati, è consigliabile che aggiungere altri filtri per offrire agli utenti più opzioni per restringere la ricerca.

Un'esperienza di ricerca solo facet

Se l'applicazione usa esclusivamente l'esplorazione in base a facet (vale a dire nessuna casella di ricerca), è possibile contrassegnare il campo come searchable=false, filterable=true, facetable=true per produrre un indice più compatto. L'indice non include indici invertiti e non esiste alcuna analisi del testo o tokenizzazione durante l'indicizzazione. I filtri vengono eseguiti in base alle corrispondenze esatte a livello di carattere.

Convalidare gli input in fase di query

Se si compila l'elenco di facet dinamicamente in base all'input dell'utente non attendibile, verificare che i nomi dei campi in base ai facet siano validi. In alternativa, escluderne i nomi durante la creazione degli URL usando Uri.EscapeDataString() in .NET o l'equivalente nella piattaforma preferita.

Esempi

È consigliabile usare gli esempi seguenti per la navigazione in base a facet. Gli esempi includono anche filtri, suggerimenti e completamento automatico. Questi esempi usano React per il livello di presentazione.