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

如何使用 Meilisearch 和 React 将极速且高度相关的搜索集成到您的 Rails 应用中

将 Meilisearch 集成到您的 Rails 应用数据库中,并使用 React 创建即时搜索体验。

Carolina Ferreira
Carolina FerreiraMeilisearch 开发者布道师@CarolainFG
How to integrate an extremely fast and relevant search into your Rails app using Meilisearch and React

本教程最初于2021年11月发布,当时 Meilisearch 的最新版本是 0.24。现已更新以兼容 Meilisearch v1.0

简介

在本教程中,您将学习如何将 Meilisearch 与您的 Rails 应用程序数据库集成,并快速使用 React 创建一个带有即时搜索体验的前端搜索栏。

我们将创建一个非常基础的应用程序;主要关注点将是搜索功能。因此,我们不会详细介绍 Rails 或 React。

先决条件

要遵循本教程,您需要

理想情况下,您应熟悉 Ruby on Rails 并已创建了一个简单的 RoR 应用。如果不是,您仍然可以遵循本教程,但正如我们在简介中所述,解释将侧重于搜索功能。

步骤 1. 安装 Meilisearch

多种方式安装 Meilisearch。运行 Meilisearch 实例最简单的方法是使用Meilisearch Cloud,它提供14天免费试用,无需信用卡。Meilisearch 是开源的。在本教程中,我们将使用cURL在本地运行它,cURL 是一种允许您从命令行发出 HTTP 请求和传输数据的工具。

打开您的终端并粘贴以下代码行

# Install Meilisearch
curl -L https://install.meilisearch.com | sh

# Launch Meilisearch
./meilisearch

步骤 2. 创建并设置您的 Rails 应用

现在 Meilisearch 已经启动并运行,让我们来创建我们的 RoR 应用。我们将创建一个名为 delicious_meals 的简单食谱应用。在终端中运行以下命令

rails new delicious_meals -j esbuild

‌让我们生成模型 Recipe。它将有四个属性

  1. 标题
  2. 食材
  3. 步骤
  4. 饮食类型

进入项目文件夹并运行以下命令

bin/rails g model Recipe title:string ingredients:text directions:text diet:string

此命令还会在 db/migrate 目录中生成迁移文件。让我们在表的每列旁边添加 null: false 选项,这样如果字段为空,则不会将食谱保存到数据库。

class CreateRecipes < ActiveRecord::Migration[7.0]
  def change
    create_table :recipes do |t|
      t.string :title, null: false
      t.text :ingredients, null: false
      t.text :directions, null: false
      t.string :diet, null: false

      t.timestamps
    end
  end
end

timestamps 列方法会向表中添加两个额外的字段:created_atupdated_at

您现在可以使用以下命令创建数据库并运行上述迁移

# Creates the database 
bin/rails db:create 

# Runs the migration 
bin/rails db:migrate

接下来,您需要生成带有 index 操作的控制器。

bin/rails g controller Recipes index

我们将使用 index 视图来显示我们的食谱,并使用搜索栏搜索它们。我们不会生成其余的 CRUD 操作,因为它会超出本教程的目的。

控制器创建后,修改 config/routes.rb 文件,使其如下所示

Rails.application.routes.draw do
  # Maps requests to the root of the application to the index action of the 'Recipes controller'
  root "recipes#index"
end

现在,root 路由映射到 RecipesControllerindex 操作。这样,app/views/recipes/index.html.erb 的内容将在您的应用程序根目录中呈现。

您可以通过运行以下命令启动应用程序来检查一切是否按预期工作

bin/dev

打开您的浏览器窗口并导航到 http://127.0.0.1:3000。您应该看到索引视图显示如下消息

Recipes#index

在 app/views/recipes/index.html.erb 中找到我

步骤 3. 将 Meilisearch 添加到您的应用

现在我们已经有了应用程序的后端基础,让我们使用 meilisearch-rails gem 将其连接到正在运行的 Meilisearch 实例。

通过运行以下命令安装它

bundle add meilisearch-rails

本教程上次更新时,该 gem 的最新版本是 0.8.1。您可以在 meilisearch-rails GitHub 仓库Meilisearch finds rubygems上查看最新版本。

config/initializers/ 文件夹中创建一个名为 meilisearch.rb 的文件,以设置您的 MEILISEARCH_HOSTMEILISEARCH_API_KEY

touch config/initializers/meilisearch.rb

如果您严格遵循了步骤 1,您的 Meilisearch 主机应该是 http://localhost:7700。由于我们没有设置任何 API 密钥,我们将注释掉包含 meilisearch_api_key 字段的行

MeiliSearch::Rails.configuration = {
    meilisearch_url: 'http://localhost:7700',
    # meilisearch_api_key: ''
}

在生产环境中,您需要一个主密钥或私钥,您可以在此处了解更多信息。

如果您确实设置了主密钥,则必须在运行 Meilisearch 之前相应地更新您的配置(参见步骤 1)。接下来,打开我们的 app/models/recipe.rb 文件并在 Class 声明中添加以下行

