Menambahkan navigasi tersaring ke aplikasi pencarian

Navigasi tersaring digunakan untuk pemfilteran drilldown yang diarahkan sendiri pada hasil kueri di aplikasi pencarian, di mana aplikasi Anda menawarkan kontrol formulir untuk pencakupan pencarian ke grup dokumen (misalnya, kategori atau merek), dan Azure AI Search menyediakan struktur dan filter data untuk mendukung pengalaman.

Dalam artikel ini, pelajari langkah-langkah dasar untuk membuat struktur navigasi tersaring di Azure AI Search.

  • Mengatur atribut bidang dalam indeks
  • Membuat struktur permintaan dan respons
  • Menambahkan kontrol navigasi dan filter di lapisan presentasi

Kode di lapisan presentasi melakukan angkat berat dalam pengalaman navigasi tersaring. Demo dan sampel yang tercantum di akhir artikel ini menyediakan kode kerja yang menunjukkan kepada Anda cara menyatukan semuanya.

Navigasi tersaring di halaman pencarian

Faset bersifat dinamis dan ditampilkan pada kueri. Respons pencarian membawa serta semua kategori faset yang digunakan untuk menavigasi dokumen dalam hasilnya. Kueri dijalankan terlebih dahulu, dan kemudian faset ditarik dari hasil saat ini dan dirakit menjadi struktur navigasi tersaring.

Di Azure AI Search, faset adalah satu lapisan dalam dan tidak bisa hierarkis. Jika Anda tidak terbiasa dengan struktur navigasi tersaring, contoh berikut menunjukkannya di sebelah kiri. Hitungan menunjukkan jumlah kecocokan untuk setiap faset. Dokumen yang sama dapat diwakili dalam berbagai faset.

Screenshot of faceted search results.

Faset dapat membantu Anda menemukan apa yang Anda cari, sambil memastikan bahwa Anda tidak mendapatkan hasil nol. Sebagai pengembang, faset memungkinkan Anda mengekspos kriteria pencarian yang paling berguna untuk menavigasi indeks pencarian Anda.

Mengaktifkan faset dalam indeks

Faceting diaktifkan berdasarkan bidang demi bidang dalam definisi indeks ketika Anda mengatur atribut "dapat dibuat faset" menjadi true.

Meskipun tidak sepenuhnya diperlukan, Anda juga harus mengatur atribut "dapat disaring" sehingga Anda dapat membangun filter yang diperlukan yang mendukung pengalaman navigasi tersaring dalam aplikasi pencarian Anda.

Contoh berikut dari indeks sampel "hotel" menunjukkan "dapat dibuat faset" dan "dapat difilter" pada bidang kardinalitas rendah yang berisi nilai tunggal atau frasa pendek: "Kategori", "Tag", "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" }
  ]
}

Memilih bidang

Faset dapat dihitung melalui bidang nilai tunggal serta kumpulan. Bidang yang paling sesuai dalam navigasi tersaring memiliki karakteristik ini:

  • Kardinalitas rendah (sejumlah kecil nilai berbeda yang berulang di seluruh dokumen di korpus pencarian Anda)

  • Nilai deskriptif pendek (satu atau dua kata) yang akan merender dengan baik di pohon navigasi

Nilai dalam bidang, dan bukan nama bidang itu sendiri, menghasilkan faset dalam struktur navigasi tersaring. Jika faset adalah bidang string bernama Color, faset akan berwarna biru, hijau, dan nilai lainnya untuk bidang tersebut.

Sebagai praktik terbaik, periksa bidang untuk nilai null, kesalahan ejaan atau perbedaan kasus, dan versi tunggal dan jamak dari kata yang sama. Secara default, filter dan faset tidak menjalani analisis leksikal atau pemeriksaan ejaan, yang berarti bahwa semua nilai bidang "faset" adalah faset potensial, bahkan jika kata-kata berbeda dengan satu karakter. Secara opsional, Anda dapat menetapkan normalizer ke bidang "dapat difilter" dan "dapat difaset" untuk memuluskan variasi dalam casing dan karakter.

