Kafka 실전 개발 및 운영 학습

Kafka의 기본 개념을 익혔다면, 이제 Java(Spring Boot) 기반 Kafka 연동, 메시지 처리 설정, 데이터 직렬화 및 연동 기술을 학습할 차례입니다.


📌 1. Kafka Java Client (Java + Spring Boot 연동)

Kafka를 Java(Spring Boot) 애플리케이션에서 사용하려면 Kafka Java Client 라이브러리를 활용합니다.

🔹 Spring Boot 프로젝트 설정

Maven 의존성 추가 (pom.xml)

<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
    <version>3.0.7</version>
</dependency>

🔹 Producer 코드 (메시지 전송)

import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Service;

@Service
public class KafkaProducerService {
    private final KafkaTemplate<String, String> kafkaTemplate;

    public KafkaProducerService(KafkaTemplate<String, String> kafkaTemplate) {
        this.kafkaTemplate = kafkaTemplate;
    }

    public void sendMessage(String topic, String message) {
        kafkaTemplate.send(topic, message);
    }
}

🔹 Consumer 코드 (메시지 소비)

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class KafkaConsumerService {
    @KafkaListener(topics = "test-topic", groupId = "my-group")
    public void consume(String message) {
        System.out.println("Received message: " + message);
    }
}

이제 KafkaProducerService.sendMessage("test-topic", "Hello Kafka") 를 호출하면 Kafka에 메시지가 전송되고 Consumer가 이를 소비합니다.


📌 2. Producer 설정 (Acknowledgment, Key 기반 메시지 전송)

🔹 Producer 설정 옵션

Kafka Producer는 다양한 설정을 지원합니다.

옵션 설명
acks all: 모든 리플리케이션에 메시지가 저장될 때까지 대기
key.serializer 메시지 키 직렬화 방식 (예: StringSerializer)
value.serializer 메시지 값 직렬화 방식 (예: JsonSerializer)
retries 실패 시 재시도 횟수
batch.size 메시지 배치 크기
linger.ms 배치 전송 대기 시간

🔹 Key 기반 메시지 전송

Kafka에서는 Partition을 결정할 때 Key를 활용할 수 있습니다.

public void sendMessageWithKey(String topic, String key, String message) {
    kafkaTemplate.send(topic, key, message);
}

✅ 같은 Key를 가진 메시지는 같은 Partition으로 전송됩니다.


📌 3. Consumer 설정 (Offset 관리, Consumer Group 활용)

Kafka Consumer는 Offset 관리가 중요합니다.

🔹 Offset 자동/수동 커밋

설정 설명
enable.auto.commit=true 자동으로 Offset을 커밋
enable.auto.commit=false 수동으로 Offset을 커밋

🔹 수동 Offset 관리 예제

@KafkaListener(topics = "test-topic", groupId = "my-group")
public void consume(ConsumerRecord<String, String> record, Acknowledgment ack) {
    System.out.println("Received: " + record.value());
    ack.acknowledge(); // 수동 커밋
}

✅ ack.acknowledge(); 를 호출해야 Offset이 저장됩니다.


📌 4. Serialization / Deserialization (JSON, Avro, Protocol Buffers 활용)

Kafka 메시지는 JSON, Avro, Protocol Buffers 등 다양한 포맷을 사용할 수 있습니다.

🔹 JSON 직렬화/역직렬화 설정

@Configuration
public class KafkaConfig {
    @Bean
    public ProducerFactory<String, Object> producerFactory() {
        Map<String, Object> config = new HashMap<>();
        config.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        config.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
        return new DefaultKafkaProducerFactory<>(config);
    }
}

🔹 Avro 사용 예시

@KafkaListener(topics = "avro-topic", groupId = "group")
public void consumeAvro(AvroMessage avroMessage) {
    System.out.println("Received Avro message: " + avroMessage);
}

Avro를 사용하면 메시지 크기를 줄일 수 있어 성능 최적화에 유리합니다.


📌 5. Kafka Connect (DB, File, HTTP 등 외부 시스템 연동)

Kafka Connect를 사용하면 데이터베이스, 파일, HTTP API 등과 Kafka를 쉽게 연동할 수 있습니다.

🔹 Kafka Connect 주요 플러그인

플러그인 설명
JDBC Connector MySQL, PostgreSQL 데이터를 Kafka로
FileStream Connector 파일 로그를 Kafka로
Elasticsearch Connector Kafka 데이터를 Elasticsearch로

🔹 MySQL → Kafka 연동 (JDBC Connector 예제)

{
  "name": "mysql-source",
  "config": {
    "connector.class": "io.confluent.connect.jdbc.JdbcSourceConnector",
    "connection.url": "jdbc:mysql://localhost:3306/testdb",
    "topic.prefix": "mysql-",
    "mode": "incrementing",
    "incrementing.column.name": "id"
  }
}

✅ Kafka Connect를 이용하면 코드 없이 데이터 연동 가능


📌 6. Kafka Streams (데이터 스트리밍 및 실시간 변환 처리)

Kafka Streams는 Kafka 데이터를 실시간으로 처리하는 라이브러리입니다.

🔹 Kafka Streams 기본 예제

StreamsBuilder builder = new StreamsBuilder();
KStream<String, String> stream = builder.stream("input-topic");
stream.mapValues(value -> value.toUpperCase()).to("output-topic");
KafkaStreams streams = new KafkaStreams(builder.build(), props);
streams.start();

✅ input-topic에서 받은 메시지를 대문자로 변환하여 output-topic으로 전송


📌 7. Monitoring (Kafka UI 도구 활용)

Kafka를 운영할 때 모니터링이 중요합니다.

🔹 Kafka 모니터링 도구

도구 설명
Kafka Manager Kafka 상태 및 Topic 모니터링
Confluent Control Center Kafka 클러스터 관리
Prometheus & Grafana Kafka 메트릭 시각화
Kafka UI 웹 기반 Kafka 관리 도구

🔹 Kafka UI 실행

docker run -d -p 8080:8080 provectuslabs/kafka-ui

✅ http://localhost:8080 에서 Kafka 메시지를 시각적으로 확인 가능


✅ 정리

학습 주제 설명
Kafka Java Client Java(Spring Boot)에서 Kafka 연동
Producer 설정 Acknowledgment, Key 기반 메시지 전송
Consumer 설정 Offset 관리, Consumer Group 활용
Serialization JSON, Avro, Protocol Buffers 활용
Kafka Connect DB, File, HTTP 등 외부 시스템과 연동
Kafka Streams 데이터 스트리밍 및 실시간 변환 처리
Monitoring Kafka UI 도구(Kafka Manager, Confluent Control Center)

 

이제 Kafka를 실무 프로젝트에서 활용할 준비가 되었습니다! 🚀
다음 단계에서는 Kafka 운영 및 성능 최적화를 학습하면 더욱 강력한 Kafka 시스템을 구축할 수 있습니다.

Kafka 개념 및 기초 학습

Kafka를 학습하는 첫 단계로, Kafka가 무엇인지, 기존 메시지 큐와의 차이점, 기본적인 아키텍처 및 메시지 처리 방식을 이해하는 것이 중요합니다.
아래 내용을 따라가며 하나씩 익혀보세요.


📌 1. Kafka란 무엇인가? 어떤 문제를 해결하는가?

🔹 Kafka의 정의

Apache Kafka대량의 데이터를 빠르고 안정적으로 처리할 수 있는 분산 메시징 시스템입니다.
Pub/Sub(발행-구독) 모델을 기반으로 하며, 실시간 데이터 스트리밍과 로그 수집, 데이터 파이프라인 구축 등에 사용됩니다.

🔹 Kafka가 해결하는 문제

  • 대량의 데이터 처리
    • 기존 메시지 큐(RabbitMQ, ActiveMQ)로는 수천만 개 이상의 메시지를 처리하기 어려움
  • 실시간 데이터 스트리밍
    • Kafka는 이벤트 기반 시스템으로 실시간 분석 및 데이터 처리 가능
  • 확장성 문제 해결
    • Kafka는 분산 아키텍처 기반으로 확장성이 뛰어남
  • 데이터 손실 최소화
    • 디스크 기반 로그 저장을 사용하여 장애 발생 시 데이터 유실을 최소화

