Facetnavigatie toevoegen aan een zoek-app

Facetnavigatie wordt gebruikt voor zelfgestuurde analysefiltering op queryresultaten in een zoek-app, waarbij uw toepassing formulierbesturingselementen biedt voor het verkennen van zoekacties naar groepen documenten (bijvoorbeeld categorieën of merken) en Azure AI Search biedt de gegevensstructuren en filters om de ervaring te herstellen.

In dit artikel leert u de basisstappen voor het maken van een facetnavigatiestructuur in Azure AI Search.

  • Veldkenmerken instellen in de index
  • De aanvraag en het antwoord structuren
  • Navigatiebesturingselementen en filters toevoegen in de presentatielaag

Code in de presentatielaag doet het zware werk in een facetnavigatie-ervaring. De demo's en voorbeelden die aan het einde van dit artikel worden vermeld, bevatten werkende code die laat zien hoe u alles samenbrengt.

Facetnavigatie op een zoekpagina

Facetten zijn dynamisch en worden geretourneerd op een query. Een zoekantwoord bevat alle facetcategorieën die worden gebruikt om door de documenten in het resultaat te navigeren. De query wordt eerst uitgevoerd en vervolgens worden facetten opgehaald uit de huidige resultaten en samengevoegd in een facetnavigatiestructuur.

In Azure AI Search zijn facetten één laag diep en kunnen ze niet hiërarchisch zijn. Als u niet bekend bent met facetnavigatiestructuren, ziet u in het volgende voorbeeld aan de linkerkant een structuur. Aantallen geven het aantal overeenkomsten voor elk facet aan. Hetzelfde document kan in meerdere facetten worden weergegeven.

Schermopname van facetzoekresultaten.

Facetten kunnen u helpen te vinden wat u zoekt, terwijl u ervoor zorgt dat u geen nul resultaten krijgt. Als ontwikkelaar kunt u met facetten de nuttigste zoekcriteria weergeven voor het navigeren in uw zoekindex.

Facetten in de index inschakelen

Faceting wordt ingeschakeld op basis van een veld per veld in een indexdefinitie wanneer u het kenmerk 'facetable' instelt op true.

Hoewel dit niet strikt vereist is, moet u ook het kenmerk 'filterbaar' instellen, zodat u de benodigde filters kunt bouwen die de facetnavigatie-ervaring in uw zoektoepassing ondersteunen.

In het volgende voorbeeld van de voorbeeldindex 'hotels' ziet u 'facetable' en 'filterable' op velden met lage kardinaliteit die enkele waarden of korte woordgroepen bevatten: 'Categorie', 'Tags', 'Beoordeling'.

{
  "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" }
  ]
}

Velden kiezen

Facetten kunnen worden berekend over velden met één waarde en verzamelingen. Velden die het beste werken in facetnavigatie hebben deze kenmerken:

  • Lage kardinaliteit (een klein aantal afzonderlijke waarden die worden herhaald in alle documenten in uw zoektekst)

  • Korte beschrijvende waarden (een of twee woorden) die mooi worden weergegeven in een navigatiestructuur

De waarden in een veld, en niet de veldnaam zelf, produceren de facetten in een facetnavigatiestructuur. Als het facet een tekenreeksveld met de naam Kleur is, zijn facetten blauw, groen en eventuele andere waarden voor dat veld.

Als best practice controleert u velden op null-waarden, spelfouten of hoofdletterverschillen en enkele en meervoudsversies van hetzelfde woord. Filters en facetten ondergaan standaard geen lexicale analyse of spellingcontrole, wat betekent dat alle waarden van een 'facetable'-veld potentiële facetten zijn, zelfs als de woorden met één teken verschillen. U kunt desgewenst een normalizer toewijzen aan een veld 'filterbaar' en 'facetable' om variaties in hoofdletters en tekens glad te maken.

Standaardinstellingen in REST- en Azure-SDK's

Als u een van de Azure SDK's gebruikt, moet uw code expliciet de veldkenmerken instellen. De REST API bevat daarentegen standaardwaarden voor veldkenmerken op basis van het gegevenstype. De volgende gegevenstypen zijn standaard 'filterbaar' en 'facetable':

  • Edm.String
  • Edm.DateTimeOffset
  • Edm.Boolean
  • Edm.Int32, , Edm.Int64Edm.Double
  • Verzamelingen van een van de bovenstaande typen, bijvoorbeeld Collection(Edm.String) of Collection(Edm.Double)

U kunt geen velden gebruiken Edm.GeographyPoint in Collection(Edm.GeographyPoint) facetnavigatie. Facetten werken het beste voor velden met een lage kardinaliteit. Vanwege de resolutie van geocoördinaten is het zelden dat twee sets coördinaten gelijk zijn aan een bepaalde gegevensset. Als zodanig worden facetten niet ondersteund voor geocoördinaten. U hebt een plaats- of regioveld nodig om te facet op locatie.

