Dodawanie nawigacji aspektowej do aplikacji wyszukiwania

Nawigacja aspektowa służy do samodzielnego filtrowania przechodzenia do szczegółów w wynikach zapytania w aplikacji wyszukiwania, w której aplikacja oferuje kontrolki formularzy umożliwiające określenie zakresu wyszukiwania do grup dokumentów (na przykład kategorii lub marek), a usługa Azure AI Search udostępnia struktury danych i filtry umożliwiające powrót do środowiska.

W tym artykule przedstawiono podstawowe kroki tworzenia struktury nawigacji aspektowej w usłudze Azure AI Search.

  • Ustawianie atrybutów pól w indeksie
  • Tworzenie struktury żądania i odpowiedzi
  • Dodawanie kontrolek nawigacji i filtrów w warstwie prezentacji

Kod w warstwie prezentacji wykonuje duże obciążenie w środowisku nawigacji aspektowej. Pokazy i przykłady wymienione na końcu tego artykułu zawierają kod roboczy, który pokazuje, jak połączyć wszystkie elementy.

Nawigacja aspektowa na stronie wyszukiwania

Aspekty są dynamiczne i zwracane w zapytaniu. Odpowiedź wyszukiwania zawiera wszystkie kategorie aspektów używane do nawigowania po dokumentach w wyniku. Zapytanie jest wykonywane najpierw, a następnie aspekty są pobierane z bieżących wyników i składane w strukturę nawigacji aspektowej.

W usłudze Azure AI Search aspekty są jedną warstwą głęboką i nie mogą być hierarchiczne. Jeśli nie znasz struktur nawigacji aspektowych, poniższy przykład przedstawia jedną z nich po lewej stronie. Liczba wskazuje liczbę dopasowań dla każdego aspektu. Ten sam dokument może być reprezentowany w wielu aspektach.

Screenshot of faceted search results.

Aspekty mogą pomóc w znalezieniu szukanych wyników, przy jednoczesnym zapewnieniu, że nie uzyskasz żadnych wyników. Jako deweloper aspekty umożliwiają uwidocznienie najbardziej przydatnych kryteriów wyszukiwania na potrzeby nawigowania po indeksie wyszukiwania.

Włączanie aspektów w indeksie

Aspektowanie jest włączone na podstawie pól w definicji indeksu po ustawieniu atrybutu "facetable" na true.

Mimo że nie jest to ściśle wymagane, należy również ustawić atrybut "filtrowalny", aby można było utworzyć niezbędne filtry, które obsługują środowisko nawigacji aspektowej w aplikacji wyszukiwania.

Poniższy przykładowy indeks "hotels" pokazuje "facetable" i "filterable" w polach o niskiej kardynalności, które zawierają pojedyncze wartości lub krótkie frazy: "Category", "Tags", "Rating".

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

Wybieranie pól

Aspekty można obliczyć za pomocą pól z jedną wartością, a także kolekcji. Pola, które najlepiej sprawdzają się w nawigacji aspektowej, mają następujące cechy:

  • Niska kardynalność (niewielka liczba unikatowych wartości powtarzanych w dokumentach w korpusie wyszukiwania)

  • Krótkie wartości opisowe (jeden lub dwa wyrazy), które będą renderowane ładnie w drzewie nawigacji

Wartości w polu, a nie sama nazwa pola, generują aspekty w strukturze nawigacji aspektowej. Jeśli aspekt jest polem ciągu o nazwie Color, aspekty będą niebieskie, zielone i wszelkie inne wartości dla tego pola.

Najlepszym rozwiązaniem jest sprawdzenie pól pod kątem wartości null, błędnych pisowni lub rozbieżności wielkości liter oraz pojedynczych i mnogich wersji tego samego słowa. Domyślnie filtry i aspekty nie są poddawane analizie leksykalnej ani sprawdzaniu pisowni, co oznacza, że wszystkie wartości pola "facetable" są potencjalnymi aspektami, nawet jeśli wyrazy różnią się jednym znakiem. Opcjonalnie można przypisać normalizator do pola "z możliwością filtrowania" i "facetable", aby wygładzić różnice wielkości liter i znaków.