Default di REST dan Azure SDK

Jika Anda menggunakan salah satu Azure SDK, kode Anda harus secara eksplisit mengatur atribut bidang. Sebaliknya, REST API memiliki default untuk atribut bidang berdasarkan jenis data. Jenis data berikut adalah "dapat disaring" dan "dapat dibuat faset" secara default:

  • Edm.String
  • Edm.DateTimeOffset
  • Edm.Boolean
  • Edm.Int32, , Edm.Int64Edm.Double
  • Kumpulan jenis di atas, misalnya, Collection(Edm.String) atau Collection(Edm.Double)

Anda tidak dapat menggunakan Edm.GeographyPoint bidang atau Collection(Edm.GeographyPoint) dalam navigasi tersaring. Faset paling efektif untuk bidang dengan kardinalitas rendah. Karena resolusi koordinat geografis, jarang ada dua set koordinat yang akan sama dalam himpunan data tertentu. Dengan demikian, faset tidak didukung untuk koordinat geografis. Anda memerlukan bidang kota atau wilayah untuk faset berdasarkan lokasi.

Tip

Sebagai praktik terbaik untuk pengoptimalan kinerja dan penyimpanan, nonaktifkan faset untuk bidang yang tidak boleh digunakan sebagai faset. Khususnya, bidang string untuk nilai unik, seperti ID atau nama produk, harus diatur ke "facetable": false untuk mencegah penggunaan yang tidak disengaja (dan tidak efektif) dalam navigasi tersaring. Hal ini terutama berlaku untuk REST API yang memungkinkan filter dan faset secara default.

Permintaan dan respons faset

Faset ditentukan pada kueri, dan struktur navigasi tersaring dikembalikan di bagian atas respons. Struktur permintaan dan tanggapan cukup sederhana. Bahkan, pekerjaan nyata di balik navigasi tersaring terletak di lapisan presentasi, tercakup dalam bagian selanjutnya.

Contoh REST berikut adalah kueri yang tidak memenuhi syarat ("search": "*") yang masuk cakupan ke seluruh indeks (lihat sampel hotel bawaan). Faset biasanya adalah daftar bidang, tetapi kueri ini hanya menunjukkan satu untuk respons yang lebih mudah dibaca di bawah ini.

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
}

Sangat berguna untuk menginisialisasi halaman pencarian dengan kueri terbuka untuk sepenuhnya mengisi struktur navigasi tersaring. Setelah Anda melewati istilah kueri dalam permintaan, struktur navigasi tersaring akan membuat cakupan hanya berisi kecocokan dalam hasil, bukan seluruh indeks.

Jawaban untuk contoh di atas mencakup struktur navigasi tersaring di bagian atas. Struktur terdiri dari nilai "Kategori" dan hitungan hotel untuk masing-masing. Hal ini diikuti oleh sisa hasil pencarian, dipangkas di sini untuk singkatnya. Contoh ini bekerja dengan baik karena beberapa alasan. Jumlah faset untuk bidang ini berada di bawah batas (defaultnya adalah 10) sehingga semuanya muncul, dan setiap hotel dalam indeks 50 hotel diwakili dalam salah satu kategori ini.

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

Sintaks faset

Parameter kueri faset diatur ke daftar bidang "dapat dibuat faset" yang dibatasi koma dan tergantung pada jenis data, dapat di parameter lebih lanjut untuk mengatur jumlah, mensortir urutan, dan rentang: count:<integer>, sort:<>, interval:<integer>, and values:<list>. Untuk detail selengkapnya tentang parameter faset, lihat "Parameter kueri" di REST API.

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
}

