개요

OpenSearch는 Apache 2.0 라이선스의 오픈소스 검색 및 분석 엔진입니다. 이 가이드에서는 macOS에서 Docker Compose를 사용하여 OpenSearch 3.2, Nori 플러그인, OpenSearch Dashboards를 함께 설치하는 방법을 설명합니다.

왜 Docker를 사용해야 하는가?

macOS에서 OpenSearch를 설치할 때 Docker를 사용하는 것이 권장되는 이유는 다음과 같습니다:

1. k-NN 플러그인의 macOS 비지원

k-NN (k-Nearest Neighbors) 플러그인은 벡터 검색 기능을 제공하는 핵심 플러그인입니다. 그러나 이 플러그인은 macOS에서 공식적으로 지원되지 않습니다1.

  • Homebrew로 OpenSearch를 설치한 후 k-NN 플러그인을 설치하려고 하면 실패합니다
  • k-NN 플러그인은 네이티브 라이브러리(NMSLIB, Faiss)를 포함하고 있어 Linux와 Windows에서만 지원됩니다
  • macOS에서 벡터 검색 기능을 사용하려면 Docker를 통해 Linux 환경을 구성해야 합니다

2. Docker 이미지의 장점

OpenSearch 공식 Docker 이미지를 사용하면 다음과 같은 이점이 있습니다:

  • k-NN 플러그인 기본 포함: 별도 설치 없이 바로 벡터 검색 사용 가능
  • 일관된 환경: macOS, Linux, Windows에서 동일하게 작동
  • 클린 설치/제거: 컨테이너 삭제만으로 완전히 제거 가능
  • 버전 관리 용이: 이미지 태그로 원하는 버전 선택 가능
  • 개발/프로덕션 환경 일치: 동일한 환경에서 테스트 및 배포 가능

3. 추가 플러그인 설치의 유연성

Docker를 사용하면 커스텀 Dockerfile을 통해 필요한 플러그인(예: Nori)을 쉽게 추가할 수 있습니다.

사전 요구사항

  • macOS (Apple Silicon 또는 Intel)
  • Docker Desktop for Mac 설치

Nori 플러그인이란?

Nori는 한국어 형태소 분석을 위한 플러그인입니다. Lucene의 nori 분석 모듈을 기반으로 하며, 한글 텍스트를 의미 있는 토큰으로 분해하여 검색 품질을 향상시킵니다.

주요 기능:

  • nori_tokenizer: 한국어 텍스트를 형태소 단위로 토큰화
  • nori_part_of_speech: 품사 기반 토큰 필터링
  • nori_readingform: 토큰을 읽기 형태로 변환
  • nori_number: 숫자 토큰 처리

OpenSearch Dashboards란?

OpenSearch Dashboards는 OpenSearch의 공식 시각화 및 관리 도구입니다 (Elasticsearch의 Kibana와 유사).

주요 기능:

  • 인덱스 관리: 인덱스 생성, 수정, 삭제를 GUI에서 수행
  • Dev Tools: SQL과 같은 쿼리 언어로 데이터 조회 및 테스트
  • 대시보드: 데이터 시각화 및 차트 생성
  • Discover: 인덱스 데이터 탐색 및 검색

설치 방법

1. Dockerfile 생성

Nori 플러그인이 포함된 커스텀 OpenSearch 이미지를 만들기 위해 프로젝트 디렉토리에 Dockerfile을 작성합니다:

FROM opensearchproject/opensearch:3.2.0
 
# Nori 플러그인 설치
RUN /usr/share/opensearch/bin/opensearch-plugin install analysis-nori --batch
 
# 권한 설정
USER opensearch

2. 이미지 빌드

Dockerfile이 있는 디렉토리에서 커스텀 이미지를 빌드합니다:

docker build -t opensearch-with-nori:3.2.0 .

3. Docker Compose 파일 생성

같은 디렉토리에 docker-compose.yml 파일을 생성합니다:

services:
  opensearch:
    image: opensearch-with-nori:3.2.0
    container_name: opensearch-node
    restart: unless-stopped  # 재부팅 시 자동 시작
    environment:
      - cluster.name=opensearch-cluster
      - node.name=opensearch-node
      - discovery.type=single-node
      - bootstrap.memory_lock=true
      - "OPENSEARCH_JAVA_OPTS=-Xms4g -Xmx4g"  # 힙 메모리 4GB (벡터 검색용)
      - DISABLE_SECURITY_PLUGIN=true  # 보안 플러그인 비활성화
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 65536
        hard: 65536
    volumes:
      - opensearch-data:/usr/share/opensearch/data
    ports:
      - 9200:9200
      - 9600:9600
    networks:
      - opensearch-net
 
  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:3.2.0
    container_name: opensearch-dashboards
    restart: unless-stopped  # 재부팅 시 자동 시작
    ports:
      - 5601:5601
    expose:
      - "5601"
    environment:
      OPENSEARCH_HOSTS: '["http://opensearch-node:9200"]'  # HTTP 사용
      DISABLE_SECURITY_DASHBOARDS_PLUGIN: "true"  # Dashboard 보안 비활성화
    networks:
      - opensearch-net
    depends_on:
      - opensearch
 
volumes:
  opensearch-data:
 
networks:
  opensearch-net:

4. 서비스 시작

# 백그라운드에서 실행
docker-compose up -d
 
# 로그 확인
docker-compose logs -f

5. 설치 확인

설치가 정상적으로 완료되었는지 확인합니다:

# OpenSearch 실행 확인
curl -XGET http://localhost:9200
 
# 설치된 플러그인 확인 (analysis-nori와 opensearch-knn이 포함되어 있어야 함)
curl -XGET http://localhost:9200/_cat/plugins?v

