AI 驅動的混合搜尋目前處於封閉測試階段。 加入候補名單 以取得搶先體驗!

前往首頁Meilisearch 的標誌
返回文章
2023 年 9 月 14 日

使用 InstantSearch 依 ID 精煉篩選條件

了解如何在 UI 中使用 InstantSearch 顯示篩選條件名稱,同時依其唯一識別碼精煉篩選條件。

Carolina Ferreira
Carolina Ferreira開發人員推廣專員 @ Meilisearch@CarolainFG
Refining facets by ID with InstantSearch

在本指南中,我們將深入探討 Meilisearch 中的篩選條件概念,以及如何使用它來顯示篩選條件名稱,同時依 ID 進行篩選。

什麼是篩選條件?

篩選條件是搜尋引擎中使用的一種技術,可將搜尋結果分類為多個類別或「篩選條件」。這些篩選條件可以是類別、標籤、價格範圍,甚至顏色等。這使得使用者可以更輕鬆地瀏覽和篩選結果,提供更精煉和有效率的搜尋體驗。

為什麼要使用 ID 作為篩選條件過濾器?

對於大多數應用程式和使用者而言,依篩選條件名稱(例如電影類型)進行篩選通常已足夠且直觀。篩選條件名稱是人類可讀的,並清楚地說明了篩選器的作用。但是,在某些使用案例中,最好依 ID 進行篩選,原因如下:

  • 較不易出錯:ID 通常更簡單且標準化,因此不易發生篩選條件名稱中可能存在的錯字或不一致情況。
  • 唯一識別碼:在某些資料庫中,篩選條件名稱可能會以略有不同的特性重複,而 ID 始終是唯一的。這在您擁有名稱相似或相同但屬性不同的項目時特別有用。

藉由使用 ID 進行篩選,但向使用者顯示對應的篩選條件名稱,您可以同時獲得最佳的效率和可用性。這樣,您就可以利用 ID 和名稱的優勢,使您的應用程式更加穩健且使用者友善。

ID 到名稱的挑戰