📌 2. Kafka vs 메시지 큐(RabbitMQ, ActiveMQ)

비교 항목 Kafka RabbitMQ / ActiveMQ
데이터 처리 모델 Pub/Sub (스트리밍 중심) 큐 기반 (비동기 메시징)
메시지 저장 방식 디스크 로그 기반 저장 (장기 보관 가능) 메시지 소모 후 삭제
확장성 분산 시스템 (수평 확장 용이) 노드 추가 시 관리 복잡
사용 사례 실시간 데이터 분석, 로그 수집, 이벤트 스트리밍 요청-응답 비동기 메시징
메시지 소비 방식 Consumer Group 활용 (병렬 처리 가능) 1:1 혹은 Pub/Sub 모델
메시지 순서 보장 Partition 단위에서 순서 유지 일반적으로 순서 보장 없음
성능 초당 수백만 TPS 가능 수십만 TPS 수준
내구성 (Durability) 디스크에 저장하여 복구 가능 메시지 소비 후 삭제

📌 결론:

  • Kafka고성능, 확장성, 실시간 데이터 처리가 필요한 경우 유리
  • RabbitMQ, ActiveMQ는 단순한 비동기 메시징(예: 주문 처리, 트랜잭션 큐) 용도로 적합

📌 3. Kafka 아키텍처 (Broker, Producer, Consumer, Topic, Partition, Offset)

Kafka는 분산 아키텍처로 동작하며, 주요 구성 요소는 다음과 같습니다.

🔹 Kafka의 주요 구성 요소

구성 요소 설명

구성 요소 설명
Broker Kafka 서버 역할 (메시지 저장 및 관리)
Producer 메시지를 Kafka에 전송하는 클라이언트
Consumer 메시지를 구독(소비)하는 클라이언트
Topic 메시지가 저장되는 논리적 공간 (카테고리)
Partition Topic을 나누어 여러 Broker에 분산 저장
Offset 메시지의 고유한 위치 (Consumer가 어디까지 읽었는지 저장)

🔹 Kafka 데이터 흐름

  1. ProducerTopic에 메시지를 전송
  2. Topic은 여러 개의 Partition으로 나뉘어 저장됨
  3. Broker가 Partition을 관리하고 데이터 저장
  4. Consumer는 특정 Topic을 구독하여 메시지를 가져감
  5. 메시지의 위치(Offset)를 사용하여 데이터를 추적

🔹 Kafka 구조 예시

Producer → [ Kafka Topic (Partition 0, 1, 2) ] → Consumer Group
  • Producer가 메시지를 Kafka Topic에 전송
  • Topic은 여러 개의 Partition으로 나뉘어 Broker에 분산 저장
  • Consumer Group이 메시지를 읽고 처리

📌 4. 메시지 처리 방식 (Pub/Sub 모델 및 Consumer Group)

Kafka는 Pub/Sub(발행-구독) 모델을 사용합니다.

🔹 Pub/Sub 모델 (Publish-Subscribe)

  • Producer가 메시지를 Topic에 게시
  • 여러 개의 Consumer가 메시지를 구독 가능
  • Consumer Group을 활용하여 메시지를 병렬로 처리 가능

🔹 Consumer Group 활용

Kafka에서는 Consumer Group을 사용하여 메시지를 효과적으로 분산 처리합니다.

Consumer Group 방식 설명
Single Consumer 하나의 Consumer가 모든 메시지를 소비
Multiple Consumers 여러 개의 Consumer가 각기 다른 Partition을 소비
Consumer Group 여러 Consumer가 하나의 그룹으로 묶여 병렬 처리

예시

  • Topic에 3개의 Partition이 있고, **2개의 Consumer(C1, C2)**가 있다면:
    • C1이 Partition 0, 1을 소비
    • C2가 Partition 2를 소비

장점: Consumer Group을 사용하면 부하를 분산하여 처리 속도를 향상할 수 있습니다.


📌 5. Kafka 설치 및 실행 (로컬 & Docker)

Kafka를 실습하려면 직접 설치하고 실행해보는 것이 중요합니다.

🔹 Kafka 로컬 설치 (Zookeeper 포함)

# Kafka 다운로드
wget https://downloads.apache.org/kafka/3.6.0/kafka_2.13-3.6.0.tgz
tar -xzf kafka_2.13-3.6.0.tgz
cd kafka_2.13-3.6.0

# Zookeeper 실행
bin/zookeeper-server-start.sh config/zookeeper.properties &

# Kafka 실행
bin/kafka-server-start.sh config/server.properties &

🔹 Docker로 Kafka 실행

docker-compose up -d

📌 Docker-Compose 예시 파일

version: '3'
services:
  zookeeper:
    image: wurstmeister/zookeeper
    ports:
      - "2181:2181"

  kafka:
    image: wurstmeister/kafka
    ports:
      - "9092:9092"
    environment:
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092

📌 6. 기본 CLI 명령어 (Topic 생성, 메시지 전송 및 소비 테스트)

Kafka의 기본 명령어를 사용하여 직접 테스트해봅니다.

🔹 Topic 생성

bin/kafka-topics.sh --create --topic test-topic --bootstrap-server localhost:9092 --partitions 3 --replication-factor 1

🔹 Producer 메시지 전송

bin/kafka-console-producer.sh --topic test-topic --bootstrap-server localhost:9092
> Hello Kafka!  # 메시지 입력 후 Enter

🔹 Consumer 메시지 수신

bin/kafka-console-consumer.sh --topic test-topic --bootstrap-server localhost:9092 --from-beginning

출력 예시:
Hello Kafka!


✅ 정리

주제 요약
Kafka 개념 대량 데이터 처리, 실시간 스트리밍을 위한 분산 메시징 시스템
Kafka vs 메시지 큐 메시지 큐(RabbitMQ)보다 확장성과 성능이 뛰어남
Kafka 아키텍처 Producer → Topic(Partition) → Consumer Group 구조
Pub/Sub 모델 다수의 Consumer가 메시지를 병렬 처리 가능
Kafka 설치 로컬 또는 Docker로 쉽게 실행 가능
CLI 테스트 Topic 생성, 메시지 전송 및 소비

 

Kafka의 기본 개념과 동작 방식이 이해되었다면, 이제 실제 애플리케이션과 연동하는 방법을 학습하면 좋습니다! 🚀

'kafka' 카테고리의 다른 글

[Kafka] Kafka 고급 활용 학습  (0) 2025.02.03
[Kafka] Kafka 운영 및 최적화 학습  (0) 2025.02.03
[Kafka] 학습 로드맵  (0) 2025.02.03

Kafka 학습 로드맵

Kafka를 학습하는 과정은 초급부터 고급까지 단계적으로 진행하는 것이 좋습니다. 아래는 Kafka를 처음 접하는 사람부터 실무에서 최적화 및 운영을 고려하는 사람까지 단계적으로 학습할 수 있도록 구성한 로드맵입니다.


📌 1단계: 기본 개념 이해 (입문자용)

🔹 핵심 목표

Kafka의 개념과 기본 구조를 이해하고, 메시지 큐와의 차이를 파악합니다.

📚 학습 내용

학습 주제 설명
Kafka 개념 Kafka란 무엇인가? 어떤 문제를 해결하는가?
Kafka vs 메시지 큐 RabbitMQ, ActiveMQ와의 차이점 -
Kafka 아키텍처 Broker, Producer, Consumer, Topic, Partition, Offset 개념
메시지 처리 방식 Pub/Sub 모델 및 Consumer Group 이해
설치 및 기본 실행 Kafka 설치 (로컬 및 Docker 환경에서 실행)
기본 CLI 명령어 Topic 생성, 메시지 전송 및 소비 테스트

📌 2단계: 실전 사용 및 개발 (초급 ~ 중급)

🔹 핵심 목표