Untuk setiap pohon navigasi tersaring, ada batas default dari sepuluh faset teratas. Default ini masuk akal untuk struktur navigasi karena default ini menjaga agar daftar nilai tetap berada dalam ukuran yang dapat dikelola. Anda dapat mengganti default dengan menetapkan nilai yang akan "dihitung". Misalnya, "Tags,count:5" mengurangi jumlah tag di bawah bagian Tag ke lima besar.

Hanya untuk nilai Numerik dan DateTime, Anda dapat secara eksplisit mengatur nilai pada bidang faset (misalnya, facet=Rating,values:1|2|3|4|5) untuk memisahkan hasil menjadi rentang bersebelahan (baik rentang berdasarkan nilai numerik atau periode waktu). Atau, Anda dapat menambahkan "interval", seperti dalam facet=Rating,interval:1.

Setiap rentang dibangun menggunakan 0 sebagai titik awal, nilai dari daftar sebagai titik akhir, lalu dipangkas dari rentang sebelumnya untuk membuat interval diskrit.

Perbedaan dalam jumlah faset

Dalam keadaan tertentu, Anda mungkin menemukan bahwa jumlah faset tidak sepenuhnya akurat karena arsitektur sharding. Setiap indeks pencarian tersebar di beberapa pecahan, dan setiap shard melaporkan aspek N teratas menurut jumlah dokumen, yang kemudian digabungkan menjadi satu hasil. Karena ini hanya faset N teratas untuk setiap shard, anda dapat melewatkan atau menghitung dokumen yang cocok dalam respons faset.

Untuk menjamin akurasi, Anda dapat secara artifisial menggelembungkan hitungan:<angka> ke angka besar untuk memaksa pelaporan penuh dari setiap pecahan. Anda dapat menentukan "count": "0" faset tanpa batas. Atau, Anda dapat mengatur "hitungan" ke nilai yang lebih besar dari atau sama dengan jumlah nilai unik bidang tersaring. Misalnya, jika Anda menghadapi bidang "ukuran" yang memiliki lima nilai unik, Anda dapat mengatur "count:5" untuk memastikan semua kecocokan diwakili dalam respons faset.

Tradeoff dengan solusi ini adalah peningkatan latensi kueri, jadi gunakan hanya jika perlu.

Lapisan presentasi

Dalam kode aplikasi, polanya adalah menggunakan parameter kueri faset untuk menampilkan struktur navigasi tersaring bersama dengan hasil faset, ditambah ekspresi $filter. Ekspresi filter menangani peristiwa klik dan semakin mempersempit hasil pencarian berdasarkan pemilihan faset.

Kombinasi faset dan filter

Cuplikan kode berikut dari file JobsSearch.cs di NYCJobs demo menambahkan Judul Bisnis yang dipilih ke filter jika Anda memilih nilai dari faset Judul Bisnis.

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

Berikut adalah contoh lain dari sampel hotel. Cuplikan kode berikut ditambahkan categoyrFacet ke filter jika pengguna memilih nilai dari faset kategori.

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

HTML untuk navigasi tersaring

Contoh berikut, diambil dari file index.cshtml aplikasi contoh NYCJobs, menunjukkan struktur HTML statik untuk menampilkan navigasi tersaring pada halaman hasil pencarian. Daftar faset dibangun atau dibangun kembali secara dinamis saat Anda mengirimkan istilah pencarian, atau memilih atau menghapus faset.

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

Membangun HTML secara dinamis

Cuplikan kode berikut dari index.cshtml (juga dari demo NYCJobs) secara dinamis membangun HTML untuk menampilkan faset pertama, Judul Bisnis. Fungsi serupa secara dinamis membangun HTML untuk faset lainnya. Setiap faset memiliki label dan hitungan, yang menampilkan jumlah item yang ditemukan untuk hasil faset tersebut.

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 untuk bekerja dengan faset

Bagian ini adalah kumpulan tips dan solusi yang mungkin bermanfaat.

Mempertahankan struktur navigasi aspek secara asinkron dari hasil yang difilter