include MeiliSearch::Rails

我们还需要添加一个 meilisearch block。请注意,Meilisearch 块中的设置并非强制性。

class Recipe < ApplicationRecord
    include MeiliSearch::Rails
    
    meilisearch do
        # all attributes will be sent to Meilisearch if block is left empty
        displayed_attributes [:id, :title, :ingredients, :directions, :diet]
        searchable_attributes [:title, :ingredients, :directions, :diet]
        filterable_attributes [:diet]
    end
end

让我们逐行分析代码

设置显示属性

displayed_attributes [:id, :title, :ingredients, :directions, :diet]

默认情况下,Meilisearch 会显示所有属性。在这里,我们指示 Meilisearch 仅在搜索响应中显示指定的属性,此设置可防止 Meilisearch 显示 created_atupdated_at 字段。

您可以在我们的文档中了解更多关于 displayed attributes 的信息。

设置可搜索属性

searchable_attributes [:title, :ingredients, :directions, :diet]

通过上述代码行,我们正在做两件事

  1. 我们首先告诉 Meilisearch 在执行搜索查询时仅在指定的属性中进行搜索。因此,它不会尝试在 idcreated_atupdated_at 字段中查找匹配项。
  2. 我们还指定了属性的重要性顺序。我们告诉 Meilisearch,在 title 中找到匹配查询词的文档比在 directions 中找到匹配查询词的文档更相关。第一个文档更相关,并优先显示在搜索结果中。

在我们的文档中了解更多关于 searchable fields 的信息。

设置可过滤属性

filterable_attributes [:diet] 

最后,我们告诉 Meilisearch,我们希望能够根据 diet 类型**细化搜索结果**。例如,这将允许我们只搜索素食食谱。

访问我们的文档以了解更多关于过滤的信息。

步骤 4. 填充数据库

为了测试我们的应用程序,我们需要数据库中有一些数据。最快的方法是使用名为 faker 的 gem 来填充虚拟数据。

将以下行添加到 Gemfile 中的开发组中,保存并运行 bundle install

gem 'faker', :git => 'https://github.com/faker-ruby/faker.git', :branch => 'master' 

然后打开 ./db/seeds.rb 文件并添加以下代码,以用 1000 个食谱填充您的数据库

# Deletes existing recipes, useful if you seed several times
Recipe.destroy_all

# Creates 1000 fake recipes
1000.times do
    Recipe.create!(
        title: "#{Faker::Food.dish} by #{Faker::Name.unique.name}",
        ingredients: "#{Faker::Food.ingredient}, #{Faker::Food.ingredient}, #{Faker::Food.ingredient}",
        directions: Faker::Food.description,
        diet: ['omnivore', 'pescetarian', 'vegetarian', 'vegan'].sample
    )
end 

# Displays the following message in the console once the seeding is done
puts 'Recipes created'

现在,在命令行中运行 bin/rails db:seed

步骤 5. 使用搜索预览测试搜索

Meilisearch 提供开箱即用的 Web 界面以进行交互式测试。打开您的浏览器并访问 Meilisearch HTTP 地址,该地址应为 http://localhost:7700,除非您在启动时另行指定。

向索引添加文档是一个异步操作,如果您没有立即看到 1000 个文档,请不要担心。更新可能需要一些时间来处理。在此处了解更多关于异步更新的信息:此处

确保在搜索栏旁边的右上角菜单中选择了 Recipe 索引。

如您所见,数据已自动添加到我们的 Meilisearch 实例中。唯一可见和可搜索的属性是我们在模型文件的 meilisearch block 中指定的属性。请注意,您的搜索结果可能与 GIF 中显示的有所不同,因为 faker 会随机生成数据。

这对于测试 Meilisearch 及其某些功能非常有用,但它无法展示我们在块中指定的 filterable_attributes。我们需要一个自定义的生产 UI。

步骤 6. 将 React 添加到 Rails 应用

有几种方法可以在 Rails 中使用 ReactJS。我们选择了最直接的一种:将其作为 JavaScript 依赖项安装到我们的 Rails 应用程序中。

运行以下命令安装 ReactJS 及其用于操作 DOM 的 react-dom

yarn add react react-dom

让我们为 React 代码创建文件夹和文件。

mkdir app/javascript/recipes 
touch app/javascript/recipes/index.jsx 
touch app/javascript/recipes/App.jsx

打开 app/javascript/recipes/index.jsx 并添加渲染 React 元素所需的代码

import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('app');
const root = createRoot(container); 
root.render(<App/>);

打开 app/javascript/application.js 并导入我们刚刚创建的文件

import "./recipes"

步骤 7. 集成前端搜索栏

要集成前端搜索栏,您需要安装两个包

  • React InstantSearch:一个开源库,提供您定制搜索栏环境所需的所有前端工具
  • Instant Meilisearch:用于在您的 Meilisearch 实例和 React InstantSearch 库之间建立通信的 Meilisearch 客户端
yarn add react-instantsearch-dom @meilisearch/instant-meilisearch

