- Meilisearch 기반 일정 검색 API 구현 - 멤버 별명으로 검색 지원 (하냥 → 송하영) - 영문 자판 → 한글 변환 검색 지원 - 검색 응답 구조 개선 (category 객체, datetime 통합, members 배열) - 개발/배포 환경 Dockerfile 통합 (주석 전환 방식) - docker-compose.yml 단일 파일로 통합 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
92 lines
2.2 KiB
JavaScript
92 lines
2.2 KiB
JavaScript
import fp from 'fastify-plugin';
|
|
import { MeiliSearch } from 'meilisearch';
|
|
|
|
const INDEX_NAME = 'schedules';
|
|
|
|
async function meilisearchPlugin(fastify, opts) {
|
|
const { host, apiKey } = fastify.config.meilisearch;
|
|
|
|
const client = new MeiliSearch({
|
|
host,
|
|
apiKey,
|
|
});
|
|
|
|
// 연결 테스트 및 인덱스 초기화
|
|
try {
|
|
await client.health();
|
|
fastify.log.info('Meilisearch 연결 성공');
|
|
|
|
// 인덱스 초기화
|
|
await initIndex(client, fastify.log);
|
|
} catch (err) {
|
|
fastify.log.error('Meilisearch 연결 실패:', err.message);
|
|
// Meilisearch가 없어도 서버는 동작하도록 에러를 던지지 않음
|
|
}
|
|
|
|
fastify.decorate('meilisearch', client);
|
|
fastify.decorate('meilisearchIndex', INDEX_NAME);
|
|
}
|
|
|
|
/**
|
|
* 인덱스 초기화 및 설정
|
|
*/
|
|
async function initIndex(client, log) {
|
|
try {
|
|
// 인덱스 생성 (이미 존재하면 무시)
|
|
try {
|
|
await client.createIndex(INDEX_NAME, { primaryKey: 'id' });
|
|
} catch (err) {
|
|
// 이미 존재하는 경우 무시
|
|
}
|
|
|
|
const index = client.index(INDEX_NAME);
|
|
|
|
// 검색 가능한 필드 설정 (순서가 우선순위 결정)
|
|
await index.updateSearchableAttributes([
|
|
'title',
|
|
'member_names',
|
|
'description',
|
|
'source_name',
|
|
'category_name',
|
|
]);
|
|
|
|
// 필터링 가능한 필드 설정
|
|
await index.updateFilterableAttributes(['category_id', 'date']);
|
|
|
|
// 정렬 가능한 필드 설정
|
|
await index.updateSortableAttributes(['date', 'time']);
|
|
|
|
// 랭킹 규칙 설정 (동일 유사도일 때 최신 날짜 우선)
|
|
await index.updateRankingRules([
|
|
'words',
|
|
'typo',
|
|
'proximity',
|
|
'attribute',
|
|
'exactness',
|
|
'date:desc',
|
|
]);
|
|
|
|
// 오타 허용 설정
|
|
await index.updateTypoTolerance({
|
|
enabled: true,
|
|
minWordSizeForTypos: {
|
|
oneTypo: 2,
|
|
twoTypos: 4,
|
|
},
|
|
});
|
|
|
|
// 페이징 설정
|
|
await index.updatePagination({
|
|
maxTotalHits: 10000,
|
|
});
|
|
|
|
log.info('Meilisearch 인덱스 초기화 완료');
|
|
} catch (err) {
|
|
log.error('Meilisearch 인덱스 초기화 오류:', err.message);
|
|
}
|
|
}
|
|
|
|
export default fp(meilisearchPlugin, {
|
|
name: 'meilisearch',
|
|
dependencies: ['db'],
|
|
});
|