Wartości domyślne w zestawach SDK REST i Azure

Jeśli używasz jednego z zestawów SDK platformy Azure, kod musi jawnie ustawić atrybuty pola. Z kolei interfejs API REST ma wartości domyślne atrybutów pól na podstawie typu danych. Następujące typy danych są domyślnie "filtrowalne" i "facetable":

  • Edm.String
  • Edm.DateTimeOffset
  • Edm.Boolean
  • Edm.Int32, Edm.Int64, Edm.Double
  • Kolekcje dowolnego z powyższych typów, na przykład Collection(Edm.String) lub Collection(Edm.Double)

Nie można używać Edm.GeographyPoint pól ani Collection(Edm.GeographyPoint) w nawigacji aspektowej. Aspekty działają najlepiej na polach o niskiej kardynalności. Ze względu na rozdzielczość współrzędnych geograficznych rzadko zdarza się, że wszystkie dwa zestawy współrzędnych będą równe w danym zestawie danych. W związku z tym aspekty nie są obsługiwane dla współrzędnych geograficznych. Potrzebujesz pola miasta lub regionu, aby utworzyć aspekt według lokalizacji.

Napiwek

Najlepszym rozwiązaniem w zakresie wydajności i optymalizacji magazynu jest wyłączenie aspektów dla pól, które nigdy nie powinny być używane jako aspekt. W szczególności pola ciągów dla unikatowych wartości, takich jak identyfikator lub nazwa produktu, powinny być ustawione tak, aby "facetable": false zapobiec przypadkowemu (i nieskutecznemu) użyciu w nawigacji aspektowej. Dotyczy to szczególnie interfejsu API REST, który domyślnie włącza filtry i aspekty.

Żądanie aspektu i odpowiedź

Aspekty są określane w zapytaniu, a struktura nawigacji aspektowej jest zwracana w górnej części odpowiedzi. Struktura żądania i odpowiedzi jest dość prosta. W rzeczywistości prawdziwa praca za nawigacją aspektową znajduje się w warstwie prezentacji, omówionej w dalszej sekcji.

Poniższy przykład REST to niekwalifikowane zapytanie (), które jest ograniczone do całego indeksu ("search": "*"zobacz przykład wbudowane hotele). Aspekty są zwykle listą pól, ale to zapytanie pokazuje tylko jeden dla bardziej czytelnej odpowiedzi poniżej.

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
}

Warto zainicjować stronę wyszukiwania za pomocą otwartego zapytania, aby całkowicie wypełnić strukturę nawigacji aspektowej. Gdy tylko przekażesz terminy zapytania w żądaniu, struktura nawigacji aspektowej będzie ograniczona do tylko dopasowań w wynikach, a nie całego indeksu.

Odpowiedź na powyższy przykład zawiera strukturę nawigacji aspektowej u góry. Struktura składa się z wartości "Kategoria" i liczby hoteli dla każdego z nich. Następnie następuje reszta wyników wyszukiwania, przycięta tutaj w celu zwięzłości. Ten przykład działa dobrze z kilku powodów. Liczba aspektów dla tego pola mieści się w limicie (wartość domyślna to 10), więc wszystkie z nich pojawiają się, a każdy hotel w indeksie 50 hoteli jest reprezentowany w dokładnie jednej z tych kategorii.

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

Składnia aspektów

Parametr zapytania aspektowego jest ustawiony na rozdzielaną przecinkami listę pól "facetable" i w zależności od typu danych można dodatkowo sparametryzować w celu ustawiania liczby, kolejności sortowania i zakresów: count:<integer>, , sort:<>interval:<integer>i values:<list>. Aby uzyskać więcej informacji na temat parametrów aspektu, zobacz "Parametry zapytania" w interfejsie 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
}

Dla każdego drzewa nawigacji aspektowej istnieje domyślny limit dziesięciu pierwszych aspektów. To ustawienie domyślne ma sens w przypadku struktur nawigacji, ponieważ przechowuje listę wartości w zarządzanym rozmiarze. Możesz zastąpić wartość domyślną, przypisując wartość do wartości "count". Na przykład "Tags,count:5" zmniejsza liczbę tagów w sekcji Tagi do pięciu pierwszych.

