Lägga till fasetterad navigering i en sökapp

Fasetterad navigering används för självriktad filtrering av detaljnivå på frågeresultat i en sökapp, där ditt program erbjuder formulärkontroller för omfångssökning till grupper av dokument (till exempel kategorier eller varumärken), och Azure AI Search tillhandahåller datastrukturer och filter för att stödja upplevelsen.

I den här artikeln lär du dig de grundläggande stegen för att skapa en fasetterad navigeringsstruktur i Azure AI Search.

  • Ange fältattribut i indexet
  • Strukturera begäran och svar
  • Lägga till navigeringskontroller och filter i presentationsskiktet

Kod i presentationsskiktet utför tunga lyft i en fasetterad navigeringsupplevelse. Demonstrationerna och exemplen som visas i slutet av den här artikeln innehåller arbetskod som visar hur du sammanför allt.

Fasetterad navigering på en söksida

Fasetter är dynamiska och returneras i en fråga. Ett söksvar innehåller alla fasetteringskategorier som används för att navigera i dokumenten i resultatet. Frågan körs först och sedan hämtas fasetter från de aktuella resultaten och monteras till en fasetterad navigeringsstruktur.

I Azure AI Search är fasetter ett lager djupt och kan inte vara hierarkiska. Om du inte är bekant med fasetterade navigeringsstrukturer visar följande exempel en till vänster. Antal anger antalet matchningar för varje aspekt. Samma dokument kan representeras i flera fasetter.

Skärmbild av fasetterade sökresultat.

Fasetter kan hjälpa dig att hitta det du letar efter, samtidigt som du ser till att du inte får noll resultat. Som utvecklare kan du med fasetter exponera de mest användbara sökkriterierna för att navigera i ditt sökindex.

Aktivera fasetter i indexet

Fasettering aktiveras fält för fält i en indexdefinition när du anger attributet "facetable" till true.

Även om det inte är absolut nödvändigt bör du också ange attributet "filterable" så att du kan skapa nödvändiga filter som stöder den fasetterade navigeringsupplevelsen i sökprogrammet.

I följande exempel på exempelindexet "hotels" visas "facetable" och "filterable" på fält med låg kardinalitet som innehåller enkla värden eller korta fraser: "Kategori", "Taggar", "Omdöme".

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

Välja fält

Fasetter kan beräknas över fält med ett värde samt samlingar. Fält som fungerar bäst i fasetterad navigering har följande egenskaper:

  • Låg kardinalitet (ett litet antal distinkta värden som upprepas i dokument i din sökkorus)

  • Korta beskrivande värden (ett eller två ord) som återges snyggt i ett navigeringsträd

Värdena i ett fält, och inte själva fältnamnet, skapar fasetter i en fasetterad navigeringsstruktur. Om aspekten är ett strängfält med namnet Färg blir fasetter blå, gröna och andra värden för det fältet.

Vi rekommenderar att du kontrollerar fälten för null-värden, felstavningar eller skiftlägesavvikelser samt enskilda versioner och pluralversioner av samma ord. Som standard genomgår filter och fasetter inte lexikal analys eller stavningskontroll, vilket innebär att alla värden i ett "facetable"-fält är potentiella fasetter, även om orden skiljer sig åt med ett tecken. Du kan också tilldela en normaliserare till ett "filtreringsbart" och "fasettbart" fält för att jämna ut variationer i hölje och tecken.

Standardvärden i REST- och Azure SDK:er

Om du använder någon av Azure SDK:erna måste koden uttryckligen ange fältattributen. REST-API:et har däremot standardvärden för fältattribut baserat på datatypen. Följande datatyper är "filterbara" och "facetable" som standard:

  • Edm.String
  • Edm.DateTimeOffset
  • Edm.Boolean
  • Edm.Int32, , Edm.Int64Edm.Double
  • Samlingar av någon av ovanstående typer, till exempel Collection(Edm.String) eller Collection(Edm.Double)

Du kan inte använda Edm.GeographyPoint eller Collection(Edm.GeographyPoint) fält i fasetterad navigering. Fasetter fungerar bäst på fält med låg kardinalitet. På grund av geo-koordinaternas upplösning är det ovanligt att två uppsättningar koordinater är lika i en viss datamängd. Därför stöds inte fasetter för geo-koordinater. Du skulle behöva ett fält för stad eller region för att fasettera efter plats.

