728x90
반응형

Elasticsearch를 사용할 때 문서의 title 필드에서 특정 단어가 포함된 문서를 찾으려고 matchmatch_phrase 쿼리를 사용했는데, 기대한 결과가 나오지 않는 경우가 있습니다. 본 글에서는 그 이유를 정리하고, Elasticsearch에 적합한 문서 제목 명명 규칙에 대해 안내합니다.


🔍 문제 상황: title 검색이 안 되는 이유

예를 들어 문서에 다음과 같은 title 값이 있다고 가정합니다.

"title": "Title_Including_Word"

이 문서에서 "Shaft" 라는 단어가 포함된 문서를 찾기 위해 아래와 같은 쿼리를 사용했지만 결과가 0이 나왔습니다.

{
  "query": {
    "match": {
      "title": "Word"
    }
  }
}

혹은 아래와 같은 match_phrase 쿼리를 사용했을 때도 결과가 나오지 않았습니다.

{
  "query": {
    "match_phrase": {
      "title": "Word"
    }
  }
}

✅ 이유는?

  • title 필드가 text 타입이며 기본 standard analyzer를 사용하고 있는 상태에서,
  • "Title_Including_Word"은 하나의 토큰(단어) 으로 분석됨
    (_ 언더스코어는 기본 analyzer에서 단어 구분자가 아님)
  • 따라서 "Word"와 같은 개별 단어는 존재하지 않는 것으로 인식되어 검색되지 않음

✅ 해결 방법

1. regexp 쿼리 사용

text 타입 필드에서 특정 단어가 포함된 문서를 찾고 싶다면 regexp 쿼리를 사용할 수 있습니다.

{
  "query": {
    "regexp": {
      "title": ".*[Ww]ord.*"
    }
  }
}
  • 대소문자 구분을 피하고 싶다면 정규식 안에 [Ss]와 같이 처리
  • 단점: regexp 쿼리는 느릴 수 있고, 복잡한 검색에는 부적합할 수 있음

2. wildcard 쿼리 사용 (단, keyword 필드가 있을 경우에만)

{
  "query": {
    "wildcard": {
      "title.keyword": {
        "value": "*word*",
        "case_insensitive": true
      }
    }
  }
}
  • 단, title.keyword 필드가 존재해야 동작함 (text 필드의 서브 필드로 keyword 타입이 있어야 함)
  • 현재 인덱스 매핑에 keyword 서브 필드가 없다면 사용 불가

📘 문서 제목(title) 명명 방식 가이드

검색 효율성과 정밀도를 높이기 위해 title 필드의 값을 어떻게 구성하는 것이 좋은지에 대한 가이드입니다.

명명 방식 예시 검색 친화도 비고
띄어쓰기 기반 "Title Including Word" ✅ 매우 좋음 analyzer가 자연스럽게 토큰화
kebab-case (-) "title-including-word" ✅ 좋음 - 는 토큰 구분자로 인식됨
snake_case (_) "title_including_word" ❌ 안 좋음 _ 는 기본 analyzer가 분리 못함
camelCase "titleIncludingWord" ❌ 안 좋음 전체가 한 단어로 인식됨

✅ 추천

  • 사람에게 보여질 title, content, summary 같은 필드는 띄어쓰기 기반 자연어 문장 사용
  • 시스템에서 사용하는 id, slug, key 등은 snake_case 또는 kebab-case + keyword 타입 필드로 구성

🧠 팁: 매핑 설정 시 title에 .keyword 필드 추가하기

"title": {
  "type": "text",
  "fields": {
    "keyword": {
      "type": "keyword"
    }
  }
}

이렇게 하면 full-text 검색(text)과 exact match / wildcard 검색(keyword)을 모두 지원할 수 있어 유연성이 높아집니다.


✨ 결론

  • 기본 analyzer는 _를 단어 구분자로 인식하지 않기 때문에 match나 match_phrase로 검색되지 않는 문제가 생길 수 있음
  • 가능하다면 제목은 띄어쓰기 기반으로 작성하거나, 검색 목적에 맞는 필드(keyword)를 함께 설정하는 것이 좋음
  • 정규식이나 wildcard 검색을 사용할 수는 있지만 성능을 고려해 선택적으로 사용하자
