前往主页Meilisearch 的标志
返回文章
2022年11月15日

如何在您的 React 应用中实现即时搜索

了解如何利用 Meilisearch 和 React 的强大功能,轻松创建具有即时可靠结果的基于搜索的 Web 应用。

How to implement instant search in your React app

这篇文章最初由客座作者 Riccardo Giorato 于 2020 年 5 月发布。当时,Meilisearch 仍在 v0.09 版本。现已由 Carolina Ferreira 更新,以支持 Meilisearch v1 版本。您可以在 GitHub 上找到该文章的原始版本。

引言

在本教程中,您将学习如何利用 Meilisearch 的强大功能,轻松创建具有即时可靠结果的基于搜索的 Web 应用。

我们将介绍将数据添加到 Meilisearch 的基本步骤,创建一个自定义的前端搜索,并在最后进行定制化。

在本教程中,我们将为一家体育品牌创建即时搜索体验。以下是您将要构建的预览:

Searching for multiple items on the decathlon demo using Meilisearch

先决条件

开始之前,请确保您的机器上已安装 Node.js >= 18。

您可以按照本教程的步骤进行操作,边学边写代码,使用这个 GitHub 项目

最后,本教程假设您已熟悉 React。如果不是,您可以查阅 React 文档 以了解更多信息。

开始

克隆仓库

使用以下命令克隆 GitHub 仓库:

git clone https://github.com/meilisearch/tutorials.git
cd src/react-decathlon

运行新的 Docker 镜像

如果您克隆了仓库来设置 Meilisearch 实例,只需在主文件夹内执行以下命令:

npm install
npm run setup_meili

如果您没有克隆仓库,并希望使用 Docker 启动 Meilisearch,请执行此命令:

docker run -it --rm 
    -p 7700:7700 
    -e MEILI_ENV='development' 
    -v $(pwd)/meili_data:/meili_data 
    getmeili/meilisearch:v1.0

默认情况下,Meilisearch 的 API 是未受保护的。在生产环境中,您将需要一个主密钥。您可以在我们的文档中了解更多信息。

您可以通过访问:http://localhost:7700/ 来检查 Meilisearch 是否正在运行。

想避免本地安装?为了快速创建一流的搜索体验,我们提供了便捷的 Meilisearch Cloud,它是 Meilisearch 的托管版和完全托管版。提供 14 天免费试用,无需信用卡 😉

在 Meilisearch 中创建索引

索引是存储文档的实体,类似于一个附加了特定设置的对象数组,并具有唯一的 主键

每个被索引的文档都必须有一个主字段,这是一个必须存在于所有文档中的特殊字段。该字段保存文档的唯一值:其 id。

Meilisearch 可以从您的数据集中推断出主键,前提是该数据集包含 id 子字符串。您也可以显式设置它。

以下是一个要添加到 Meilisearch 的示例文档。

{
  "id": 100013768717,
  "name": "Fitness Foldable Shoe Bag",
  "url": "https://www.decathlon.com/products/gym-foldable-shoe-bag",
  "vendor": "Domyos",
  "category": "Sport bag",
  "tags": [
    "Artistic Gymnastics",
    "Boy's",
    "CARDIO_FITNESS_ACCESSORIES",
    "CARDIO_FITNESS_BAGS",
    "CODE_R3: 11782"
  ],
  "images": "https://cdn.shopify.com/s/files/1/1330/6287/products/sac_20a_20chaussure_20kaki_20_7C_20001_20_7C_20PSHOT_20_490180e6-44e4-4340-8e3d-c29eb70c6ac8.jpg?v=1584683232",
  "creation_date": "2020-04-03T15:58:48-07:00",
  "price": "2.49"
}

您可以使用像 Postman 这样的 REST 客户端轻松创建此索引,但在本教程中,我们将使用 Meilisearch Javascript SDK 直接从 Node.js 进行操作。

const { MeiliSearch } = require('meilisearch')

;(async () => {
  try {
    const config = {
      host: 'http://localhost:7700'
    };

    const meili = new MeiliSearch(config);
    
    await meili.createIndex('decathlon'); 
    
    // or you can set the primary key explicitly: 
    // await meili.createIndex({ uid: "decathlon", primaryKey: "id" });
        
  } catch (e) {
    console.error(e);
    console.log("Meili error: ", e.message);
  }
})();

您可以在 Meilisearch 文档中阅读更多关于索引属性的信息。

索引文档

Meilisearch 接收 JSON 格式的文档并将其存储用于搜索目的。这些文档由可以保存任何类型数据的字段组成。Meilisearch 还接受以下格式的数据集:NDJSON 和 CSV。您可以在文档中阅读更多关于格式的信息。

对于本教程,您可以下载这个包含运动服饰的数据集:decathlon.json