Kafka를 애플리케이션과 연동하고, 다양한 프로듀서/컨슈머 패턴을 익힙니다.

📚 학습 내용

학습 주제 설명
Kafka Java Client Java(Spring Boot)에서 Kafka 연동
Producer 설정 Acknowledgment, Key 기반 메시지 전송
Consumer 설정 Offset 관리, Consumer Group 활용
Serialization / Deserialization JSON, Avro, Protocol Buffers 활용
Kafka Connect DB, File, HTTP 등 외부 시스템과 연동 -
Kafka Streams 데이터 스트리밍 및 실시간 변환 처리
Monitoring Kafka / UI 혹은 다른 UI 도구 (Kafka Manager, Confluent Control Center)
Kafka Consumer Group  

📌 3단계: 운영 및 최적화 (중급 ~ 고급)

🔹 핵심 목표

Kafka 클러스터를 운영하고 성능을 최적화합니다.

📚 학습 내용

학습 주제 설명
Kafka 클러스터 구성 Multi-broker 설정 및 운영
Replication & Fault Tolerance Replication Factor, ISR 개념
Kafka 성능 튜닝 배치 전송, 압축 설정, Consumer Lag 모니터링 -
Security 설정 SASL, TLS, ACL 적용 -
Kafka Metrics & Monitoring Prometheus, Grafana를 이용한 모니터링
Kafka Admin API 활용 클러스터 상태 점검 및 동적 설정 변경

📌 4단계: 고급 활용 및 확장 (고급)

🔹 핵심 목표

Kafka를 대규모 데이터 플랫폼에서 활용하고, Kafka 기반 아키텍처를 설계할 수 있습니다.

📚 학습 내용

학습 주제 설명
Kafka + Flink/Spark 실시간 데이터 처리 프레임워크와 결합
Kafka Schema Registry Avro/JSON Schema 관리
Kafka Tiered Storage 장기 보관 데이터를 위한 스토리지 옵션
Kafka Streams vs Flink 스트리밍 데이터 처리 비교
Cross-Cluster Kafka 여러 데이터센터에서 Kafka 활용

📌 5단계: 실무 프로젝트 적용 및 사례 학습

🔹 핵심 목표

Kafka를 활용한 실전 프로젝트를 진행하면서 실무에서 활용할 수 있습니다.

📚 학습 내용

학습 주제 설명
실무 프로젝트 구현 로그 수집, 이벤트 스트리밍, IoT 데이터 처리
Kafka 성능 이슈 해결 Consumer Lag, Offset Reset, Partition 관리
대량 트래픽 처리 사례 분석 Netflix, LinkedIn의 Kafka 활용 사례
Kafka와 클라우드 AWS MSK, GCP Pub/Sub와 비교

✅ Kafka 학습 로드맵 정리

단계 학습 내용 목표
1단계 Kafka 기본 개념, 아키텍처 이해 Kafka가 무엇인지 이해
2단계 프로듀서/컨슈머 개발, Kafka Streams Kafka 연동 및 데이터 처리
3단계 클러스터 운영, 보안 설정, 성능 튜닝 Kafka 운영 및 최적화
4단계 대규모 데이터 처리, 실시간 분석 Kafka 확장 및 고급 활용
5단계 실무 적용, 프로젝트 사례 학습 Kafka를 실무에 적용

📌 Kafka를 학습해야 하는 이유

  • 대규모 데이터 처리: 실시간 로그 분석, 이벤트 스트리밍 등에 필수
  • 높은 확장성: 분산 환경에서 효율적으로 동작
  • 다양한 연동성: Spark, Flink, Hadoop 등과 손쉽게 연결 가능
  • 빠른 데이터 처리: 수백만 TPS(초당 트랜잭션)까지 가능

이 로드맵을 따라가면 Kafka의 기본 개념부터 실무 적용까지 단계적으로 학습할 수 있습니다.
각 단계별로 실습을 병행하며 진행하면 더욱 효과적인 학습이 가능합니다! 🚀

'kafka' 카테고리의 다른 글

[Kafka] Kafka 고급 활용 학습  (0) 2025.02.03
[Kafka] Kafka 운영 및 최적화 학습  (0) 2025.02.03
[Kafka] Kafka 개념 및 기초 학습  (0) 2025.02.03

Elasticsearch: 숫자 데이터 타입 (long, double, scaled_float 등) 완벽 정리

Elasticsearch는 **정수(Integer)와 실수(Float)**를 저장할 수 있도록 다양한 숫자 타입을 제공합니다.
정수 타입: long, integer, short, byte
실수 타입: double, float, half_float, scaled_float

이번 글에서는 각 숫자 타입의 특징, 주요 옵션, 그리고 실전 적용 예제까지 상세히 알아보겠습니다.


1. Elasticsearch에서 숫자 타입

🔹 기본 숫자 타입

Elasticsearch는 자바(Java)에서 사용되는 기본 숫자 타입을 지원합니다.

타입 설명 범위
long 64비트 정수 -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
integer 32비트 정수 -2,147,483,648 ~ 2,147,483,647
short 16비트 정수 -32,768 ~ 32,767
byte 8비트 정수 -128 ~ 127
double 64비트 부동소수점 매우 큰 실수값 저장 가능
float 32비트 부동소수점 일반적인 실수 저장
half_float 16비트 부동소수점 작은 크기의 실수 저장
scaled_float 부동소수점을 정수(long)로 저장하며, 소수점 위치 지정 가능 scaling_factor 사용

2. 숫자 필드의 주요 옵션

Elasticsearch의 숫자 필드는 text, keyword와 일부 동일한 옵션을 가집니다.

옵션 설명 기본값
index 색인 여부 (검색 가능 여부) true
doc_values 집계/정렬을 위한 최적화된 저장 방식 사용 여부 true
boost 검색 시 가중치 부여 1
coerce 자동 형 변환 허용 여부 true
null_value null 값이 입력될 경우 기본값 설정 없음
ignore_malformed 잘못된 숫자 입력 시 오류를 무시하고 저장할지 여부 false

3. 정수(Integer) 타입 예제

📌 예제 1: 정수 타입 매핑 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "price": {
        "type": "integer",
        "coerce": true
      }
    }
  }
}

🔹 설명:

  • "coerce": true → 4.5, "5" 등의 값도 4 또는 5로 자동 변환되어 저장됨 ✅

4. 실수(Floating Point) 타입 예제

📌 예제 2: 실수 타입 매핑 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "rating": {
        "type": "float",
        "coerce": true
      }
    }
  }
}

🔹 설명:

  • "rating": 4.7 → 그대로 저장됨 ✅

5. Scaled Float (소수점 고정형 실수)

🔹 Scaled Float이란?

부동소수점을 정수(long)로 변환하여 저장
소수점 위치를 scaling_factor로 조정
금액($19.99)과 같은 고정 소수점 데이터에 유용

📌 예제 3: scaled_float 타입 매핑 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "price": {
        "type": "scaled_float",
        "scaling_factor": 100
      }
    }
  }
}

🔹 설명:

  • "price": 19.99 → 1999로 변환 후 저장됨
  • "price": 100.25 → 10025로 저장됨

📌 주의:
scaling_factor: 100 이므로 두 자리 소수점까지 저장 가능

  • scaling_factor: 10 → 1자리 소수점까지만 저장 가능

6. 숫자 필드의 중요한 옵션 실전 예제

📌 예제 4: 숫자 필드에서 coerce, null_value, ignore_malformed 활용

PUT my_index
{
  "mappings": {
    "properties": {
      "quantity": {
        "type": "integer",
        "coerce": true,
        "null_value": 0,
        "ignore_malformed": true
      }
    }
  }
}

🔹 설명:

  • "coerce": true → "4.5", "6" 등의 값도 정수로 변환 ✅
  • "null_value": 0 → null 값이 입력되면 0으로 저장 ✅
  • "ignore_malformed": true → 숫자가 아닌 값이 입력되면 오류 없이 저장하되, 검색 및 집계에서 무시 ✅

7. 숫자 필드의 동적 매핑 문제점