반응형
728x90
반응형

이 글에서는 Ubuntu 서버에 Jira를 설치하기 위한 과정을 다룹니다. JDK(Java Development Kit) 설치부터, Jira에서 사용할 PostgreSQL 데이터베이스 설치 및 설정, 마지막으로 Jira 설치까지 순차적으로 안내합니다.


1. JDK(Java Development Kit) 설치

Jira는 Java 기반 애플리케이션이므로 Java 11 이상이 필요합니다. OpenJDK를 설치하는 방법은 다음과 같습니다.

1.1. 저장소 업데이트 및 Java 설치

sudo apt update
sudo apt install openjdk-11-jdk

1.2. 설치 확인

Java가 제대로 설치되었는지 확인합니다.

java -version

2. PostgreSQL 설치 및 설정

Jira는 다양한 데이터베이스를 지원하지만, PostgreSQL이 권장됩니다. 이제 PostgreSQL을 설치하고, Jira에서 사용할 데이터베이스를 생성합니다.

2.1. PostgreSQL 설치

sudo apt install postgresql postgresql-contrib

2.2. PostgreSQL 서비스 상태 확인

설치 후 PostgreSQL이 실행 중인지 확인합니다.

sudo systemctl status postgresql

2.3. PostgreSQL 데이터베이스 및 사용자 생성

postgres 사용자로 전환하여 PostgreSQL에 접속합니다.

sudo -i -u postgres
psql

이후, Jira에서 사용할 데이터베이스와 사용자를 생성합니다.

CREATE DATABASE jiradb WITH ENCODING 'UTF8' LC_COLLATE='en_US.UTF-8' LC_CTYPE='en_US.UTF-8' TEMPLATE=template0;
CREATE USER jirauser WITH PASSWORD 'your_password';
GRANT ALL PRIVILEGES ON DATABASE jiradb TO jirauser;

3. Jira 설치

이제 Jira를 설치합니다. 먼저 Atlassian에서 제공하는 .bin 파일을 다운로드하고, 설치를 진행합니다.

3.1. Jira 설치 파일 다운로드

wget https://www.atlassian.com/software/jira/downloads/binary/atlassian-jira-software-9.12.0-x64.bin

3.2. 파일 실행 권한 부여 및 설치

chmod +x atlassian-jira-software-9.12.0-x64.bin
sudo ./atlassian-jira-software-9.12.0-x64.bin

설치 중, 몇 가지 질문에 대한 답을 설정하면 기본적으로 Jira가 설치됩니다.


4. 추가 설정 및 유지보수

4.1. Jira 로그 확인

만약 Jira가 제대로 시작되지 않으면, 로그 파일을 확인하여 문제를 진단할 수 있습니다.

cat /opt/atlassian/jira/logs/catalina.out

4.2. Jira 시작, 중지, 재시작 상태 확인

Jira를 제어하기 위한 명령어입니다.

sudo service jira start
sudo service jira stop
sudo service jira restart
sudo service jira status
반응형
728x90
반응형

Python 프로젝트를 시작할 때, 의존성 관리와 가상환경 설정을 효율적으로 처리하려면 Poetry를 사용하는 것이 좋습니다. 이 글에서는 Poetry를 이용해 Python 패키지를 초기화하는 과정을 단계별로 설명합니다.


1. Poetry란?

Poetry는 Python 프로젝트의 의존성 관리, 가상환경 설정, 그리고 패키징을 쉽게 해주는 도구입니다. 기존의 piprequirements.txt를 사용하는 방식보다 더 현대적이고 강력한 기능을 제공합니다.

주요 기능:

  • 의존성 추가 및 관리 (dependencies, dev-dependencies 분리)
  • 가상환경 자동 생성 및 관리
  • 프로젝트 설정 파일 (pyproject.toml) 생성
  • 배포 준비 (패키징 및 배포 기능 포함)