Tip

Als best practice voor prestaties en opslagoptimalisatie schakelt u facet uit voor velden die nooit als facet mogen worden gebruikt. In het bijzonder moeten tekenreeksvelden voor unieke waarden, zoals een id of productnaam, worden ingesteld om "facetable": false te voorkomen dat ze per ongeluk (en ineffectief) worden gebruikt in facetnavigatie. Dit geldt met name voor de REST API waarmee filters en facetten standaard worden ingeschakeld.

Facet-aanvraag en -antwoord

Facetten worden opgegeven in de query en de facetnavigatiestructuur wordt boven aan het antwoord geretourneerd. De structuur van een aanvraag en antwoord is vrij eenvoudig. Het echte werk achter facetnavigatie bevindt zich in de presentatielaag, die in een latere sectie wordt behandeld.

Het volgende REST-voorbeeld is een niet-gekwalificeerde query ("search": "*") die is gericht op de volledige index (zie het voorbeeld van de ingebouwde hotels). Facetten zijn meestal een lijst met velden, maar deze query toont slechts één voor een beter leesbaar antwoord hieronder.

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
}

Het is handig om een zoekpagina te initialiseren met een geopende query om de facetnavigatiestructuur volledig in te vullen. Zodra u querytermen in de aanvraag doorgeeft, wordt de facetnavigatiestructuur beperkt tot alleen de overeenkomsten in de resultaten, in plaats van de volledige index.

Het antwoord voor het bovenstaande voorbeeld bevat de facetnavigatiestructuur bovenaan. De structuur bestaat uit 'Categorie'-waarden en een telling van de hotels voor elk hotel. Het wordt gevolgd door de rest van de zoekresultaten, ingekort hier voor beknoptheid. Dit voorbeeld werkt om verschillende redenen goed. Het aantal facetten voor dit veld valt onder de limiet (standaard is 10), zodat ze allemaal worden weergegeven en elk hotel in de index van 50 hotels wordt weergegeven in precies een van deze categorieën.

{
    "@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": "Secret Point Motel",
            "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,
        }
    ]
}

Syntaxis van facetten

Een facetqueryparameter wordt ingesteld op een door komma's gescheiden lijst met 'facetable'-velden en kan, afhankelijk van het gegevenstype, verder worden geparameteriseerd om aantallen, sorteervolgordes en bereiken in te stellen: count:<integer>, sort:<>, interval:<integer>en values:<list>. Zie 'Queryparameters' in de REST API voor meer informatie over facetparameters.

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
}

Voor elke facetnavigatiestructuur is er een standaardlimiet van de bovenste tien facetten. Deze standaardinstelling is logisch voor navigatiestructuren, omdat de lijst met waarden wordt opgeslagen in een beheersbare grootte. U kunt de standaardwaarde overschrijven door een waarde toe te wijzen aan 'count'. Vermindert bijvoorbeeld "Tags,count:5" het aantal tags onder de sectie Tags tot de top vijf.

Voor alleen numerieke en Datum/tijd-waarden kunt u expliciet waarden instellen in het facetveld (bijvoorbeeld facet=Rating,values:1|2|3|4|5) om resultaten te scheiden in aaneengesloten bereiken (bereiken op basis van numerieke waarden of tijdsperioden). U kunt ook 'interval' toevoegen, zoals in facet=Rating,interval:1.

Elk bereik wordt gebouwd met behulp van 0 als uitgangspunt, een waarde uit de lijst als eindpunt en vervolgens ingekort van het vorige bereik om discrete intervallen te maken.

Verschillen in facetaantallen

Onder bepaalde omstandigheden is het mogelijk dat facetaantallen niet volledig nauwkeurig zijn vanwege de sharding-architectuur. Elke zoekindex wordt verspreid over meerdere shards en elke shard rapporteert de belangrijkste N facetten op basis van het aantal documenten, die vervolgens worden gecombineerd tot één resultaat. Omdat het slechts de belangrijkste N facetten voor elke shard zijn, is het mogelijk om overeenkomende documenten in het facetantwoord te missen of te weinig te tellen.

Om nauwkeurigheid te garanderen, kunt u het aantal:<getallen> kunstmatig verhogen naar een groot getal om volledige rapportage van elke shard af te dwingen. U kunt opgeven "count": "0" voor onbeperkte facetten. U kunt ook 'count' instellen op een waarde die groter is dan of gelijk is aan het aantal unieke waarden van het facetveld. Als u bijvoorbeeld facet maakt met een veld 'grootte' met vijf unieke waarden, kunt u instellen "count:5" dat alle overeenkomsten worden weergegeven in het facetantwoord.

De afweging met deze tijdelijke oplossing is een hogere querylatentie, dus gebruik deze alleen wanneer dat nodig is.

Presentatielaag