숫자 필드를 동적으로 생성하면 위험할 수 있음
첫 번째 값이 4 같은 정수라면 long으로 자동 생성
✔ 이후에 5.5 같은 실수가 들어오면 자동 변환되지만 실제로는 5가 저장됨

📌 잘못된 동적 매핑 예제

PUT my_index/_doc/1
{
  "value": 4
}
PUT my_index/_doc/2
{
  "value": 5.5
}

🔹 문제:

  • value 필드가 long으로 자동 생성
  • 5.5가 입력되었지만 5로 저장됨 (소수점 손실 발생) ❗

해결 방법: 명시적 매핑 설정 사용!

PUT my_index
{
  "mappings": {
    "properties": {
      "value": {
        "type": "float"
      }
    }
  }
}

📌 이제 5.5가 올바르게 저장됨!


8. 정리

개념 설명
long, integer, short, byte 정수 타입 (64비트, 32비트, 16비트, 8비트)
double, float, half_float 부동소수점 실수 (정확도 차이)
scaled_float 부동소수점을 long 형태로 변환하여 저장 (scaling_factor 필요)
coerce 문자열 숫자를 자동 변환 ("4.5" → 4)
null_value null 값이 입력될 경우 기본값 설정
ignore_malformed 잘못된 숫자 입력 시 오류 없이 무시

9. 학습 가이드

1️⃣ 각 숫자 타입을 사용하여 데이터를 저장하고 검색하는 실습 진행
2️⃣ coerce, null_value, ignore_malformed 옵션을 활성화하고 동작 방식 실험
3️⃣ scaled_float을 활용하여 금액 데이터를 저장하고 검색 테스트
4️⃣ 동적 매핑으로 인한 문제를 직접 경험하고 해결 방법 적용


10. 마무리

Elasticsearch에서 숫자 타입을 올바르게 설정하는 것은 데이터의 정확성과 검색 성능을 높이는 중요한 요소입니다.
특히 정수 vs 실수, scaled_float 활용, 동적 매핑의 위험성을 이해하고 적절한 설정을 적용하는 것이 중요합니다.

다음 학습에서는 날짜(Date) 타입을 활용한 검색 및 최적화 방법을 다루겠습니다! 🚀

Elasticsearch: 문자열 타입 (text vs keyword) 완벽 이해

Elasticsearch에서는 문자열 데이터를 저장할 때 text 타입keyword 타입을 사용할 수 있습니다.
text: 검색을 위해 분석(Analyzed)되어 저장됨 (풀 텍스트 검색용)
keyword: 분석 없이 원본 그대로 저장됨 (정확한 값 검색 및 정렬, 집계용)

이 글에서는 text와 keyword의 차이, 각각의 주요 옵션, 그리고 실전 적용 예제까지 상세히 알아보겠습니다.


1. Elasticsearch에서 문자열 데이터 저장 방식

🔹 문자열 데이터 저장 방식의 변화

Elasticsearch 2.x 이전에는 문자열(string) 타입만 존재했으며, 분석 여부를 옵션으로 구분했습니다.
하지만 5.0 이후부터는 textkeyword 타입으로 나뉘면서, 텍스트 분석 여부를 명확히 구분하게 되었습니다.


2. text 타입 (검색용)

🔹 text란?

  • 텍스트 분석기(Analyzer)를 적용하여 검색 최적화
  • 문자열을 여러 개의 토큰(Token)으로 분리하여 역색인(Inverted Index) 저장
  • 대용량 텍스트(본문, 설명, 제목 등)에 적합
  • 집계(Aggregation)와 정렬(Sorting)에 비효율적 (메모리 사용량 증가)

📌 예제 1: text 필드 매핑

PUT my_index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      }
    }
  }
}

🔹 "The quick brown fox" → ["the", "quick", "brown", "fox"] 로 저장됨 ✅

🔹 text 필드의 주요 옵션

옵션 설명 기본값
analyzer 색인 시 사용할 애널라이저 설정 standard
search_analyzer 검색 시 사용할 애널라이저 설정 색인 애널라이저와 동일
index 색인 여부 (검색 가능 여부) true
boost 검색 시 가중치 부여 1
fielddata 집계/정렬 가능 여부 (true 시 메모리 사용 증가) false

📌 예제 2: custom analyzer 적용

PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "custom_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [ "lowercase", "stop" ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "description": {
        "type": "text",
        "analyzer": "custom_analyzer"
      }
    }
  }
}

🔹 설명:

  • "The QUICK brown fox" → ["quick", "brown", "fox"] 로 저장됨 (대소문자 변환, 불용어 제거)

3. keyword 타입 (정확한 값 검색 및 정렬)

🔹 keyword란?

  • 분석되지 않고 원본 그대로 저장
  • 정확한 값 비교(Exact Matching), 필터링, 정렬, 집계에 최적화
  • 소문자 변환, 불용어 제거 등의 처리가 필요 없다면 사용
  • 검색에는 부적합하지만, 집계(Aggregation)에는 필수

📌 예제 3: keyword 필드 매핑

PUT my_index
{
  "mappings": {
    "properties": {
      "category": {
        "type": "keyword"
      }
    }
  }
}

🔹 "The quick brown fox" → ["The quick brown fox"] 그대로 저장 ✅


🔹 keyword 필드의 주요 옵션

옵션 설명 기본값
doc_values 집계/정렬 시 메모리 사용 최적화 true
ignore_above 특정 길이 이상 문자열 색인 제외 256 (동적 매핑 시)
normalizer 대소문자 변환 등 기본적인 문자 변환 가능 없음

📌 예제 4: normalizer 적용 (소문자 변환)

PUT my_index
{
  "settings": {
    "analysis": {
      "normalizer": {
        "custom_normalizer": {
          "type": "custom",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "tag": {
        "type": "keyword",
        "normalizer": "custom_normalizer"
      }
    }
  }
}

🔹 "Elasticsearch" → "elasticsearch" 로 변환 후 저장


4. text vs keyword 비교

비교 항목 text keyword
저장 방식 분석(Analyzed) 후 토큰화됨 원본 그대로 저장
검색 방식 풀 텍스트 검색 (Match Query) 정확한 값 검색 (Term Query)
정렬(Sorting) ❌ 불가능 (fielddata 필요) ✅ 가능
집계(Aggregation) ❌ 비효율적 ✅ 최적
필터(Filter) ❌ 비효율적 ✅ 최적
애널라이저 사용 ✅ 가능 ❌ 불가능 (normalizer 사용 가능)

📌 keyword 필드의 Term Query 예제

GET my_index/_search
{
  "query": {
    "term": {
      "category": "Elasticsearch"
    }
  }
}

"Elasticsearch"와 정확히 일치하는 문서만 검색

📌 text 필드의 Match Query 예제

GET my_index/_search
{
  "query": {
    "match": {
      "title": "Elasticsearch Guide"
    }
  }
}

"Elasticsearch"와 "Guide"가 포함된 문서 검색


5. text와 keyword 함께 사용하기 (Multi-Field)

Elasticsearch에서는 text와 keyword를 동시에 사용할 수 있습니다.
✔ 검색 시 text 필드 사용
✔ 필터링, 정렬, 집계 시 keyword 필드 사용

📌 예제 5: Multi-Field 설정

PUT my_index
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "fields": {
          "keyword": {
            "type": "keyword",
            "ignore_above": 256
          }
        }
      }
    }
  }
}

🔹 검색: title 필드 사용
🔹 정렬/집계: title.keyword 필드 사용

📌 Match Query (검색)

GET my_index/_search
{
  "query": {
    "match": {
      "title": "Elasticsearch Guide"
    }
  }
}

"Elasticsearch Guide" 관련 문서 검색

📌 Term Query (정확한 값 검색)

GET my_index/_search
{
  "query": {
    "term": {
      "title.keyword": "Elasticsearch Guide"
    }
  }
}

"Elasticsearch Guide"와 정확히 일치하는 문서 검색


6. 정리