在 Meilisearch 中,篩選條件是過濾器的特定使用案例。基本上,您可以將新增至 filterableAttributes 清單中的任何屬性用作篩選條件。當您將篩選條件參數新增至搜尋查詢時,Meilisearch 將會傳回 [facetDistribution](https://meilisearch.dev.org.tw/docs/reference/api/search#facetdistribution) 物件。此物件會提供指定篩選條件的值中分散的符合文件數。

 "facetDistribution":{
    "genres":{
      "Classics":6,
      "Comedy":1,
      "Coming-of-Age":1,
      "Fantasy":2,
      "Fiction":8,

    }
  }

但是,如果您新增至 filterableAttributes 清單的欄位是 ID,則 facetDistribution 物件將會傳回這些 ID。

 "facetDistribution":{
    "genres":{
      "5":6,
      "6":1,
      "8":1,
      "13":2,
      "16":8,

    }
  }

雖然 ID 非常適合後端作業,但它們不一定在前端是使用者友善或有意義的。這就是為什麼您可能需要在使用者介面中顯示這些 ID 時,將其對應回對應的篩選條件名稱。

前端的 ID 到名稱對應

假設您有一個遵循以下結構的電影資料集

{
    "id": 5,
    "title": "Four Rooms",
    "overview": "It's Ted the Bellhop's first night on the job....",
    "genres": [
        {
            "id": 7,
            "name": "Crime"
        },
        {
            "id": 6,
            "name": "Comedy"
        },
    ],
    "release_date": 818467200,
}

您想要以電影類型為基礎的篩選搜尋。因此,您將 genres.id 新增至 可篩選屬性清單。當然,在 UI 中,您想要顯示 genres.name,以便使用者在 UI 上看到「犯罪」,而不是「7」。

讓我們深入了解如何使用 InstantSearch 和 instant-meilisearch 完成此操作。

使用 InstantSearch 和 instant-meilisearch

InstantSearch 是一個開放原始碼前端程式庫,用於建置搜尋 UI。Instant-meilisearch 是將 InstantSearch 與 Meilisearch 整合的首選搜尋用戶端。

若要搭配 InstantSearch 使用 instant-meilisearch,您需要

1. 匯入必要的模組,包括 instantMeiliSearch

import { instantMeiliSearch } from '@meilisearch/instant-meilisearch'
import instantsearch from 'instantsearch.js'
import { searchBox, infiniteHits,refinementList } from 'instantsearch.js/es/widgets'

2. 使用您的 Meilisearch 主機和搜尋 API 金鑰建立 Meilisearch 用戶端

const searchClient = instantMeiliSearch(
  'https://ms-7053a8dd7c09-72.lon.meilisearch.io',
  'meilisearchApiKey'
)

3. 使用您的 Meilisearch 索引名稱和搜尋用戶端設定 instantsearch

const searchIndex = instantsearch({
  indexName: 'movies',
  searchClient
})

在本指南中,我們將使用 InstantSearch 的 refinementList 小工具將 ID 對應至使用者友善的名稱。

此小工具隨附一個名為 transformItems 的選用參數。此函式會接收 items(或篩選條件),並允許您在它們顯示在 UI 上之前轉換它們。它也包含其參數中的完整結果資料。

每個項目(或篩選條件)都包含以下屬性

  • count:篩選條件在結果集中出現的次數
  • value:用於精煉的值(在我們的案例中,它將會是 genres.id)
  • label:要顯示的標籤
  • highlighted:已醒目提示的標籤。此值會顯示在預設範本中

如您所見,highlightedrefinementlList 小工具預設使用的標籤。

有了這些資訊,我們可以利用 transformItems 函式來顯示 genres.name,而不是 genres.id

transformItems(items, { results }) {
    // The 'results' parameter contains the full results data
    return items.map(item => {
      // Initialize genreName with the existing highlighted label
      let genreName = item.highlighted;
      
      // Loop through results.hits to find a matching genre
      for (let hit of results.hits) {
        const matchedGenre = hit.genres.find(genre => genre.id.toString() === item.value);
        
        // Update genreName if a match is found
        if (matchedGenre) {
          genreName = matchedGenre.name;
          break;
        }
      }
      
      // Return the updated item with the new tagName as the highlighted value
      return {
        ...item,
        highlighted: genreName
      };
    });
  }

透過此設定,您將有效地將 ID 對應至更使用者友善的名稱,進而提升使用者的搜尋體驗。

完整程式碼應如下所示

import { instantMeiliSearch } from '@meilisearch/instant-meilisearch'
import instantsearch from 'instantsearch.js'
import { searchBox, infiniteHits,refinementList } from 'instantsearch.js/es/widgets'

const searchClient = instantMeiliSearch(
  'https://ms-7053a8dd7c09-72.lon.meilisearch.io',
  'meilisearchApiKey'
)
  
const searchIndex = instantsearch({
  indexName: 'movies',
  searchClient
})

const searchBox = instantsearch.widgets.searchBox({
  // ...
});

const hits = instantsearch.widgets.hits({
  // ...
});

const refinementList = instantsearch.widgets.refinementList({
  container: '#facets',
  attribute: 'genres.id',
  transformItems(items, { results }) {
    return items.map(item => {
      let genreName = item.highlighted; 
      for (let hit of results.hits) {
        const matchedGenre = hit.genres.find(genre => genre.id.toString() === item.value);
        if (matchedGenre) {
          genreName = matchedGenre.name;
          break;
        }
      }
      return {
        ...item,
        highlighted: genreName
      };
    });
  }
})

searchIndex.addWidgets([searchBox, infiniteHits, refinementList]);

searchIndex.start()

此範例顯示如何使用 vanilla JavaScript 實作 ID 到名稱的對應,但您可以使用偏好的前端架構來達成類似的結果。請查看 ReactVue 的相關文件。

如需更多 Meilisearch 的相關資訊,您可以訂閱我們的電子報。您可以查看產品藍圖並參與我們的產品討論,以深入了解我們的產品。

如有任何其他問題,請加入我們的 Discord 開發人員社群。

How to add AI-powered search to a React app

如何將 AI 驅動的搜尋新增至 React 應用程式

使用 Meilisearch 的 AI 驅動的搜尋建置 React 電影搜尋和推薦應用程式。

Carolina Ferreira
Carolina Ferreira2024 年 9 月 24 日
Build your Next.js Shopify storefront with Blazity

使用 Blazity 建置您的 Next.js Shopify 店面

了解如何使用 Next.js 和 Blazity 商業啟動器建置 Shopify 店面。

Laurent Cazanove
Laurent Cazanove2024 年 8 月 19 日
Meilisearch 1.8

Meilisearch 1.8

Meilisearch 1.8 帶來負關鍵字搜尋、搜尋穩定性改進和 AI 搜尋(包括新的嵌入器)。

Carolina Ferreira
Carolina Ferreira2024 年 5 月 7 日