W przypadku wartości liczbowych i datetime można jawnie ustawić wartości w polu aspektu (na przykład facet=Rating,values:1|2|3|4|5) w celu oddzielenia wyników od ciągłych zakresów (zakresów na podstawie wartości liczbowych lub okresów). Alternatywnie możesz dodać "interwał", jak w pliku facet=Rating,interval:1.

Każdy zakres jest tworzony przy użyciu wartości 0 jako punktu początkowego, wartości z listy jako punktu końcowego, a następnie przycinany z poprzedniego zakresu w celu utworzenia odrębnych interwałów.

Rozbieżności w liczbach aspektów

W pewnych okolicznościach może się okazać, że liczba aspektów nie jest w pełni dokładna ze względu na architekturę fragmentowania. Każdy indeks wyszukiwania jest rozłożony na wiele fragmentów, a każdy fragment raportuje pierwsze N aspektów według liczby dokumentów, które następnie są łączone w jeden wynik. Ponieważ jest to tylko n pierwszych aspektów dla każdego fragmentu, można przegapić lub niedoliczać pasujące dokumenty w odpowiedzi aspektu.

Aby zagwarantować dokładność, można sztucznie zawyżać liczbę:<liczba do dużej liczby> , aby wymusić pełne raportowanie z każdego fragmentu. Można określić "count": "0" dla nieograniczonych aspektów. Możesz też ustawić wartość "count" na wartość większą lub równą liczbie unikatowych wartości pola aspektowego. Jeśli na przykład tworzysz aspekty według pola "size", które ma pięć unikatowych wartości, możesz ustawić, "count:5" aby upewnić się, że wszystkie dopasowania są reprezentowane w odpowiedzi aspektowej.

Kompromis z tym obejściem polega na zwiększonym opóźnieniu zapytań, dlatego używaj go tylko wtedy, gdy jest to konieczne.

Warstwa prezentacji

W kodzie aplikacji wzorzec polega na użyciu parametrów zapytania aspektowego w celu zwrócenia struktury nawigacji aspektowej wraz z wynikami aspektu oraz wyrażeniem $filter. Wyrażenie filtru obsługuje zdarzenie kliknięcia i dodatkowo zawęża wynik wyszukiwania na podstawie wybranego aspektu.

Kombinacja aspektów i filtrów

Poniższy fragment kodu z JobsSearch.cs pliku w pokazie NYCJobs dodaje wybrany tytuł biznesowy do filtru, jeśli wybierzesz wartość z aspektu tytułu biznesowego.

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

Oto kolejny przykład z przykładu hoteli. Poniższy fragment kodu dodaje categoyrFacet do filtru, jeśli użytkownik wybierze wartość z aspektu kategorii.

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

Html na potrzeby nawigacji aspektowej

W poniższym przykładzie pobranym index.cshtml z pliku przykładowej aplikacji NYCJobs przedstawiono statyczną strukturę HTML do wyświetlania nawigacji aspektowej na stronie wyników wyszukiwania. Lista aspektów jest kompilowana lub odbudowywana dynamicznie podczas przesyłania terminu wyszukiwania lub wybierania lub czyszczenia aspektu.

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

Dynamiczne kompilowanie kodu HTML

Poniższy fragment kodu z pokazu (również z pokazu index.cshtml NYCJobs) dynamicznie kompiluje kod HTML, aby wyświetlić pierwszy aspekt, Tytuł biznesowy. Podobne funkcje dynamicznie tworzą kod HTML dla innych aspektów. Każdy aspekt ma etykietę i liczbę, która wyświetla liczbę elementów znalezionych dla tego wyniku aspektu.

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

Wskazówki do pracy z aspektami

Ta sekcja to zbiór wskazówek i obejść, które mogą być przydatne.

Zachowywanie struktury nawigacji aspektowej asynchronicznie filtrowanych wyników