2. Poetry 설치

Poetry는 Python 패키지로 설치할 수 있습니다. 아래 명령어를 실행해 설치하세요:

pip install poetry

설치 확인:

poetry --version

3. 프로젝트 디렉토리 생성

먼저 프로젝트 디렉토리를 생성합니다:

mkdir my_project && cd my_project

여기서 my_project는 프로젝트 이름입니다.


4. Poetry로 프로젝트 초기화

Poetry를 이용해 프로젝트를 초기화합니다:

poetry init

이 명령어를 실행하면 대화형 프롬프트가 나타납니다. 아래는 입력 예시입니다:

This command will guide you through creating your pyproject.toml config.

Package name [my_project]:  
Version [0.1.0]:  
Description []: A sample Python project using Poetry
Author []: Your Name <your.email@example.com>
License []: MIT
Compatible Python versions [^3.8]: ^3.8
Would you like to define your main dependencies interactively? (yes/no) [yes]: no
Would you like to define your development dependencies interactively? (yes/no) [yes]: no

입력이 끝나면 프로젝트의 기본 설정이 pyproject.toml 파일에 저장됩니다.


5. 의존성 추가

Poetry를 사용해 프로젝트의 의존성을 추가합니다.

런타임 의존성 추가

예를 들어, Flask와 Requests 라이브러리를 추가하려면:

poetry add flask requests

개발 의존성 추가

테스트와 코드 품질 관리를 위해 pytestblack을 개발 의존성으로 추가:

poetry add --dev pytest black

6. 가상환경 관리

Poetry는 기본적으로 프로젝트 디렉토리 외부에 가상환경을 생성합니다. 가상환경을 활성화하려면:

poetry shell

가상환경을 종료하려면:

exit

가상환경이 어디에 생성되었는지 확인하려면:

poetry env info

7. 디렉토리 구조 설정

아래와 같은 기본 디렉토리 구조를 생성합니다:

mkdir src tests
mkdir src/my_project

src/my_project/__init__.py 파일을 생성하여 패키지로 인식되도록 설정:

touch src/my_project/__init__.py

테스트 디렉토리에도 기본 테스트 파일을 추가합니다:

touch tests/test_basic.py

8. 파일 생성

README 파일

프로젝트 설명을 위한 README.md 파일을 생성합니다:

echo "# My Project\nA sample Python project using Poetry." > README.md

.gitignore 파일

Git에 추가되지 않아야 할 파일을 정의하는 .gitignore 파일을 생성합니다:

curl https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore -o .gitignore

9. 스크립트 실행

가상환경에서 스크립트를 실행하려면:

poetry run python src/my_project/__init__.py

10. 최종 디렉토리 구조

설정을 완료한 뒤, 최종 디렉토리 구조는 아래와 같습니다:

my_project/
├── src/
│   └── my_project/
│       └── __init__.py
├── tests/
│   └── test_basic.py
├── README.md
├── .gitignore
├── pyproject.toml
├── poetry.lock

11. Poetry의 추가 기능

의존성 설치

pyproject.toml 파일에 정의된 의존성을 설치하려면:

poetry install

패키지 빌드

프로젝트를 패키징하려면:

poetry build

패키지 배포

PyPI에 패키지를 배포하려면:

poetry publish

결론

Poetry를 사용하면 Python 프로젝트의 초기화부터 의존성 관리, 패키징까지 모든 과정을 간단하고 체계적으로 관리할 수 있습니다. 위 과정을 따라가며 프로젝트를 시작해 보세요!

반응형
728x90
반응형

Vue.js는 컴포넌트 기반 아키텍처를 제공하여 확장 가능하고 유지보수가 용이한 애플리케이션을 구축하는 데 강력한 프레임워크입니다. Vue의 핵심 기능 중 하나인 Scoped CSS는 컴포넌트 내에서 정의된 스타일이 해당 컴포넌트에만 적용되도록 보장하여 애플리케이션 전반에 걸친 의도치 않은 스타일 영향력을 방지합니다. 그러나 v-html과 같은 동적 콘텐츠 렌더링 방식을 사용할 때 Scoped CSS를 효과적으로 적용하는 데 어려움을 겪을 수 있습니다.