使用以下脚本将此 JSON 文件中的所有对象上传到 Meilisearch。请记住在运行之前更改 JSON 文件的路径!

const { MeiliSearch } = require('meilisearch')

;(async () => {
  try {
    const config = {
      host: 'http://localhost:7700'
    };

    const meili = new MeiliSearch(config);

    const decathlon = require("../decathlon.json"); // path to json file

    const index = meili.index("decathlon");
    
    await index.addDocuments(decathlon);
        
  } catch (e) {
    console.error(e);
    console.log("Meili error: ", e.message);
  }
})();

准备 React 应用

我们需要一个标准的 React 应用。您可以使用之前在入门部分克隆的项目。

如果您更喜欢从一个空应用开始,可以使用以下命令通过 Create React App 创建您自己的应用。您可以根据需要命名应用程序。

npx create-react-app meili_react_demo
cd meili_react_demo

引入 Tailwind CSS

为了加快样式化过程,将 Tailwind CSS 样式直接添加到 index.html 文件的 <head> 元素中。

  <script src="https://cdn.tailwindcss.com"></script>

配置 App.js 状态

然后,使用此代码修改 App.js 文件,以设置一个简单的搜索表单和一些状态变量来处理搜索的各个方面。

import React, { useState, useEffect } from 'react'
import { MeiliSearch } from 'meilisearch'
import Item from './components/Item'

// TODO configure the MeiliSearch Client

const index = client.index('decathlon')

function App () {
  const [searchedWord, setSearch] = useState('')
  const [resultSearch, setResults] = useState([])

  // TODO add function to send searchedWord to Meilisearch

  return (
    <div className='mx-auto'>
      <div className='header font-sans text-white items-center justify-center'>
        <header className='py-12'>
          <img
            className='h-20 w-auto items-center justify-center p-2 mx-auto'
            src='/wide_logo.png'
            style={{ filter: 'invert(0%)' }}
            alt='Decathlon logo'
          />
          <h1 className='flex flex-wrap flex-grow text-3xl w-full justify-center p-4'>
            Stop looking for an item — find it and work hard!
          </h1>
          <div className='border rounded overflow-hidden w-full flex justify-center mx-auto searchBox mt-6'>
            <button className='flex items-center justify-center px-4 shadow-md bg-white text-black'>
              <svg
                className='h-4 w-4 text-grey-dark'
                fill='currentColor'
                xmlns='http://www.w3.org/2000/svg'
                viewBox='0 0 24 24'
              >
                <path d='M16.32 14.9l5.39 5.4a1 1 0 0 1-1.42 1.4l-5.38-5.38a8 8 0 1 1 1.41-1.41zM10 16a6 6 0 1 0 0-12 6 6 0 0 0 0 12z' />
              </svg>
            </button>
            <input
              type='text'
              value={searchedWord}
              onChange={(event) => setSearch(event.target.value)}
              className='px-6 py-4 w-full text-black'
              placeholder='Product, sport, color, …'
            />
          </div>
        </header>
      </div>
      <div>
        <div className='flex flex-wrap searchResults'>
          // TODO iterate over the search results to display them with the Item component
        </div>
      </div>
    </div>
  )
}

export default App


这段代码将输出一个带有搜索表单的精美头部。

Decathlon header with a search bar

React 中的搜索结果

使用 Javascript SDK 将 React 与 Meilisearch 连接起来是一个简单的操作,只需几个步骤即可完成。

Meilisearch 客户端

使用以下命令安装 Meilisearch SDK:

// if you use npm
npm install meilisearch
// if you use yarn
yarn add meilisearch

使用服务器 URL 设置 Meilisearch 客户端。在我们的例子中,它是 localhost Docker 机器。最后,从后端加载正确的索引。

用以下代码片段替换 App.js 中的此注释:

"// TODO 配置 Meilisearch 客户端"

import { MeiliSearch } from "meilisearch";

const client = new MeiliSearch({
  host: "http://localhost:7700/",
});

const index = client.index("decathlon");

发送搜索查询

添加一个 useEffect 钩子,将输入的词语搜索到 Meilisearch 中。所有结果都将设置到一个名为 resultsSearch 的简单状态变量中。

用以下代码片段替换 App.js 中的此注释:

"// TODO 添加函数以将 searchedWord 发送到 Meilisearch"

  useEffect(() => {
    // Create a scoped async function in the hook
    async function searchWithMeili() {
      const search = await index.search(searchedWord);
      setResults(search.hits);
    }
    // Execute the created function directly
    searchWithMeili();
  }, [searchedWord]);

展示结果

您将遍历 Meilisearch 返回的 JSON 对象——它们将与上传的 JSON 对象具有相同的结构——并将其显示在 Item 组件中,链接到产品页面。

让我们创建 Item 组件,它将帮助我们显示产品。创建一个名为 components 的文件夹,并在其中创建一个 Item.js 文件,然后复制并粘贴以下代码片段:

function Item ({ url, image, name, category, vendor, price, id }) {
  return (
    <div className='flex w-full sm:w-1/2 md:w-1/3 lg:w-1/4 xl:w-1/6 p-3' key={id}>
      <a className='flex-1 rounded overflow-hidden shadow-lg' href={url}>
        <img
          className='w-full h-48 object-cover'
          src={image}
          alt={name}
          onError={(e) => {
            e.target.onerror = null
            e.target.src = '/wide_logo.png'
          }}
        />
        <div className='px-6 py-3'>
          <div className='font-bold text-sm mb-1 text-gray-600 capitalize'>
            {category}
          </div>
          {name}
          <div className='font-bold text-xl mb-2 text-gray-800'>
            {vendor} -
          </div>
          <p className='text-black text-xl font-bold text-base py-2'>
            $ {price}
          </p>
        </div>
      </a>
    </div>
  )
}

export default Item

然后,用以下代码片段替换 App.js 中的此注释:

{resultSearch?.map((result) => (
    <Item
      url={result.url}
      image={result.images}
      name={result.name}
      category={result.category}
      vendor={result.vendor}
      price={result.price}
      key={result.id}
      />
))}

您可以在 GitHub 上查看完整代码。

配置搜索

使用 Meilisearch,您有大量的自定义选项来微调您的搜索体验。我们将在这里介绍一些功能。您可以在文档中阅读更多相关信息。

搜索排名

我们将从更改排名规则开始,即 Meilisearch 在每次进行搜索查询时用于对您上传的文档进行排序的标准。排名规则的顺序会影响搜索结果的相关性。您可以在文档中了解更多信息。

让我们使用以下顺序:

[
  "words",
  "typo",
  "proximity",
  "attribute",
  "sort",
  "exactness",
  “creation_date:desc”
]

这使用了默认顺序以及一个自定义规则:creation_date。如果所有先前的值都相同,此规则会按创建日期对项目进行排名。

S可搜索属性

您还可以配置可搜索属性。这些属性的值是 Meilisearch 用于匹配查询词的。默认情况下,所有属性都是可搜索的,但您可以将其配置为只搜索 namevendorcategorytags 字段,而排除 imagesURL

searchableAttributes: ["name", "vendor", "category", "tags"]

显示属性

显示属性是 Meilisearch 可以通过 displayedAttributes 数组返回给前端用户的属性。与可搜索属性一样,所有属性默认都显示。

    "displayedAttributes": [
      "name",
      "vendor",
      "category",
      "tags",
      "images",
      "url"
    ]

将新设置上传到 Meilisearch

现在是时候使用上面解释的搜索设置来自定义我们的 Meilisearch 索引了。

const { MeiliSearch } = require('meilisearch')

;(async () => {
  try {
    const config = {
      host: 'http://localhost:7700'
    };

    const meili = new MeiliSearch(config);
    
    const index = meili.index("decathlon");

    const newSettings = {
      rankingRules: [
        "words",
        "typo",
        "proximity",
        "attribute",
        "sort",
        "exactness",
        "creation_date:desc"
      ],
      searchableAttributes: ["name", "vendor", "category", "tags"],
      displayedAttributes: [
        "name",
        "vendor",
        "category",
        "tags",
        "images",
        "url"
      ]
    };

    await index.updateSettings(newSettings);
        
  } catch (e) {
    console.error(e);
    console.log("Meili error: ", e.message);
  }
})();


结论

如果没有一个了不起的团队夜以继日地投入到这个伟大项目中,这种快速搜索是不可能实现的!如果您喜欢为 Meilisearch 大家庭贡献力量,请查看以下仓库:


订阅我们的新闻通讯,每月更新将直接发送到您的收件箱。

要了解更多关于 Meilisearch 的信息,请加入我们在 Discord 上的开发者社区。您可以通过查看路线图并参与产品讨论来了解更多产品信息。

Meilisearch indexes embeddings 7x faster with binary quantization

Meilisearch 通过二进制量化将嵌入索引速度提高了 7 倍

通过使用向量存储 Arroy 实现二进制量化,在保持搜索相关性和效率的同时,显着减少了大型嵌入的磁盘空间使用和索引时间。

Tamo
Tamo2024年11月29日
How to add AI-powered search to a React app

如何将 AI 搜索添加到 React 应用中

使用 Meilisearch 的 AI 搜索功能构建一个 React 电影搜索和推荐应用。

Carolina Ferreira
Carolina Ferreira2024年9月24日
Meilisearch is too slow

Meilisearch 太慢了

在这篇博客文章中,我们探讨了 Meilisearch 文档索引器所需的改进。我们将讨论当前的索引引擎、其缺点以及优化性能的新技术。

Clément Renault
Clément Renault2024年8月20日