API with NestJS #12. Introduction to Elasticsearch

113 阅读1分钟

Elasticsearch Basics Learn

Running Elasticsearch

version: "3"
services:
  postgres:
    container_name: postgres
    image: postgres:latest
    ports:
      - "5432:5432"
    volumes:
      - ~/data/postgres:/data/postgres
    env_file:
      - docker.env
    networks:
      - postgres
 
  pgadmin:
    links:
      - postgres:postgres
    container_name: pgadmin
    image: dpage/pgadmin4
    ports:
      - "8080:80"
    volumes:
      - ~/data/pgadmin:/root/.pgadmin
    env_file:
      - docker.env
    networks:
      - postgres
 
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.8.2
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es02,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
      - xpack.security.enabled=false
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ~/data/elasticsearch/data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    depends_on:
      - es01
    image: docker.elastic.co/elasticsearch/elasticsearch:8.8.2
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
      - xpack.security.enabled=false
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ~/data/elasticsearch/data02:/usr/share/elasticsearch/data
    networks:
      - elastic
  es03:
    depends_on:
      - es02
    image: docker.elastic.co/elasticsearch/elasticsearch:8.8.2
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - ES_JAVA_OPTS=-Xms1g -Xmx1g
      - xpack.security.enabled=false
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ~/data/elasticsearch/data03:/usr/share/elasticsearch/data
    networks:
      - elastic
 
 
networks:
  postgres:
    driver: bridge
  elastic:
    driver: bridge
docker-compose up

The default username is “elastic“, we set password '123456' in docker-compose.yml

edit .env

POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=admin
POSTGRES_PASSWORD=admin
POSTGRES_DB=nestjs
PORT=5001

JWT_SECRET=JWT_SECRET
# time unit is second
JWT_EXPIRATION_TIME=20000

ELASTICSEARCH_NODE=http://localhost:9200
ELASTICSEARCH_USERNAME=elastic
ELASTICSEARCH_PASSWORD=123456
nest g res modules/search --no-spec
// src/modules/search/search.module.ts
import { Module } from '@nestjs/common';
import { SearchService } from './search.service';
import { SearchController } from './search.controller';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { ElasticsearchModule } from '@nestjs/elasticsearch';

@Module({
  imports: [
    ConfigModule,
    ElasticsearchModule.registerAsync({
      imports: [ConfigModule],
      useFactory: async (configService: ConfigService) => ({
        node: configService.get('ELASTICSEARCH_HOST'),
        auth: {
          username: configService.get('ELASTICSEARCH_USERNAME'),
          password: configService.get('ELASTICSEARCH_PASSWORD'),
        },
      }),
      inject: [ConfigService],
    }),
  ],
  controllers: [SearchController],
  providers: [SearchService],
})
export class SearchModule {}

Populating Elasticsearch with data

// src/modules/posts/interface/post-search-body.interface.ts
export interface PostSearchBody {
  id: number;
  title: string;
  content: string;
  authorId: number;
}
// src/modules/posts/posts-search.service.ts
import { Injectable } from '@nestjs/common';
import { ElasticsearchService } from '@nestjs/elasticsearch';
import { PostEntity } from './entities/post.entity';
import {
  PostSearchBody,
  PostSearchResult,
} from './interface/post-search-body.interface';

@Injectable()
export default class PostsSearchService {
  index = 'posts';

  constructor(private readonly elasticsearchService: ElasticsearchService) {}

  async indexPost(post: PostEntity) {
    return this.elasticsearchService.index<PostSearchBody>({
      index: this.index,
      body: {
        id: post.id,
        title: post.title,
        content: post.content,
        authorId: post.author.id,
      },
    });
  }

  async search(text: string) {
    // has error, 
    // TODO: solve the error
    const { hits } = await this.elasticsearchService.search<PostSearchResult>({
      index: this.index,
      body: {
        query: {
          multi_match: {
            query: text,
            fields: ['title', 'content'],
          },
        },
      },
    });
    const searchedHits = hits.hits;
    return searchedHits.map((item) => item._source);
  }
}

because of lack of elk basics, stucked here, i will update it later, sorry.

resources