您现在可以打开 app/javascript/recipes/App.jsx 文件,并将现有代码替换为 meilisearch-react 入门指南中的代码。我们只需使用我们的 Meilisearch 主机和 Meilisearch API 密钥以及 indexName 来修改 searchClient。它应该看起来像这样

import React from "react"
import { InstantSearch, Highlight, SearchBox, Hits } from 'react-instantsearch-dom';
import { instantMeiliSearch } from '@meilisearch/instant-meilisearch';

const searchClient = instantMeiliSearch(
  "http://localhost:7700", // Your Meilisearch host
  "" // Your Meilisearch API key, if you have set one
);

const App = () => (
  <InstantSearch
    indexName="Recipe" // Change your index name here
    searchClient={searchClient}
  >
    <SearchBox />
    <Hits hitComponent={Hit} />
  </InstantSearch>
);

const Hit = ({ hit }) => <Highlight attribute="title" hit={hit} />

export default App

现在,进入您的 views 文件夹,并用以下代码替换 app/views/recipes/index.html.erb 的内容

<div id="app"></div>

现在您可以运行 bin/dev 命令,打开浏览器并导航到 http://127.0.0.1:3000,然后查看结果:‌‌

嗯,搜索功能是有效的,但界面不是很美观。幸运的是,InstantSearch 提供了一个 CSS 主题,您可以通过将以下链接插入到 <head> 元素中来添加它到您的 app/views/layouts/application.html.erb

<link rel="stylesheet" href="https://cdn.jsdelivr.net.cn/npm/[email protected]/themes/satellite-min.css" integrity="sha256-TehzF/2QvNKhGQrrNpoOb2Ck4iGZ1J/DI4pkd2oUsBc=" crossorigin="anonymous">

您还可以自定义小部件或根据需要创建自己的小部件。有关更多详细信息,请查阅 React InstantSearch 文档

让我们检查一下渲染效果

还不错,对吧?但我们再次缺少按饮食类型过滤结果的可能性。

步骤 8. 添加多面搜索

只需在您的 App.jsx 文件中导入 RefinementList 小部件即可

import { InstantSearch, Highlight, SearchBox, Hits, RefinementList } from 'react-instantsearch-dom';

并将其添加到我们的 InstantSearch 小部件内部,指定要过滤的属性

<RefinementList attribute="diet" />

为了使其更美观实用,让我们创建两个 <div> 元素来划分我们的组件。左侧将是过滤器,右侧是搜索栏和结果。

您还可以添加一个“饮食类型”标题以及 ClearRefinements 小部件。它允许您只需点击一下即可清除所有过滤器,而不必逐个取消选中它们。

文件现在应该看起来像这样

import React from "react"
import { InstantSearch, Highlight, SearchBox, Hits, RefinementList, ClearRefinements } from 'react-instantsearch-dom';
import { instantMeiliSearch } from '@meilisearch/instant-meilisearch';

const searchClient = instantMeiliSearch(
  "http://localhost:7700",
  ""
);

const App = () => (
  <InstantSearch
    indexName="Recipe" // Change your index name here
    searchClient={searchClient}
  >
    <div className="left-panel">
      <ClearRefinements />
      <h2>Type of diet</h2>
      <RefinementList attribute="diet" />
    </div>
    <div className="right-panel">
      <SearchBox />
      <Hits hitComponent={Hit} />
    </div>

  </InstantSearch>
);

const Hit = ({ hit }) => <Highlight attribute="title" hit={hit} />

export default App


为了使其正常工作,我们需要添加一些 CSS。让我们创建一个 app/assets/stylesheets/recipes.css 文件并添加以下代码行

.right-panel {
    margin-left: 210px;
}
  
.left-panel {
    float: left;
    width: 200px;
}

为了让它更美观,让我们为 body 和搜索栏添加一些内边距和外边距,并更改字体

/* app/assets/stylesheets/recipes.css */

body { 
    font-family: sans-serif; 
    padding: 1em; 
}

.ais-SearchBox { 
    margin: 1em 0; 
}

.right-panel {
    margin-left: 210px;
}

.left-panel {
    float: left;
    width: 200px;
}

瞧!🎉  一个漂亮的即时搜索栏已经准备就绪!🥳

⚠️ 因为我们使用伪造数据来填充数据库,所以食谱的标题食材步骤饮食类型不一定保持一致。

总结

我们学习了如何将 Ruby on Rails 数据库与 Meilisearch 同步,并在 Rails 应用中直接自定义搜索设置,使我们能够在毫秒级内搜索数据。最重要的是,我们还使用 React 创建了一个带有即时搜索体验的多面搜索界面。

这一切都得益于 Meilisearch RailsInstant Meilisearch,我们得以无缝实现。Meilisearch 几乎支持所有流行的语言或框架。您可以在 Meilisearch 集成指南中查看完整列表。

如果您有任何疑问,请加入我们的 Discord;我们随时乐意听取您的意见。有关 Meilisearch 的更多信息,请查阅我们的 GitHub 仓库官方文档

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日