개념 설명
text 타입 분석(Analyzed)되어 검색 최적화, 집계/정렬 비효율적
keyword 타입 원본 그대로 저장, 필터링/정렬/집계 최적화
text 필드 옵션 analyzer, search_analyzer, boost, fielddata
keyword 필드 옵션 doc_values, ignore_above, normalizer
Multi-Field 사용 검색(text) + 집계/정렬(keyword) 함께 사용

7. 학습 가이드

1️⃣ text와 keyword 차이를 실습하며 비교
2️⃣ Analyzer와 Normalizer를 적용하여 다양한 문자열 처리 연습
3️⃣ Multi-Field 설정하여 검색 및 정렬 최적화
4️⃣ keyword 필드를 활용한 Term Query & Aggregation 실습

다음 학습에서는 Analyzer와 Tokenizer를 활용한 텍스트 분석 심화 과정을 다루겠습니다! 🚀

Elasticsearch: 매핑(Mappings) 이해하기

Elasticsearch에서 **매핑(Mappings)**은 인덱스 내 문서의 필드 유형 및 분석 방법을 정의하는 중요한 요소입니다.
동적 매핑(Dynamic Mapping): 자동으로 필드 타입을 생성
명시적 매핑(Explicit Mapping): 직접 필드 타입을 정의

이번 글에서는 매핑의 개념, 동적 매핑과 명시적 매핑의 차이, 그리고 필드 타입 설정 방법을 상세히 알아보겠습니다.


1. Elasticsearch의 매핑(Mappings) 개념

🔹 매핑이란?

  • Elasticsearch에서 문서의 각 필드에 대한 데이터 타입을 정의하는 과정입니다.
  • 인덱스를 생성할 때 매핑을 설정하면 필드의 타입을 명확히 지정하여 데이터의 일관성을 유지할 수 있습니다.
  • 매핑 정보는 GET <인덱스명>/_mapping 명령어로 확인할 수 있습니다.

📌 매핑 조회 예제

GET books/_mapping

🔹 결과 예제 (자동 매핑 적용 후)

{
  "books": {
    "mappings": {
      "properties": {
        "title": {
          "type": "text"
        },
        "author": {
          "type": "text"
        },
        "category": {
          "type": "keyword"
        },
        "publish_date": {
          "type": "date"
        },
        "pages": {
          "type": "long"
        }
      }
    }
  }
}

📌 설명:

  • title, author → text (검색 가능)
  • category → keyword (정확한 값 비교)
  • publish_date → date (ISO 8601 형식)
  • pages → long (정수)

2. 동적(Dynamic) 매핑

🔹 동적 매핑이란?

Elasticsearch는 새로운 필드가 문서에 추가될 경우 자동으로 매핑을 생성하는 기능을 제공합니다.
즉, 사전에 필드를 정의하지 않아도 문서를 색인하면 자동으로 매핑이 설정됩니다.

📌 예제 1: books 인덱스 없이 문서 입력

PUT books/_doc/1
{
  "title": "Romeo and Juliet",
  "author": "William Shakespeare",
  "category": "Tragedies",
  "publish_date": "1562-12-01T00:00:00",
  "pages": 125
}

📌 자동 매핑 결과 확인

GET books/_mapping

🔹 자동 매핑 결과

  • title, author: text
  • category: keyword
  • publish_date: date
  • pages: long

3. 명시적(Explicit) 매핑

🔹 명시적 매핑이란?

  • 데이터가 인덱싱되기 전에 필드 타입을 미리 정의하는 방식입니다.
  • 자동 매핑은 필드 타입이 의도와 다르게 설정될 수 있으므로, 중요한 필드는 명시적으로 설정하는 것이 좋습니다.
  • 특히 숫자, 날짜, 키워드 필드는 명확한 설정이 필요합니다.

📌 예제 2: 명시적 매핑 설정

PUT books
{
  "mappings": {
    "properties": {
      "title": {
        "type": "text"
      },
      "author": {
        "type": "text"
      },
      "category": {
        "type": "keyword"
      },
      "publish_date": {
        "type": "date"
      },
      "pages": {
        "type": "integer"
      }
    }
  }
}

🔹 설명

  • title, author: text (검색 최적화)
  • category: keyword (필터링 및 정렬 가능)
  • publish_date: date (날짜 필드)
  • pages: integer (정수값)

📌 새로운 문서 입력 (매핑 유지됨)

PUT books/_doc/2
{
  "title": "Hamlet",
  "author": "William Shakespeare",
  "category": "Tragedies",
  "publish_date": "1603-01-01T00:00:00",
  "pages": 200
}

📌 매핑 확인

GET books/_mapping

🔹 결과: 기존 설정된 필드 타입이 유지됨 ✅


4. 기존 인덱스에 필드 추가

Elasticsearch에서는 기존 인덱스에 새로운 필드를 추가할 수 있지만, 기존 필드의 타입 변경은 불가능합니다.

📌 예제 3: 기존 인덱스에 publisher 필드 추가

PUT books/_mapping
{
  "properties": {
    "publisher": {
      "type": "keyword"
    }
  }
}

📌 매핑 확인

GET books/_mapping

🔹 결과: publisher 필드가 keyword 타입으로 추가됨 ✅

하지만 기존 필드의 타입 변경은 불가능

PUT books/_mapping
{
  "properties": {
    "pages": {
      "type": "float"  ❌ (에러 발생)
    }
  }
}

이미 설정된 필드 타입은 변경 불가능 → 새로운 인덱스를 만들어 데이터를 재색인해야 함


5. 주요 데이터 타입 정리

Elasticsearch에서 사용할 수 있는 주요 데이터 타입을 정리하면 다음과 같습니다.

데이터 타입 설명
text 전문 검색(Full-Text Search)용 필드
keyword 정확한 값 비교, 필터링, 정렬
integer 정수값
long 큰 정수값
float 소수점 포함 숫자
double 높은 정밀도의 소수점 숫자
date 날짜 필드 (ISO 8601)
boolean true/false 값
object JSON 객체 저장
nested 다중 필드(Nested Documents)

6. 정리

개념 설명
동적 매핑 (Dynamic Mapping) 문서가 입력될 때 자동으로 필드 타입을 생성
명시적 매핑 (Explicit Mapping) 필드 타입을 사전에 정의하여 데이터의 일관성 유지
기존 인덱스에 필드 추가 가능 여부 ✅ 새로운 필드는 추가 가능
기존 필드 타입 변경 가능 여부 ❌ 기존 필드 타입 변경 불가능 (재색인 필요)

7. 학습 가이드

1️⃣ 동적 매핑과 명시적 매핑을 비교하며 실습
2️⃣ 다양한 필드 타입을 정의하고 검색 결과 비교
3️⃣ keyword와 text 필드의 차이를 이해하고 적절히 사용
4️⃣ 기존 필드 타입 변경이 불가능하므로, 새로운 인덱스를 생성하고 데이터 재색인 연습


8. 마무리

Elasticsearch에서 **매핑(Mappings)**은 데이터를 효율적으로 저장하고 검색하는 데 중요한 역할을 합니다.
특히 keyword vs text, 동적 매핑 vs 명시적 매핑, 기존 필드 타입 변경 불가능 등의 개념을 이해하고 올바르게 활용하는 것이 중요합니다.

다음 학습에서는 Nested & Object 타입을 활용한 문서 구조 설계 방법을 다루겠습니다! 🚀

Elasticsearch: 설정(Settings) 이해하기

Elasticsearch에서 **인덱스를 생성할 때 필요한 설정(Settings)**은 매우 중요한 요소입니다.
모든 인덱스는 두 개의 핵심 정보 단위를 가지며,
Settings (설정): 인덱스의 기본적인 동작을 정의
Mappings (매핑): 필드의 데이터 유형과 분석 방법을 지정

이번 글에서는 Settings의 개념, 주요 설정 요소, 그리고 변경 가능 여부에 대해 상세히 알아보겠습니다.


1. Elasticsearch Settings란?