Jednym z wyzwań związanych z nawigacją aspektową w usłudze Azure AI Search jest to, że aspekty istnieją tylko dla bieżących wyników. W praktyce często zachowuje statyczny zestaw aspektów, dzięki czemu użytkownik może przechodzić odwrotnie, co powoduje wycofanie kroków w celu eksplorowania alternatywnych ścieżek za pośrednictwem zawartości wyszukiwania.

Chociaż jest to typowy przypadek użycia, nie jest to coś, co struktura nawigacji aspektowej obecnie udostępnia gotowe do użycia. Deweloperzy, którzy chcą, aby statyczne aspekty zwykle działały wokół ograniczenia, wydając dwa przefiltrowane zapytania: jeden z zakresem wyników, drugi używany do tworzenia statycznej listy aspektów na potrzeby nawigacji.

Wyczyść aspekty

Podczas projektowania strony wyników wyszukiwania pamiętaj, aby dodać mechanizm czyszczenia aspektów. Jeśli dodasz pola wyboru, możesz łatwo zobaczyć, jak wyczyścić filtry. W przypadku innych układów może być potrzebny wzorzec stron nadrzędnych lub inne kreatywne podejście. W przykładzie hotels C# możesz wysłać puste wyszukiwanie, aby zresetować stronę. Z kolei przykładowa aplikacja NYCJobs zapewnia możliwość kliknięcia [X] po wybranym aspektie w celu wyczyszczenia aspektu, który jest silniejszą kolejką wizualną dla użytkownika.

Przycinanie wyników aspektów przy użyciu większej liczby filtrów

Wyniki aspektów są dokumentami znajdującymi się w wynikach wyszukiwania, które pasują do terminu aspektu. W poniższym przykładzie w wynikach wyszukiwania dla przetwarzania w chmurze 254 elementy mają również wewnętrzną specyfikację jako typ zawartości. Elementy nie muszą wykluczać się wzajemnie. Jeśli element spełnia kryteria obu filtrów, jest on liowany w każdym z nich. Takie duplikowanie jest możliwe podczas tworzenia aspektów w Collection(Edm.String) polach, które są często używane do implementowania tagowania dokumentów.

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

Ogólnie rzecz biorąc, jeśli okaże się, że wyniki aspektów są stale zbyt duże, zalecamy dodanie większej liczby filtrów w celu zapewnienia użytkownikom większej liczby opcji zawężenia wyszukiwania.

Środowisko wyszukiwania tylko aspektami

Jeśli aplikacja korzysta wyłącznie z nawigacji aspektowej (czyli bez pola wyszukiwania), możesz oznaczyć pole jako searchable=false, filterable=truefacetable=true w celu utworzenia bardziej kompaktowego indeksu. Indeks nie będzie zawierać odwróconych indeksów i nie będzie analizy tekstu ani tokenizacji. Filtry są wykonywane na dokładnych dopasowaniach na poziomie znaku.

Weryfikowanie danych wejściowych w czasie wykonywania zapytań

Jeśli tworzysz listę aspektów dynamicznie na podstawie niezaufanych danych wejściowych użytkownika, sprawdź, czy nazwy pól aspektowych są prawidłowe. Możesz też użyć nazwy podczas kompilowania adresów URL przy użyciu platformy Uri.EscapeDataString() .NET lub odpowiednika wybranej platformy.

Pokazy i przykłady

Kilka przykładów obejmuje nawigację aspektowa. Ta sekcja zawiera linki do przykładów, a także informacje o bibliotece klienta i języku używanym dla każdego z nich.

Dodawanie wyszukiwania do aplikacji internetowych (React)

Samouczki i przykłady w języku C#, Python i JavaScript obejmują nawigację aspektową, a także filtry, sugestie i autouzupełnianie. Te przykłady używają platformy React dla warstwy prezentacji.

Przykładowy kod i pokaz NYCJobs (Ajax)

Przykładowe zadania NYCJobs to aplikacja ASP.NET MVC, która używa Ajax w warstwie prezentacji. Jest ona dostępna jako aplikacja demonstracyjna na żywo i jako kod źródłowy w repozytorium Azure-Samples w witrynie GitHub.