이 블로그 포스트에서는 Scoped 스타일과 v-html과 관련된 일반적인 문제를 살펴보고, 그 근본 원인을 이해하며, Vue의 최신 기능을 활용하여 이를 해결하는 방법에 대해 논의하겠습니다.

목차

  1. Vue의 Scoped CSS 이해하기
  2. v-html의 도전 과제
  3. 문제 식별하기
  4. 해결 방법: :deep() 선택자 사용하기
  5. 최고의 실천 방법
  6. 결론

Vue의 Scoped CSS 이해하기

Scoped CSS는 컴포넌트에 특정한 스타일을 작성할 수 있게 해줍니다. 이는 컴포넌트 내에서 정의된 스타일이 다른 컴포넌트에 영향을 미치지 않도록 보장합니다. Vue는 각 요소에 고유한 데이터 속성을 자동으로 추가하여 스타일의 적용 범위를 제한합니다.

Scoped CSS의 예제

<template>
  <div class="example">
    <p>이것은 scoped된 단락입니다.</p>
  </div>
</template>

<script setup lang="ts">
</script>

<style scoped>
.example {
  background-color: #f0f0f0;
}

p {
  color: blue;
}
</style>

위 예제에서:

  • .example 클래스와 p 태그에 대한 스타일은 해당 컴포넌트에만 적용됩니다.
  • 다른 컴포넌트에서 동일한 클래스나 태그가 있어도 영향을 받지 않습니다.

v-html의 도전 과제

Vue의 v-html 디렉티브는 동적으로 원시 HTML 콘텐츠를 렌더링할 수 있게 해줍니다. 이는 API에서 가져온 콘텐츠나 사용자 생성 콘텐츠를 표시할 때 유용합니다. 그러나 Scoped CSS를 사용하는 컴포넌트 내에서 v-html을 사용할 경우, 동적으로 렌더링된 콘텐츠에 스타일이 예상대로 적용되지 않는 문제가 발생할 수 있습니다.

왜 이런 일이 발생할까요?

Scoped CSS는 컴포넌트의 요소에 고유한 속성을 추가하여 스타일을 적용합니다. 그러나 v-html을 통해 렌더링된 콘텐츠는 이러한 고유 속성을 받지 않기 때문에 Scoped 스타일이 적용되지 않습니다.

예제 시나리오

다음은 v-html을 사용하여 마크다운 콘텐츠를 렌더링하는 컴포넌트 예제입니다:

<template>
  <div class="content" v-html="renderedContent"></div>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import MarkdownIt from 'markdown-it'

const props = defineProps(['content'])

const markdownParser = new MarkdownIt({
  html: true,
  breaks: true,
  linkify: true,
})

const renderedContent = computed(() => {
  return markdownParser.render(props.content || '')
})
</script>

<style scoped>
.content {
  font-family: Arial, sans-serif;
  color: #333;
}

ul, ol {
  padding-left: 20px;
}
</style>

이 예제에서:

  • 컴포넌트는 v-html을 사용하여 마크다운 콘텐츠를 렌더링합니다.
  • ulol 요소에 패딩을 적용하려 하지만, Scoped CSS로 인해 스타일이 적용되지 않습니다.

문제 식별하기

Scoped 스타일을 v-html과 함께 사용하면 동적으로 삽입된 HTML에 고유한 속성이 적용되지 않아 스타일이 의도대로 적용되지 않는 문제가 발생합니다. 특히 ul, ol, li 요소에서 들여쓰기가 제대로 적용되지 않는 현상이 나타날 수 있습니다.

일반적인 문제점

  • 들여쓰기 부족: 리스트(ul, ol)에 원하는 들여쓰기가 적용되지 않습니다.
  • 스타일 미적용: v-html을 통해 삽입된 다른 HTML 요소에도 스타일이 적용되지 않습니다.