🔹 기본 개념

  • Settings는 Elasticsearch 인덱스의 구성 및 동작을 정의하는 설정 값입니다.
  • 주요 설정에는 샤드(Shard) 개수, 복제본(Replica) 개수, 리프레시 간격(refresh_interval), 애널라이저(analyzer) 등이 포함됩니다.
  • 인덱스를 생성할 때 설정되며, 일부 설정은 운영 중에도 변경 가능하지만, 일부는 한 번 설정되면 변경 불가능합니다.

📌 인덱스 정보 조회 예제

GET my_index

🔹 결과:

  • settings → 인덱스의 설정 정보
  • mappings → 필드 타입 및 매핑 정보

📌 설정만 따로 조회

GET my_index/_settings

📌 매핑 정보만 따로 조회

GET my_index/_mappings

2. 샤드(Shard)와 복제본(Replica) 설정

🔹 샤드(Shard)란?

  • Elasticsearch의 인덱스는 여러 개의 샤드(Shard)로 분할 저장됩니다.
  • 기본적으로 하나의 인덱스는 **프라이머리 샤드(Primary Shard)와 복제 샤드(Replica Shard)**로 구성됩니다.

설정 값 설명 기본값

number_of_shards 인덱스의 프라이머리 샤드 개수 7.x부터 기본값 1
number_of_replicas 복제본 개수 (프라이머리 샤드 당) 7.x부터 기본값 1

📌 샤드 & 복제본 설정 예제

PUT my_index
{
  "settings": {
    "index": {
      "number_of_shards": 3,
      "number_of_replicas": 1
    }
  }
}

🔹 샤드 개수 변경 가능 여부

  • number_of_replicas운영 중 변경 가능
  • number_of_shards인덱스 생성 후 변경 불가

📌 복제본 개수 변경 예제

PUT my_index/_settings
{
  "number_of_replicas": 2
}

📌 샤드 개수 변경이 필요한 경우
샤드 개수를 변경하려면 새로운 인덱스를 생성하고 기존 데이터를 다시 색인(reindexing) 해야 합니다.


3. Refresh Interval 설정

🔹 Refresh Interval이란?

  • Elasticsearch는 새로운 문서를 색인한 후 일정 주기로 검색 가능하도록 처리합니다.
  • 이 주기를 refresh interval이라고 하며, 기본값은 1초(1s) 입니다.
  • 값을 늘리면 색인 성능이 향상되지만, 검색 반영이 느려질 수 있음

📌 refresh_interval 설정 예제 (30초로 변경)

PUT my_index
{
  "settings": {
    "refresh_interval": "30s"
  }
}

📌 운영 중 refresh_interval 변경 가능

PUT my_index/_settings
{
  "refresh_interval": "5s"
}

색인 작업이 많을 때는 "refresh_interval": "-1" 로 설정하여 자동 리프레시를 비활성화하고, 배치 색인 후 POST my_index/_refresh 를 실행하여 직접 리프레시할 수도 있습니다.


4. Analyzer, Tokenizer, Filter 설정

Elasticsearch에서 **애널라이저(Analyzer)**를 설정하려면 settings 내부의 analysis 항목을 사용합니다.

📌 사용자 정의 애널라이저 설정 예제

PUT my_index
{
  "settings": {
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "type": "custom",
          "char_filter": [ "html_strip" ],
          "tokenizer": "standard",
          "filter": [ "lowercase", "stop" ]
        }
      }
    }
  }
}

🔹 설명

  • "type": "custom" → 사용자 정의 애널라이저
  • "char_filter": ["html_strip"] → HTML 태그 제거
  • "tokenizer": "standard" → 기본 토큰화
  • "filter": ["lowercase", "stop"] → 소문자 변환, 불용어(stopword) 제거

🔹 Analyzer 변경 가능 여부

  • 애널라이저 설정(analysis)은 변경 불가능
  • 변경하려면 인덱스를 close → 설정 변경 → 다시 open 해야 함

📌 애널라이저 변경 방법

POST my_index/_close
PUT my_index/_settings
{
  "analysis": {
    "analyzer": {
      "new_analyzer": {
        "type": "custom",
        "tokenizer": "whitespace"
      }
    }
  }
}
POST my_index/_open

❗ 하지만 이미 존재하는 필드의 분석 방식은 변경할 수 없음새로운 인덱스를 만들고 데이터를 다시 색인해야 함


5. 정리

설정 값 설명 변경 가능 여부
number_of_shards 인덱스의 프라이머리 샤드 개수 ❌ 변경 불가
number_of_replicas 프라이머리 샤드 당 복제본 개수 ✅ 변경 가능
refresh_interval 색인된 데이터가 검색 가능해지는 주기 ✅ 변경 가능
analysis (Analyzer) 텍스트 분석기 설정 ❌ 변경 불가 (재색인 필요)

6. 학습 가이드

1️⃣ 샤드와 복제본 개수 설정 방법 실습
2️⃣ refresh_interval을 변경하며 색인 성능 테스트
3️⃣ 사용자 정의 애널라이저를 설정하고 분석 결과 확인
4️⃣ Analyzer 변경 불가 원리를 이해하고, 새로운 인덱스로 재색인 연습


7. 마무리

Elasticsearch의 Settings는 인덱스의 성능과 검색 효율성을 결정하는 중요한 요소입니다.
특히 샤드와 복제본 개수, Refresh Interval, 분석기 설정을 이해하고 적절히 활용하는 것이 중요합니다.

다음 학습에서는 Mappings을 활용한 필드 타입 및 데이터 구조 정의 방법을 다루겠습니다! 🚀

Elasticsearch: 범위 쿼리 (Range Query)

Elasticsearch에서는 숫자 및 날짜 데이터를 효과적으로 검색할 수 있도록 **범위 쿼리(Range Query)**를 제공합니다.
이 쿼리는 특정 범위 안에 포함되는 데이터를 찾을 때 사용되며, 가격, 날짜, 온도, 점수 등 연속적인 값(Continuous Data)을 검색하는 데 유용합니다.

이번 글에서는 Range Query의 기본 개념, 사용법, 그리고 날짜 검색을 포함한 실전 예제까지 살펴보겠습니다.


1. Range Query란?

🔹 기본 개념

  • 특정 필드의 값이 특정 범위에 포함되는 문서만 검색할 때 사용됩니다.
  • 숫자(Number), 날짜(Date), IP 주소(IP Address) 등의 필드에서 주로 사용됩니다.
  • 점수(score)를 계산하지 않으며, 오로지 True/False 조건만으로 필터링합니다.

2. Range Query의 기본 문법

Range Query는 아래와 같은 4가지 조건을 지원합니다.

연산자 설명
gte (Greater Than or Equal) 이상 (≥) - 특정 값보다 크거나 같은 데이터 검색
gt (Greater Than) 초과 (>) - 특정 값보다 큰 데이터 검색
lte (Less Than or Equal) 이하 (≤) - 특정 값보다 작거나 같은 데이터 검색
lt (Less Than) 미만 (<) - 특정 값보다 작은 데이터 검색

📌 예제 데이터 (phones 인덱스)

POST phones/_bulk
{"index":{"_id":1}}
{"model":"Samsung GalaxyS 5","price":475,"date":"2014-02-24"}
{"index":{"_id":2}}
{"model":"Samsung GalaxyS 6","price":795,"date":"2015-03-15"}
{"index":{"_id":3}}
{"model":"Samsung GalaxyS 7","price":859,"date":"2016-02-21"}
{"index":{"_id":4}}
{"model":"Samsung GalaxyS 8","price":959,"date":"2017-03-29"}
{"index":{"_id":5}}
{"model":"Samsung GalaxyS 9","price":1059,"date":"2018-02-25"}

(📌 위 데이터는 실제 상품과 무관한 예제 데이터입니다.)


3. 숫자 검색 (Number Range Query)

📌 예제 1: 가격(price)이 700 이상, 900 미만인 스마트폰 검색

