Nestjs项目实战 使用Elasticsearch进行全文搜索

在Nestjs项目中集成Elasticsearch进行全文搜索时,如何正确配置Elasticsearch模块?

我按照官方文档进行了基本配置,但始终无法建立连接,出现了"No Living connections"的错误提示。具体应该如何排查和解决这个问题?

另外,在Nestjs中创建Elasticsearch索引的最佳实践是什么?是否需要单独编写脚本,还是可以直接在应用启动时自动创建?

对于中文全文搜索,应该如何设置分词器和映射字段才能获得较好的搜索结果?能否分享一些实际项目中的配置示例?

最后,在性能方面,有哪些优化Elasticsearch查询效率的技巧?比如批量操作、缓存策略等方面的实践经验。


3 回复

在NestJS项目中使用Elasticsearch进行全文搜索,首先需要安装@nestjs/elasticsearchelasticsearch库。先配置Elasticsearch模块:

npm install @nestjs/elasticsearch elasticsearch

创建一个Elasticsearch服务:

import { Injectable } from '@nestjs/common';
import { Client, ElasticsearchService } from '@nestjs/elasticsearch';

@Injectable()
export class SearchService {
  constructor(private readonly elasticsearchService: ElasticsearchService) {}

  async indexDocument(index: string, id: string, body: any) {
    return this.elasticsearchService.index({ index, id, body });
  }

  async search(index: string, query: any) {
    return this.elasticsearchService.search({ index, body: query });
  }
}

接着,在控制器中使用该服务实现搜索功能:

import { Controller, Get, Param } from '@nestjs/common';
import { SearchService } from './search.service';

@Controller('search')
export class SearchController {
  constructor(private readonly searchService: SearchService) {}

  @Get(':index/_search')
  async search(@Param('index') index: string, @Body() query: any) {
    const result = await this.searchService.search(index, query);
    return result.body;
  }
}

最后,通过NestJS的依赖注入机制管理Elasticsearch客户端,完成全文搜索功能。记得在app.module.ts中注册ElasticsearchModule,并配置ElasticsearchClient选项。


在Nestjs项目中使用Elasticsearch进行全文搜索的步骤如下:

  1. 安装依赖
    首先需要安装[@nestjs](/user/nestjs)/elasticsearchelasticsearch包:

    npm install [@nestjs](/user/nestjs)/elasticsearch elasticsearch
    
  2. 配置Elasticsearch模块
    创建一个Elasticsearch服务,在app.module.ts中注册它:

    import { Module } from '[@nestjs](/user/nestjs)/common';
    import { ElasticsearchModule } from '[@nestjs](/user/nestjs)/elasticsearch';
    
    [@Module](/user/Module)({
      imports: [
        ElasticsearchModule.register({
          node: 'http://localhost:9200', // Elasticsearch地址
        }),
      ],
    })
    export class AppModule {}
    
  3. 创建数据模型
    假设我们有一个文章模型,包含标题和内容字段。首先在Elasticsearch中创建索引:

    import { Injectable } from '[@nestjs](/user/nestjs)/common';
    import { ElasticsearchService } from '[@nestjs](/user/nestjs)/elasticsearch';
    
    [@Injectable](/user/Injectable)()
    export class ArticleService {
      constructor(private readonly elastic: ElasticsearchService) {}
    
      async createIndex(indexName: string) {
        await this.elastic.indices.create({
          index: indexName,
          body: {
            mappings: {
              properties: {
                title: { type: 'text' },
                content: { type: 'text' },
              },
            },
          },
        });
      }
    }
    
  4. 实现全文搜索
    编写搜索方法,利用Elasticsearch的query_string查询:

    async search(indexName: string, query: string) {
      const result = await this.elastic.search({
        index: indexName,
        body: {
          query: {
            query_string: {
              query,
            },
          },
        },
      });
      return result.hits.hits;
    }
    
  5. 使用服务
    在控制器中调用服务进行搜索:

    [@Controller](/user/Controller)('articles')
    export class ArticleController {
      constructor(private readonly articleService: ArticleService) {}
    
      @Get('search')
      async search(@Query('q') query: string) {
        return this.articleService.search('article_index', query);
      }
    }
    

这样就完成了一个简单的基于Nestjs和Elasticsearch的全文搜索功能。

NestJS项目实战:使用Elasticsearch进行全文搜索

基本配置

首先安装必要的依赖:

npm install @nestjs/elasticsearch @elastic/elasticsearch

然后在NestJS模块中配置Elasticsearch:

// elasticsearch.module.ts
import { Module } from '@nestjs/common';
import { ElasticsearchModule } from '@nestjs/elasticsearch';

@Module({
  imports: [
    ElasticsearchModule.register({
      node: 'http://localhost:9200',
    }),
  ],
  exports: [ElasticsearchModule],
})
export class ElasticsearchCustomModule {}

服务层实现

创建一个搜索服务:

// search.service.ts
import { Injectable } from '@nestjs/common';
import { ElasticsearchService } from '@nestjs/elasticsearch';

@Injectable()
export class SearchService {
  constructor(private readonly elasticsearchService: ElasticsearchService) {}

  async createIndex(index: string) {
    return this.elasticsearchService.indices.create({ index });
  }

  async indexDocument(index: string, id: string, document: any) {
    return this.elasticsearchService.index({
      index,
      id,
      body: document,
    });
  }

  async search(index: string, query: string) {
    return this.elasticsearchService.search({
      index,
      body: {
        query: {
          multi_match: {
            query,
            fields: ['title', 'content'],
          },
        },
      },
    });
  }

  async deleteDocument(index: string, id: string) {
    return this.elasticsearchService.delete({
      index,
      id,
    });
  }
}

控制器实现

// search.controller.ts
import { Controller, Get, Post, Body, Query } from '@nestjs/common';
import { SearchService } from './search.service';

@Controller('search')
export class SearchController {
  constructor(private readonly searchService: SearchService) {}

  @Post('index')
  async indexDocument(
    @Body('index') index: string,
    @Body('id') id: string,
    @Body('document') document: any,
  ) {
    return this.searchService.indexDocument(index, id, document);
  }

  @Get()
  async search(@Query('q') query: string, @Query('index') index: string) {
    return this.searchService.search(index, query);
  }
}

高级功能

  1. 批量索引:
async bulkIndex(index: string, documents: Array<{id: string; document: any}>) {
  const body = documents.flatMap(doc => [
    { index: { _index: index, _id: doc.id } },
    doc.document,
  ]);
  
  return this.elasticsearchService.bulk({ body });
}
  1. 聚合查询:
async aggregateByField(index: string, field: string) {
  return this.elasticsearchService.search({
    index,
    body: {
      aggs: {
        group_by_field: {
          terms: { field }
        }
      }
    }
  });
}
  1. 分页查询:
async searchWithPagination(index: string, query: string, page: number, size: number) {
  return this.elasticsearchService.search({
    index,
    from: (page - 1) * size,
    size,
    body: {
      query: {
        multi_match: {
          query,
          fields: ['title', 'content'],
        },
      },
    },
  });
}

最佳实践

  1. 为不同的数据类型创建不同的索引
  2. 使用映射(mapping)定义字段类型
  3. 考虑使用别名(alias)来管理索引
  4. 实现重试机制处理连接问题
  5. 监控Elasticsearch集群健康状态

希望这个实战指南能帮助你在NestJS项目中集成Elasticsearch实现全文搜索功能!

回到顶部