基于 NestJS 集成 ElasticSearch 实现模糊搜索功能

前言

Elasticsearch 是一个基于 Lucene 的开源搜索引擎。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful web 接口。Elasticsearch 具有高弹性,支持即时和实时的复杂搜索功能。NestJS 是一个用于构建高效、可扩展的 Node.js 服务器端应用程序的框架,它使用 TypeScript 开发并且结合了 OOP(面向对象编程)、FP(函数式编程)和 FRP(函数响应式编程)。

整合 Elasticsearch 和 NestJS 可以为我们提供一种十分强大的搜索解决方案,我们可以用这个组合来建立获取及解析数据的高效应用。

准备工作

  1. 确保你本地已经安装了 Node.js、Npm/Yarn 和 NestJS CLI 工具
  2. 需要一个运行中的 Elasticsearch 实例。你可以在本地机器上进行安装或者在供应商处购买服务。

集成步骤

一、创建 NestJS 项目

首先,我们需要使用 NestJS CLI 工具创建一个新的 NestJS 项目。在你的命令行中输入以下命令:

shell
shell复制代码 nest new nest-elasticsearch-project

二、安装 @nestjs/elasticsearch 模块

在创建好 NestJS 项目后,我们要安装 Elasticsearch 模块。打开命令行,进入项目文件夹,然后输入以下命令:

shell
npm install --save @nestjs/elasticsearch @elastic/elasticsearch

这里,@nestjs/elasticsearch 是 NestJS 的 Elasticsearch 模块,@elastic/elasticsearch 是 ElasticSearch 提供的 Node.js 客户端。

三、配置 ElasticSearch Module

接着,我们需要在根模块 (app.module.ts) 中导入并配置 ElasticSearch Module。这个模块将允许我们在整个项目中使用 ElasticSearch。

typescript
// app.module.ts import { Module } from '@nestjs/common'; import { ElasticsearchModule } from '@nestjs/elasticsearch'; @Module({ imports: [ ElasticsearchModule.register({ node: 'http://localhost:9200', }), ], }) export class AppModule { }

在这个例子中,我们假设 ElasticSearch 在本地的 9200 端口运行。如果你的 ElasticSearch 实例运行在其他地方,根据你的实际情况修改 node 的配置。

四、创建服务支持使用 ElasticSearch

现在我们可以创建一个服务来使用 ElasticSearch 了。在这个服务中,我们可以注入 ElasticsearchService 来调用 ElasticSearch 的 API。

shell
nest generate service search

在生成的 search.service.ts 中,我们可以编写以下代码:

typescript
// search.service.ts import { Injectable } from '@nestjs/common'; import { ElasticsearchService } from '@nestjs/elasticsearch'; @Injectable() export class SearchService { constructor(private readonly elasticsearchService: ElasticsearchService) { } async search(query: string) { const { body } = await this.elasticsearchService.search({ index: 'your_index', body: { query: { match: { title: query }, }, }, }); return body.hits.hits.map(hit => hit._source); } }

上面的步骤中创建了一个 search 方法,这个方法会在指定的索引中搜索匹配查询的文档。

实战

ElasticSearch 的优势就是支持数据的模糊搜索,然后系统数据一般会存在MySQL这种持久性数据库。为了能够实现数据的模糊搜索,我们需要将MySQL的关键数据同步到 ElasticSearch,然后利用 ElasticSearch 的模糊搜索能力实现高级搜索功能。

接下来介绍整个流程的实现步骤:

一、使用 TypeORM 查询 MySQL 的数据

可以基于 typeorm 实现对MySQL数据的操作,但是不是本文的重点,可以参考我之前写的 NestJS集成 TypeORM 的教程https://www.levenx.com/article/how-to-implement-curd-restful-api-interface-using-nestjs-and-typeorm

二、ElasticSearch 中构建数据索引

使用 TypeORM 从 MySQL 数据库中获取数据,并使用 Elasticsearch 的 Node.js 客户端在 Elasticsearch 中索引这些数据。

typescript
// search.service.ts import { Injectable } from '@nestjs/common'; import { ElasticsearchService } from '@nestjs/elasticsearch'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { Article } from './article.entity'; @Injectable() export class SearchService { constructor( private readonly elasticsearchService: ElasticsearchService, @InjectRepository(Article) private readonly articleRepo: Repository<Article>, ) { } async **indexArticles**() { const articles = await this.articleRepo.find(); articles.forEach(async article => { await this.elasticsearchService.index({ index: 'articles', id: String(article.id), body: article, }); }); } }

三、ElasticSearch 执行模糊搜索

typescript
async search(query: string) { const { body } = await this.elasticsearchService.search({ index: 'articles', body: { query: { multi_match: { query, fields: ['title', 'content'], }, }, }, }); return body.hits.hits.map(hit => hit._source); }
typescript
async search(query: string) { const { body } = await this.elasticsearchService.search({ index: 'articles', body: { query: { fuzzy: { title: { value: query, }, }, }, }, }); return body.hits.hits.map(hit => hit._source); }

总结

Elasticsearch 是一个强大的搜索和分析引擎,而 NestJS 则是一个能够帮助我们创建可维护、可测试和可扩展的 Node.js 服务端应用的框架。将它们结合在一起,可以让我们更轻松地创建出能够拥有复杂搜索功能的应用。