GET phones/_search
{
  "query": {
    "range": {
      "price": {
        "gte": 700,
        "lt": 900
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 6 (price: 795) ✅
  • Samsung GalaxyS 7 (price: 859) ✅

📌 설명:

  • gte: 700 → 700 이상
  • lt: 900 → 900 미만

4. 날짜 검색 (Date Range Query)

📌 예제 2: 2016년 1월 1일 이후 출시된 스마트폰 검색

GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "2016-01-01"
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 7 (date: 2016-02-21) ✅
  • Samsung GalaxyS 8 (date: 2017-03-29) ✅
  • Samsung GalaxyS 9 (date: 2018-02-25) ✅

📌 설명:

  • gt: "2016-01-01" → 2016년 1월 1일보다 이후(>)인 데이터 검색

5. 날짜 포맷 변환 (Format 옵션 활용)

Elasticsearch는 기본적으로 **ISO8601 날짜 형식 (yyyy-MM-dd 또는 yyyy-MM-dd'T'HH:mm:ss)**을 사용합니다.
하지만 format 옵션을 사용하면 다른 날짜 형식도 검색할 수 있습니다.

📌 예제 3: 2016년 1월 1일 ~ 2018년 1월 1일 사이 출시된 스마트폰 검색

GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "31/12/2015",
        "lt": "2018",
        "format": "dd/MM/yyyy||yyyy"
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 7 (date: 2016-02-21) ✅
  • Samsung GalaxyS 8 (date: 2017-03-29) ✅

📌 설명:

  • format: "dd/MM/yyyy||yyyy" → 31/12/2015 또는 2018 형식 허용

6. 현재 시간(now)과 상대적 날짜 검색

Elasticsearch에서는 now 키워드를 사용하여 현재 시간을 기준으로 상대적인 날짜를 검색할 수 있습니다.

📌 예제 4: 2016년 1월 1일 이후 + 6개월 ~ 현재(now) 기준 1년 전 사이 검색

GET phones/_search
{
  "query": {
    "range": {
      "date": {
        "gt": "2016-01-01||+6M",
        "lt": "now-365d"
      }
    }
  }
}

🔹 결과:

  • Samsung GalaxyS 8 (date: 2017-03-29) ✅
  • Samsung GalaxyS 9 (date: 2018-02-25) ✅

📌 설명:

  • "2016-01-01||+6M" → 2016년 1월 1일 이후 6개월 후
  • "now-365d" → 현재 시간(now) 기준 1년 전

7. Range Query의 특징 및 제한사항

점수(score)를 계산하지 않음

  • range 쿼리는 정확성(True/False)만 확인하고 점수를 계산하지 않습니다.
  • 검색 결과는 _score: 1.0으로 동일합니다.

점수를 조정하고 싶다면 Function Score Query 활용

  • 예를 들어, 나이가 채용 조건(24~55세)과 가까울수록 높은 점수를 부여하고 싶다면 Function Score Query를 사용해야 합니다.

📌 Function Score Query 예제 (추후 학습 필요)

GET jobs/_search
{
  "query": {
    "function_score": {
      "query": {
        "range": {
          "age": {
            "gte": 24,
            "lte": 55
          }
        }
      },
      "functions": [
        {
          "gauss": {
            "age": {
              "origin": 35,
              "scale": 10
            }
          }
        }
      ]
    }
  }
}

🔹 설명: 35세를 기준으로 점수를 조정 (추후 학습 필요)


8. 정리

개념 설명
Range Query 숫자, 날짜, IP 주소 등의 범위를 검색하는 쿼리
gte / gt 이상(≥), 초과(>)
lte / lt 이하(≤), 미만(<)
Format 옵션 날짜 포맷 변경 가능
now 키워드 현재 시간 기준 검색 가능
Function Score Query 기준점에 따라 점수를 조정하고 싶을 때 사용

9. 학습 가이드

1️⃣ Range Query의 숫자 및 날짜 검색 실습
2️⃣ Format 옵션을 사용하여 다양한 날짜 포맷 테스트
3️⃣ now, +6M, -365d 같은 상대적 날짜 검색 연습
4️⃣ Function Score Query 학습 (추후 검색 점수 조정 시 활용 가능)


다음 학습에서는 Function Score Query를 활용한 검색 결과 가중치 조정 방법을 다루겠습니다! 🚀

Elasticsearch: 정확값 쿼리 (Exact Value Query)

Elasticsearch에서는 **풀 텍스트 검색(Full-Text Search)**과는 다르게 정확한 값(Exact Value)을 검색하는 방식도 지원합니다. 이 방식을 활용하면 특정 값과 정확히 일치하는 문서만 조회할 수 있으며, 검색 **점수(score)**가 계산되지 않기 때문에 빠른 검색 속도를 보장할 수 있습니다. 이번 글에서는 정확값 검색이란 무엇인지, 그리고 이를 구현하는 filter, keyword, range 쿼리에 대해 알아보겠습니다.


1. 정확값(Exact Value) 검색이란?

🔹 기본 개념

  • 풀 텍스트 검색은 **검색어와 문서의 연관성(relevancy)**을 계산하여 가장 관련성이 높은 결과를 반환합니다.
  • 하지만 정확값 검색정확히 일치하는 값을 찾는 방식이며, 점수(score)를 계산하지 않습니다.
  • 대표적인 쿼리로는 term, range 쿼리가 있으며, bool 쿼리의 filter 절에서 주로 사용됩니다.

🔹 RDBMS와 비교

RDBMS에서 WHERE column = '값' 같은 조건을 사용하여 정확히 일치하는 데이터만 조회하는 것과 비슷합니다.

📌 예제

검색어 풀 텍스트 검색 (match) 정확값 검색 (term)
fox "The quick brown fox" ✅ "fox" 단독으로 포함된 문서만 ✅
Brown fox brown dog "brown"과 "fox"를 포함한 모든 문서 "Brown fox brown dog"와 정확히 일치하는 문서 ✅

2. Bool 쿼리의 Filter 사용

🔹 Filter의 특징

  • 검색 점수(score)에 영향을 주지 않음
  • 쿼리 캐싱을 활용하여 성능 최적화
  • 정확한 값을 필터링할 때 주로 사용

📌 예제 1: match 쿼리 vs filter 쿼리

① match 쿼리 (연관성 기반 검색)

GET my_index/_search
{
  "query": {
    "match": {
      "message": "fox"
    }
  }
}

🔹 결과:

  • "The quick brown fox jumps over the lazy dog" 🆙 (연관성이 높은 문서가 우선 노출됨)
  • "The quick brown fox"

② match 쿼리 + bool must (여러 조건 검색, 점수 적용됨)

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "fox" } },
        { "match": { "message": "quick" } }
      ]
    }
  }
}

🔹 결과:

  • "fox"와 "quick"이 포함된 문서만 검색되며, 점수가 반영됨

③ must + filter 조합 (정확값 필터링, 점수 미반영)

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "fox" } }
      ],
      "filter": [
        { "match": { "message": "quick" } }
      ]
    }
  }
}

🔹 결과 비교

  • "fox"를 포함한 모든 문서 중 "quick"이 포함된 문서만 반환됨
  • 하지만 점수(score)는 변화 없음

3. Filter 내부에서 must_not 사용

  • 특정 단어가 포함되지 않은 문서를 찾을 때 사용
  • 점수에 영향을 주지 않으며, 빠르게 검색 가능

📌 예제 2: "fox" 포함 & "dog" 제외

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "message": "fox" } }
      ],
      "filter": [
        {
          "bool": {
            "must_not": [
              { "match": { "message": "dog" } }
            ]
          }
        }
      ]
    }
  }
}

🔹 결과:

  • "fox"가 포함된 문서 중 "dog"가 포함되지 않은 문서만 검색됨
  • 점수(score)는 변화 없음

4. Keyword 타입을 활용한 정확값 검색

🔹 Keyword 타입이란?

  • keyword 필드는 분석되지 않는(Analyzed X) 문자열 필드
  • 검색어가 정확히 일치하는 데이터만 반환
  • 대소문자, 공백까지 동일해야 검색됨
  • filter 절과 함께 사용하면 빠르게 검색 가능

📌 예제 3: keyword 필드 검색