해결 방법: :deep() 선택자 사용하기

Vue는 Scoped CSS의 경계를 넘어 자식 컴포넌트나 특정 요소에 스타일을 적용할 수 있는 :deep() 선택자를 제공합니다. 이는 v-html로 렌더링된 콘텐츠에 스타일을 적용하는 데 특히 유용합니다.

:deep()인가?

  • Scoped 스타일 유지: Scoped 스타일의 이점을 유지하면서 특정 요소에 스타일을 적용할 수 있습니다.
  • 유연성 제공: Scoped CSS의 제한을 우회하여 필요한 부분에만 스타일을 적용할 수 있습니다.

deprecated된 ::v-deep 대체

과거에는 ::v-deep 조합자를 사용하여 유사한 결과를 얻었지만, 이제는 ::v-deep이 deprecated 되어 :deep() 구문을 사용하는 것이 권장됩니다.

구문

:deep(selector) {
  /* 스타일 정의 */
}

최고의 실천 방법

  1. 가능한 한 Scoped CSS 사용 유지:

    • 컴포넌트 스타일의 격리를 유지하여 의도치 않은 스타일 영향력을 방지합니다.
  2. 동적 콘텐츠에는 :deep() 활용:

    • v-html이나 자식 컴포넌트에 스타일을 적용할 때 :deep()을 선택적으로 사용합니다.
  3. 전역 스타일의 과도한 사용 피하기:

    • scoped 속성을 제거하고 전역 스타일을 사용하는 것은 스타일 충돌을 유발할 수 있으므로 신중하게 사용합니다.
  4. 스타일 정리 및 주석 추가:

    • :deep()을 사용하는 부분에 명확한 주석을 추가하여 코드의 가독성을 높입니다.
  5. 컴포넌트 간 스타일 충돌 테스트:

    • :deep()으로 적용한 스타일이 다른 컴포넌트에 영향을 미치지 않는지 확인합니다.

결론

Vue.js에서 동적으로 렌더링된 콘텐츠를 스타일링하는 것은 Scoped CSS와 v-html 디렉티브를 사용할 때 도전 과제가 될 수 있습니다. 그러나 :deep() 선택자를 활용하면 Scoped 스타일의 이점을 유지하면서도 특정 요소에 필요한 스타일을 적용할 수 있습니다. 이를 통해 v-html로 삽입된 ul, ol 요소의 들여쓰기가 정상적으로 적용되며, 스타일 충돌 없이 깔끔한 UI를 유지할 수 있습니다.

스타일을 조직적으로 관리하고 :deep()을 적절히 사용함으로써 Vue.js 애플리케이션의 스타일링 문제를 효과적으로 해결할 수 있습니다. 최신 Vue의 모범 사례를 따르며 유지보수가 용이한 코드베이스를 구축하시기 바랍니다.

반응형
728x90
반응형

1. Elasticsearch란?

Elasticsearch분산 검색 및 분석 엔진입니다. 대량의 데이터를 실시간으로 검색하고 분석할 수 있으며, Apache Lucene을 기반으로 만들어졌습니다. 흔히 ELK 스택 (Elasticsearch, Logstash, Kibana)의 핵심 구성 요소로 사용됩니다.

주요 특징

  • 실시간 검색: 대규모 데이터에서도 빠른 검색 성능을 제공합니다.
  • 분산 시스템: 클러스터를 구성해 데이터를 수평 확장할 수 있습니다.
  • RESTful API: HTTP를 통한 JSON 기반의 인터페이스 제공.
  • 데이터 저장: JSON 형식으로 문서를 저장하고 관리합니다.
  • 강력한 분석: 검색된 데이터를 분석하고 시각화할 수 있습니다.

2. Elasticsearch의 기본 구성

Elasticsearch는 크게 다음과 같은 요소로 구성됩니다.

2.1. 노드(Node)

  • 노드는 Elasticsearch의 실행 인스턴스입니다.
  • 각 노드는 데이터를 저장하고 검색, 색인 작업을 처리합니다.