Dricks

Som bästa praxis för prestanda- och lagringsoptimering inaktiverar du fasettering för fält som aldrig ska användas som fasettering. I synnerhet bör strängfält för unika värden, till exempel ett ID eller produktnamn, anges för att "facetable": false förhindra oavsiktlig (och ineffektiv) användning i fasetterad navigering. Detta gäller särskilt för REST-API:et som aktiverar filter och fasetter som standard.

Fasetteringsbegäran och svar

Fasetter anges i frågan och den fasetterade navigeringsstrukturen returneras överst i svaret. Strukturen för en begäran och ett svar är ganska enkel. Faktum är att det verkliga arbetet bakom fasetterad navigering ligger i presentationsskiktet, som beskrivs i ett senare avsnitt.

Följande REST-exempel är en okvalificerad fråga ("search": "*") som är begränsad till hela indexet (se det inbyggda hotellexemplet). Fasetter är vanligtvis en lista med fält, men den här frågan visar bara en för ett mer läsbart svar nedan.

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
}

Det är användbart att initiera en söksida med en öppen fråga för att helt fylla i den fasetterade navigeringsstrukturen. Så snart du skickar frågetermer i begäran begränsas den fasetterade navigeringsstrukturen till bara matchningarna i resultatet i stället för hela indexet.

Svaret för exemplet ovan innehåller den fasetterade navigeringsstrukturen överst. Strukturen består av "Kategori"-värden och antalet hotell för var och en. Det följs av resten av sökresultaten, trimmade här för korthet. Det här exemplet fungerar bra av flera orsaker. Antalet fasetter för det här fältet ligger under gränsen (standardvärdet är 10) så alla visas, och varje hotell i indexet för 50 hotell representeras i exakt en av dessa kategorier.

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

Syntax för fasetter

En fasettfrågeparameter är inställd på en kommaavgränsad lista över "fasettbara" fält och kan, beroende på datatypen, parameteriseras ytterligare för att ange antal, sorteringsordningar och intervall: count:<integer>, sort:<>, interval:<integer>och values:<list>. Mer information om fasetteringsparametrar finns i "Frågeparametrar" i REST-API:et.

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
}

För varje fasetterat navigeringsträd finns det en standardgräns för de tio främsta fasetter. Den här standardinställningen är lämplig för navigeringsstrukturer eftersom den håller värdelistan till en hanterbar storlek. Du kan åsidosätta standardvärdet genom att tilldela ett värde till "count". Till "Tags,count:5" exempel minskar antalet taggar under avsnittet Taggar till de fem översta.

Endast för numeriska värden och DateTime-värden kan du uttryckligen ange värden i fasetteringsfältet (till exempel facet=Rating,values:1|2|3|4|5) för att separera resultat i sammanhängande intervall (antingen intervall baserade på numeriska värden eller tidsperioder). Du kan också lägga till "intervall", som i facet=Rating,interval:1.

Varje intervall skapas med 0 som utgångspunkt, ett värde från listan som en slutpunkt och trimmas sedan av föregående intervall för att skapa diskreta intervall.

Avvikelser i antal fasetter

Under vissa omständigheter kan det hända att antalet fasetter inte är helt korrekta på grund av arkitekturen för horisontell partitionering. Varje sökindex sprids över flera shards, och varje shard rapporterar de översta N fasetter efter antal dokument, som sedan kombineras till ett enda resultat. Eftersom det bara är de översta N fasetter för varje shard, är det möjligt att missa eller underberäkning matchande dokument i fasetteringssvaret.

För att garantera noggrannheten kan du artificiellt blåsa upp antalet:<tal> till ett stort tal för att tvinga fram fullständig rapportering från varje shard. Du kan ange "count": "0" obegränsade fasetter. Eller så kan du ange "count" till ett värde som är större än eller lika med antalet unika värden i det fasetterade fältet. Om du till exempel fasetterar med ett "storleksfält" som har fem unika värden kan du ange "count:5" så att alla matchningar representeras i fasetteringssvaret.

Kompromissen med den här lösningen är ökad frågesvarstid, så använd den bara när det behövs.

Presentationslager