GET my_index/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "term": {
            "message.keyword": "Brown fox brown dog"
          }
        }
      ]
    }
  }
}

🔹 결과:

  • "Brown fox brown dog"와 완벽하게 일치하는 문서만 반환됨
  • 점수(score)는 _score: 0.0 (점수 계산 없음)

📌 Keyword 필드의 특성
빠른 검색 속도
정확한 값 비교
대소문자 및 공백 차이까지 구분


5. Filter를 활용한 성능 최적화

filter는 점수를 계산하지 않기 때문에 성능이 우수합니다.
filter 내부의 조건들은 캐싱되므로 반복적인 검색 시 더 빠르게 실행됩니다.
숫자 범위(range) 검색이나 정확한 값(term) 검색은 filter를 사용하는 것이 유리합니다.

📌 filter 절을 사용해야 하는 경우
1️⃣ 상품 검색에서 제조사, 브랜드, 가격 필터링
2️⃣ 로그 검색에서 날짜 범위 필터링
3️⃣ ID 기반 검색에서 정확한 ID 값을 찾을 때


6. 정리

개념 설명
풀 텍스트 검색 (match) 연관성을 기준으로 검색 결과 정렬
정확값 검색 (Exact Value) 값이 정확히 일치하는 문서만 검색
Bool Query - Filter 검색 점수를 계산하지 않고 문서를 필터링
Must vs Filter must는 점수를 반영하지만, filter는 점수를 무시
Keyword 필드 분석되지 않는 문자열 필드, 정확한 검색 가능
Must Not (필터 내부 사용) 특정 단어가 포함되지 않은 문서 검색

7. 학습 가이드

1️⃣ Bool Query의 filter 절을 실습하여 정확값 검색 연습
2️⃣ Match vs Term 쿼리의 차이점을 비교하며 성능 테스트
3️⃣ Keyword 타입을 사용하여 필터링 적용
4️⃣ Range, Term, Exists 쿼리를 활용한 검색 최적화


8. 마무리

Elasticsearch에서 정확한 값을 검색할 때는 풀 텍스트 검색이 아닌 filter 기반 검색을 사용하는 것이 성능적으로 더 유리합니다.
특히 상품 검색, 로그 분석, ID 조회 등의 경우 filter와 keyword 필드를 적극 활용하면 더 빠르고 정확한 검색을 할 수 있습니다.

다음 학습에서는 Range Query를 활용한 숫자 및 날짜 범위 검색 방법을 다루겠습니다! 🚀

Elasticsearch Bool Query: Should 사용법

Elasticsearch의 bool 쿼리는 여러 개의 검색 조건을 조합할 수 있도록 도와줍니다. 그중에서도 should 절은 검색 결과의 가중치를 조정하여 더 관련성이 높은 문서를 상위에 배치할 때 유용합니다.

이번 글에서는 should 절이 어떻게 동작하는지, 그리고 match_phrase와 결합하여 검색 품질을 향상시키는 방법을 살펴보겠습니다.


1. Bool Query의 Should 절이란?

🔹 기본 개념

  • should 절은 검색 결과의 점수(score)를 조정하는 데 사용됩니다.
  • must 절과 다르게 should 절의 조건을 만족하지 않아도 검색 결과에 포함될 수 있습니다.
  • 하지만 should 조건을 만족하는 문서는 더 높은 점수를 부여받아 상위에 노출됩니다.

🔹 RDBMS와 비교

RDBMS에서는 단순히 조건을 만족하는 데이터만 반환할 뿐, 어느 데이터가 더 중요한지는 판단하지 않습니다.
Elasticsearch에서는 should 절을 활용하여 특정 키워드가 포함된 문서에 더 높은 점수를 부여할 수 있습니다.


2. Should 절을 활용한 검색 예제

🔹 예제 1: 특정 키워드에 가중치 부여

먼저, "fox"라는 단어가 포함된 문서를 검색하는 match 쿼리를 실행합니다.

GET my_index/_search
{
  "query": {
    "match": {
      "message": "fox"
    }
  }
}

📌 검색 결과:

  • "The quick brown fox jumps over the lazy dog"
  • "The quick brown fox"

이제 should 절을 추가하여 "lazy"가 포함된 문서에 가중치를 부여해 보겠습니다.

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "message": "fox"
          }
        }
      ],
      "should": [
        {
          "match": {
            "message": "lazy"
          }
        }
      ]
    }
  }
}

📌 검색 결과 변경:

  • "The quick brown fox jumps over the lazy dog" 🆙 (점수 증가, 최상위 노출)
  • "The quick brown fox" (점수 변화 없음)

"lazy"라는 단어가 포함된 문서는 더 높은 점수를 받아 상위에 표시됩니다.


3. Should 절 + Match Phrase로 정확도 향상

should 절을 match_phrase와 함께 사용하면 정확한 구문이 포함된 문서를 최상위에 배치할 수 있습니다.

📌 예제 2: "lazy" 또는 "dog"가 포함된 문서 검색 + "lazy dog" 구문 포함 문서 가중치 부여

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "message": "lazy dog"
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "message": "lazy dog"
          }
        }
      ]
    }
  }
}

📌 검색 결과:
1️⃣ "The quick brown fox jumps over the lazy dog" 🆙 (최상위 노출, 점수 증가)
2️⃣ "Lazy jumping dog"

"lazy"나 "dog"가 포함된 모든 문서를 검색하면서, "lazy dog"라는 정확한 구문을 포함한 문서는 더 높은 점수를 받습니다.


4. Should 절을 활용한 검색 최적화

1) 쇼핑몰 검색 최적화

쇼핑몰에서는 "스키 장갑"을 검색할 때 스키 용품과 장갑을 모두 표시하되, "스키 장갑"이 포함된 상품을 최상위에 배치할 수 있습니다.

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "product_name": "스키 장갑"
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "product_name": "스키 장갑"
          }
        }
      ]
    }
  }
}

🔹 결과:

  • "스키 장갑 방한용" 🆙 (점수 증가, 최상위 노출)
  • "방수 장갑 (스키 가능)"
  • "스키 장비 풀세트"

"스키 장갑"이 정확히 포함된 상품이 가장 위에 표시됩니다.


2) Slop 옵션을 활용한 유연한 검색

slop 옵션을 추가하면 단어 간의 순서가 바뀌어도 검색이 가능합니다.

GET my_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "match": {
            "product_name": "스키 장갑"
          }
        }
      ],
      "should": [
        {
          "match_phrase": {
            "product_name": "스키 장갑",
            "slop": 1
          }
        }
      ]
    }
  }
}

📌 slop 옵션 설명:

  • "스키 보드 장갑" ✅
  • "스키 방한 장갑" ✅
  • "방한용 스키 장갑" ✅
  • "스키 장갑" ✅ (가장 높은 점수)

"스키 장갑"이 정확히 일치하지 않더라도 일정한 간격 내에서 허용하여 검색 유연성을 높일 수 있습니다.


5. 정리

개념 설명
Bool Query 여러 검색 조건을 조합하는 Elasticsearch의 강력한 기능
Must 절 검색 결과에 반드시 포함되어야 하는 조건
Should 절 점수를 조정하여 특정 문서를 상위에 배치
Match Phrase 정확한 구문 검색
Slop 옵션 단어 간 순서를 유연하게 허용

6. 학습 가이드

1️⃣ Should 절을 사용하여 가중치를 조절하는 방법을 실습
2️⃣ Match Phrase와 Slop 옵션을 결합하여 검색 최적화 적용
3️⃣ Boosting, Function Score Query와 비교 학습
4️⃣ Elasticsearch에서 실제 데이터(상품, 뉴스, 블로그 등)로 실습 진행


7. 마무리

Elasticsearch의 should 절을 사용하면 검색 결과의 가중치를 조정하여 더 적절한 결과를 상위에 배치할 수 있습니다.

다음 학습에서는 Function Score Query를 활용하여 검색 결과의 점수를 더욱 정밀하게 조정하는 방법을 살펴보겠습니다! 🚀

+ Recent posts