Salah satu tantangan navigasi tersaring di Azure AI Search adalah bahwa faset hanya ada untuk hasil saat ini. Dalam praktiknya, umum untuk mempertahankan sekumpulan faset statik sehingga pengguna dapat menavigasi secara terbalik, menelusuri kembali langkah-langkah untuk menjelajahi jalur alternatif melalui konten pencarian.

Meskipun ini adalah kasus penggunaan umum, ini bukan struktur navigasi tersaring yang saat ini menyediakan struktur siap pakai. Pengembang yang menginginkan aspek statik biasanya bekerja di sekitar batasan dengan mengeluarkan dua kueri yang difilter: satu tercakup ke hasil, yang lain digunakan untuk membuat daftar statik faset untuk tujuan navigasi.

Faset yang jelas

Saat Anda mendesain halaman hasil pencarian, ingatlah untuk menambahkan mekanisme untuk membersihkan faset. Jika Anda menambahkan kotak centang, Anda dapat dengan mudah melihat cara membersihkan filter. Untuk tata letak lain, Anda mungkin memerlukan pola breadcrumb atau pendekatan kreatif lainnya. Di sampel hotel C#, Anda dapat mengirim pencarian kosong untuk mereset halaman. Sebaliknya, aplikasi sampel NYCJobs menyediakan [X] yang dapat diklik setelah faset yang dipilih untuk menghapus faset, yang merupakan antrean visual yang lebih kuat kepada pengguna.

Memangkas hasil faset dengan lebih banyak filter

Hasil faset adalah dokumen yang ditemukan dalam hasil pencarian yang cocok dengan istilah faset. Dalam contoh berikut, dalam hasil pencarian untuk komputasi cloud, 254 item juga memiliki spesifikasi internal sebagai jenis konten. Item tidak selalu saling eksklusif. Jika item memenuhi kriteria kedua filter, item dihitung di masing-masing filter. Duplikasi ini dimungkinkan saat melakukan faset pada bidang Collection(Edm.String), yang sering digunakan untuk mengimplementasikan pemberian tag dokumen.

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

Secara umum, jika Anda mendapati bahwa hasil faset secara konsisten terlalu besar, sebaiknya Anda menambahkan lebih banyak filter untuk memberi pengguna lebih banyak opsi untuk mempersempit pencarian.

Pengalaman pencarian hanya faset

Jika aplikasi Anda menggunakan navigasi tersaring secara eksklusif (yaitu tidak ada kotak pencarian), Anda dapat menandai bidang sebagai searchable=false, filterable=true, facetable=true untuk menghasilkan indeks yang lebih ringkas. Indeks Anda tidak akan menyertakan indeks terbalik dan tidak akan ada analisis teks atau tokenisasi. Filter dibuat pada pertandingan yang tepat pada tingkat karakter.

Memvalidasi input pada waktu kueri

Jika Anda membangun daftar faset secara dinamis berdasarkan input pengguna yang tidak tepercaya, validasikan bahwa nama bidang faset valid. Atau, beri karakter escape pada nama saat membuat URL menggunakan Uri.EscapeDataString() di .NET, atau yang setara di platform pilihan Anda.

Demo dan sampel

Beberapa sampel termasuk navigasi tersaring. Bagian ini memiliki tautan ke sampel dan juga mencatat pustaka klien dan bahasa mana yang digunakan untuk masing-masing.

Menambahkan pencarian ke aplikasi web (React)

Tutorial dan contoh di C#, Python, dan JavaScript menyertakan navigasi tersaring serta filter, saran, dan pelengkapan otomatis. Sampel ini menggunakan React untuk lapisan presentasi.

NYCJobs contoh kode dan demo (Ajax)

Sampel NYCJobs adalah aplikasi MVC ASP.NET yang menggunakan Ajax di lapisan presentasi. Ini tersedia sebagai aplikasi demo langsung dan sebagai kode sumber di repositori Azure-Samples di GitHub.