I programkod är mönstret att använda fasetterade frågeparametrar för att returnera den fasetterade navigeringsstrukturen tillsammans med fasetterade resultat, plus ett $filter uttryck. Filteruttrycket hanterar klickhändelsen och begränsar sökresultatet ytterligare baserat på fasetteringsmarkeringen.

Kombination av fasetter och filter

Följande kodfragment från JobsSearch.cs filen i NYCJobs-demonstrationen lägger till den valda företagstiteln i filtret om du väljer ett värde från aspekten Affärsrubrik.

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

Här är ett annat exempel från hotellexemplet. Följande kodfragment lägger categoyrFacet till i filtret om en användare väljer ett värde från kategorifasten.

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

HTML för fasetterad navigering

I följande exempel, som hämtats från index.cshtml filen i NYCJobs-exempelprogrammet, visas den statiska HTML-strukturen för att visa fasetterad navigering på sökresultatsidan. Listan över fasetter skapas eller återskapas dynamiskt när du skickar en sökterm, eller väljer eller rensar en aspekt.

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

Skapa HTML dynamiskt

Följande kodfragment från index.cshtml (även från NYCJobs demo) skapar dynamiskt HTML för att visa den första aspekten, Business Title. Liknande funktioner skapar dynamiskt HTML-koden för de andra fasetter. Varje aspekt har en etikett och ett antal, som visar antalet objekt som hittades för det fasetterade resultatet.

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 för att arbeta med fasetter

Det här avsnittet är en samling tips och lösningar som kan vara till hjälp.

Bevara en fasetterad navigeringsstruktur asynkront för filtrerade resultat

En av utmaningarna med fasetterad navigering i Azure AI Search är att fasetter endast finns för aktuella resultat. I praktiken är det vanligt att behålla en statisk uppsättning fasetter så att användaren kan navigera i omvända, retracing-steg för att utforska alternativa sökvägar via sökinnehåll.

Även om det här är ett vanligt användningsfall är det inte något som den fasetterade navigeringsstrukturen för närvarande ger out-of-the-box. Utvecklare som vill ha statiska fasetter kringgår vanligtvis begränsningen genom att utfärda två filtrerade frågor: en som är begränsad till resultaten, den andra används för att skapa en statisk lista med fasetter i navigeringssyfte.

Rensa fasetter

När du utformar sökresultatsidan bör du komma ihåg att lägga till en mekanism för att rensa fasetter. Om du lägger till kryssrutor kan du enkelt se hur du rensar filtren. För andra layouter kan du behöva ett sökvägsmönster eller en annan kreativ metod. I exemplet hotels C# kan du skicka en tom sökning för att återställa sidan. NycJobs-exempelprogrammet ger däremot ett klickbart [X] objekt efter en vald fasettering för att rensa aspekten, vilket är en starkare visuell kö till användaren.

Trimma fasetteringsresultat med fler filter

Fasetteringsresultat är dokument som finns i sökresultaten som matchar en fasetteringsterm. I följande exempel har 254 objekt även intern specifikation som innehållstyp i sökresultat för molnbaserad databehandling. Objekt är inte nödvändigtvis ömsesidigt uteslutande. Om ett objekt uppfyller kriterierna för båda filtren räknas det i var och en. Den här dupliceringen är möjlig när du fasetterar fält Collection(Edm.String) , som ofta används för att implementera dokumenttaggning.

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

Om du tycker att fasetteringsresultaten är konsekvent för stora rekommenderar vi att du lägger till fler filter för att ge användarna fler alternativ för att begränsa sökningen.

En fasetterad sökupplevelse

Om ditt program endast använder fasetterad navigering (dvs. ingen sökruta) kan du markera fältet som searchable=false, filterable=truefacetable=true för att skapa ett mer kompakt index. Ditt index inkluderar inte inverterade index och det blir ingen textanalys eller tokenisering. Filter görs på exakta matchningar på teckennivå.

Verifiera indata vid frågetid

Om du skapar listan över fasetter dynamiskt baserat på ej betrodda användarindata kontrollerar du att namnen på de fasetterade fälten är giltiga. Du kan också undvika namnen när du skapar URL:er med hjälp av antingen Uri.EscapeDataString() i .NET eller motsvarande i valfri plattform.

Exempel

Vi rekommenderar följande exempel för fasetterad navigering. Exemplen innehåller även filter, förslag och automatisk komplettering. Dessa exempel använder React för presentationsskiktet.