OpenSearch Dashboards 접속:

  • 브라우저에서 http://localhost:5601 접속
  • 별도 로그인 없이 바로 사용 가능

6. 서비스 관리 명령어

# 서비스 중지
docker-compose down
 
# 볼륨까지 완전히 제거 (데이터 삭제)
docker-compose down -v
 
# 서비스 재시작
docker-compose restart
 
# 로그 실시간 확인
docker-compose logs -f opensearch

7. 메모리 설정 조정

기본 설정은 힙 메모리 4GB로 되어 있습니다. 데이터 양에 따라 조정이 필요할 수 있습니다:

메모리 권장 사양:

  • 테스트/소규모 데이터: 2GB (-Xms2g -Xmx2g)
  • 중규모 데이터: 4GB (-Xms4g -Xmx4g)
  • 대규모 벡터 데이터: 8GB 이상 (-Xms8g -Xmx8g 이상)

참고:

  • k-NN 벡터 인덱스는 메모리에 로드되므로, 벡터 데이터가 많을수록 더 많은 메모리가 필요합니다
  • -Xms(초기 힙)와 -Xmx(최대 힙)는 동일한 값으로 설정하는 것이 권장됩니다 (GC 성능 최적화)
  • Docker Desktop for Mac의 메모리 설정이 충분한지 확인하세요 (Settings → Resources → Memory)

사용 예제

Nori 한국어 분석기 사용

인덱스 생성 및 분석기 설정

Nori 분석기를 사용하는 인덱스를 생성합니다:

curl -X PUT "http://localhost:9200/korean-index" \
  -H 'Content-Type: application/json' -d'
{
  "settings": {
    "analysis": {
      "tokenizer": {
        "nori_user_dict": {
          "type": "nori_tokenizer",
          "decompound_mode": "mixed"
        }
      },
      "analyzer": {
        "korean_analyzer": {
          "type": "custom",
          "tokenizer": "nori_tokenizer",
          "filter": ["nori_part_of_speech"]
        }
      }
    }
  }
}
'

분석 테스트

Nori 분석기가 한글을 어떻게 분석하는지 테스트:

curl -X POST "http://localhost:9200/korean-index/_analyze" \
  -H 'Content-Type: application/json' -d'
{
  "analyzer": "korean_analyzer",
  "text": "OpenSearch는 강력한 검색 엔진입니다"
}
'

응답에서 한글 텍스트가 형태소 단위로 분해된 결과를 확인할 수 있습니다.

k-NN 벡터 검색 사용

Docker 이미지에는 k-NN 플러그인이 기본으로 포함되어 있으므로, 바로 벡터 검색을 사용할 수 있습니다.

벡터 인덱스 생성

k-NN 벡터 검색을 사용하려면 인덱스 설정에서 index.knn: true를 활성화하고, 필드 매핑에서 method 파라미터를 지정해야 합니다:

PUT /hotels-index
{
  "settings": {
    "index.knn": true
  },
  "mappings": {
    "properties": {
      "location": {
        "type": "knn_vector",
        "dimension": 2,
        "method": {
          "name": "hnsw",
          "space_type": "l2",
          "engine": "lucene"
        }
      }
    }
  }
}

주요 파라미터:

  • settings:
    • index.knn: k-NN 검색 기능 활성화 (필수)
  • mappings:
    • type: knn_vector로 지정
    • dimension: 벡터의 차원 (이 예제에서는 2차원)
    • method: ANN 검색 알고리즘 설정
      • name: 알고리즘 이름 (HNSW 권장)
      • space_type: 거리 측정 방식 (l2, cosinesimil, innerproduct 등)
      • engine: 벡터 엔진 (lucene, nmslib, faiss 등)

참고: OpenSearch 3.0부터는 k-NN 관련 파라미터(예: ef_construction, m, space_type)가 인덱스 레벨 설정에서 제거되었으며, 이러한 파라미터는 필드 매핑의 method 섹션에서 지정해야 합니다2.

벡터 데이터 색인

인덱스에 호텔 위치 데이터를 추가합니다. 각 문서는 2차원 벡터로 호텔의 위치를 나타냅니다:

POST /_bulk
{ "index": { "_index": "hotels-index", "_id": "1" } }
{ "location": [5.2, 4.4] }
{ "index": { "_index": "hotels-index", "_id": "2" } }
{ "location": [5.2, 3.9] }
{ "index": { "_index": "hotels-index", "_id": "3" } }
{ "location": [4.9, 3.4] }
{ "index": { "_index": "hotels-index", "_id": "4" } }
{ "location": [4.2, 4.6] }
{ "index": { "_index": "hotels-index", "_id": "5" } }
{ "location": [3.3, 4.5] }

가장 가까운 호텔 검색

특정 위치 [5, 4]에서 가장 가까운 호텔 상위 3개를 검색합니다:

POST /hotels-index/_search
{
  "size": 3,
  "query": {
    "knn": {
      "location": {
        "vector": [5, 4],
        "k": 3
      }
    }
  }
}

검색 결과는 가장 가까운 3개의 호텔(ID 2, 1, 3)을 반환하며, 각각의 유사도 점수는 0.952381, 0.8333333, 0.72992706입니다.

문제 해결

컨테이너가 시작되지 않는 경우

컨테이너 로그를 확인하여 문제를 진단합니다:

# 단일 컨테이너 로그 확인
docker logs opensearch-node
 
# Docker Compose 로그 확인
docker-compose logs opensearch

참고 자료

Footnotes

  1. GitHub Issue #2197 - k-NN plugin installation fails on macOS

  2. OpenSearch k-NN 3.0.0 Breaking Changes