In toepassingscode is het patroon het gebruik van facetqueryparameters om de facetnavigatiestructuur samen met facetresultaten te retourneren, plus een $filter expressie. De filterexpressie verwerkt de klikgebeurtenis en beperkt het zoekresultaat verder op basis van de facetselectie.

Combinatie van facet en filter

Met het volgende codefragment uit het JobsSearch.cs bestand in de NYCJobs-demo wordt de geselecteerde zakelijke titel aan het filter toegevoegd als u een waarde selecteert in het facet Bedrijfstitel.

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

Hier volgt een ander voorbeeld uit het voorbeeld van hotels. Het volgende codefragment wordt toegevoegd categoyrFacet aan het filter als een gebruiker een waarde in het categorie-facet selecteert.

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

HTML voor facetnavigatie

In het volgende voorbeeld uit het index.cshtml bestand van de voorbeeldtoepassing NYCJobs ziet u de statische HTML-structuur voor het weergeven van facetnavigatie op de pagina met zoekresultaten. De lijst met facetten wordt dynamisch gebouwd of opnieuw opgebouwd wanneer u een zoekterm verzendt of een facet selecteert of wist.

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

HTML dynamisch bouwen

Met het volgende codefragment uit de index.cshtml (ook uit NYCJobs-demo) wordt de HTML dynamisch gebouwd om het eerste facet, bedrijfstitel, weer te geven. Vergelijkbare functies bouwen dynamisch de HTML voor de andere facetten. Elk facet heeft een label en een telling, waarmee het aantal items wordt weergegeven dat voor dat facetresultaat is gevonden.

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

Tips voor het werken met facetten

Deze sectie is een verzameling tips en tijdelijke oplossingen die nuttig kunnen zijn.

Een facetnavigatiestructuur asynchroon van gefilterde resultaten behouden

Een van de uitdagingen van facetnavigatie in Azure AI Search is dat facetten alleen bestaan voor huidige resultaten. In de praktijk is het gebruikelijk om een statische set facetten te behouden, zodat de gebruiker in omgekeerde richtingen kan navigeren, stappen om alternatieve paden te verkennen via zoekinhoud.

Hoewel dit een veelvoorkomend gebruiksscenario is, is dit niet iets wat de facetnavigatiestructuur momenteel kant-en-klare biedt. Ontwikkelaars die statische facetten willen gebruiken, werken doorgaans rond de beperking door twee gefilterde query's uit te geven: één bereik voor de resultaten, de andere die wordt gebruikt om een statische lijst met facetten te maken voor navigatiedoeleinden.

Duidelijke facetten

Wanneer u de pagina met zoekresultaten ontwerpt, moet u een mechanisme toevoegen voor het wissen van facetten. Als u selectievakjes toevoegt, kunt u eenvoudig zien hoe u de filters wist. Voor andere indelingen hebt u mogelijk een breadcrumb-patroon of een andere creatieve benadering nodig. In het C#-voorbeeld van hotels kunt u een lege zoekopdracht verzenden om de pagina opnieuw in te stellen. De voorbeeldtoepassing NYCJobs biedt daarentegen een klikbare [X] na een geselecteerde facet om het facet te wissen. Dit is een sterkere visuele wachtrij voor de gebruiker.

Facetresultaten bijsnijden met meer filters

Facetresultaten zijn documenten in de zoekresultaten die overeenkomen met een facetterm. In het volgende voorbeeld hebben 254 items in zoekresultaten voor cloud-computing ook interne specificatie als inhoudstype. Items sluiten elkaar niet noodzakelijkerwijs uit. Als een item voldoet aan de criteria van beide filters, wordt het in elk item meegeteld. Deze duplicatie is mogelijk bij faceting van Collection(Edm.String) velden, die vaak worden gebruikt voor het implementeren van documenttags.

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

Als u merkt dat facetresultaten consistent te groot zijn, raden we u aan meer filters toe te voegen om gebruikers meer opties te bieden voor het beperken van de zoekopdracht.

Een facet-only zoekervaring

Als uw toepassing uitsluitend facetnavigatie gebruikt (dus geen zoekvak), kunt u het veld markeren als searchable=false, filterable=trueom facetable=true een compactere index te produceren. Uw index bevat geen omgekeerde indexen en er is geen tekstanalyse of tokenisatie. Filters worden gemaakt op exacte overeenkomsten op tekenniveau.

Invoer valideren tijdens querytijd

Als u de lijst met facetten dynamisch bouwt op basis van niet-vertrouwde gebruikersinvoer, controleert u of de namen van de facetvelden geldig zijn. Of escape de namen bij het bouwen van URL's met behulp van Uri.EscapeDataString() .NET of het equivalent in uw platform naar keuze.

Voorbeelden

We raden de volgende voorbeelden aan voor facetnavigatie. De voorbeelden bevatten ook filters, suggesties en automatisch aanvullen. In deze voorbeelden wordt React gebruikt voor de presentatielaag.