[Node.js] 검색 기능2

Comely·2025년 6월 9일

Node.js

목록 보기
12/14

검색 기능 구현 과정

기본 흐름
1. 검색 UI 생성 → 사용자가 검색어 입력
2. 서버에서 DB 검색 → 검색어가 포함된 게시물 조회
3. 결과를 EJS로 전송 → 검색 결과 페이지 표시


1. 검색 UI 만들기

HTML 구조

<!-- list.ejs -->
<input class="search">
<button class="search-send">검색</button>

CSS 스타일링

.search {
  margin-left: 20px;
  padding: 5px;
}
.search-send {
  padding: 6px 10px;
  background: lightgray;
  border: none;
  border-radius: 5px;
  vertical-align: middle;
}

JavaScript로 검색 요청

<!-- list.ejs 하단 -->
<script>
  document.querySelector('.search-send').addEventListener('click', function(){
    let 입력한거 = document.querySelector('.search').value
    location.href = '/search?val=' + 입력한거
  })
</script>
  • location.href: 페이지 이동과 동시에 GET 요청 전송
  • Query String: URL에 검색어를 파라미터로 전달

2. 서버에서 검색 처리

기본 검색 (정확히 일치하는 제목)

app.get('/search', async (요청, 응답) => {
  let result = await db.collection('post').find({title: 요청.query.val}).toArray()
  응답.render('search.ejs', { 글목록: result })
})

정규식을 활용한 부분 검색

app.get('/search', async (요청, 응답) => {
  let result = await db.collection('post').find({
    title: { $regex: 요청.query.val }
  }).toArray()
  응답.render('search.ejs', { 글목록: result })
})
  • $regex 연산자: 특정 문자를 포함하는 모든 결과 검색
  • 단점: 모든 문서를 하나씩 검사하므로 속도가 느림

Database 검색 최적화

일반적인 검색 방식의 문제점

  • DB가 모든 문서를 하나씩 검사
  • 문서가 많을수록 검색 속도 급격히 저하
  • 1억 개 문서가 있으면 1억 개 모두 확인

Index의 필요성

  • Binary Search: 정렬된 데이터에서 반씩 나누어 검색
  • Index: 정렬된 컬렉션 복사본으로 빠른 검색 지원

Index 만들기와 활용

MongoDB에서 Index 생성
1. Collection → Indexes → Create Index
2. 필드명과 데이터 타입 설정

  • 문자: "title": "text"
  • 숫자: "title": 1

Text Index 활용한 검색

db.collection().find({
  $text: { $search: '안녕' }
}).toArray()

성능 확인

// 성능 비교
db.collection().find({title: '안녕'}).explain('executionStats')
db.collection().find({$text: {$search: '안녕'}}).explain('executionStats')
  • COLLSCAN: 전체 컬렉션 스캔 (느림)
  • Index 사용: 특정 문서만 검사 (빠름)

Index의 단점
1. 용량 증가: 컬렉션을 복사하여 저장하므로 용량 2배
2. 수정 시 부담: 문서 추가/수정/삭제 시 Index도 함께 수정
3. 정확한 단어만 검색: 한국어 조사나 어미 변화 검색 불가


동작 원리
1. 전처리: 불용어, 조사 제거 (은/는/이/가/을/를 등)
2. 단어 추출 및 정렬: 의미있는 단어들만 정렬하여 저장
3. 문서 위치 기록: 각 단어가 어떤 문서에 있는지 매핑
4. 점수 계산: 검색 정확도에 따른 Score 부여

Search Index 생성
1. Collection → Search Indexes → Create Index
2. Analyzer: lucene.korean 선택 (한국어 불용어 제거)
3. Dynamic Mapping: 끄기 (수동으로 필드 선택)
4. Field Mapping: 검색할 필드 지정 (예: title)

서버에서 Search Index 활용

app.get('/search', async (요청, 응답) => {
  let 검색조건 = [
    {
      $search: {
        index: '사용할 인덱스 이름',
        text: { 
          query: 요청.query.val, 
          path: 'title' 
        }
      }
    }
  ]
  let result = await db.collection('post').aggregate(검색조건).toArray()
  응답.render('search.ejs', { 글목록: result })
})

고급 검색 옵션

다양한 검색 조건 조합

let 검색조건 = [
  {
    $search: {
      index: '사용할 인덱스 이름',
      text: { query: '검색어', path: '검색할 필드이름' }
    }
  },
  { $sort: { _id: 1 } },        // 정렬 (기본값: score 순)
  { $limit: 10 },               // 결과 개수 제한
  { $skip: 5 },                 // 앞의 5개 건너뛰기
  { $project: { 제목: 1, _id: 0 } }  // 특정 필드만 반환
]

주요 연산자 설명

  • $sort: 검색 결과 정렬 (기본적으로 relevance score 순)
  • $limit: 결과 개수 제한 (페이지네이션에 유용)
  • $skip: 지정된 개수만큼 건너뛰기
  • $project: 반환할 필드 선택 (1: 포함, 0: 제외)

검색 결과 페이지네이션 예시

// 첫 번째 페이지: 3개씩, skip 0
{ $skip: 0 }, { $limit: 3 }

// 두 번째 페이지: 3개씩, skip 3  
{ $skip: 3 }, { $limit: 3 }

// 세 번째 페이지: 3개씩, skip 6
{ $skip: 6 }, { $limit: 3 }

Search Index의 장점

  • 자동 불용어 제거: 한국어 조사, 어미 자동 처리
  • 유연한 검색: '안녕' 검색 시 '안녕하세요', '안녕하십니까' 모두 검색
  • 자동 점수 계산: 검색 정확도에 따른 자동 순위 매김
  • 빠른 성능: 대용량 데이터에서도 빠른 검색 속도
profile
App, Web Developer

0개의 댓글