아래 내용은 엘라스틱서치 적용 후 개인적인 이해를 돕기 위해 작성한 글입니다. 틀린 내용이 있다면 알려주세요.
엘라스틱서치는 독립적인 검색 서버로, 도커 컨테이너 또는 직접 설치한 서버 상에서 실행할 수 있다. 개발 및 테스트 단계에서 도커를 활용하면 설치와 실행이 간편하다. 배포할 때는 별도의 서버에 설치하는 것이 일반적이다.
엘라스틱서치는 NoSQL 형식의 데이터베이스로 분류될 수 있다. JSON 형식의 문서를 인덱스에 저장하여 빠른 검색과 분석을 가능하게 한다. 각 문서는 고유한 ID로 식별되며, 복잡한 검색 쿼리를 통해 실시간으로 데이터를 조회할 수 있다.
엘라스틱서치에서 데이터를 효율적으로 검색하고 분석하기 위해서는 인덱싱이 필수적이다. 인덱싱은 데이터를 엘라스틱서치의 구조에 맞게 변환하고 저장하는 과정으로, 이를 통해 빠른 검색 속도와 높은 성능을 달성할 수 있다. 데이터가 인덱싱되지 않은 상태에서는 원하는 정보를 신속하게 검색하거나 분석하는 것이 어렵다. 따라서, 엘라스틱서치를 사용하여 대량의 데이터를 관리하고 이를 기반으로 빠른 검색과 정확한 분석 결과를 얻고자 한다면, 적절한 인덱싱 전략을 수립하고 실행하는 것이 중요하다.
초기 인덱싱 이후, 추가되는 데이터에 대한 인덱싱에는 크게 두 가지 방법이 있다. 첫 번째 방법은 데이터가 생성되거나 변경될 때마다 실시간으로 인덱싱을 수행하는 것이다. 이 방법은 데이터의 변경 사항을 즉각적으로 반영할 수 있어 정보의 최신성을 유지하는 데 유리하다. 두 번째 방법은 주기적으로 데이터를 검사하여 변경 사항을 인덱싱하는 것이다. 이 방법은 시스템의 부하를 균등하게 분산시키고, 인덱싱 작업을 보다 체계적으로 관리할 수 있게 해준다. 데이터의 특성과 애플리케이션의 요구 사항에 따라 적절한 인덱싱 전략을 선택하는 것이 중요하다.
위 내용을 따라 내가 했던 과정은 다음과 같다.
.env
파일에 다음과 같은 변수를 추가 - 로컬에서 실행시 보통 9200포트가 사용된다.# .env 파일
ELASTICSEARCH_NODE= "http://localhost:9200"
# 터미널에서
npm install @elastic/elasticsearch
nest g module elasticsearch
nest g service elasticsearch
nest g controller elasticsearch
elasticsearch.service.ts
세팅//elasticsearch.service.ts
import { Injectable } from '@nestjs/common';
import { ElasticsearchService } from '@nestjs/elasticsearch';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Article } from 'src/article/entities/article.entity';
@Injectable()
export class SearchService {
constructor(
@InjectRepository(Article)
private readonly articleRepository: Repository<Article>,
private readonly esService: ElasticsearchService,
) {}
튜터님이 제공해주신 깃허브 레포지토리를 참고하여 상단에 임포트 해오는 ElasticsearchService
와 중복을 피하기 위해 class
를 SearchService
로 바꾸었다.
elasticsearch.module.ts
세팅//elasticsearch.module.ts
import { Module } from '@nestjs/common';
import { ElasticsearchModule } from '@nestjs/elasticsearch';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { SearchService } from './elasticsearch.service';
import { SearchController } from './elasticsearch.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Article } from 'src/article/entities/article.entity';
@Module({
imports: [
ElasticsearchModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
node: configService.get<string>('ELASTICSEARCH_NODE'),
}),
inject: [ConfigService],
}),
TypeOrmModule.forFeature([Article]),
],
providers: [SearchService],
controllers: [SearchController],
})
export class SearchModule {}
프로젝트 내에서 이미 ConfigService
를 통해 .env
의 환경변수들을 사용하고 있었기 때문에 위와 같이 불러왔다.
imports
부분의 ElasticsearchModule
는 @nestjs/elasticsearch
에서 불러오도록 하고, providers, controllers, export
의 이름은 다 바꾸어주었다.
SearchModule
id, title, writer
세가지만 인덱싱했다.//elasticsearch.service.ts
// 데이터를 인덱스(엘라스틱서치 형태로 주입)
async indexData(indexName: string, data: any) {
return await this.esService.index({
index: indexName,
body: data,
});
}
// 인덱스(테이블)를 생성
async createIndex(indexName: string) {
const { body: indexExists } = await this.esService.indices.exists({ index: indexName });
if (!indexExists) {
await this.esService.indices.create({ index: indexName });
}
}
//인덱스(테이블)를 삭제
async deleteIndex(indexName: string) {
const { body: indexExists } = await this.esService.indices.exists({ index: indexName });
if (indexExists) {
await this.esService.indices.delete({ index: indexName });
}
}
//기존에 있는 인덱스(테이블)를 삭제하고 새로 생성한 뒤 데이터를 넣는다.
async indexAllArticle() {
await this.deleteIndex('articles');
await this.createIndex('articles');
const articles = await this.articleRepository.find();
const indexPromises = articles.map((article) => {
const placeToIndex = {
id: article.id,
title: article.articleTitle,
writer: article.user,
};
return this.indexData('articles', placeToIndex);
});
return Promise.all(indexPromises);
}
service
의 기능을 만들었다면 컨트롤러에서 실행할 수 있는 세팅을 한다.//elasticsearch.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
import { SearchService } from './elasticsearch.service';
@Controller('api/es')
export class SearchController {
constructor(private readonly searchService: SearchService) {}
@Get('/article')
async indexing() {
const result = await this.searchService.indexAllArticle();
console.log('인덱싱');
return { message: '인덱싱함' };
}
}
- 검색기능을 구현하기 위해 `elasticsearch.service.ts`에 검색기능을 만들어준다.
//elasticsearch.service.ts
async search(index: string, query: any) {
const hits = await this.esService.search({
index,
body: query,
});
const result = hits.body.hits.hits.map((hit) => ({
id: hit._id,
...hit._source,
}));
return result;
}
컨트롤러에서 사용할 수 있도록 세팅한다.
//elasticsearch.controller.ts
@Controller('api/es')
export class SearchController {
constructor(private readonly searchService: SearchService) {}
//최종 경로 http://localhost:3000/api/es/search?title=검색어
@Get('search')
async search(@Query('title') title: string) {
const query = {
query: {
match: {
title: {
query: title,
fuzziness: 1,
},
},
},
};
return await this.searchService.search('articles', query);
}
http://localhost:3000/api/es/search?title=검색어
이제 위 경로로 가서 검색어를 입력하면 인덱싱한 데이터가 확인된다.
npm install @elastic/elasticsearch
로 받았던 엘라스틱서치는 수정이 필요하다."@elastic/elasticsearch": "^7.16.2",
선댓글 후감상입니다.