2.2. 클러스터(Cluster)

  • 여러 노드가 모여 하나의 클러스터를 구성합니다.
  • 데이터를 분산 저장하고 확장성, 고가용성을 제공합니다.

2.3. 인덱스(Index)

  • 인덱스는 Elasticsearch에서 데이터를 저장하는 논리적 단위입니다.
  • 하나의 인덱스는 여러 개의 샤드(Shard)로 나뉩니다.

2.4. 샤드(Shard)와 레플리카(Replica)

  • 샤드(Shard): 데이터를 나누어 저장하는 단위로, 데이터의 수평 확장을 돕습니다.
  • 레플리카(Replica): 샤드의 복제본으로, 고가용성과 장애 복구를 지원합니다.

3. Elasticsearch 설치 및 실행

3.1. 개발 환경 버전 (단일 노드, 보안 비활성화)

개발 환경에서는 간단한 단일 노드 설정으로 시작할 수 있습니다.

Docker 명령어:

docker run -d \
  --name elasticsearch \
  -p 9200:9200 \
  -p 9300:9300 \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=false" \
  -v ~/elasticsearch/data:/usr/share/elasticsearch/data \
  elasticsearch:8.5.0

설정 요약

  • 단일 노드: discovery.type=single-node
  • 보안 비활성화: xpack.security.enabled=false
  • 데이터 저장: ~/elasticsearch/data에 영구 저장.

실행 확인

Elasticsearch가 정상 실행되었는지 확인합니다:

curl -X GET "http://localhost:9200"

3.2. 운영 환경 버전 (리소스 제한 및 보안 활성화)

운영 환경에서는 보안과 리소스 관리를 철저히 해야 합니다.

Docker 명령어:

docker run -d \
  --name elasticsearch \
  -p 9200:9200 \
  -p 9300:9300 \
  --memory="2g" \
  --cpus="2" \
  -e "discovery.type=single-node" \
  -e "xpack.security.enabled=true" \
  -v ~/elasticsearch/data:/usr/share/elasticsearch/data \
  elasticsearch:8.5.0

설정 요약

  • 리소스 제한: 메모리 2GB, CPU 2 코어
  • 보안 활성화: xpack.security.enabled=true
  • 데이터 영구 저장: ~/elasticsearch/data

보안 설정

보안을 활성화하면 Elasticsearch는 사용자 인증을 요구합니다.

  1. 기본 사용자 비밀번호 설정:

    docker exec -it elasticsearch /usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic

    이 명령어로 elastic 사용자 비밀번호를 설정할 수 있습니다.

  2. 비밀번호를 사용해 접속:

    curl -X GET -u "elastic:<비밀번호>" "http://localhost:9200"

4. Elasticsearch 확인 및 테스트

4.1. 인덱스 생성

curl -X PUT "http://localhost:9200/my_index"

4.2. 인덱스 삭제

curl -X DELETE "http://localhost:9200/my_index"

4.3. 데이터 삽입

curl -X POST "http://localhost:9200/my_index/_doc/1" -H 'Content-Type: application/json' -d'{
  "name": "example document",
  "content": "Elasticsearch 테스트 문서입니다."
}'

4.4. 데이터 검색

curl -X GET "http://localhost:9200/my_index/_search?q=content:테스트&pretty"

5. 결론

Elasticsearch는 빠른 검색, 확장성, 실시간 분석이 필요한 환경에서 유용하게 사용됩니다. 개발 환경과 운영 환경에 따라 설정을 최적화하고, 보안 및 리소스 관리를 철저히 수행하면 안정적인 검색 엔진을 운영할 수 있습니다.

추가 권장 사항

  • Kibana 설치: Elasticsearch 데이터를 시각화하려면 Kibana를 함께 사용하세요.
  • 모니터링: Elastic 제공 모니터링 도구를 활용해 성능 및 상태를 체크하세요.
  • 백업 및 복구: 운영 환경에서는 정기적으로 데이터 백업을 수행하세요.
반응형