<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>lyj_0316.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 09 May 2025 07:44:40 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>lyj_0316.log</title>
            <url>https://velog.velcdn.com/images/lyj_0316/profile/11f5849a-e59e-41d6-b81a-359e2308adaa/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. lyj_0316.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/lyj_0316" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Vector DB 미래 기술 발전 방향]]></title>
            <link>https://velog.io/@lyj_0316/Vector-DB-%EB%AF%B8%EB%9E%98-%EA%B8%B0%EC%88%A0-%EB%B0%9C%EC%A0%84-%EB%B0%A9%ED%96%A5</link>
            <guid>https://velog.io/@lyj_0316/Vector-DB-%EB%AF%B8%EB%9E%98-%EA%B8%B0%EC%88%A0-%EB%B0%9C%EC%A0%84-%EB%B0%A9%ED%96%A5</guid>
            <pubDate>Fri, 09 May 2025 07:44:40 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="서론">서론</h2>
<p>AI·빅데이터 시대에 벡터 DB는 단순 유사도 검색을 넘어서 저장·검색·추론·보안·운영을 통합하는 핵심 인프라로 부상하고 있습니다. </p>
<p>특히 기존 RDBMS 벤더의 시장 진출 가능성과 AI 기능의 네이티브 통합, 멀티모달 지원, 분산 아키텍처, 실시간 인제스트, 표준화·상호운용성, 에지 컴퓨팅 통합 등은 벡터 DB의 미래를 결정짓는 주요 축이라고 생각됩니다. 이들 각 축을 살펴보고, 향후 벡터 DB가 나아갈 방향을 예측해 보고자 합니다.</p>
<hr>
<h2 id="본론">본론</h2>
<h3 id="1-오라클과-같은-기업들의-de-facto-standard">1. 오라클과 같은 기업들의 De Facto Standard</h3>
<p>오라클과 같은 전통적 DB 벤더가 벡터 DB 기능을 자사 제품에 통합해 시장에 진출하면, 사실상 업계 표준으로 자리잡을 가능성이 높을 것 같습니다. </p>
<p>금융·의료·공공 등 보안·규제 준수가 중요한 환경에서 엔터프라이즈급 암호화·감사 로그 기능은 큰 강점이 될 것이며, 기존 RDBMS 환경과의 통합 운영 편의성도 도입 장벽을 낮춰줄 것 같습니다.</p>
<h3 id="2-ai-네이티브-데이터-플랫폼-통합">2. AI-네이티브 데이터 플랫폼 통합</h3>
<p>벡터 DB가 임베딩 생성, RAG(Retrieval-Augmented Generation), 분류·요약 같은 AI 기능을 네이티브로 제공하게 될 것 같습니다. </p>
<p>이를 통해 별도의 AI 파이프라인 구축·운영 부담이 줄어들고, 데이터 저장소와 추론 엔진을 하나의 플랫폼에서 통합 관리할 수 있게 될 것 같습니다.</p>
<h3 id="3-멀티모달-지원-강화">3. 멀티모달 지원 강화</h3>
<p>텍스트뿐 아니라 이미지, 음성, 그래프 데이터를 모두 벡터화해 단일 인덱스에서 처리할 수 있을 것 같습니다. </p>
<p>의료 영상과 전자의무기록을 동시에 탐색하거나, 음성 명령과 텍스트 쿼리를 결합한 시나리오가 보편화되면서 데이터 소스 간 상호 보완적 분석이 더욱 활성화될 것 같습니다.</p>
<h3 id="4-클라우드-네이티브-분산-아키텍처">4. 클라우드-네이티브 분산 아키텍처</h3>
<p>벡터 DB가 완전 관리형 클라우드 서비스로 제공되어, 사용자는 서버 설정이나 용량 계획에 신경 쓰지 않아도 될 것 같습니다. </p>
<p>자동 스케일링을 통해 트래픽 급증에도 안정적으로 대응할 수 있고, 투명하게 관리되어 운영 효율이 크게 향상될 것 같습니다.</p>
<h3 id="5-실시간-스트리밍-인제스트">5. 실시간 스트리밍 인제스트</h3>
<p>배치 색인 방식을 벗어나 신규 벡터를 생성 즉시 색인하는 ‘실시간 Vector DB’가 일반화될 것 같습니다. </p>
<p>금융 거래, IoT 센서, 자율주행 차량 등 초저지연 응답이 필요한 분야에서 필수적인 기능으로 자리잡아, 항상 최신 데이터를 놓치지 않고 활용할 수 있을 것 같습니다.</p>
<h3 id="6-표준화·상호운용성">6. 표준화·상호운용성</h3>
<p>ONNX·OpenVector 같은 오픈 포맷이 표준으로 채택되어, 서로 다른 벡터 DB 간 데이터 이전이 자유로워질 것 같습니다. </p>
<p>Milvus, Qdrant, OpenSearch 등 주요 오픈소스 프로젝트가 공통 REST/gRPC API 레이어를 제공하면서, 벤더 종속성을 최소화하고 다양한 제품을 유연하게 조합할 수 있을 것 같습니다.</p>
<h3 id="7-에지-컴퓨팅과-llm-통합">7. 에지 컴퓨팅과 LLM 통합</h3>
<p>에지 디바이스에 소형 LLM과 벡터 DB를 결합하면 실시간 처리 성능이 크게 향상될 것 같습니다. </p>
<p>특히 자율주행차량에서는 내부에서 센서 데이터를 즉시 벡터로 변환해 도로 상황을 분석하고, 네트워크 지연 없이 즉각적인 주행 결정을 지원할 수 있을 것 같습니다. 스마트 팩토리나 원격 장비 제어 환경에서도 현장 데이터를 실시간으로 처리해 예측 가능한 성능을 제공할 것 같습니다.</p>
<hr>
<h2 id="결론">결론</h2>
<p>벡터 DB는 전통적 DB 벤더의 시장 주도력과 오픈 소스·혁신 생태계의 융합을 통해, AI 네이티브 플랫폼으로 자리매김할 것 같습니다. </p>
<p>멀티모달 지원, 분산 아키텍처, 실시간 인제스트, 표준화·상호운용성, 에지 컴퓨팅 통합 등을 통해 저장·검색·추론·보안·운영이 통합된 차세대 인프라로 발전할 것이라 생각됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Vector DB 미래 기술 발전 방향]]></title>
            <link>https://velog.io/@lyj_0316/Vector-DB-%EB%AF%B8%EB%9E%98-%EA%B8%B0%EC%88%A0-%EB%B0%9C%EC%A0%84-%EB%B0%A9%ED%96%A5</link>
            <guid>https://velog.io/@lyj_0316/Vector-DB-%EB%AF%B8%EB%9E%98-%EA%B8%B0%EC%88%A0-%EB%B0%9C%EC%A0%84-%EB%B0%A9%ED%96%A5</guid>
            <pubDate>Fri, 09 May 2025 07:44:39 GMT</pubDate>
            <description><![CDATA[<hr>
<h2 id="서론">서론</h2>
<p>AI·빅데이터 시대에 벡터 DB는 단순 유사도 검색을 넘어서 저장·검색·추론·보안·운영을 통합하는 핵심 인프라로 부상하고 있습니다. </p>
<p>특히 기존 RDBMS 벤더의 시장 진출 가능성과 AI 기능의 네이티브 통합, 멀티모달 지원, 분산 아키텍처, 실시간 인제스트, 표준화·상호운용성, 에지 컴퓨팅 통합 등은 벡터 DB의 미래를 결정짓는 주요 축이라고 생각됩니다. 이들 각 축을 살펴보고, 향후 벡터 DB가 나아갈 방향을 예측해 보고자 합니다.</p>
<hr>
<h2 id="본론">본론</h2>
<h3 id="1-오라클과-같은-기업들의-de-facto-standard">1. 오라클과 같은 기업들의 De Facto Standard</h3>
<p>오라클과 같은 전통적 DB 벤더가 벡터 DB 기능을 자사 제품에 통합해 시장에 진출하면, 사실상 업계 표준으로 자리잡을 가능성이 높을 것 같습니다. </p>
<p>금융·의료·공공 등 보안·규제 준수가 중요한 환경에서 엔터프라이즈급 암호화·감사 로그 기능은 큰 강점이 될 것이며, 기존 RDBMS 환경과의 통합 운영 편의성도 도입 장벽을 낮춰줄 것 같습니다.</p>
<h3 id="2-ai-네이티브-데이터-플랫폼-통합">2. AI-네이티브 데이터 플랫폼 통합</h3>
<p>벡터 DB가 임베딩 생성, RAG(Retrieval-Augmented Generation), 분류·요약 같은 AI 기능을 네이티브로 제공하게 될 것 같습니다. </p>
<p>이를 통해 별도의 AI 파이프라인 구축·운영 부담이 줄어들고, 데이터 저장소와 추론 엔진을 하나의 플랫폼에서 통합 관리할 수 있게 될 것 같습니다.</p>
<h3 id="3-멀티모달-지원-강화">3. 멀티모달 지원 강화</h3>
<p>텍스트뿐 아니라 이미지, 음성, 그래프 데이터를 모두 벡터화해 단일 인덱스에서 처리할 수 있을 것 같습니다. </p>
<p>의료 영상과 전자의무기록을 동시에 탐색하거나, 음성 명령과 텍스트 쿼리를 결합한 시나리오가 보편화되면서 데이터 소스 간 상호 보완적 분석이 더욱 활성화될 것 같습니다.</p>
<h3 id="4-클라우드-네이티브-분산-아키텍처">4. 클라우드-네이티브 분산 아키텍처</h3>
<p>벡터 DB가 완전 관리형 클라우드 서비스로 제공되어, 사용자는 서버 설정이나 용량 계획에 신경 쓰지 않아도 될 것 같습니다. </p>
<p>자동 스케일링을 통해 트래픽 급증에도 안정적으로 대응할 수 있고, 투명하게 관리되어 운영 효율이 크게 향상될 것 같습니다.</p>
<h3 id="5-실시간-스트리밍-인제스트">5. 실시간 스트리밍 인제스트</h3>
<p>배치 색인 방식을 벗어나 신규 벡터를 생성 즉시 색인하는 ‘실시간 Vector DB’가 일반화될 것 같습니다. </p>
<p>금융 거래, IoT 센서, 자율주행 차량 등 초저지연 응답이 필요한 분야에서 필수적인 기능으로 자리잡아, 항상 최신 데이터를 놓치지 않고 활용할 수 있을 것 같습니다.</p>
<h3 id="6-표준화·상호운용성">6. 표준화·상호운용성</h3>
<p>ONNX·OpenVector 같은 오픈 포맷이 표준으로 채택되어, 서로 다른 벡터 DB 간 데이터 이전이 자유로워질 것 같습니다. </p>
<p>Milvus, Qdrant, OpenSearch 등 주요 오픈소스 프로젝트가 공통 REST/gRPC API 레이어를 제공하면서, 벤더 종속성을 최소화하고 다양한 제품을 유연하게 조합할 수 있을 것 같습니다.</p>
<h3 id="7-에지-컴퓨팅과-llm-통합">7. 에지 컴퓨팅과 LLM 통합</h3>
<p>에지 디바이스에 소형 LLM과 벡터 DB를 결합하면 실시간 처리 성능이 크게 향상될 것 같습니다. </p>
<p>특히 자율주행차량에서는 내부에서 센서 데이터를 즉시 벡터로 변환해 도로 상황을 분석하고, 네트워크 지연 없이 즉각적인 주행 결정을 지원할 수 있을 것 같습니다. 스마트 팩토리나 원격 장비 제어 환경에서도 현장 데이터를 실시간으로 처리해 예측 가능한 성능을 제공할 것 같습니다.</p>
<hr>
<h2 id="결론">결론</h2>
<p>벡터 DB는 전통적 DB 벤더의 시장 주도력과 오픈 소스·혁신 생태계의 융합을 통해, AI 네이티브 플랫폼으로 자리매김할 것 같습니다. </p>
<p>멀티모달 지원, 분산 아키텍처, 실시간 인제스트, 표준화·상호운용성, 에지 컴퓨팅 통합 등을 통해 저장·검색·추론·보안·운영이 통합된 차세대 인프라로 발전할 것이라 생각됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MariaDB를 활용한 VectorDB 하이브리드 검색]]></title>
            <link>https://velog.io/@lyj_0316/MariaDB%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-VectorDB-%ED%95%98%EC%9D%B4%EB%B8%8C%EB%A6%AC%EB%93%9C-%EA%B2%80%EC%83%89</link>
            <guid>https://velog.io/@lyj_0316/MariaDB%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-VectorDB-%ED%95%98%EC%9D%B4%EB%B8%8C%EB%A6%AC%EB%93%9C-%EA%B2%80%EC%83%89</guid>
            <pubDate>Fri, 09 May 2025 07:38:36 GMT</pubDate>
            <description><![CDATA[<h1 id="0-환경-설정-및-의존성-설치">0. 환경 설정 및 의존성 설치</h1>
<pre><code class="language-python">!pip install pymysql sentence-transformers scikit-learn python-dotenv faiss-cpu</code></pre>
<h1 id="환경-변수-로드-및-db-접속-정보-초기화">환경 변수 로드 및 DB 접속 정보 초기화</h1>
<pre><code class="language-python">import os
from dotenv import load_dotenv
import pymysql

# 1) .env 파일 내용을 읽어 환경변수로 설정
load_dotenv()  

# 2) os.getenv 로 값을 가져오기
HOST     = os.getenv(&#39;HOST&#39;)
PORT     = int(os.getenv(&#39;PORT&#39;, 3306))
USER     = os.getenv(&#39;USER&#39;)
PASSWORD = os.getenv(&#39;PASSWORD&#39;)
DB_NAME  = os.getenv(&#39;DB_NAME&#39;)</code></pre>
<p><strong><code>.env</code></strong> 에 정의해 둔 DB 접속 정보를 읽어서 파이썬 변수(<code>HOST, PORT, USER, PASSWORD, DB_NAME</code>)로 할당</p>
<hr>
<h1 id="mariadb-연결-및-문서-불러오기">MariaDB 연결 및 문서 불러오기</h1>
<pre><code class="language-python">import pymysql

# 2) MariaDB에 연결 (autocommit=True 로 하면 별도 commit() 불필요)
conn = pymysql.connect(
    host=HOST,
    port=PORT,
    user=USER,
    password=PASSWORD,
    db=DB_NAME,
    charset=&#39;utf8mb4&#39;,
    autocommit=True
)

try:
    with conn.cursor() as cursor:
        # 3) documents 테이블 생성
        cursor.execute(&quot;&quot;&quot;
        CREATE TABLE IF NOT EXISTS documents (
            id INT PRIMARY KEY,
            content TEXT
        );
        &quot;&quot;&quot;)

        # 4) 10개 레코드를 한 번에 INSERT
        insert_sql = &quot;&quot;&quot;
        INSERT INTO documents (id, content) VALUES
        (1,  &#39;Artificial intelligence is transforming many industries.&#39;),
        (2,  &#39;Machine learning models can improve over time with more data.&#39;),
        (3,  &#39;Natural language processing enables computers to understand human language.&#39;),
        (4,  &#39;Deep learning is a subset of machine learning using neural networks.&#39;),
        (5,  &#39;Transformers have revolutionized natural language processing tasks.&#39;),
        (6,  &#39;AI applications range from healthcare to autonomous vehicles.&#39;),
        (7,  &#39;Neural networks are inspired by the structure of the human brain.&#39;),
        (8,  &#39;Training a deep learning model requires large datasets and computing power.&#39;),
        (9,  &#39;Transfer learning allows models to adapt quickly to new tasks.&#39;),
        (10, &#39;Explainable AI helps humans understand how AI systems make decisions.&#39;)
        ;
        &quot;&quot;&quot;
        cursor.execute(insert_sql)

        print(&quot;✅ test_db.documents 테이블에 10개 레코드 삽입 완료&quot;)
finally:
    conn.close()
</code></pre>
<p>테이블을 만들고 데이터(문장)을 삽입</p>
<blockquote>
<p>결과 : ✅ test_db.documents 테이블에 10개 레코드 삽입 완료</p>
</blockquote>
<pre><code class="language-python">try:
    with conn.cursor() as cursor:
        # 1) 모든 레코드 조회
        cursor.execute(&quot;SELECT id, content FROM documents ORDER BY id;&quot;)
        rows = cursor.fetchall()

        # 2) 출력
        if not rows:
            print(&quot;⚠️ documents 테이블에 데이터가 없습니다.&quot;)
        else:
            print(&quot;✅ documents 테이블 내용:&quot;)
            for row in rows:
                print(f&quot;  • id={row[0]}: {row[1]}&quot;)
finally:
    conn.close()</code></pre>
<p>✅ documents 테이블 내용:
• id=1: Artificial intelligence is transforming many industries.
• id=2: Machine learning models can improve over time with more data.
• id=3: Natural language processing enables computers to understand human language.
• id=4: Deep learning is a subset of machine learning using neural networks.
• id=5: Transformers have revolutionized natural language processing tasks.
• id=6: AI applications range from healthcare to autonomous vehicles.
• id=7: Neural networks are inspired by the structure of the human brain.
• id=8: Training a deep learning model requires large datasets and computing power.
• id=9: Transfer learning allows models to adapt quickly to new tasks.
• id=10: Explainable AI helps humans understand how AI systems make decisions.</p>
<p>정상적으로 데이터가 저장되었음을 확인할 수 있다.</p>
<hr>
<h1 id="sentence-bert-모델-로딩-및-임베딩-생성-확인">Sentence-BERT 모델 로딩 및 임베딩 생성 확인</h1>
<pre><code class="language-python">from sentence_transformers import SentenceTransformer

# 2) 코드 내에서 직접 사용할 모델명 지정
model_name = &#39;all-MiniLM-L6-v2&#39;  # 원하는 SBERT 프리트레인 모델로 변경 가능

# 3) 모델 로딩
print(f&quot;Loading Sentence-BERT model: {model_name} …&quot;)
model = SentenceTransformer(model_name)
print(&quot;Model loaded successfully!&quot;)

# 4) (테스트) 간단히 임베딩 생성 확인
examples = [
    &quot;안녕하세요, Sentence-BERT 테스트입니다.&quot;,
    &quot;자연어 처리 모델이 잘 로드되었는지 확인합니다.&quot;
]
embeddings = model.encode(examples, show_progress_bar=True)
for text, emb in zip(examples, embeddings):
    print(f&quot;– \&quot;{text}\&quot; → embedding 크기: {len(emb)}&quot;)</code></pre>
<blockquote>
<p>Model loaded successfully!
Batches: 100%|██████████| 1/1 [00:00&lt;00:00,  4.55it/s]
– &quot;안녕하세요, Sentence-BERT 테스트입니다.&quot; → embedding 크기: 384
– &quot;자연어 처리 모델이 잘 로드되었는지 확인합니다.&quot; → embedding 크기: 384</p>
</blockquote>
<p>모델이 정상적으로 로딩되고 임베딩이 정상적으로 이루어짐을 확인</p>
<hr>
<h1 id="vectordb-생성">VectorDB 생성</h1>
<p>기존에 연결되었던 MariaDB를 사용하지 않고 새로운 벡터 DB를 생성하여 임베딩 정보들을 저장하였다.</p>
<p>벡터 연산에 최적화된 벡터 DB를 도입함으로써 대규모·고속 검색이 가능해지고, 애플리케이션의 응답성과 유지보수성이 크게 향상시키고자 하였다.</p>
<pre><code class="language-python">import json
import numpy as np
import faiss
from sentence_transformers import SentenceTransformer
import os
from dotenv import load_dotenv
import pymysql
</code></pre>
<pre><code class="language-python">def build_vector_db(conn, model,
                    index_path=&#39;corpus.index&#39;,
                    ids_path=&#39;ids.json&#39;):
    &quot;&quot;&quot;
    conn: pymysql 커넥션
    model: 이미 로드된 SentenceTransformer 객체
    index_path, ids_path: 저장할 파일명
    &quot;&quot;&quot;
    # 1) DB에서 문장 불러오기
    with conn.cursor(pymysql.cursors.DictCursor) as cur:
        cur.execute(&quot;SELECT id, content FROM documents;&quot;)
        rows = cur.fetchall()

    ids    = [r[&#39;id&#39;]      for r in rows]
    corpus = [r[&#39;content&#39;] for r in rows]

    # 2) 문장 임베딩 (NumPy 배열)
    embeddings = model.encode(
        corpus,
        convert_to_numpy=True,
        show_progress_bar=True
    )

    # 3) FAISS 인덱스 구축 (코사인 유사도용)
    d     = embeddings.shape[1]
    index = faiss.IndexFlatIP(d)
    faiss.normalize_L2(embeddings)
    index.add(embeddings)

    # 4) 디스크에 저장
    faiss.write_index(index, index_path)
    with open(ids_path, &#39;w&#39;, encoding=&#39;utf-8&#39;) as f:
        json.dump(ids, f, ensure_ascii=False)

    print(f&quot;✅ VectorDB 저장 완료 → {index_path}, {ids_path}&quot;)

# — 호출 예 —
# (앞에서 model 이 이미 로드된 상태여야 함)
build_vector_db(conn, model)

conn.close()</code></pre>
<p>“데이터베이스에서 문장 데이터를 로드 → SBERT로 임베딩 생성 → FAISS 기반 벡터DB 인덱싱 및 저장”</p>
<blockquote>
<p>Batches: 100%|██████████| 1/1 [00:00&lt;00:00, 15.15it/s]
✅ VectorDB 저장 완료 → corpus.index, ids.json</p>
</blockquote>
<hr>
<h1 id="시맨틱-검색-함수-정의">시맨틱 검색 함수 정의</h1>
<pre><code class="language-python"># FAISS 인덱스 &amp; ID 매핑
index = faiss.read_index(&#39;corpus.index&#39;)
with open(&#39;ids.json&#39;,&#39;r&#39;,encoding=&#39;utf-8&#39;) as f:
    ids = json.load(f)</code></pre>
<p>corpus.index 파일에서 FAISS 벡터 인덱스를 로드하고, ids.json에서 벡터↔문서 ID 매핑을 불러옴</p>
<pre><code class="language-python">def get_connection():
    &quot;&quot;&quot; .env 기반으로 새 커넥션 반환 &quot;&quot;&quot;
    return pymysql.connect(
        host=os.getenv(&#39;HOST&#39;),
        port=int(os.getenv(&#39;PORT&#39;, 3306)),
        user=os.getenv(&#39;USER&#39;),
        password=os.getenv(&#39;PASSWORD&#39;),
        db=os.getenv(&#39;DB_NAME&#39;),
        charset=&#39;utf8mb4&#39;
    )</code></pre>
<p><code>.env</code> 에 정의된 환경변수(<code>HOST</code>, <code>PORT</code>, <code>USER</code>, <code>PASSWORD</code>, <code>DB_NAME</code>)를 읽는 함수</p>
<pre><code class="language-python">def semantic_search(query: str, top_k: int = 5):
    # 1) 쿼리 임베딩
    q_emb = model.encode(query, convert_to_numpy=True).astype(&#39;float32&#39;)
    q_emb = q_emb.reshape(1, -1)
    faiss.normalize_L2(q_emb)

    # 2) FAISS 검색
    D, I = index.search(q_emb, k=top_k)

    results = []
    conn = get_connection()
    try:
        with conn.cursor(pymysql.cursors.DictCursor) as cur:
            for dist, idx in zip(D[0], I[0]):
                doc_id = ids[int(idx)]
                cur.execute(
                    &quot;SELECT content FROM documents WHERE id = %s&quot;, 
                    (doc_id,)
                )
                row = cur.fetchone()
                if row:
                    results.append({
                        &#39;id&#39;:      doc_id,
                        &#39;content&#39;: row[&#39;content&#39;],
                        &#39;score&#39;:   float(dist)
                    })
    finally:
        conn.close()

    return results</code></pre>
<ul>
<li><strong>쿼리 임베딩</strong>: 입력된 검색어 <code>query</code> 를 SBERT 모델로 벡터화하고 L2 정규화</li>
<li><strong>FAISS 검색</strong>: 미리 구축해 둔 FAISS 인덱스(<code>index</code>)에서 상위 <code>top_k</code>개의 벡터 이웃을 찾아</li>
<li><strong>DB 조회</strong>: FAISS가 반환한 인덱스 번호(<code>idx</code>)→실제 문서 ID(<code>ids[idx]</code>)로 매핑한 뒤, 그 ID로 <code>documents</code> 테이블에서 원문(<code>content</code>)을 꺼내 함께 결과 리스트에 담아 리턴</li>
</ul>
<pre><code class="language-python">hits = semantic_search(&quot;What is transfer learning?&quot;, top_k=3)
for hit in hits:
    print(f&quot;id={hit[&#39;id&#39;]}  score={hit[&#39;score&#39;]:.4f}&quot;)
    print(&quot;→&quot;, hit[&#39;content&#39;], &quot;\n&quot;)</code></pre>
<blockquote>
<p>What is transfer learning 라는 질문에 대해 3개의 유사도 있는 문장을 찾아온다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b440b6c3-f721-4824-b63d-90cd954d51e7/image.png" alt=""></p>
<hr>
<h1 id="하이브리드-검색">하이브리드 검색</h1>
<pre><code class="language-python">!pip install rank-bm25</code></pre>
<p><strong>키워드 기반 랭킹</strong> 계산을 위한 라이브러리</p>
<pre><code class="language-python">from rank_bm25 import BM25Okapi
import json, os</code></pre>
<h2 id="검색-함수-정의">검색 함수 정의</h2>
<pre><code class="language-python">def hybrid_search(query: str,
                  top_k: int = 5,
                  alpha: float = 0.5):
    &quot;&quot;&quot;
    * query: 검색어
    * top_k: 최종 반환 개수
    * alpha: 시맨틱(score_sem) vs BM25(score_bm) 가중치
    &quot;&quot;&quot;
    # 1) 쿼리 임베딩 &amp; 정규화
    q_emb = model.encode(query, convert_to_numpy=True).astype(&#39;float32&#39;)
    q_emb = q_emb.reshape(1, -1)
    faiss.normalize_L2(q_emb)

    # 2) FAISS 시맨틱 검색
    D_sem, I_sem = index.search(q_emb, k=top_k * 2)
    sem_scores = { ids[int(idx)]: float(dist)
                   for dist, idx in zip(D_sem[0], I_sem[0]) }

    # 3) BM25 점수 계산 및 정규화
    tokenized_query = query.split()
    bm25_scores = bm25.get_scores(tokenized_query)
    bm25_norm   = bm25_scores / (bm25_scores.max() or 1.0)
    bm25_scores_map = { ids[i]: bm25_norm[i] for i in range(len(ids)) }

    # 4) 하이브리드 스코어 결합
    all_ids = set(sem_scores) | set(bm25_scores_map)
    hybrid_list = [
        (doc_id, alpha * sem_scores.get(doc_id, 0.0) + 
                 (1 - alpha) * bm25_scores_map.get(doc_id, 0.0))
        for doc_id in all_ids
    ]
    hybrid_list.sort(key=lambda x: x[1], reverse=True)
    topk = hybrid_list[:top_k]

    # 5) 결과 조회
    results = []
    conn = get_connection()
    try:
        with conn.cursor(pymysql.cursors.DictCursor) as cur:
            for doc_id, score in topk:
                cur.execute(
                    &quot;SELECT content FROM documents WHERE id=%s&quot;, (doc_id,)
                )
                row = cur.fetchone()
                if row:
                    results.append({
                        &#39;id&#39;:      doc_id,
                        &#39;content&#39;: row[&#39;content&#39;],
                        &#39;score&#39;:   score
                    })
    finally:
        conn.close()

    return results</code></pre>
<p><code>hybrid_search</code> 함수는 <strong>시맨틱 검색(SBERT+FAISS)</strong> 과 <strong>키워드 검색(BM25)</strong> 점수를 동시에 활용해, 두 점수를 <code>alpha</code> 비율로 가중 결합한 뒤 최종 상위 k개 결과를 반환</p>
<pre><code class="language-python">for hit in hybrid_search(&quot;What is transfer learning?&quot;, top_k=3, alpha=0.7):
    print(f&quot;id={hit[&#39;id&#39;]}  hybrid_score={hit[&#39;score&#39;]:.4f}&quot;)
    print(&quot;→&quot;, hit[&#39;content&#39;], &quot;\n&quot;)</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/29a9caed-709c-420d-9187-e3a9dc7d2ccd/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (11) - AI와 머신러닝에서의 활용]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-11-AI%EC%99%80-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%97%90%EC%84%9C%EC%9D%98-%ED%99%9C%EC%9A%A9-0tl3ri4u</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-11-AI%EC%99%80-%EB%A8%B8%EC%8B%A0%EB%9F%AC%EB%8B%9D%EC%97%90%EC%84%9C%EC%9D%98-%ED%99%9C%EC%9A%A9-0tl3ri4u</guid>
            <pubDate>Fri, 09 May 2025 07:10:22 GMT</pubDate>
            <description><![CDATA[<h2 id="추천-시스템">추천 시스템</h2>
<p><strong>벡터가 왜 필요할까?</strong></p>
<p><strong>1. 기존 추천 시스템의 한계</strong></p>
<ul>
<li><p><strong>명시적 행동 기반</strong> 추천 (예: A를 샀으니 B 추천)</p>
</li>
<li><p>유저의 구매 이력 + 제품 속성 조합으로 추천</p>
<p>  → 의미 기반 유사성 파악에 어려움 존재</p>
</li>
</ul>
<hr>
<p><strong>벡터 기반 추천 시스템</strong></p>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td><strong>정의</strong></td>
<td>사용자의 행동이나 관심사를 벡터로 표현하고, 제품/콘텐츠도 벡터로 만들어 <strong>의미상 가까운 것</strong>을 추천</td>
</tr>
<tr>
<td><strong>예시</strong></td>
<td>유저 A가 본 영화 → 로맨틱 코미디 → 해당 벡터 생성 → 유사한 영화 벡터 추천 (장르 다르지만 분위기 유사 등)</td>
</tr>
</tbody></table>
<hr>
<p><strong>작동 방식</strong></p>
<ol>
<li>사용자 행동 데이터 수집 (클릭, 시청, 좋아요 등)</li>
<li>AI 모델로 사용자와 아이템을 임베딩 (Embedding)</li>
<li>벡터 DB에 저장</li>
<li>유저가 들어오면 해당 유저의 벡터와 가장 유사한 아이템 벡터 검색</li>
</ol>
<hr>
<p><strong>장점</strong></p>
<ul>
<li><strong>콜드 스타트 문제 해결</strong>: 행동 데이터 적어도 의미 기반 추천 가능</li>
<li><strong>의미 기반 추천</strong>: 카테고리, 장르가 달라도 분위기 유사한 콘텐츠 추천 가능</li>
<li><strong>실시간 반영</strong>: 벡터 변화 반영 시 즉시 추천 가능</li>
</ul>
<hr>
<p><strong>실제 사용 예시</strong></p>
<table>
<thead>
<tr>
<th>플랫폼</th>
<th>활용 방식</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Netflix</strong></td>
<td>시청 기록 → 벡터 → 유사 콘텐츠 추천</td>
</tr>
<tr>
<td><strong>Spotify</strong></td>
<td>음악 벡터 → 분위기 유사 음악 추천</td>
</tr>
<tr>
<td><strong>쿠팡/아마존</strong></td>
<td>상품 벡터 + 유저 행동 → 유사 상품 추천</td>
</tr>
</tbody></table>
<hr>
<h2 id="이미지-검색">이미지 검색</h2>
<p><strong>벡터 기반 이미지 검색</strong></p>
<p><strong>정의</strong></p>
<ul>
<li>이미지 자체를 AI 모델로 분석하여 벡터로 변환</li>
<li>이미지의 시각적 특성을 수치로 표현</li>
<li>쿼리 이미지와 유사한 벡터를 찾아 <strong>의미적으로 유사한 이미지 검색</strong></li>
</ul>
<hr>
<p><strong>예시</strong></p>
<ul>
<li><p>사용자가 사진을 업로드</p>
<p>  → AI 모델이 벡터로 변환</p>
<p>  → DB에 있는 수백만 벡터 중 가장 유사한 5개 이미지 검색</p>
<p>  예: &quot;강아지가 모래사장에서 노는 사진&quot; → 비슷한 분위기의 강아지 사진 반환</p>
</li>
</ul>
<hr>
<p><strong>기존 이미지 검색 방식의 한계</strong></p>
<ul>
<li><p><strong>텍스트 기반 검색</strong>: 이미지에 태그나 파일명이 있어야 검색 가능</p>
<p>  예: &quot;노을 사진&quot; → <code>sunset.jpg</code> 또는 <code>#sunset</code> 태그 필요</p>
<p>  → 텍스트 정보 없으면 검색 불가</p>
</li>
</ul>
<hr>
<p><strong>작동 방식</strong></p>
<ol>
<li>이미지 → AI 모델(CNN, CLIP 등) → 고차원 벡터</li>
<li>벡터 DB에 저장</li>
<li>쿼리 이미지 → 동일 모델로 벡터화</li>
<li>쿼리 벡터와 가장 유사한 벡터를 <strong>Top-K</strong>로 검색</li>
</ol>
<hr>
<p><strong>장점</strong></p>
<ul>
<li><strong>텍스트 없이도 검색 가능</strong> (이미지 그 자체로 검색)</li>
<li>색감, 구성, 분위기 등의 <strong>시각적 유사성</strong>까지 반영</li>
<li>패션, 디자인, 건축 등 <strong>비정형 시각 데이터</strong>에 강력</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/6c5289f2-0f6d-4163-900c-62fd6af0517b/image.png" alt=""></p>
<hr>
<h2 id="자연어-처리-응용">자연어 처리 응용</h2>
<p><strong>텍스트 벡터화란?</strong></p>
<ul>
<li><strong>벡터화(embedding)</strong>: 문장, 문서, 질문 등을 AI 모델을 통해 숫자의 배열(벡터)로 변환</li>
<li>이 숫자 배열은 텍스트의 <strong>의미, 감정, 주제, 스타일</strong> 등을 반영</li>
</ul>
<hr>
<p><strong>주요 응용 분야</strong></p>
<table>
<thead>
<tr>
<th>분야</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>의미 기반 검색 (Semantic Search)</td>
<td>- 사용자가 입력한 문장의 의도에 맞는 결과를 검색 - 예시: “휴가용 가벼운 책 추천” → 여행 에세이, 소설 추천 - 과학 기술 관련 서적 → 기술 서적 목록 출력</td>
</tr>
<tr>
<td>유사 문서 찾기</td>
<td>- 논문, 기사, 리뷰 등에서 비슷한 문서 자동 연결 - 예시: 특정 논문과 관련된 다른 논문 자동 찾기</td>
</tr>
<tr>
<td>챗봇 응답 검색 (RAG 방식)</td>
<td>- 질문 → 벡터화 → 벡터 DB에서 유사한 문서 검색 - 검색된 문서를 LLM에 넣어 답변 생성 → 최신 정보 + 정확한 응답 가능 (예: ChatGPT with Retrieval)</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b09a7218-2c60-443e-a37d-53f33f9540f2/image.png" alt=""></p>
<hr>
<p><strong>대표 벡터 모델</strong></p>
<table>
<thead>
<tr>
<th>모델</th>
<th>용도</th>
</tr>
</thead>
<tbody><tr>
<td><strong>BERT</strong></td>
<td>문장/단어의 문맥 벡터화</td>
</tr>
<tr>
<td><strong>Sentence-BERT</strong></td>
<td>문장 간 유사도 계산에 특화</td>
</tr>
<tr>
<td><strong>OpenAI Embedding</strong></td>
<td>문장 → 벡터 변환에 강력</td>
</tr>
<tr>
<td><strong>CLIP</strong></td>
<td>텍스트 + 이미지 공동 벡터화</td>
</tr>
</tbody></table>
<hr>
<p><strong>이 분야 공통점</strong></p>
<ul>
<li>텍스트 / 이미지 / 사용자 / 상품 → <strong>벡터로 변환</strong></li>
<li><strong>벡터 DB에 저장</strong></li>
<li><strong>유사도 기반 검색</strong> 수행</li>
</ul>
<blockquote>
<p>벡터 DB는 AI 시스템의 의미 기반 검색 엔진 역할을 수행함.</p>
</blockquote>
<hr>
<h3 id="clip">CLIP</h3>
<p>OPENAI가 만든, 텍스트와 이미지를 함께 이해할 수 있는 AI 모델</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/65e14f46-7fb7-4e07-9875-520d655d3117/image.png" alt=""></p>
<blockquote>
<p>CLIP은 이미지와 텍스트를 같은 공간(벡터 공간)에 매핑</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/fb8e5182-7aec-4bdc-8d4e-6a6285131c2e/image.png" alt=""></p>
<hr>
<p>CLIP은 2개의 인코더를 가지고 있음</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/2f026fd8-c59f-4bf1-b62c-fb4cb91e6088/image.png" alt=""></p>
<blockquote>
<p>CLIP은 텍스트와 이미지를 같은 벡터 공간에서 비교할 수 있기 때문에 텍스트로 이미지 찾기, 이미지로 텍스트 찾기 둘 다 가능</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/27ce8c79-912b-414c-8103-59e53e1fa096/image.png" alt=""></p>
<pre><code class="language-python">import clip
import torch
from PIL import Image

model, preprocess = clip.load(&quot;ViT-B/32&quot;)
image = preprocess(Image.open(&quot;cat.jpg&quot;)).unsqueeze(0)
text = clip.tokenize([&quot;a cat&quot;, &quot;a dog&quot;, &quot;a car&quot;])

with torch.no_grad():
    image_features = model.encode_image(image)
    text_features = model.encode_text(text)

# 유사도 계산 (Cosine similarity)
similarity = (image_features @ text_features.T).softmax(dim=-1)
print(similarity)</code></pre>
<hr>
<h1 id="대규모-언어-모델-llm-과의-통합">대규모 언어 모델 LLM 과의 통합</h1>
<h2 id="rag">RAG</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/5ee7851f-31d2-4ab8-9a4e-302d12490222/image.png" alt=""></p>
<ul>
<li>필요한 정보를 먼저 찾아오고</li>
<li>그걸 참고해서 답변을 생성하는 방식</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/7ad7ca92-ef1e-487b-941a-8d7554c70eec/image.png" alt=""></p>
<hr>
<p><strong>RAG를 구성하는 핵심 요소</strong></p>
<table>
<thead>
<tr>
<th>구성 요소</th>
<th>역할</th>
<th>쉽게 말하면</th>
</tr>
</thead>
<tbody><tr>
<td><strong>질문 임베딩 (Embedding)</strong></td>
<td>질문을 숫자(벡터)로 변환</td>
<td>&quot;의미를 계산하는 방식&quot;</td>
</tr>
<tr>
<td><strong>벡터 DB</strong></td>
<td>의미가 비슷한 문서를 저장하고 검색</td>
<td>&quot;AI용 검색창&quot;</td>
</tr>
<tr>
<td><strong>LLM (GPT 등)</strong></td>
<td>문서를 참고해서 응답 생성</td>
<td>&quot;지식과 언어 능력 담당&quot;</td>
</tr>
</tbody></table>
<hr>
<p><strong>장점</strong></p>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>최신 정보 사용 가능</strong></td>
<td>실시간으로 새로운 문서를 검색해서 반영 가능</td>
</tr>
<tr>
<td><strong>사내 문서 기반 응답</strong></td>
<td>기업 내부 매뉴얼, 정책 등을 연결해 정확한 응답 가능</td>
</tr>
<tr>
<td><strong>환각(Hallucination) 줄이기</strong></td>
<td>LLM이 &quot;모른다&quot; 하지 않고, 문서를 기반으로 응답하여 신뢰도 향상</td>
</tr>
<tr>
<td><strong>유연한 시스템 확장</strong></td>
<td>모델을 다시 학습할 필요 없이 문서만 바꾸면 됨</td>
</tr>
</tbody></table>
<hr>
<h3 id="llm-모델의-제약으로-벡터-db가-필요">LLM 모델의 제약으로 벡터 DB가 필요</h3>
<table>
<thead>
<tr>
<th>LLM 한계</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>오래된 지식</strong></td>
<td>최신 뉴스나 문서는 알지 못함</td>
</tr>
<tr>
<td><strong>긴 문서 기억 어려움</strong></td>
<td>긴 텍스트를 한 번에 모두 입력할 수 없음</td>
</tr>
<tr>
<td><strong>헛소리(?) 가능성</strong></td>
<td>모르면 그럴듯한 거짓말을 함 (AI 환각 현상)</td>
</tr>
</tbody></table>
<blockquote>
<p>이 문제를 해결하기 위해 등장한 것이 바로 벡터 데이터베이스 + RAG 조합</p>
</blockquote>
<hr>
<h1 id="벡터-database-구축-및-관리">벡터 Database 구축 및 관리</h1>
<h2 id="벡터-저장-공간-구분">벡터 저장 공간 구분</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0cc7a025-2913-49f5-9f54-fcc4cb42baeb/image.png" alt=""></p>
<hr>
<h2 id="주요-벡터-database-솔루션-비교">주요 벡터 Database 솔루션 비교</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/6649370f-0dfe-447f-9126-89eccbe89972/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/93d22a56-d95b-4cac-907f-8ea82841570e/image.png" alt=""></p>
<hr>
<h2 id="성능-최적화-전략">성능 최적화 전략</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/4d1b9692-0249-4ac9-a24f-9a9c9e9a3102/image.png" alt=""></p>
<hr>
<h2 id="스케일링-전략-규모-확장">스케일링 전략, 규모 확장</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/a8ae6863-0b09-4a24-9e39-22b9dc305517/image.png" alt=""></p>
<hr>
<h2 id="사례">사례</h2>
<p><img src="blob:https://velog.io/dec4ebc2-3dda-4290-b445-693ed231919c" alt="업로드중.."></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (10) - 벡터 DB 쿼리 처리]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-10-%EB%B2%A1%ED%84%B0-DB-%EC%BF%BC%EB%A6%AC-%EC%B2%98%EB%A6%AC</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-10-%EB%B2%A1%ED%84%B0-DB-%EC%BF%BC%EB%A6%AC-%EC%B2%98%EB%A6%AC</guid>
            <pubDate>Fri, 09 May 2025 07:05:45 GMT</pubDate>
            <description><![CDATA[<h2 id="쿼리">쿼리</h2>
<p>단순 키워드 검색이 아닌 텍스트, 이미지, 오디오 등의 의미 기반 유사성 검색</p>
<h3 id="벡터-db-쿼리-단계">벡터 DB 쿼리 단계</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/84bbe99e-019d-416a-a204-3db465bce0d3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/62878050-59d6-4deb-9500-7c66b11d62a2/image.png" alt=""></p>
<hr>
<h3 id="전통-db와-벡터-db-비교">전통 DB와 벡터 DB 비교</h3>
<table>
<thead>
<tr>
<th>구분</th>
<th>전통 RDB</th>
<th>벡터 DB</th>
</tr>
</thead>
<tbody><tr>
<td><strong>목적</strong></td>
<td>조건 일치 검색</td>
<td>의미 기반 유사 검색</td>
</tr>
<tr>
<td><strong>쿼리 방식</strong></td>
<td>SQL</td>
<td>벡터 유사도 기반</td>
</tr>
<tr>
<td><strong>인덱스</strong></td>
<td>B-Tree 등</td>
<td>HNSW, IVF 등</td>
</tr>
<tr>
<td><strong>반환 결과</strong></td>
<td>일치하는 값</td>
<td>유사한 결과 (확률/유사도 기반)</td>
</tr>
</tbody></table>
<hr>
<h2 id="병렬-처리와-분산-시스템---병렬-처리">병렬 처리와 분산 시스템 - 병렬 처리</h2>
<p><strong>병렬처리 개요</strong></p>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td><strong>정의</strong></td>
<td>하나의 머신(서버) 안에서 여러 개의 CPU 또는 GPU 코어가 동시에 계산을 수행하는 것</td>
</tr>
<tr>
<td><strong>필요 이유</strong></td>
<td>- 하나의 쿼리 벡터 실행 시<br>- 수백만 개 벡터와 유사도 계산 필요<br>- 벡터 간 연산은 128~1536차원 사이의 수치 연산 반복<br>→ 거리 계산 반복으로 인해 병렬 처리 필수</td>
</tr>
</tbody></table>
<blockquote>
<p>이런 연산을 하나하나 직렬로 처리하면 느려서 <strong>병렬처리 필요</strong></p>
</blockquote>
<hr>
<p><strong>병렬 처리 방식</strong></p>
<table>
<thead>
<tr>
<th>처리 방식</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>CPU 멀티스레드</strong></td>
<td>여러 CPU 코어가 벡터 계산을 나눠서 처리</td>
</tr>
<tr>
<td><strong>GPU 가속</strong></td>
<td>수천 개의 코어를 가진 GPU가 병렬로 벡터 연산 수행</td>
</tr>
<tr>
<td><strong>SIMD 명령어</strong></td>
<td>CPU 내부에서 동일 명령을 동시에 실행 (예: AVX, SSE)</td>
</tr>
</tbody></table>
<hr>
<p><strong>예시</strong></p>
<ul>
<li>사용자가 <code>query_vector</code> 하나로 <strong>1,000만 개 벡터</strong>와 유사도 비교 요청 시<ul>
<li><strong>직렬 처리</strong>: 1 CPU가 1개씩 비교 → 시간 매우 오래 걸림</li>
<li><strong>병렬 처리 예시</strong>:<ul>
<li><strong>8코어 CPU</strong> → 코어당 125만 개씩 병렬 비교</li>
<li><strong>GPU 수천 개 코어</strong> → 병렬 벡터 내적 연산으로 훨씬 빠름</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/40fb0005-0d4a-4ec3-bdb6-658791e8aeef/image.png" alt=""></p>
<hr>
<h2 id="병렬-처리와-분산-시스템---분산-시스템">병렬 처리와 분산 시스템 - 분산 시스템</h2>
<p><strong>분산 시스템 개요</strong></p>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>정의</td>
<td>벡터 데이터를 여러 대의 서버(노드)에 나눠서 저장하고, 검색 요청도 동시에 분산해서 처리하는 구조</td>
</tr>
<tr>
<td>필요 이유</td>
<td>- 벡터 데이터 증가 시 저장용량/연산량이 기하급수적으로 증가<br>- 단일 서버의 처리 능력(CPU, 메모리 등)에 한계 존재<br>- 예: 벡터 1개가 512차원, float32(4byte)일 때<br>→ 1억 개 벡터: 512 × 4 × 100,000,000 = 200GB<br>→ 인덱스 및 메타데이터 추가 시 수백 GB ~ TB급 용량 필요</td>
</tr>
</tbody></table>
<blockquote>
<p>여러 서버에 나눠서 저장하고 동시에 검색하는 구조가 필요</p>
</blockquote>
<hr>
<p><strong>구성요소 및 역할</strong></p>
<table>
<thead>
<tr>
<th>구성요소</th>
<th>역할</th>
</tr>
</thead>
<tbody><tr>
<td>Proxy/Router</td>
<td>클라이언트 요청을 적절한 노드에 분배</td>
</tr>
<tr>
<td>Query Node</td>
<td>쿼리 요청을 처리하고 유사도 계산</td>
</tr>
<tr>
<td>Data Node</td>
<td>벡터 데이터를 저장</td>
</tr>
<tr>
<td>Index Node</td>
<td>벡터 인덱스 생성 및 유지</td>
</tr>
<tr>
<td>Coordinator</td>
<td>전체 클러스터 상태를 관리</td>
</tr>
</tbody></table>
<hr>
<p><strong>예시</strong></p>
<ul>
<li>1억 개 벡터 데이터를 10대의 서버에 나눠 저장</li>
<li>쿼리가 들어오면 10대 서버가 동시에 검색 수행</li>
<li>각 서버는 1,000만 개씩 검색 → 속도 10배 향상</li>
<li>결과는 병합해서 최종 Top-K 반환</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b2c39e68-72bf-4fab-9b5a-ee0d65d91ea8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e52b0340-fea4-4463-9436-acfb7d265a63/image.png" alt=""></p>
<hr>
<h2 id="요약-병렬처리-vs-분산-시스템">요약: 병렬처리 vs 분산 시스템</h2>
<table>
<thead>
<tr>
<th>항목</th>
<th>병렬 처리</th>
<th>분산 시스템</th>
</tr>
</thead>
<tbody><tr>
<td>처리 위치</td>
<td>1대 서버 내부</td>
<td>여러 대의 서버 간</td>
</tr>
<tr>
<td>사용 리소스</td>
<td>CPU, GPU 코어</td>
<td>전체 클러스터 자원</td>
</tr>
<tr>
<td>확장 방법</td>
<td>코어 수 늘리기</td>
<td>서버 수 늘리기</td>
</tr>
<tr>
<td>장점</td>
<td>빠른 연산, 적은 네트워크 비용</td>
<td>고용량 데이터 처리, 높은 확장성</td>
</tr>
</tbody></table>
<p><strong>요약 정리</strong>:</p>
<ul>
<li>벡터 검색은 수많은 벡터 간 고차원 거리 계산으로 연산량이 큼</li>
<li>병렬 처리는 한 서버 안에서 연산을 빠르게 → CPU/GPU 활용</li>
<li>분산 시스템은 여러 서버에 데이터를 나눠 → 속도 및 저장 확장</li>
<li>실제 서비스에서는 두 가지를 함께 활용하는 것이 일반적<ul>
<li>예: Milvus + CUDA + 클러스터 구성</li>
</ul>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (9) - 벡터 DB 검색]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-9-%EB%B2%A1%ED%84%B0-DB-%EA%B2%80%EC%83%89-2y0qc9te</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-9-%EB%B2%A1%ED%84%B0-DB-%EA%B2%80%EC%83%89-2y0qc9te</guid>
            <pubDate>Fri, 09 May 2025 07:01:43 GMT</pubDate>
            <description><![CDATA[<h2 id="검색프로세스">검색프로세스</h2>
<p>벡터 DB는 텍스트, 이미지, 음성 등을 벡터(숫자 배열)로 변환한 뒤, 비슷한 벡터끼리 검색하므로 검색 요청 시 4단계를 거쳐 결과를 출력</p>
<h3 id="1-쿼리-임베딩-생성-query-embedding"><strong>1. 쿼리 임베딩 생성 (Query Embedding)</strong></h3>
<ul>
<li><p>검색어나 질문을 벡터로 변환하는 단계</p>
</li>
<li><p>사용자가 입력한 텍스트(예: &quot;붉은 드레스&quot;)를 벡터로 변환</p>
</li>
<li><p>NLP 또는 멀티모달 AI 모델(BERT, CLIP 등)을 사용</p>
</li>
<li><p>예시 임베딩 결과: <code>[0.12, -0.45, 0.89, ...]</code> (보통 128~768차원 이상)</p>
</li>
</ul>
<blockquote>
<p><strong>검색 품질은 사용하는 모델에 따라 달라짐</strong></p>
</blockquote>
<h3 id="2-인덱스-트리-탐색-index-tree-search"><strong>2. 인덱스 트리 탐색 (Index Tree Search)</strong></h3>
<ul>
<li><p>전체 벡터 중에서 빠르게 후보 벡터를 찾기 위한 구조적 탐색</p>
</li>
<li><p><strong>ANN 알고리즘</strong> 사용 (예: HNSW, IVF, PQ 등)</p>
</li>
</ul>
<blockquote>
<p><strong>검색 속도 최적화에 핵심적인 역할</strong></p>
</blockquote>
<h3 id="3-유사도-스코어-계산-similarity-score-calculation"><strong>3. 유사도 스코어 계산 (Similarity Score Calculation)</strong></h3>
<ul>
<li><p>쿼리 벡터와 후보 벡터 간의 유사도 또는 거리 계산</p>
</li>
<li><p>주요 방법:</p>
<ul>
<li><strong>Cosine Similarity</strong> (0~1): 각도 기반 유사성</li>
<li><strong>L2 거리</strong>: 유클리드 거리 (작을수록 유사)</li>
<li><strong>Dot Product</strong>: 내적 계산</li>
</ul>
</li>
<li><p>예: 코사인 유사도가 0.92면 거의 비슷한 것으로 간주</p>
</li>
</ul>
<h3 id="4-결과-정렬-및-필터링-ranking--filtering"><strong>4. 결과 정렬 및 필터링 (Ranking &amp; Filtering)</strong></h3>
<ul>
<li><p>유사도 점수 기준으로 정렬 (Top-K 등)</p>
</li>
<li><p>필터링 조건 적용 가능 (예: 가격, 브랜드, 카테고리 등)</p>
</li>
<li><p><strong>메타데이터 기반 필터링도 가능</strong></p>
</li>
</ul>
<hr>
<h2 id="하이브리드-검색--벡터--메타데이터-결합">하이브리드 검색 : 벡터 + 메타데이터 결합</h2>
<blockquote>
<p>“벡터 검색 결과 + 조건 기반 필터”를 함께 사용하는 방식</p>
</blockquote>
<p><strong>예시 쿼리</strong></p>
<blockquote>
<p>“붉은 색 드레스 + 가격 &lt; 5만 원”</p>
</blockquote>
<p><strong>처리 방식</strong></p>
<ul>
<li><strong>“붉은 색 드레스”</strong> → 텍스트 벡터화 → 유사도 검색 수행</li>
<li><strong>가격 &lt; 50,000</strong> → 메타데이터 필터링 조건으로 적용</li>
</ul>
<p><strong>동작 순서</strong></p>
<ol>
<li>쿼리 <code>&quot;붉은 드레스&quot;</code>를 임베딩 → 벡터 <strong>A</strong> 생성</li>
<li>벡터 A와 데이터셋 내 임베딩들과 유사도 비교</li>
<li>유사도 상위 결과 <strong>Top-K</strong> 추출</li>
<li>그 중 <strong>가격이 5만 원 미만</strong>인 항목만 필터링</li>
<li><strong>최종 결과 반환</strong></li>
</ol>
<p>즉, <strong>벡터 기반 의미 검색</strong>과 <strong>속성 기반 필터링</strong>이 결합된 형태로, 텍스트 의미 유사성과 숫자 조건을 함께 만족하는 결과를 효율적으로 추출</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d91c33df-7e8a-47c4-825f-48627f4bac8c/image.png" alt=""></p>
<hr>
<h2 id="벡터-db애서-하이브리드-검색-구현">벡터 DB애서 하이브리드 검색 구현</h2>
<p><strong>[하이브리드 검색 구현 가능 대상]</strong></p>
<ul>
<li>벡터 인덱싱</li>
<li>ANN 탐색</li>
<li>메타데이터 필터링 쿼리</li>
<li>정렬 및 랭킹 전략</li>
</ul>
<hr>
<p><strong>[요약]</strong></p>
<table>
<thead>
<tr>
<th>단계</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>1. 쿼리 임베딩</td>
<td>입력 쿼리를 벡터로 변환</td>
</tr>
<tr>
<td>2. 인덱스 탐색</td>
<td>ANN 인덱스를 통해 빠르게 후보 벡터 탐색</td>
</tr>
<tr>
<td>3. 유사도 계산</td>
<td>코사인, L2, 내적 등을 이용하여 유사도 측정</td>
</tr>
<tr>
<td>4. 결과 정렬/필터</td>
<td>유사도 순 정렬 후 <strong>메타 조건으로 필터링</strong></td>
</tr>
</tbody></table>
<hr>
<p><strong>[하이브리드 검색]</strong></p>
<ul>
<li><strong>설명</strong>: 의미 기반 + 구조 기반 필터를 동시에 사용</li>
<li><strong>장점</strong>: 정확도 향상, 사용자의 외도(의도 외 조건)까지 반영 가능</li>
<li><strong>예시</strong>:<ul>
<li><code>&quot;빨간색 가방&quot;</code> + 브랜드 = 구찌</li>
<li>가격 &lt; 100만 원</li>
</ul>
</li>
</ul>
<hr>
<h2 id="qdrant-기반-벡터-db-실습">Qdrant 기반 벡터 DB 실습</h2>
<ol>
<li>사전 설치</li>
</ol>
<pre><code class="language-python">pip install qdrant-client sentence-transformers</code></pre>
<ol>
<li>예제 코드</li>
</ol>
<pre><code class="language-python">from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, Filter, FieldCondition, Range
from sentence_transformers import SentenceTransformer

# 1. 벡터화 모델 로딩 (텍스트 -&gt; 벡터)
encoder = SentenceTransformer(&#39;all-MiniLM-L6-v2&#39;)

# 2. Qdrant 클라이언트 연결 (로컬 or 클라우드)
client = QdrantClient(host=&#39;localhost&#39;, port=6333)

# 3. 예시 데이터 (신발 정보 + 가격)
products = [
    {&quot;id&quot;: 1, &quot;name&quot;: &quot;노란색 운동화&quot;, &quot;price&quot;: 30000},
    {&quot;id&quot;: 2, &quot;name&quot;: &quot;검정 구두&quot;, &quot;price&quot;: 70000},
    {&quot;id&quot;: 3, &quot;name&quot;: &quot;노란색 슬리퍼&quot;, &quot;price&quot;: 45000},
    {&quot;id&quot;: 4, &quot;name&quot;: &quot;빨간색 운동화&quot;, &quot;price&quot;: 40000}
]</code></pre>
<pre><code class="language-python"># 4. 벡터 생성 및 업로드
points = []
for p in products:
    벡터 = encoder.encode(p[&quot;name&quot;]).tolist()
    payload = {&quot;name&quot;: p[&quot;name&quot;], &quot;price&quot;: p[&quot;price&quot;]}
    points.append(PointStruct(id=p[&quot;id&quot;], vector=벡터, payload=payload))

# 5. 컬렉션 생성 및 데이터 업로드
collection_name = &quot;shoes&quot;
client.recreate_collection(
    collection_name=collection_name,
    vector_size=len(points[0].vector),
    distance=&quot;Cosine&quot;
)
client.upsert(collection_name=collection_name, points=points)</code></pre>
<p>→ 유사도는 코사인을 기준으로 측정함</p>
<pre><code class="language-python"># 6. 검색 쿼리: &quot;노란색 신발&quot; + 가격 &lt; 50000
query_text = &quot;노란색 신발&quot;
query_벡터 = encoder.encode(query_text).tolist()

# 메타데이터 필터 정의
price_filter = Filter(
    must=[
        FieldCondition(
            key=&quot;price&quot;,
            range=Range(lt=50000)
        )
    ]
)</code></pre>
<pre><code class="language-python"># 7. 벡터 + 필터 검색 (하이브리드)
results = client.search(
    collection_name=collection_name,
    query_vector=query_벡터,
    limit=3,
    query_filter=price_filter
)

# 8. 결과 출력
for r in results:
    print(f&quot;{r.payload[&#39;name&#39;]} | {r.payload[&#39;price&#39;]}원 | 유사도: {r.score:.4f}&quot;)</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1828f2a1-9ee4-40ca-b73b-aba3fcd19a7a/image.png" alt=""></p>
<hr>
<h2 id="벡터-db-검색-방식-비교">벡터 DB 검색 방식 비교</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e4f8f868-0bf4-4ab3-a73f-9f98800ea0da/image.png" alt=""></p>
<hr>
<h3 id="키워드-검색">키워드 검색</h3>
<blockquote>
<p>단어의 등장 빈도가 비슷한 문서를 검색하거나, 등장 여부를 필터링하여 검색하는 방식</p>
</blockquote>
<p><strong>[키워드 검색]</strong></p>
<p>■ 개념</p>
<ul>
<li>사용자가 입력한 <strong>정확한 단어(키워드)</strong>가 포함된 문서를 찾는 전통적인 검색 방식</li>
<li>일반적으로 <strong>역 색인 구조</strong> 사용</li>
<li>입력된 단어와 일치하는 문서를 색인에서 빠르게 조회</li>
</ul>
<p>■ 기술적 구성</p>
<ul>
<li>텍스트 토큰화 → 불용어 제거(Stopword removal) → 소문자 변환 등 전처리</li>
<li>사용자 쿼리도 동일 방식으로 처리하여 색인과 매칭</li>
</ul>
<p>■ 예시</p>
<ul>
<li><code>&quot;인공지능 기술 동향&quot;</code> → 문서 내 일치 문장 검색</li>
<li><code>&quot;2023년 AI 기술이 급속히 발전&quot;</code> → 연도 포함 문서 매칭</li>
<li><code>&quot;BERT&quot;</code> → 기술 키워드 필터링</li>
<li><code>&quot;AI 관련 정보 사례&quot;</code> 등 명확 키워드 기반 문장</li>
</ul>
<p>■ 장점</p>
<ul>
<li>빠른 검색 속도 (역색인 기반)</li>
<li>구현이 용이하고 단순</li>
</ul>
<p>■ 단점</p>
<ul>
<li><strong>동의어</strong>, <strong>오탈자</strong>, 유사 표현 인식 어려움</li>
<li>의미나 문맥 이해 없이 <strong>문자 그대로만 매칭</strong>되므로 질의 의도 파악이 어렵다</li>
</ul>
<hr>
<p><strong>[보완 방식]</strong></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/6242cc63-449f-4666-9713-d6c9b47bb092/image.png" alt=""></p>
<ol>
<li><strong>Attribute Filter (속성 필터 검색)</strong></li>
</ol>
<ul>
<li>검색 조건으로 특정 속성(attribute, column, field)의 값을 기준으로 필터링</li>
<li>SQL의 <code>WHERE</code> 절과 유사</li>
<li>예: <code>가격 &lt; 50000</code>, <code>카테고리 = &#39;신발&#39;</code></li>
</ul>
<ol start="2">
<li><strong>Sparse 벡터 검색 (희소 벡터 검색)</strong></li>
</ol>
<ul>
<li>텍스트 문서를 단어 중심의 희소 벡터(sparse vector)로 표현하여 검색</li>
<li>대표 알고리즘: <strong>TF-IDF</strong>, <strong>BM25</strong> 등</li>
<li>단어 등장 빈도 기반으로 관련 문서 검색</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/86e97248-2ff8-4d47-ab68-98f866c914e6/image.png" alt=""></p>
<hr>
<h3 id="키워드-검색-sparse-벡터-search">키워드 검색 (Sparse 벡터 Search)</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/ff134355-f772-4aec-9d45-2bbcc5aaad06/image.png" alt=""></p>
<p><strong>개념</strong></p>
<ul>
<li>단순 키워드 기반 필터 검색보다 한 단계 진화한 형태의 키워드 검색 방식</li>
<li>문서 내 <strong>단어 출현 빈도</strong>를 기반으로 문서를 벡터로 표현</li>
</ul>
<p><strong>구성 방식</strong></p>
<ul>
<li><p>문서 전체를 대상으로 <strong>단어 은행(Vocabulary)</strong>을 만들고,</p>
<p>  이를 기반으로 <strong>n-gram 형태</strong>로 벡터화</p>
</li>
<li><p><em>Sparse(희소)*</em>하다고 불리는 이유는</p>
<p>  대부분의 단어가 해당 문서에 존재하지 않기 때문에 0이 많은 벡터가 생성되기 때문</p>
</li>
</ul>
<p><strong>장점</strong></p>
<ul>
<li><p>단어 간 유사성보다는 <strong>정확한 단어 매칭</strong>에 초점</p>
</li>
<li><p>단어가 벡터 차원별로 매핑되고 빈도수로 표현되므로</p>
<p>  <strong>해당 단어의 중요도 반영 가능</strong></p>
</li>
<li><p>단순히 등장 여부뿐만 아니라 <strong>빈도 기반의 정밀한 모델링</strong> 가능</p>
</li>
</ul>
<p><strong>대표 모델</strong></p>
<ul>
<li><strong>BM25</strong>, <strong>SPLADE</strong> 등이 대표적인 sparse 벡터 검색 모델</li>
</ul>
<hr>
<h3 id="sparse-벡터-search---bm25">Sparse 벡터 Search - <strong>BM25</strong></h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/7d503605-cb9d-4f05-94b5-ec6384143f54/image.png" alt=""></p>
<p><strong>개념</strong></p>
<ul>
<li><p><strong>TF-IDF 기반 메커니즘</strong>을 활용한 키워드 중심 검색 모델</p>
</li>
<li><p><strong>TF (Term Frequency)</strong>: 문서에서 특정 단어가 얼마나 자주 등장하는지를 기반으로 n-gram 형태로 벡터화</p>
</li>
<li><p><strong>IDF (Inverse Document Frequency)</strong>: 전체 문서에서 얼마나 희귀한 단어인지를 반영</p>
<p>  → 흔하게 등장하지 않는 단어일수록 높은 가중치를 부여</p>
</li>
</ul>
<p><strong>작동 원리</strong></p>
<ul>
<li>사용자가 쿼리에서 입력한 단어들이 문서에 얼마나 등장했는지(TF), 그리고 해당 단어가 전체 문서 집합에서 얼마나 희귀한지(IDF)를 바탕으로 각 문서에 대해 <strong>BM25 점수</strong>를 계산</li>
<li>높은 점수를 가진 문서가 결과로 반환됨</li>
</ul>
<p><strong>특징</strong></p>
<ul>
<li><p>Dense 벡터가 아닌 <strong>희소 벡터 기반</strong>이므로 일반적인 벡터 DB (예: Faiss, Qdrant)에서는 직접 사용이 어려움</p>
<p>  → 별도로 <strong>sparse 벡터를 위한 인덱싱 시스템</strong> 필요</p>
</li>
</ul>
<hr>
<h3 id="sparse-벡터-search---splade">Sparse 벡터 Search - <strong>SPLADE</strong></h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8e91a0b8-38ab-4f40-8597-c2f27fd2a26b/image.png" alt=""></p>
<p><strong>개념</strong></p>
<ul>
<li><p>기존 Sparse 벡터 검색 방식의 한계인 <strong>유연성 부족</strong>을 개선하기 위해,</p>
<p>  <strong>BERT 기반 모델을 활용하여 sparse 벡터를 생성</strong>하는 방법</p>
</li>
<li><p>단순 등장 빈도가 아닌 <strong>단어의 문서 내 중요도(score)</strong>에 따라 스파스하게 표현</p>
</li>
</ul>
<p><strong>주요 특징</strong></p>
<ul>
<li><strong>중요도 기반 가중치 부여</strong><ul>
<li>단어가 문서에서 얼마나 중요한지를 수치로 표현하여 벡터 생성</li>
</ul>
</li>
<li><strong>Term Expansion</strong><ul>
<li>BERT 모델과 결합하여 의미적으로 유사한 단어 표현까지 확장</li>
<li>예: &quot;2단&quot;, &quot;2중적 표현&quot; 등이 같은 의미로 확장되어 검색 가능</li>
</ul>
</li>
<li><strong>유연한 검색 가능</strong><ul>
<li>단순 키워드 일치 외에도 의미 기반 검색 지원(오타, 간접적 표현을 인식할 수 있음)</li>
<li>사용자 쿼리에 포함되지 않은 단어라도 문서의 중요도 기반으로 관련성이 높은 문서를 찾을 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h2 id="시맨틱-검색">시맨틱 검색</h2>
<p><strong>개념</strong></p>
<ul>
<li><p>사용자의 검색 질의(Query)와 문서 간의 <strong>의미적 유사도(Semantic Similarity)</strong>를 계산하여</p>
<p>  의미가 유사한 문서를 찾아주는 검색 방식</p>
</li>
<li><p>핵심 기술: 자연어 문장을 벡터로 변환하는 <strong>임베딩(Embedding)</strong></p>
</li>
</ul>
<p><strong>기술적 구성</strong></p>
<ul>
<li>문장을 벡터로 변환 (임베딩)</li>
<li>사용자 질의도 같은 방식으로 벡터화</li>
<li>두 벡터 간 <strong>거리 계산</strong> (예: 코사인 유사도, 유클리디안 거리 등)</li>
</ul>
<p><strong>예시</strong></p>
<ul>
<li><p>검색어: <code>&quot;변비로 고생한 김철민&quot;</code></p>
<p>  → 문서: <code>&quot;고양이를 키우면서 주의해야할 건강요소&quot;</code> → 유사도 낮음</p>
<p>  → 문서: <code>&quot;변비 증상과 해결법&quot;</code> → 유사도 높음</p>
<p>  → 문서: <code>&quot;변화됨을 본질 비교&quot;</code> → 유사도 낮음</p>
</li>
</ul>
<p><strong>장점</strong></p>
<ul>
<li>의미가 비슷한 문장도 검색 가능</li>
<li>고도화된 사용자 질의 대응 가능</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>느린 검색 속도 (벡터 기반 거리 계산 필요)</li>
<li>벡터 DB 등 추가 시스템 필요</li>
<li>포괄적 결과를 반환하여 정확성이 떨어질 수 있음</li>
</ul>
<hr>
<h3 id="추가-설명">추가 설명</h3>
<p><strong>인덱싱 및 거리 계산 알고리즘</strong></p>
<ul>
<li><strong>LSH 기반</strong>: 해싱 방식, 유클리디안 거리 사용</li>
<li><strong>HNSW + PQ 기반</strong>: 그래프 탐색 + 압축, 반복 탐색 기반</li>
</ul>
<p><strong>거리 계산 방식</strong></p>
<ul>
<li><strong>Euclidean Distance</strong></li>
<li><strong>Cosine Similarity</strong></li>
<li><strong>Dot Product Similarity</strong></li>
</ul>
<blockquote>
<p>어떤 인덱싱/알고리즘을 사용하느냐에 따라 정확도 및 속도는 달라짐</p>
<p>일반적으로 임베딩 모델의 벡터를 그대로 사용하는 것이 가장 이상적</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b21978cf-f36f-4853-9aa5-d160337b0ee7/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1567800c-7988-4386-97f7-5d35f0dd439d/image.png" alt=""></p>
<hr>
<table>
<thead>
<tr>
<th>구분</th>
<th><strong>Keyword Search</strong>(Attribute Filter / Sparse 벡터)</th>
<th><strong>Semantic Search</strong>(Dense 벡터)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>장점</strong></td>
<td>- 속도가 빠르다<br>- 비용 효율적이다<br>- 제한적 검색 요건에 적합<br>- 표기 형태가 중요한 경우(고유명사 등)에 유리</td>
<td>- 정확한 표현이 아니어도 검색 가능<br>- 오타, 표현의 다양성에 강함<br>- 유사도 기반 결과 제공 가능<br>- 멀티모달 콘텐츠 지원 (텍스트, 이미지, 오디오 등)</td>
</tr>
<tr>
<td><strong>단점</strong></td>
<td>- 유연성이 떨어진다<br>- 의미 기반 표현 인식에 약함<br>- 쿼리의 디테일에 검색 성능이 의존적</td>
<td>- 속도가 느릴 수 있음<br>- 리소스 소비가 큼 (Heavy)<br>- 고유명사 중심 콘텐츠에 약할 수 있음</td>
</tr>
</tbody></table>
<hr>
<h2 id="하이브리드-검색">하이브리드 검색</h2>
<blockquote>
<p>키워드 서칭 방식과 Semantic 서칭 방식을 조합하여 상호 간의 장점만 취하는 방향으로 안정적인 성능</p>
</blockquote>
<p><strong>개념</strong></p>
<ul>
<li>키워드 검색과 시맨틱 검색을 결합한 방식</li>
<li>정확한 단어 일치 정보와 문맥적 의미 유사성을 동시에 고려하여 검색 품질을 높임</li>
<li>“키워드 서칭 방식과 Semantic 서칭 방식을 조합하여 상호 간의 장점만 취하는 방향으로 더욱 안정적인 성능을 노리는 방식”</li>
</ul>
<hr>
<p><strong>기술적 구성</strong></p>
<ul>
<li><p>키워드 필터링 후 시맨틱 정렬</p>
</li>
<li><p>점수 계산 방식:</p>
<p>  <code>최종점수 = 키워드 점수 * 가중치 + 시맨틱 점수 * 가중치</code></p>
</li>
</ul>
<hr>
<h3 id="예시">예시</h3>
<ul>
<li><p>검색어: “고양이 건강 정보”<br></p>
<p>  → 문서 A: 키워드+시맨틱 모두 높음 (정확한 노출)<br></p>
<p>  → 문서 B: 키워드만 존재, 시맨틱은 낮음<br></p>
<p>  → 문서 C: 시맨틱만 높음 (유사 표현)</p>
</li>
<li><p>예시 쿼리:<br></p>
<p>  → “○○일에만 한 번 전 발간된 급리 관련 내용을 찾아줘”<br></p>
<p>  → Attribute Filter(발간일, 발행일) + Semantic Search<br></p>
<p>  → “축구 관련 기사를 찾는데, 그 중에서도 해외파 선수들의 소속팀에서의 성적과 관련된 부분을 찾아줘”<br></p>
<p>  → SPLADE(해외파 선수 = 손흥민, 김민재 등) + Semantic Search</p>
</li>
</ul>
<hr>
<p><strong>장점</strong></p>
<ul>
<li>키워드 정확도 + 시맨틱 문맥 이해 → 검색 정확도 향상</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>구현 복잡도, 리소스 사용 증가</li>
<li>검색결과 튜닝 필요 (가중치 설정 등)</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/ea83fd9c-8dc7-4864-9500-8de75495a807/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/c34c9deb-8ece-4eb4-9162-10d4a1db34db/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/09116de1-24fa-47a3-899c-f0685c151a7f/image.png" alt=""></p>
<ul>
<li>RRF</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/aec91935-cb3c-41b9-849d-487c495981ac/image.png" alt=""></p>
<ul>
<li>RSF</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/a3da571e-8304-4508-9587-245e9549ab8b/image.png" alt=""></p>
<ul>
<li>DBSF</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/4ddcaf9b-be08-4227-9a22-b56e36763e17/image.png" alt=""></p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (8) - 원천 테이터 청킹 전략]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-8-%EC%9B%90%EC%B2%9C-%ED%85%8C%EC%9D%B4%ED%84%B0-%EC%B2%AD%ED%82%B9-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-8-%EC%9B%90%EC%B2%9C-%ED%85%8C%EC%9D%B4%ED%84%B0-%EC%B2%AD%ED%82%B9-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Fri, 09 May 2025 05:31:52 GMT</pubDate>
            <description><![CDATA[<h1 id="원천-테이터-청킹-전략">원천 테이터 청킹 전략</h1>
<h2 id="청크">청크</h2>
<p>Vector화 할 대상이 되는 데이터</p>
<blockquote>
<p>청크로 구분된 데이터는 임베딩 처리를 통해 고정된 크기의 Vector 값으로 변환</p>
</blockquote>
<ul>
<li><p>청크 크기와 응답시간 간의 관계는 정보 검색 및 자연어 처리 시스템의 전체적인 성능에 매우 중요한 영향을 미침</p>
</li>
<li><p>청크 크기를 적절하게 설정하는 것이 시스템의 효율성과 정확도를 좌우함</p>
</li>
<li><p>따라서, RAG 시스템의 효율성과 정확성에 영향을 미칠 수 있는 중요한 결정 중 하나는 <strong>적절한 청크 크기(Chunk Size)</strong>를 선택하는 것</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d2ca7140-7dbd-40c0-b45c-fece482ea744/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/42d5b285-962e-4fe9-bc42-62566d7d503e/image.png" alt=""></p>
<blockquote>
<p>→ 청크 사이즈가 증가할수록 정확도가 감소하고, 속도가 늘어남</p>
</blockquote>
<hr>
<h2 id="fixed-size-chunking">Fixed Size Chunking</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/c397421c-abcf-449c-b66a-ca336954776a/image.png" alt=""></p>
<p><strong>장점</strong></p>
<ul>
<li><p>구현이 간단</p>
</li>
<li><p>균일한 데이터 분포</p>
</li>
<li><p>예측 가능한 성능</p>
</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li><p><strong>비효율성</strong>: 고정된 크기를 채우지 못할 경우 공간이 비효율적으로 사용됨</p>
</li>
<li><p><strong>데이터 경계의 의미 상실</strong>: 데이터의 논리적 경계를 무시하게 되어 의미를 온전히 이해하기 어려움</p>
</li>
</ul>
<p><strong>사용 예시</strong></p>
<ul>
<li>대량의 로그 데이터</li>
</ul>
<hr>
<h2 id="overlapping-chunking">Overlapping Chunking</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/3f89f60a-4b5a-4bfd-97d8-79839272b7ff/image.png" alt=""></p>
<p><strong>장점</strong></p>
<ul>
<li><p>높은 검색 포괄성</p>
</li>
<li><p>검색 정확성 증가</p>
</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li>저장 공간 증가</li>
</ul>
<p><strong>사용 예시</strong></p>
<ul>
<li><p><strong>문서 검색:</strong> 문단 간 연결 정보를 보존하고 싶을 때</p>
</li>
<li><p><strong>멀티 미디어 데이터:</strong> 장면 단위로 나눌 때, 장면 간 전환 부분을 중복 포함하고 싶을 때</p>
</li>
</ul>
<hr>
<h2 id="recursive-chunking">Recursive Chunking</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/42f745c9-1347-4ba3-b942-81299f5800bf/image.png" alt=""></p>
<p><strong>Chunk2와 Chunk4</strong> 처럼 의미 있는 문맥 단위가 너무 커서 고정 크기를 넘는 경우에는</p>
<p>→ <strong>재귀적으로</strong> 또는 추가적으로 <strong>문맥을 고려한 분할(Content Aware)</strong>을 적용함</p>
<hr>
<h2 id="semantic-chunking">Semantic Chunking</h2>
<p><strong>의미</strong></p>
<ul>
<li><p>청크의 <strong>유사성</strong>을 기준으로 텍스트를 분할하는 방법</p>
</li>
<li><p>문장을 단위로 청크한 후, 각 청크를 임베딩하여 벡터화</p>
</li>
<li><p>청크 간 <strong>코사인 유사도</strong>를 계산하고,</p>
<ul>
<li>설정한 임계값보다 유사도가 낮을 때 분할 수행</li>
<li>분할 기준 이전은 하나의 청크로 간주, 이후도 같은 방식으로 반복</li>
</ul>
</li>
</ul>
<p><strong>장점</strong></p>
<ul>
<li><p><strong>높은 이해도</strong></p>
</li>
<li><p><strong>정확한 검색 결과</strong></p>
</li>
<li><p><strong>효율적인 처리</strong> 가능</p>
</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li><strong>구현 복잡성:</strong> 의미 단위를 인식하고 정확하게 분할하는 알고리즘이 복잡할 수 있음</li>
</ul>
<hr>
<h2 id="summarization-chunking">Summarization Chunking</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1200f6c8-1db4-423f-8a75-2e988d0d24e6/image.png" alt=""></p>
<p><strong>의미</strong></p>
<ul>
<li><p>데이터를 요약된 형태로 나누는 방법</p>
</li>
<li><p>긴 텍스트나 문서를 요약하여 <strong>중요한 정보만 포함하는 청크</strong>를 만드는 것이 목적</p>
</li>
</ul>
<p><strong>장점</strong></p>
<ul>
<li><p>빠른 정보 파악</p>
</li>
<li><p>효율적인 검색</p>
</li>
<li><p>데이터 축소</p>
</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li><p>정보 손실</p>
</li>
<li><p>요약 정확도 품질 저하 가능</p>
</li>
</ul>
<p><strong>사용 예시</strong></p>
<ul>
<li><p>뉴스 요약</p>
</li>
<li><p>리포트 요약</p>
</li>
</ul>
<hr>
<h2 id="parent-child-chunking">Parent Child Chunking</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/90c28f71-dab0-47d7-8d86-011076b0de0f/image.png" alt=""></p>
<p><strong>의미</strong></p>
<ul>
<li><p>데이터를 <strong>계층 구조</strong>로 나누는 방식</p>
</li>
<li><p>큰 청크(부모)와 작은 청크(자식)로 분할하고, 각 청크를 <strong>계층적으로 연결</strong></p>
</li>
<li><p>청크 자체에는 원문 전체를 저장하지 않고, 원문은 <strong>별도 저장소에 저장</strong></p>
<ul>
<li>검색 시, 청크에 연결된 포인터를 통해 원문 위치를 찾아감</li>
</ul>
</li>
</ul>
<p><strong>장점</strong></p>
<ul>
<li><p><strong>효율적 탐색</strong></p>
</li>
<li><p><strong>구조적 접근</strong></p>
</li>
<li><p><strong>세분화된 분석</strong> 가능</p>
</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li><p><strong>구현 복잡성</strong></p>
</li>
<li><p><strong>데이터 중복 가능성</strong></p>
</li>
</ul>
<p><strong>사용 예시</strong></p>
<ul>
<li><p>문서 구조화</p>
</li>
<li><p>웹사이트 구조화</p>
</li>
</ul>
<blockquote>
<p>단계를 내려가며 청크를 쪼갬, 원문을 각 청크로 요약해서 원문을 찾아갈 수 있도록</p>
</blockquote>
<hr>
<h2 id="rag를-위한-5가지-청킹">Rag를 위한 5가지 청킹</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/180f2242-6af1-4d1b-b67a-780c7eab92bb/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/39f5c6f2-d7f4-4f57-88b9-0668616d50fe/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/598fb166-324b-41ee-bb41-b707ce4b395f/image.png" alt=""></p>
<p><a href="https://blog.dailydoseofds.com/p/5-chunking-strategies-for-rag">https://blog.dailydoseofds.com/p/5-chunking-strategies-for-rag</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (7) - 벡터 DB 스키마 설계 ]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-7-%EB%B2%A1%ED%84%B0-DB-%EC%8A%A4%ED%82%A4%EB%A7%88-%EC%84%A4%EA%B3%84</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-7-%EB%B2%A1%ED%84%B0-DB-%EC%8A%A4%ED%82%A4%EB%A7%88-%EC%84%A4%EA%B3%84</guid>
            <pubDate>Fri, 09 May 2025 05:27:12 GMT</pubDate>
            <description><![CDATA[<h1 id="벡터-db-스키마-설계">벡터 DB 스키마 설계</h1>
<p>벡터 DB 스키마 설계는 벡터 임베딩을 효율적으로 저장하고 검색하는 구조를 계획하는 과정 데이터 특성과 Application의 요구사항을 고려하여 수행</p>
<hr>
<p><strong>1. 데이터 구조 계획</strong></p>
<ul>
<li><p><strong>데이터 유형 결정</strong></p>
<ul>
<li>벡터 임베딩의 출처(이미지, 텍스트, 지리 좌표 등)에 따라 저장할 데이터 유형을 정의</li>
</ul>
</li>
<li><p><strong>벡터 차원 정의</strong></p>
<ul>
<li>각 임베딩 벡터의 차원 수를 설정 (예: 일반적으로 768차원)</li>
</ul>
</li>
</ul>
<p><strong>2. 필드 정의</strong></p>
<ul>
<li><p><strong>벡터 필드</strong></p>
<ul>
<li>실제 임베딩을 저장할 필드들(example)<ul>
<li><code>image_vector</code>, <code>summary_dense_vector</code> 등</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>메타데이터 필드</strong></p>
<ul>
<li>문서나 항목에 대한 추가 정보를 저장할 필드들(example)<ul>
<li><code>summary</code>, <code>publish_ts</code> 등</li>
</ul>
</li>
</ul>
</li>
</ul>
<p><strong>3. 확장성 및 성능</strong></p>
<ul>
<li><p><strong>수평 확장 고려</strong></p>
<ul>
<li>데이터 양 또는 쿼리 부하가 증가해도 성능을 유지할 수 있도록 노드 증설 계획</li>
</ul>
</li>
<li><p><strong>부하 분산</strong></p>
<ul>
<li>여러 노드에 쿼리 요청을 효율적으로 분배하기 위한 로드 밸런싱 전략</li>
</ul>
</li>
</ul>
<p><strong>4. 인덱싱 전략</strong></p>
<ul>
<li><p><strong>인덱스 유형</strong></p>
<ul>
<li><p>HNSW, IVF 등 다양한 알고리즘 중에서 선택</p>
</li>
<li><p>쿼리 성능과 데이터 크기에 따라 최적의 인덱스 구조 결정</p>
</li>
</ul>
</li>
<li><p><strong>메트릭 유형</strong></p>
<ul>
<li>유사도를 측정하는 데 사용할 메트릭 선택</li>
<li>내적(dot product) 또는 코사인 유사도가 일반적으로 사용됨</li>
</ul>
</li>
</ul>
<p><strong>5. 데이터 저장 및 검색</strong></p>
<ul>
<li><p><strong>저장 방식</strong></p>
<ul>
<li><p>메모리 기반 저장 또는 디스크 기반 저장</p>
<ul>
<li>메모리 기반: 빠른 응답 속도, 메모리 사용량 증가</li>
<li>디스크 기반: 대용량 데이터 저장에 유리하나 상대적으로 느림</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>검색 최적화</strong></p>
<ul>
<li>캐싱, 병렬 처리 등을 통해 쿼리 속도 최적화</li>
<li>요청을 분산 처리하여 부하를 효율적으로 관리</li>
</ul>
</li>
</ul>
<hr>
<h2 id="필드-정의-및-인덱싱">필드 정의 및 인덱싱</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>벡터 필드</strong></td>
<td>- 고차원 벡터를 저장하는 필드  (예: 이미지나 텍스트의 임베딩 벡터 저장)<br>- 예시: <code>image_vector</code>, <code>text_embedding</code></td>
</tr>
<tr>
<td><strong>메타데이터 필드</strong></td>
<td>- <strong>ID 필드</strong>: 각 벡터의 고유 식별자 저장 (예: <code>id</code>, <code>article_id</code>)<br>- <strong>텍스트 필드</strong>: 관련 텍스트 데이터 저장 (예: <code>title</code>, <code>summary</code>)<br>- <strong>타임스탬프 필드</strong>: 생성/수정 시간 저장 (예: <code>publish_ts</code>)<br>- <strong>기타 메타데이터</strong>: 추가 정보 저장 (예: <code>author_info</code>, <code>category</code>)</td>
</tr>
<tr>
<td><strong>인덱싱</strong></td>
<td>- <strong>벡터 인덱스</strong>: 벡터 필드에 대한 인덱스 생성으로 효율적 검색 지원 (예: HNSW, IVF, PQ 등)<br>- <strong>메타데이터 인덱스</strong>: 메타데이터 필드에 인덱스 생성 및 필터링·검색 기능 지원</td>
</tr>
</tbody></table>
<hr>
<h2 id="vectordb-일반적인-스키마-구조">VectorDB 일반적인 스키마 구조</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/a6ca1470-317d-4324-8911-f2b3bc4a884a/image.png" alt=""></p>
<blockquote>
<p>collection 안에 원본 데이터가 존재</p>
</blockquote>
<hr>
<h2 id="단일-collection-vs-멀티-collection">단일 Collection vs 멀티 collection</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/3104ed8e-384e-4698-8984-d59a317b33f3/image.png" alt=""></p>
<blockquote>
<p>상황, 데이터형태 별로 VectorDB의 분할 저장을 결정할 수 있음
→ <strong>검색 속도 &amp; 정확도</strong></p>
</blockquote>
<ul>
<li><strong>Collection 관리 기법</strong></li>
</ul>
<p>Vector DB에서 Collection을 효율적으로 관리하기 위한 전략</p>
<ul>
<li><p><strong>단일 Collection 관리</strong></p>
<ul>
<li>데이터 양이 적거나 단순한 서비스에서는 하나의 Collection에 모든 데이터를 저장·검색</li>
</ul>
</li>
<li><p><strong>다중 Collection 분리</strong></p>
<ul>
<li>대규모 데이터 또는 높은 <strong>동시성</strong> 요구 시, 여러 Collection으로 분산 저장</li>
<li>병렬 처리로 검색 성능 및 확장성 확보</li>
</ul>
</li>
<li><p><strong>분리 기준 설정</strong></p>
<ul>
<li><strong>정확도</strong>: 서로 다른 도메인·속성의 데이터를 별도 Collection으로 분리해 검색 품질 유지</li>
<li><strong>성능</strong>: 읽기·쓰기 부하 분산, 인덱스 크기 관리 등을 고려하여 분할</li>
</ul>
</li>
<li><p><strong>상황별 판단</strong></p>
<ul>
<li>소량 데이터 &amp; 단일 워크로드 → 단일 Collection</li>
<li>대량 데이터 &amp; 복합 워크로드 → 다중 Collection 분리</li>
</ul>
</li>
</ul>
<hr>
<h2 id="멀티-모달에서-단일-collection">멀티 모달에서 단일 Collection</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8c52cd31-1364-455a-925e-d12eb6945e9d/image.png" alt=""></p>
<p><strong>장점</strong></p>
<ul>
<li><strong>간소화된 검색</strong>: 하나의 벡터로 문서와 동영상의 복합 정보를 표현할 수 있어 검색이 간편해짐.</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li><p><strong>복합 표현의 한계</strong>: 문서와 동영상의 정보를 하나의 벡터에 결합하는 과정에서 정보 손실 발생 가능.</p>
</li>
<li><p><strong>벡터 크기 증가</strong>: 두 벡터를 결합하며 벡터 크기가 커지고, 이에 따라 저장공간과 계산 비용이 증가.</p>
</li>
</ul>
<hr>
<h2 id="collection으로-나누는-기준">Collection으로 나누는 기준</h2>
<table>
<thead>
<tr>
<th>기준</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>데이터의 크기와 스케일링</td>
<td>대용량 데이터를 다룰 때는 Collection을 적절하게 나누어 DB의 성능을 유지하고 스케일링을 용이하게 해야 한다.</td>
</tr>
<tr>
<td>데이터의 접근 패턴</td>
<td>데이터에 접근하는 패턴을 분석하여, 자주 접근하는 데이터끼리 묶어서 Collection을 설계하는 것이 효과적이다.</td>
</tr>
<tr>
<td>데이터의 생명 주기</td>
<td>데이터의 라이프사이클에 따라 Collection을 나누면, 오래된 데이터를 쉽게 아카이브하거나 삭제할 수 있다.</td>
</tr>
<tr>
<td>데이터의 속성</td>
<td>비슷한 속성을 가진 데이터끼리 묶어 관리하면 검색과 인덱싱이 효율적이다.</td>
</tr>
<tr>
<td>운영 및 관리의 용이성</td>
<td>Collection의 수가 너무 많으면 관리가 복잡해질 수 있으므로, 관리의 용이성을 고려해 적절한 단위로 나누어야 한다.</td>
</tr>
</tbody></table>
<hr>
<h2 id="사례---뉴스기사-대상-collection-설계">사례 - 뉴스기사 대상 Collection 설계</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/5df8c189-17db-4ed0-bb59-8228ef86e6bb/image.png" alt=""></p>
<ul>
<li><p>날짜 기준으로 나누기</p>
<ul>
<li><p>기준: 날짜 별로 Collection을 나누어, 매일 생성된 뉴스를 별도의 Collection에 저장</p>
</li>
<li><p>장점: 최신 뉴스에 대한 빠른 접근이 가능하고, 오래된 뉴스를 쉽게 아카이브할 수 있다.</p>
</li>
<li><p>예시: news_20250201, news_20250202</p>
</li>
</ul>
</li>
<li><p>주제 또는 카테고리 기준으로 나누기</p>
<ul>
<li>기준: 주제별로 Collection을 나누어, 정치, 경제, 스포츠 등 카테고리 별로 뉴스를 저장</li>
<li>장점: 특정 주제에 대한 검색이 빠르고 효율적이다.</li>
<li>예시: news_politics, news_economy, news_sports</li>
</ul>
</li>
<li><p>날짜와 주제 기준을 혼합한 기준으로 나누기</p>
<ul>
<li>기준: 날짜와 주제 기준을 혼합하여 Collection을 나눈다. 예를 들어, 매달 주제별로 Collection을 생성</li>
<li>장점: 데이터가 너무 세분화되지 않으면서도, 특정 기간과 주제에 대한 검색이 효율적이다.</li>
<li>예시: news_202501_politics, news_202501_economy, news_202501_sports</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/4919e2b3-2ada-4d2d-af7b-3fdf4b31ced3/image.png" alt=""></p>
<hr>
<h2 id="멀티-collection에서의-유사도-검색">멀티 Collection에서의 유사도 검색</h2>
<p>멀티 Collection 유사도 검색을 위해서는 <strong>벡터 공간의 일관성</strong> 필요</p>
<h3 id="일관된-벡터-공간이란"><strong>일관된 벡터 공간이란?</strong></h3>
<blockquote>
<p>벡터 데이터베이스에서 서로 다른 데이터 항목들이 <strong>동일한 차원 수</strong>와 <strong>동일한 의미적 해석</strong>을 갖도록 변환된 공간</p>
</blockquote>
<ul>
<li><p>벡터 간 유사도를 <strong>정확하게 계산하고 비교</strong>할 수 있도록 함</p>
</li>
<li><p>서로 다른 Collection의 벡터들도 <strong>동일한 임베딩 스페이스</strong>에 있어야 함</p>
</li>
</ul>
<h3 id="벡터-공간의-일관성-요건"><strong>벡터 공간의 일관성 요건</strong></h3>
<ol>
<li><p><strong>동일한 차원 수:</strong> 모든 벡터는 동일한 차원 수를 가져야 함</p>
</li>
<li><p><strong>동일한 임베딩 모델:</strong> 동일한 임베딩 모델을 사용하여 데이터를 벡터화해야 함</p>
</li>
<li><p><strong>동일한 처리 방식:</strong> 데이터 전처리와 임베딩 생성 과정이 일관되어야 함</p>
</li>
</ol>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/6d23e242-23c8-499f-86dc-8ddbc801d8fd/image.png" alt=""></p>
<blockquote>
<p>하나의 문서를 다양한 방식(Sparse+Dense)의 벡터로 저장 → <strong>하이브리드 검색</strong>(Hybrid Retrieval) 가능</p>
</blockquote>
<hr>
<h2 id="멀티-vector-값을-관리하는-이유-sparse--dense">멀티 Vector 값을 관리하는 이유 Sparse + Dense</h2>
<p><strong>다양한 인덱싱 전략 사용</strong></p>
<ul>
<li><strong>Sparse Vector</strong>: 효율적인 저장과 검색을 위한 특화된 인덱싱 방식</li>
<li><strong>Dense Vector</strong>: 빠른 유사도 검색을 위한 인덱싱 방식 사용 가능</li>
</ul>
<p><strong>복합 검색 기능</strong></p>
<ul>
<li>Sparse Vector와 Dense Vector의 <strong>혼합 저장</strong>을 통해 다양한 검색 조건 동시 적용 가능</li>
<li>예: 텍스트와 이미지 데이터를 동시에 검색하여 <strong>관련성 평가 가능</strong></li>
</ul>
<p><strong>확장성</strong></p>
<ul>
<li>다양한 유형의 벡터 데이터를 하나의 Collection에 저장함으로써 시스템의 <strong>확장성 향상</strong></li>
<li>데이터 타입과 저장 방식에 구애받지 않고 <strong>Collection 확장 가능</strong></li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/86a0f5ba-b1d2-47e0-af20-9c6ad1e72144/image.png" alt=""></p>
<hr>
<table>
<thead>
<tr>
<th>항목</th>
<th>Sparse Vector</th>
<th>Dense Vector</th>
</tr>
</thead>
<tbody><tr>
<td>대부분의 값</td>
<td>0</td>
<td>0이 아님</td>
</tr>
<tr>
<td>크기</td>
<td>고차원</td>
<td>상대적으로 저차원</td>
</tr>
<tr>
<td>계산 효율</td>
<td>일부 계산에서 빠름</td>
<td>계산량 많지만 의미가 풍부함</td>
</tr>
<tr>
<td>사용 예</td>
<td>One-hot, BoW, TF-IDF</td>
<td>Word2Vec, BERT 임베딩</td>
</tr>
<tr>
<td>유사도 측정</td>
<td>비효율적일 수 있음</td>
<td>코사인 유사도 등 효율적</td>
</tr>
</tbody></table>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[Word2Vec & 벡터 DB - 나무위키 학습]]></title>
            <link>https://velog.io/@lyj_0316/Word2Vec-%EB%B2%A1%ED%84%B0-DB-%EB%82%98%EB%AC%B4%EC%9C%84%ED%82%A4-%ED%95%99%EC%8A%B5</link>
            <guid>https://velog.io/@lyj_0316/Word2Vec-%EB%B2%A1%ED%84%B0-DB-%EB%82%98%EB%AC%B4%EC%9C%84%ED%82%A4-%ED%95%99%EC%8A%B5</guid>
            <pubDate>Thu, 08 May 2025 08:42:30 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-python">from gensim.models import Word2Vec

# 기본 문장
sentences = [
  [&quot;사과&quot;, &quot;바나나&quot;, &quot;포도&quot;, &quot;수박&quot;],
  [&quot;개&quot;, &quot;고양이&quot;, &quot;토끼&quot;, &quot;호랑이&quot;],
  [&quot;컴퓨터&quot;, &quot;노트북&quot;, &quot;스마트폰&quot;, &quot;태블릿&quot;],
  [&quot;의자&quot;, &quot;테이블&quot;, &quot;침대&quot;, &quot;소파&quot;],
  [&quot;한국&quot;, &quot;일본&quot;, &quot;중국&quot;, &quot;미국&quot;]
]

# 모델 훈련: 벡터 차원 50, 윈도우 3
model = Word2Vec(sentences, vector_size=50, window=3, min_count=1, workers=2, sg=1)</code></pre>
<p>주어진 단어들을 바탕으로 Word2Vec 모델을 학습시켰다.</p>
<hr>
<pre><code class="language-python">new_sentences = [
  [&quot;기차&quot;, &quot;자동차&quot;, &quot;자전거&quot;, &quot;비행기&quot;, &quot;배&quot;]
]

# 기존 모델 업데이트를 위한 빌드
model.build_vocab(new_sentences, update=True)
model.train(new_sentences, total_examples=len(new_sentences), epochs=10)

# 단어 벡터 확인
print(model.wv[&#39;기차&#39;])  # 예시 출력</code></pre>
<p>새로 추가된 단어들을 바탕으로 모델을 재 학습 시키고</p>
<blockquote>
<p>[ 0.01417759 -0.00313586  0.015895   -0.01897732 -0.016059   -0.01328074 … 와 같이 임베딩됨을 확인할 수 있다.</p>
</blockquote>
<hr>
<pre><code class="language-python">from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import numpy as np

# Word2Vec 모델에서 단어 벡터 추출
words = list(model.wv.index_to_key)
vectors = np.array([model.wv[word] for word in words])

# t-SNE 차원 축소
tsne = TSNE(n_components=2, random_state=42, perplexity=5)
reduced = tsne.fit_transform(vectors)

# 한글 폰트 설정 (환경별로 구분)
import platform
if platform.system() == &#39;Windows&#39;:
    font_path = &quot;C:/Windows/Fonts/malgun.ttf&quot;  # Windows: 맑은 고딕
elif platform.system() == &#39;Darwin&#39;:
    font_path = &quot;/System/Library/Fonts/AppleGothic.ttf&quot;  # macOS
else:
    font_path = &quot;/usr/share/fonts/truetype/nanum/NanumGothic.ttf&quot;  # Colab (NanumGothic 설치 필요)

font_name = fm.FontProperties(fname=font_path).get_name()
plt.rc(&quot;font&quot;, family=font_name)
plt.rcParams[&quot;axes.unicode_minus&quot;] = False

# 시각화
plt.figure(figsize=(12, 8))
for i, word in enumerate(words):
    plt.scatter(reduced[i, 0], reduced[i, 1])
    plt.annotate(word, (reduced[i, 0], reduced[i, 1]))
plt.title(&quot;Word2Vec 임베딩 시각화 (t-SNE)&quot;)
plt.grid(True)
plt.show()
</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0d37f8ba-41a6-452d-8736-88cc02adb101/image.png" alt=""></p>
<p>임베딩된 단어들을 시각화하였을 때 다음 이미지처럼 나왔는데, 학습 데이터가 굉장히 적어 적절한 임베딩이 되지 않았다고 생각하였다.</p>
<hr>
<h2 id="annoy를-사용하여-단어-임베딩">Annoy를 사용하여 단어 임베딩</h2>
<pre><code class="language-python">from annoy import AnnoyIndex

dim = model.vector_size
annoy_index = AnnoyIndex(dim, &#39;angular&#39;)

# 모든 단어 벡터 추가
for i, word in enumerate(words):
    annoy_index.add_item(i, model.wv[word])
annoy_index.build(10)

# 유사한 단어 검색 (예: &#39;사과&#39;)
target_word = &#39;사과&#39;
target_index = words.index(target_word)
similar_indices = annoy_index.get_nns_by_item(target_index, 5)

print(f&quot;&#39;{target_word}&#39;와 유사한 단어:&quot;)
for i in similar_indices:
    print(words[i])
</code></pre>
<p>FAISS 대신 ANNOY를 사용하여 진행해보았고, </p>
<blockquote>
<p>&#39;사과&#39;와 유사한 단어:
사과
일본
자전거
소파
중국</p>
</blockquote>
<p>이 또한 적절하지 않음을 확인할 수 있었다.</p>
<hr>
<h1 id="나무위키-파일로-학습하기">나무위키 파일로 학습하기</h1>
<pre><code class="language-python">from datasets import load_dataset

# Hugging Face에서 나무위키 데이터셋 로드
dataset = load_dataset(&quot;heegyu/namuwiki-extracted&quot;)
documents = dataset[&quot;train&quot;].select(range(1000))  # 처음 1000개 문서만 사용 (속도 고려)
print(documents[0])</code></pre>
<p>학습데이터가 적은 문제점을 해결하기 위하여 Hugging Face에서 제공하는 나무위키 데이터셋을 불러와 학습하고자 하였다. </p>
<p>시간이 오래 걸리는 관계 상 100개, 1000개, 3000개의 문서를 비교군으로 사용하였다.</p>
<hr>
<pre><code class="language-python">import re
import kss
from tqdm import tqdm

def simple_tokenize(text):
    text = re.sub(r&quot;[^\uAC00-\uD7A3\s]&quot;, &quot;&quot;, text)
    return text.strip().split()

tokenized_sentences = []
for doc in tqdm(documents, desc=&quot;문장 분리 및 토큰화&quot;):
    try:
        if not doc[&quot;text&quot;].strip():
            continue
        sentences = kss.split_sentences(doc[&quot;text&quot;])
        for sent in sentences:
            tokens = simple_tokenize(sent)
            if len(tokens) &gt;= 1:
                tokenized_sentences.append(tokens)
    except Exception as e:
        continue</code></pre>
<p>기본적으로 형태소를 기준으로 나눌 수는 없어 조사는 제외시키지 못하였고, 단순히 띄어쓰기를 기준으로 단어를 구분하였다.</p>
<hr>
<pre><code class="language-python">from gensim.models import Word2Vec

model = Word2Vec(
    sentences=tokenized_sentences,
    vector_size=200,
    window=5,
    min_count=5,
    workers=4,
    sg=1,
    epochs=5
)</code></pre>
<p>구분한 단어를 기준으로 모델을 학습시켜 단어 임베딩을 진행하였다.</p>
<hr>
<pre><code class="language-python">print(model.wv.most_similar(&quot;한국&quot;))</code></pre>
<p>다음과 같이 단어를 입력하고 입력된 단어를 기반으로 유사한 단어를 출력하도록 유도하였다.</p>
<hr>
<h3 id="1-100개의-문서-만을-학습한-경우">1. 100개의 문서 만을 학습한 경우</h3>
<p>[(&#39;신체&#39;, 0.9989925622940063), (&#39;일부터&#39;, 0.998943030834198), (&#39;앨범&#39;, 0.9982248544692993), (&#39;게임&#39;, 0.9980660080909729), (&#39;상대로&#39;, 0.9975945353507996), (&#39;일에&#39;, 0.9973501563072205), (&#39;기록했으나&#39;, 0.9973440170288086), (&#39;북미&#39;, 0.9972758293151855), (&#39;에서&#39;, 0.9972389340400696), (&#39;첫&#39;, 0.9970090389251709)]</p>
<h3 id="2-1000개의-문서-만을-학습한-경우">2. 1000개의 문서 만을 학습한 경우</h3>
<p>[(&#39;중국&#39;, 0.7050928473472595), (&#39;일본&#39;, 0.6985045075416565), (&#39;대한민국&#39;, 0.6862316131591797), (&#39;정식&#39;, 0.6725090742111206), (&#39;아프리카&#39;, 0.6644840836524963), (&#39;공식&#39;, 0.656909704208374), (&#39;홍콩&#39;, 0.639904797077179), (&#39;텔레비전&#39;, 0.6321231126785278), (&#39;미&#39;, 0.6287841796875), (&#39;일본에서&#39;, 0.6239179968833923)]</p>
<h3 id="3-3000개의-문서로-학습한-경우">3. 3000개의 문서로 학습한 경우</h3>
<p>[(&#39;대한민국&#39;, 0.5823025703430176), (&#39;국내&#39;, 0.5639891624450684), (&#39;중국&#39;, 0.5514899492263794), (&#39;그룹&#39;, 0.5409524440765381), (&#39;일본&#39;, 0.5325442552566528), (&#39;대만&#39;, 0.505932092666626), (&#39;아이돌&#39;, 0.49861907958984375), (&#39;중국의&#39;, 0.49011966586112976), (&#39;국적의&#39;, 0.4735112488269806), (&#39;인기&#39;, 0.471205472946167)]</p>
<p>위와 같이 문서의 양이 늘어났을 때, 출력되는 단어의 종류가 육안으로도 향상됨을 확인할 수 있었다.</p>
<hr>
<h2 id="학습된-모델로-시각화">학습된 모델로 시각화</h2>
<p>위의 나무위키를 통해서 학습된 모델을 바탕으로 위의 sentences 를 다시 시각화해보았다.</p>
<pre><code class="language-python"># 시각화할 단어 리스트
visual_words = [
    &quot;사과&quot;, &quot;바나나&quot;, &quot;포도&quot;, &quot;수박&quot;,
    &quot;개&quot;, &quot;고양이&quot;, &quot;토끼&quot;, &quot;호랑이&quot;,
    &quot;컴퓨터&quot;, &quot;노트북&quot;, &quot;스마트폰&quot;, &quot;태블릿&quot;,
    &quot;의자&quot;, &quot;테이블&quot;, &quot;침대&quot;, &quot;소파&quot;,
    &quot;한국&quot;, &quot;일본&quot;, &quot;중국&quot;, &quot;미국&quot;
]</code></pre>
<pre><code class="language-python">import numpy as np

valid_words = []
vectors = []

for word in visual_words:
    if word in model.wv:
        valid_words.append(word)
        vectors.append(model.wv[word])
    else:
        print(f&quot;⚠️ &#39;{word}&#39; 단어는 어휘 사전에 없습니다.&quot;)

vectors = np.array(vectors)</code></pre>
<p>앞서 말했던 학습데이터에 없던 데이터를 확인하고 제거하는 방식으로 시각화를 진행하였다.</p>
<p>1000개의 데이터셋을 활용한 경우에는 다음과 같이 존재하지 않는 단어도 존재했지만,</p>
<blockquote>
<p>⚠️ &#39;포도&#39; 단어는 어휘 사전에 없습니다.
⚠️ &#39;노트북&#39; 단어는 어휘 사전에 없습니다.
⚠️ &#39;태블릿&#39; 단어는 어휘 사전에 없습니다.
⚠️ &#39;소파&#39; 단어는 어휘 사전에 없습니다.</p>
</blockquote>
<p>3000개의 문서를 활용한 경우 학습데이터에서 제거되는 데이터는 존재하지 않았다. 즉, <strong>모든 데이터를 시각화</strong>할 수 있었다.</p>
<hr>
<pre><code class="language-python">from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import platform

# t-SNE 차원 축소
tsne = TSNE(n_components=2, random_state=42, perplexity=5)
reduced = tsne.fit_transform(vectors)

# 한글 폰트 설정
if platform.system() == &#39;Windows&#39;:
    font_path = &quot;C:/Windows/Fonts/malgun.ttf&quot;
elif platform.system() == &#39;Darwin&#39;:
    font_path = &quot;/System/Library/Fonts/AppleGothic.ttf&quot;
else:
    font_path = &quot;/usr/share/fonts/truetype/nanum/NanumGothic.ttf&quot;

font_name = fm.FontProperties(fname=font_path).get_name()
plt.rc(&quot;font&quot;, family=font_name)
plt.rcParams[&quot;axes.unicode_minus&quot;] = False

# 시각화
plt.figure(figsize=(10, 7))
for i, word in enumerate(valid_words):
    plt.scatter(reduced[i, 0], reduced[i, 1])
    plt.annotate(word, (reduced[i, 0], reduced[i, 1]))
plt.title(&quot;지정 단어 Word2Vec 시각화 (t-SNE)&quot;)
plt.grid(True)
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1a69d865-6004-4870-9607-774ab5c9058f/image.png" alt=""></p>
<hr>
<h3 id="비교-및-정리">비교 및 정리</h3>
<ol>
<li>5개의 데이터로 학습한 모델의 경우</li>
</ol>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/9aa5dc79-6eee-4396-a998-6da5f699ad76/image.png" alt=""></p>
<p>비슷한 종류의 데이터끼리 흩어져 있음을 확인할 수 있다.</p>
<hr>
<ol start="2">
<li>나무위키를 통해 1000개의 데이터로 학습한 모델의 경우</li>
</ol>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/c4ce1d55-7507-4b5f-849b-c96f6c086f6b/image.png" alt=""></p>
<p>많은 향상을 이루어내지는 못했지만, 어느 정도 향상된 결과가 나옴을 확인할 수 있었다.</p>
<hr>
<ol start="3">
<li>나무위키 3000개의 문서로 학습한 모델의 경우</li>
</ol>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/c0489618-2717-4d88-81f4-b251f13c7177/image.png" alt=""></p>
<p>육안으로도 1000개의 데이터를 통해 학습한 모델보다 3000개의 데이터를 활용한 모델이 더 잘 구분됨을 확인할 수 있었다. </p>
<table>
<thead>
<tr>
<th>모델</th>
<th>군집수</th>
</tr>
</thead>
<tbody><tr>
<td>5개로 학습</td>
<td>X</td>
</tr>
<tr>
<td>1000개로 학습</td>
<td>3개 정도의 군집</td>
</tr>
<tr>
<td>3000개로 학습</td>
<td>4~5개 정도의 군집</td>
</tr>
</tbody></table>
<hr>
<h2 id="한계">한계</h2>
<ol>
<li>학습 데이터 부족</li>
</ol>
<blockquote>
<p>KeyError: &quot;Key &#39;인공지능&#39; not present in vocabulary”</p>
</blockquote>
<p>위의 코드는 모델에 “인공지능”이라는 키워드를 넣었을 때, 출력되는 단어였다. 위의 에러처럼 만약 학습시킨 문서에 해당 단어가 없다면 유사도를 출력할 수 없는 문제가 존재했다.</p>
<ol>
<li>조사 처리 X</li>
</ol>
<p>또한, 위의 출력 결과들을 확인하면 조사를 제거하지 않아 “일본”과 “알본에서”가 각각 출력되는 것을 확인할 수 있다. </p>
<p>만약 모델의 성능을 향상시키기 위해서는 조사를 처리하는 방식으로 형태소를 구분해 모델 성능을 향상시킬 수 있을 것이라고 생각된다.</p>
<hr>
<h2 id="한계의-보완---조사-처리">한계의 보완 - 조사 처리</h2>
<h3 id="konlpy란"><code>KoNLPy</code>란?</h3>
<ul>
<li>한국어 형태소 분석을 위한 파이썬 라이브러리이다.</li>
<li>여러 형태소 분석기(예: Okt, Kkma, Hannanum, Mecab 등)를 파이썬에서 사용할 수 있도록 래핑할 수 있다.</li>
</ul>
<p>그 중에서, <code>Okt</code>는 &quot;Open Korea Text&quot;를 사용하여 품사를 태깅해 명사와 동사만을 추출하여 단어 임베딩을 진행하였다.</p>
<pre><code class="language-python">import re
import kss
from konlpy.tag import Okt
from tqdm import tqdm

okt = Okt()

def extract_nouns_verbs(text):
    text = re.sub(r&quot;[^\uAC00-\uD7A3\s]&quot;, &quot;&quot;, text)  # 한글과 공백만 유지
    return [word for word, pos in okt.pos(text) if pos in [&#39;Noun&#39;, &#39;Verb&#39;]]

tokenized_sentences = []

for doc in tqdm(documents, desc=&quot;문장 분리 및 품사 필터링&quot;):
    try:
        if not doc[&quot;text&quot;].strip():
            continue
        sentences = kss.split_sentences(doc[&quot;text&quot;])
        for sent in sentences:
            tokens = extract_nouns_verbs(sent)
            if len(tokens) &gt;= 1:
                tokenized_sentences.append(tokens)
    except:
        continue</code></pre>
<pre><code class="language-python">print(model.wv.most_similar(&quot;수학&quot;))</code></pre>
<p>[(&#39;과목&#39;, 0.9074293375015259), (&#39;응시&#39;, 0.8836804032325745), (&#39;성적표&#39;, 0.8830194473266602), (&#39;수생&#39;, 0.8793541789054871), (&#39;시험&#39;, 0.8571914434432983), (&#39;국어&#39;, 0.853074848651886), (&#39;한국사&#39;, 0.8445228338241577), (&#39;고과&#39;, 0.8427404761314392), (&#39;학년&#39;, 0.8421928882598877), (&#39;대학&#39;, 0.8208978176116943)]</p>
<p>성능이 향상됨을 확인할 수 있으며, 조사 또한 제거되었다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (6) - 근사 최근접 이웃 (ANN) 검색]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-6-%EA%B7%BC%EC%82%AC-%EC%B5%9C%EA%B7%BC%EC%A0%91-%EC%9D%B4%EC%9B%83-ANN-%EA%B2%80%EC%83%89</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-6-%EA%B7%BC%EC%82%AC-%EC%B5%9C%EA%B7%BC%EC%A0%91-%EC%9D%B4%EC%9B%83-ANN-%EA%B2%80%EC%83%89</guid>
            <pubDate>Thu, 08 May 2025 08:38:59 GMT</pubDate>
            <description><![CDATA[<h1 id="7-근사-최근접-이웃-ann-검색">#7. 근사 최근접 이웃 (ANN) 검색</h1>
<p>ANN이란 질문 벡터(Query 벡터)에 대해 가장 비슷한 데티어(Nearest Neighbor)를 찾는 작업</p>
<blockquote>
<p>정확도는 조금 낮아져도, 속도를 크게 높이는 것이 목표!!</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/77bc41fa-74dc-4b1a-ad22-2e827804b421/image.png" alt=""></p>
<hr>
<p><strong>VDB 검색 알고리즘</strong></p>
<p>■ <strong>VDB</strong></p>
<ul>
<li>고차원 벡터 데이터를 저장</li>
<li>벡터 간의 유사성 검색을 효율적으로 수행하는 시스템</li>
</ul>
<p>■ <strong>VDB 중요성</strong></p>
<ul>
<li><p>이미지 검색, 자연어 처리, 추천 시스템 등 대규모 벡터 데이터를 다루는 경우</p>
<p>  검색 속도는 시스템의 성능과 사용자 경험에 매우 중요</p>
</li>
</ul>
<hr>
<h3 id="knn-k-nearest-neighbor-알고리즘"><strong>KNN (K-Nearest Neighbor) 알고리즘</strong></h3>
<p><strong>정의</strong></p>
<p>KNN(K-Nearest Neighbor, K-최근접 이웃) 알고리즘은 머신러닝과 검색 시스템에서 가장 기본적인 알고리즘 중 하나</p>
<hr>
<h3 id="【-knn이란-】">【 KNN이란? 】</h3>
<ul>
<li><p>단순하지만 강력한 분류(Classification) 및 회귀(Regression) 알고리즘</p>
</li>
<li><p>새로운 데이터 포인트(예측할 데이터)가 들어오면,</p>
<ul>
<li>주변에 있는 K개의 가장 가까운 데이터를 찾아서</li>
<li>다수결(분류) 또는 평균(회귀)을 통해 예측</li>
</ul>
</li>
<li><p>비슷한 친구가 많으면 나도 그 부류에 속할 가능성이 높다는 개념</p>
</li>
</ul>
<blockquote>
<p>“비슷한 데이터는 비슷한 특성을 가진다”는 아이디어에서 출발</p>
</blockquote>
<hr>
<p><strong>&lt;장/단점&gt;</strong></p>
<table>
<thead>
<tr>
<th><strong>장점</strong></th>
<th><strong>단점</strong></th>
</tr>
</thead>
<tbody><tr>
<td>이해하기 쉽고 구현이 간단</td>
<td>데이터가 많아질수록 속도가 느려짐</td>
</tr>
<tr>
<td>선형적(직선 형태) 관계가 아닌 복잡한 패턴도 잘 찾음</td>
<td>차원이 높아지면 거리 계산이 어려워짐 (고차원 문제)</td>
</tr>
<tr>
<td>특정한 학습 과정이 필요 없음 (즉시 예측 가능)</td>
<td>메모리 사용량이 큼 (모든 데이터를 저장해야 함)</td>
</tr>
</tbody></table>
<blockquote>
<p>보통 K는 <strong>홀수</strong>로 설정하여 다수결 판별이 용이하도록 함.</p>
</blockquote>
<hr>
<p><strong>주요 내용</strong></p>
<ul>
<li><p>브루트포스 검색(유사한 데이터 찾는 데 집중) 대비 <strong>KNN은 예측을 목표</strong></p>
</li>
<li><p>KNN에서 거리 계산을 하기 위해 브루트포스, KD-Tree, Ball Tree, ANN(HNSW 등) 사용 가능</p>
</li>
<li><p>쿼리 벡터와 전체 벡터를 거리(L2, Cos 등)로 직접 비교하여 유사한 것 탐색</p>
<ul>
<li>검색을 위한 쿼리 벡터 검색 시 모든 벡터와 직접 비교 (L2, Cos, Dot-product)</li>
</ul>
</li>
<li><p>가장 정확한 검색 방법</p>
</li>
<li><p>데이터 개수가 많아지면 검색 시간이 데이터 개수에 따라 증가</p>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/a2659a36-49cd-49a1-baa0-9524ffa83078/image.png" alt=""></p>
<h3 id="knn을-활용하여-간단한-분류">KNN을 활용하여 간단한 분류</h3>
<pre><code class="language-python">from sklearn.neighbors import KNeighborsClassifier
import numpy as np

# 간단한 데이터: [키(cm), 몸무게(kg)]
X = np.array([[180, 80], [160, 50], [170, 60], [155, 45], [190, 90]])

# 정답(라벨)
y = np.array([&quot;남자&quot;, &quot;여자&quot;, &quot;남자&quot;, &quot;여자&quot;, &quot;남자&quot;])

# KNN 모델 생성 (K=3)
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X, y)

# 새로운 사람 [165cm, 55kg]이 남자인지 여자인지 예측
new_person = np.array([[165, 55]])
prediction = knn.predict(new_person)

print(&quot;예측 결과:&quot;, prediction)  # 출력: [&#39;여자&#39;]</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e7482a72-2c23-47a4-88d9-970c4e1a8afa/image.png" alt=""></p>
<blockquote>
<p>ANN은 <strong>근사값</strong>을 사용해서 속도를 빠르게 하는 KNN의 개선 버전</p>
</blockquote>
<hr>
<h3 id="브루트포스-검색">브루트포스 검색</h3>
<p>가능한 모든 경우를 전부 탐색하여 해답을 찾는 방식</p>
<pre><code class="language-python">import numpy as np
from sklearn.metrics.pairwise import euclidean_distances

# 쿼리 벡터 (예: [3, 3])
query = np.array([[3, 3]])

# 데이터셋 (비교 대상 벡터들)
data = np.array([[1, 1], [2, 2], [5, 5], [6, 6]])

# 거리 계산
distances = euclidean_distances(query, data)
print(&quot;거리:&quot;, distances)

# 가장 가까운 2개 인덱스 추출
nearest_index = np.argsort(distances[0])[:2]
print(&quot;가장 가까운 2개:&quot;, data[nearest_index])</code></pre>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d068f8b7-acb0-4519-898f-8487aae77e55/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/224f8f05-a0a4-4932-98bf-93e11d2d446b/image.png" alt=""></p>
<blockquote>
<p>시간이 매우 오래 걸리므로 GPU를 사용하여 병렬처리함</p>
</blockquote>
<hr>
<h3 id="브루트포스-검색--search-on-gpu-flat-브루트포스"><strong>브루트포스 검색 – Search on GPU (Flat: 브루트포스)</strong></h3>
<p><strong>개요</strong></p>
<ul>
<li><p>모든 임베딩 벡터를 GPU의 VRAM에 업로드한 후 검색 수행</p>
</li>
<li><p>브루트포스 방식이지만 <strong>GPU를 사용하면 매우 빠른 응답 속도 제공</strong></p>
</li>
<li><p><strong>VRAM 용량에 따라 처리 가능한 벡터 수가 결정됨</strong></p>
</li>
</ul>
<hr>
<p><strong>◾ 단일 GPU 사용</strong></p>
<pre><code class="language-python">res = faiss.StandardGpuResources()                 # GPU 자원 할당
index_flat = faiss.IndexFlatL2(d)                  # L2 거리 기반 Flat Index 생성

gpu_index_flat = faiss.index_cpu_to_gpu(res, 0, index_flat)  # GPU로 인덱스 이동
gpu_index_flat.add(xb)                             # 임베딩 벡터 추가
D, I = index.search(xq, k)                         # 검색 수행</code></pre>
<hr>
<p><strong>◾ 멀티 GPU 사용</strong></p>
<pre><code class="language-python">cpu_index = faiss.IndexFlatL2(d)                            # CPU 상의 인덱스 생성
gpu_index_flat = faiss.index_cpu_to_all_gpus(cpu_index)     # 모든 GPU로 인덱스 복사
gpu_index_flat.add(xb)                                      # 임베딩 벡터 추가
D, I = index.search(xq, k)                                  # 검색 수행</code></pre>
<hr>
<h2 id="ann-알고리즘">ANN 알고리즘</h2>
<h3 id="ann-알고리즘-approximate-nearest-neighbor"><strong>ANN 알고리즘 (Approximate Nearest Neighbor)</strong></h3>
<ul>
<li><p><strong>정의</strong>:</p>
<p>  대규모 벡터 데이터셋에서 특정 벡터와 가장 유사한 벡터를 <strong>빠르게 찾기 위한 검색 기법</strong></p>
</li>
<li><p><strong>특징</strong>:</p>
<ul>
<li>KNN과 비교 시 <strong>정확도를 약간 희생</strong>하는 대신 <strong>검색 속도 향상</strong></li>
<li><strong>고차원 벡터 공간</strong>에서 근사값을 빠르게 계산해 유사한 결과 반환</li>
</ul>
</li>
</ul>
<hr>
<h3 id="주요-ann-알고리즘"><strong>주요 ANN 알고리즘</strong></h3>
<table>
<thead>
<tr>
<th>알고리즘</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>LSH (Locality Sensitive Hashing)</strong></td>
<td>해시 함수를 통해 유사한 벡터가 동일한 해시 버킷에 위치하도록 설계</td>
</tr>
<tr>
<td><strong>IVF (Inverted File Index)</strong></td>
<td>벡터를 클러스터로 나눈 후, 각 클러스터 내에서 세부 검색 수행</td>
</tr>
<tr>
<td><strong>PQ (Product Quantization)</strong></td>
<td>벡터를 여러 하위 벡터로 분할 후, 양자화하여 압축 검색</td>
</tr>
<tr>
<td><strong>HNSW (Hierarchical Navigable Small World)</strong></td>
<td>그래프 기반 알고리즘으로 고차원에서도 정확도와 검색 속도를 모두 확보 가능</td>
</tr>
</tbody></table>
<hr>
<h2 id="lsh-locality-sensitive-hashing">LSH, Locality Sensitive Hashing</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td><strong>구조</strong></td>
<td>해시테이블 기반</td>
</tr>
<tr>
<td><strong>원리</strong></td>
<td>- 비슷한 데이터는 같은 해시 버킷에 들어가도록 설계<br>- 질의 벡터가 들어오면 같은 해시 버킷만 조회하여 전체 비교를 피함</td>
</tr>
<tr>
<td><strong>장점</strong></td>
<td>- 계산 속도가 빠름</td>
</tr>
<tr>
<td><strong>단점</strong></td>
<td>- 차원이 높아질수록 성능 저하 발생<br>- 정확도는 다소 낮은 편</td>
</tr>
<tr>
<td><strong>사용 예시</strong></td>
<td>텍스트 유사도 검색, 대규모 <strong>로그 데이터 분석</strong></td>
</tr>
</tbody></table>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8a7af39e-541b-42e7-a157-b068cd3ea67a/image.png" alt=""></p>
<h3 id="lsh의-구조"><strong>LSH의 구조</strong></h3>
<table>
<thead>
<tr>
<th>구성 요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Keys</strong></td>
<td>입력 벡터들 (예: 문서 임베딩, 이미지 벡터 등)</td>
</tr>
<tr>
<td><strong>Hashing Function</strong></td>
<td>각 벡터에 해시 함수를 적용하여 특정 해시 값으로 변환</td>
</tr>
<tr>
<td><strong>Hash Buckets</strong></td>
<td>해시 값이 같은 벡터들은 동일한 버킷에 저장됨 <br>→ 유사한 벡터들이 같은 버킷에 위치하도록 해시 함수 설계</td>
</tr>
<tr>
<td><strong>Values (우측)</strong></td>
<td>각 버킷 내 값들만 대상으로 최근접 탐색 (Nearest Neighbor Search) 수행</td>
</tr>
</tbody></table>
<hr>
<h3 id="lsh의-장점"><strong>LSH의 장점</strong></h3>
<ul>
<li><p>전체 벡터를 비교하지 않아 <strong>속도가 빠름</strong></p>
</li>
<li><p>해시 버킷을 기준으로 검색 대상이 <strong>자동으로 줄어듦</strong></p>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/2085ff49-6f55-4ed0-8bea-9d4e69395799/image.png" alt=""></p>
<h3 id="해시-비트-수nbit-vs-recall"><strong>해시 비트 수(nbit) vs Recall</strong></h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>nbit</strong></td>
<td>해싱 비트 수 (해시 표현의 정밀도, x축)</td>
</tr>
<tr>
<td><strong>recall</strong></td>
<td>검색 정확도 (실제 가장 유사한 벡터를 잘 찾았는지, y축)</td>
</tr>
</tbody></table>
<hr>
<h3 id="관계-및-특징"><strong>관계 및 특징</strong></h3>
<ul>
<li><p><strong>nbit가 작을수록</strong>: recall이 낮아짐 (정확도 떨어짐)</p>
</li>
<li><p><strong>nbit가 커질수록</strong>: recall이 높아짐 (정확도 향상)</p>
</li>
<li><p><strong>그러나 32bit ~ 64bit 이상부터는</strong> 성능 향상이 <strong>둔화</strong></p>
<ul>
<li>일정 수준 이상에서는 <strong>정확도 증가가 미미</strong>함</li>
</ul>
</li>
</ul>
<blockquote>
<p>즉, <strong>성능 향상은 있으나 한계가 존재</strong>함</p>
</blockquote>
<hr>
<h2 id="ivf-inverted-file-index">IVF, Inverted File Index</h2>
<table>
<thead>
<tr>
<th><strong>구분</strong></th>
<th><strong>내용</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>구조</strong></td>
<td>데이터 클러스터링 기반 (예: K-means)</td>
</tr>
<tr>
<td><strong>사용 예시</strong></td>
<td>영상 검색, 문서 검색, 이미지 인식</td>
</tr>
<tr>
<td><strong>원리</strong></td>
<td>- 전체 벡터 데이터를 여러 개 클러스터로 나눔  <br> - 쿼리 벡터가 속할 가능성이 높은 몇 개의 클러스터만 탐색  <br> - 각 클러스터는 중심점(centroid)을 대표 벡터로 사용  <br> - 쿼리 벡터와 중심점 간 거리 비교 후 유사한 클러스터 선택  <br> - 선택된 클러스터 내부에서만 KNN 검색 수행</td>
</tr>
<tr>
<td><strong>장점</strong></td>
<td>- 빠른 검색 속도 (탐색 범위 축소)  <br> - 효율적인 메모리 관리 (인덱스 구축 시간 및 메모리 사용량 증가 가능성 있음)</td>
</tr>
<tr>
<td><strong>단점</strong></td>
<td>- 정확도는 클러스터 품질에 의존  <br> - 탐색할 클러스터 수(nprobe)가 많을수록 정확도는 향상되나 검색 속도는 저하됨</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b763a8ef-33ce-4f16-b3b1-65de7e128b22/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e774ac01-55ee-4c6a-aa1b-6c3b2a2a0f82/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/82411e88-8509-42db-89c1-eb3d163eda7c/image.png" alt=""></p>
<h3 id="voronoi-cell-기반-분할-ivf-구조"><strong>Voronoi Cell 기반 분할 (IVF 구조)</strong></h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>기본 원리</strong></td>
<td>전체 벡터 공간을 K-means 알고리즘으로 분할하여 <strong>Voronoi Cell</strong>(보로노이 셀) 생성</td>
</tr>
<tr>
<td><strong>구조</strong></td>
<td>각 셀은 <strong>centroid</strong>(중심점)를 기준으로 가장 가까운 벡터들이 모여 있음</td>
</tr>
<tr>
<td><strong>탐색 방식</strong></td>
<td>검색 시, 먼저 쿼리 벡터와 <strong>가장 가까운 centroid</strong>를 찾고 → 해당 셀 내부에서만 탐색 수행</td>
</tr>
</tbody></table>
<blockquote>
<p>IVF의 핵심은 <strong>검색 범위를 셀 단위로 줄여 속도를 향상</strong>시키는 것이며, <strong>클러스터링 기반의 효율적인 인덱싱 구조</strong></p>
</blockquote>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/aa142285-3122-407f-a45d-0426bb99fc68/image.png" alt=""></p>
<h3 id="nprobe--1일-때-ivf-탐색-설정"><strong>nprobe = 1일 때 (IVF 탐색 설정)</strong></h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>탐색 범위</strong></td>
<td>쿼리 벡터 <code>xq</code>는 <strong>가장 가까운 하나의 셀만 탐색</strong> (예: 파란 셀 영역)</td>
</tr>
<tr>
<td><strong>장점</strong></td>
<td>탐색 속도가 매우 빠름</td>
</tr>
<tr>
<td><strong>단점</strong></td>
<td>- 정확도가 낮아질 수 있음<br></td>
</tr>
<tr>
<td>- 근처에 유사한 벡터가 있어도 다른 셀에 있다면 <strong>탐색되지 않을 수 있음</strong></td>
<td></td>
</tr>
</tbody></table>
<p><code>nprobe=1</code>은 <strong>속도 우선 전략</strong>이며, <strong>정확도는 희생될 수 있음</strong></p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/f8059088-b356-4727-8a4f-1ffde8dba006/image.png" alt=""></p>
<h3 id="nprobe--8일-때-ivf-탐색-설정"><strong>nprobe = 8일 때 (IVF 탐색 설정)</strong></h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>탐색 범위</strong></td>
<td>쿼리 벡터 <code>xq</code> 주변의 <strong>8개 셀을 함께 탐색</strong></td>
</tr>
<tr>
<td><strong>정확도</strong></td>
<td>Recall(정확도) 향상됨 → 유사 벡터를 찾을 확률 증가</td>
</tr>
<tr>
<td><strong>속도</strong></td>
<td>연산량이 많아져 <strong>속도는 느려짐</strong></td>
</tr>
<tr>
<td><strong>추가 특징</strong></td>
<td><code>nprobe</code> 값이 클수록 <strong>더 넓은 영역을 커버</strong>함</td>
</tr>
</tbody></table>
<blockquote>
<p><code>nprobe=8</code>은 <strong>정확도 우선 전략</strong>으로, 속도를 일부 희생하더라도 유사 벡터를 <strong>더 놓치지 않고 찾기 위함</strong></p>
</blockquote>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d3486b48-6903-40a5-a386-786f3d31b33b/image.png" alt=""></p>
<h3 id="ivf-성능-그래프-해석">IVF 성능 그래프 해석</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>x축</strong></td>
<td>벡터 수 (단위: 1e6 = 백만 개)</td>
</tr>
<tr>
<td><strong>y축</strong></td>
<td>쿼리 소요 시간 (단위: ms)</td>
</tr>
<tr>
<td><strong>탐색 셀 수 변화</strong></td>
<td>탐색하는 셀 수에 따라 성능이 달라짐</td>
</tr>
<tr>
<td>- <code>IVFflat 1</code>: 빠르지만 정확도 낮음</td>
<td></td>
</tr>
<tr>
<td>- <code>IVFflat 20</code>: 느리지만 정확도 높음</td>
<td></td>
</tr>
</tbody></table>
<blockquote>
<p><strong>속도 vs 정확도 트레이드오프</strong> 존재</p>
</blockquote>
<hr>
<h3 id="ivf-관련-주요-용어-정리"><strong>IVF 관련 주요 용어 정리</strong></h3>
<table>
<thead>
<tr>
<th><strong>용어</strong></th>
<th><strong>설명</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>IVF (Inverted File Index)</strong></td>
<td>- 벡터를 K개의 클러스터로 나눈 뒤, 일부 클러스터만 검색<br>- 검색 시 탐색할 클러스터 수 지정</td>
</tr>
<tr>
<td><strong>nprobe</strong></td>
<td>- 탐색할 클러스터 수- <code>nprobe = 1</code>: 빠르지만 정확도 낮음<br>- <code>nprobe ↑</code>: 느려지지만 정확도 상승<br>- 적절한 <code>nprobe</code> 선택은 속도/정확도 균형 조절의 핵심</td>
</tr>
<tr>
<td><strong>centroid</strong></td>
<td>각 클러스터의 중심점</td>
</tr>
<tr>
<td><strong>Voronoi cell</strong></td>
<td>중심점 기준으로 벡터가 소속되는 영역</td>
</tr>
<tr>
<td><strong>IVFflat</strong></td>
<td>IVF 구조에서 각 클러스터 내부를 <strong>Flat(정확히)</strong> 방식으로 검색</td>
</tr>
</tbody></table>
<hr>
<h2 id="pq">PQ</h2>
<table>
<thead>
<tr>
<th>구분</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td><strong>구조</strong></td>
<td>압축 기반 인코딩</td>
</tr>
<tr>
<td><strong>원리</strong></td>
<td>- 벡터를 여러 블록으로 나누고, 각 블록을 <strong>압축 코드북(codebook)</strong>으로 표현<br>- 예: 128차원 벡터<br> → 8개 블록 <br>→ 각 블록을 코드북에서 대표값으로 대체<br>- 보통 K-means를 활용해 각 블록별 코드북 생성- 고차원 벡터 <br>→ 저차원 <strong>서브벡터</strong>로 분할 <br>→ 각 서브벡터를 양자화하여 저장</td>
</tr>
<tr>
<td><strong>장점</strong></td>
<td>- <strong>대용량 벡터 처리에 적합</strong>- <strong>메모리 절약</strong> + 거리 계산 속도 향상</td>
</tr>
<tr>
<td><strong>단점</strong></td>
<td>- <strong>약간의 정확도 손실</strong> 발생 가능<br>- <strong>설정 및 튜닝</strong> 필요 (코드북 수, 블록 수 등)</td>
</tr>
<tr>
<td><strong>활용</strong></td>
<td>각 서브벡터는 코드북 인덱스로 표현되며, IVF와 <strong>함께 사용</strong> 가능 (IVFPQ 등)</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/2c13b614-6ed2-4f80-85a7-22ae8ee67169/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/bba888c9-d968-466c-8ee7-783f43490c3d/image.png" alt=""></p>
<h3 id="인덱스-방식별-비교"><strong>인덱스 방식별 비교</strong></h3>
<table>
<thead>
<tr>
<th><strong>인덱스 방식</strong></th>
<th><strong>설명</strong></th>
<th><strong>특징</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>FlatL2</strong></td>
<td>모든 벡터를 정확히 비교</td>
<td>느리지만 <strong>정확도 높음</strong></td>
</tr>
<tr>
<td><strong>IVFFlat</strong></td>
<td>IVF 구조 기반, 선택된 셀만 정밀 비교</td>
<td><strong>빠르고</strong>, 정확도는 <strong>중간 수준</strong></td>
</tr>
<tr>
<td><strong>IVFPQ</strong></td>
<td>IVF + PQ 압축 구조</td>
<td><strong>가장 빠름</strong>, 정확도는 약간 손실 가능</td>
</tr>
</tbody></table>
<hr>
<h3 id="요약-포인트"><strong>요약 포인트</strong></h3>
<ul>
<li><p><strong>IVFPQ</strong>: 벡터 수가 많아져도 시간 증가 거의 없음 → 대규모 데이터에 적합</p>
</li>
<li><p><strong>FlatL2</strong>: 가장 정확하지만, 데이터 많을수록 <strong>기하급수적으로 느려짐</strong></p>
</li>
<li><p><strong>IVFFlat</strong>: 속도·정확도 <strong>균형</strong> 잡힌 선택지</p>
</li>
</ul>
<hr>
<h2 id="hnsw">HNSW</h2>
<h3 id="hnsw-정리"><strong>HNSW 정리</strong></h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>구조</strong></td>
<td>계층적 그래프 기반</td>
</tr>
<tr>
<td><strong>사용 예시</strong></td>
<td>벡터 검색, 추천 시스템, 문서 검색 등</td>
</tr>
</tbody></table>
<p><strong>&lt;원리&gt;</strong></p>
<ul>
<li><p>데이터 포인트를 <strong>노드로 간주</strong>, 이들 간 <strong>근접성 기반 그래프 구성</strong></p>
</li>
<li><p><strong>계층 구조</strong>로 구성되며, <strong>상위 레벨일수록 노드 수는 적고 연결은 추상적</strong></p>
</li>
<li><p>검색은 <strong>최상위 레벨부터 시작</strong>, 점점 하위 레벨로 내려가며 이웃 노드를 탐색</p>
</li>
<li><p>각 단계에서 <strong>가장 가까운 노드로 이동</strong>하면서 목표 벡터에 점차적으로 접근</p>
</li>
</ul>
<p><strong>&lt;장점&gt;</strong></p>
<ul>
<li><p><strong>정확도 매우 높음 (95~99%)</strong></p>
</li>
<li><p><strong>속도도 빠름</strong></p>
</li>
</ul>
<p><strong>&lt;단점&gt;</strong></p>
<ul>
<li><p><strong>메모리 사용량 큼</strong></p>
</li>
<li><p><strong>구조 구축 시간 오래 걸리고 구현 복잡도 높음</strong></p>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8e69dc50-1911-4709-8f6e-babe01b03b48/image.png" alt=""></p>
<hr>
<h3 id="skip-list-일종의-계층형-연결-리스트"><strong>Skip List: 일종의 계층형 연결 리스트</strong></h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/821ba8f8-80fd-4b81-bf99-5ef3ae5c7dc3/image.png" alt=""></p>
<p><strong>개념</strong></p>
<ul>
<li><p>기본 연결 리스트는 <strong>노드를 순서대로 연결</strong></p>
</li>
<li><p>Skip List는 &quot;<strong>건너뛸 수 있는 고속도로</strong>&quot; 개념</p>
<p>  → <strong>상위 레벨 링크</strong>를 추가하여 일부 노드를 <strong>건너뛰며 탐색 속도 향상</strong></p>
</li>
</ul>
<p><strong>구조</strong></p>
<ul>
<li><strong>Balanced Tree</strong>와 <strong>Linked List</strong>의 장점을 결합한 자료 구조</li>
</ul>
<hr>
<p><strong>탐색 흐름</strong></p>
<ol>
<li><p><strong>최상위 레벨에서 시작</strong></p>
</li>
<li><p><strong>다음 노드의 키와 검색하려는 값 비교</strong></p>
<ul>
<li>다음 키가 <strong>작으면 오른쪽</strong>으로 이동</li>
<li>다음 키가 <strong>크면 하위 레벨</strong>로 이동</li>
</ul>
</li>
<li><p><strong>가장 하위 레벨에 도달할 때까지 반복</strong></p>
</li>
</ol>
<hr>
<h3 id="navigable-small-world-nsw"><strong>Navigable Small World (NSW)</strong></h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/ca14fb6b-2f71-4790-bcc0-d352ae2e3618/image.png" alt=""></p>
<p><strong>개념</strong></p>
<ul>
<li><p>네트워크 구조에서 <strong>효율적인 검색과 탐색</strong>을 가능하게 하는 데이터 구조 및 알고리즘 개념</p>
</li>
<li><p>전체 노드가 넓게 퍼져 있어도, <strong>몇 번의 연결만으로 거의 모든 노드에 도달</strong>할 수 있음</p>
</li>
<li><p>각 노드는 <strong>k개의 이웃 노드</strong>와 연결되어 있으며,</p>
<ul>
<li><strong>long-range 연결</strong>과 <strong>short-range 연결</strong>을 조합하여 구성됨</li>
</ul>
</li>
<li><p>가까운 노드만 따라가도 목표 노드에 도달 가능</p>
</li>
</ul>
<p><strong>예시</strong></p>
<ul>
<li><strong>SNS(소셜 네트워크)</strong><ul>
<li>“세상은 좁다”는 말처럼 대부분의 사람은 <strong>6단계 이내</strong>로 연결됨 (&quot;6 degrees of separation&quot;)</li>
</ul>
</li>
</ul>
<hr>
<h3 id="탐색-흐름"><strong>탐색 흐름</strong></h3>
<ol>
<li><p><strong>쿼리 벡터가 입력되면</strong></p>
</li>
<li><p><strong>상위 레벨에서 출발</strong> (멀리 있는 친구들부터 시작)</p>
</li>
<li><p><strong>가까운 노드를 따라 이동</strong></p>
<ul>
<li>점점 정확히 위치를 좁혀가며</li>
<li>최종적으로 <strong>목표에 가까운 노드에 도달</strong></li>
<li>위 과정을 <strong>목표 도달 시까지 반복</strong></li>
</ul>
</li>
</ol>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/2aa06dfc-81dc-40e1-94f4-1628dd40ef37/image.png" alt=""></p>
<blockquote>
<p>NHSW는 Skip List에서 아이디어를 얻었지만, 훨씬 더 강력한 그래프 탐색 구조로 발전했다.</p>
</blockquote>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e2f61211-12b5-4ccc-b43b-23d065cd006c/image.png" alt=""></p>
<p><img src="blob:https://velog.io/4469ab30-f9ec-408f-bd63-58f472408f63" alt="업로드중.."></p>
<pre><code class="language-python">import nmslib

index = nmslib.init(method=&#39;hnsw&#39;, space=&#39;cosinesimil&#39;)

# 데이터 추가
index.addDataPointBatch(data)

# HNSW 파라미터 설정
index.createIndex({
    &#39;M&#39;: 32,
    &#39;efConstruction&#39;: 200
}, print_progress=True)

# ef_search 설정
index.setQueryTimeParams({
    &#39;efSearch&#39;: 100
})</code></pre>
<table>
<thead>
<tr>
<th><strong>상황</strong></th>
<th><strong>추천 설정</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>정확도 중요 시</strong></td>
<td>- <code>M = 48</code><br>- <code>ef_construction = 300</code><br>- <code>ef_search = 200 ~ 500</code></td>
</tr>
<tr>
<td><strong>속도 중요 시 (실시간)</strong></td>
<td>- <code>M = 16</code><br>- <code>ef_construction = 100</code><br>- <code>ef_search = 50 ~ 100</code></td>
</tr>
<tr>
<td><strong>중간 수준</strong></td>
<td>- <code>M = 32</code><br>- <code>ef_construction = 200</code><br>- <code>ef_search = 100 ~ 150</code></td>
</tr>
</tbody></table>
<hr>
<h2 id="ann-알고리즘-평가지표">ANN 알고리즘 평가지표</h2>
<h3 id="mrr-mean-reciprocal-rank">MRR, Mean Reciprocal Rank</h3>
<blockquote>
<p>정답(정답 벡터, relevant item)<strong>이 검색 결과 중 **몇 번째에 나오는지를 평가하는 지표</strong></p>
</blockquote>
<p><img src="blob:https://velog.io/ad5be482-42bd-4d4c-9854-1d50e5d444d4" alt="업로드중.."></p>
<p><strong>■ 개념 요약</strong></p>
<ul>
<li><p>“내가 찾고자 했던 진짜 이웃(정답 벡터)이 결과 몇 번째에 있었나?”를 확인</p>
</li>
<li><p>각 쿼리의 <strong>가장 먼저 등장하는 정답 문서</strong>의 <strong>순위의 역수</strong>를 계산하여 평균</p>
</li>
<li><p>값이 <strong>1에 가까울수록 상위에 정답이 위치함</strong></p>
</li>
<li><p>하나의 쿼리에 <strong>복수 정답이 있어도 첫 번째 정답만 고려</strong></p>
</li>
</ul>
<hr>
<p><strong>■ 계산 방식</strong></p>
<ol>
<li><p><em>각 쿼리(query)*</em>에 대해 정답의 <strong>순위(rank)</strong>를 기록</p>
</li>
<li><p>해당 순위의 <strong>역수 (1 / rank)</strong>를 계산</p>
</li>
<li><p>전체 쿼리에 대해 <strong>평균</strong></p>
</li>
</ol>
<hr>
<p><strong>■ 예시</strong></p>
<ul>
<li><p>쿼리 1: 정답이 1등 → 1/1 = 1.0</p>
</li>
<li><p>쿼리 2: 정답이 3등 → 1/3 ≈ 0.333</p>
</li>
<li><p>MRR = (1.0 + 0.333) / 2 = 0.666</p>
</li>
</ul>
<hr>
<h3 id="ann-알고리즘-mrr-평가-흐름"><strong>ANN 알고리즘 MRR 평가 흐름</strong></h3>
<ol>
<li><p><strong>Ground Truth 생성</strong></p>
<ul>
<li>브루트포스 방식으로 정확한 <strong>KNN 결과를 미리 계산</strong>하여 기준값 생성</li>
</ul>
</li>
<li><p><strong>ANN 결과 도출</strong></p>
<ul>
<li>HNSW, IVF, PQ 등 다양한 <strong>ANN 방식</strong>으로 검색 결과 생성</li>
</ul>
</li>
<li><p><strong>정답 순위 확인</strong></p>
<ul>
<li>각 쿼리에 대해 <strong>정답이 검색 결과에서 몇 번째에 위치했는지</strong> 확인</li>
</ul>
</li>
<li><p><strong>MRR 계산</strong></p>
<ul>
<li>정답의 순위에 대한 역수 평균을 통해 <strong>ANN 알고리즘의 성능 평가</strong></li>
</ul>
</li>
</ol>
<hr>
<pre><code class="language-python">def compute_mrr(results, ground_truth):
    &quot;&quot;&quot;
    results: List[List[int]] -&gt; 쿼리별 검색 결과 (예: [[2, 5, 8], [1, 3, 4]])
    ground_truth: List[int] -&gt; 각 쿼리의 정답 인덱스
    &quot;&quot;&quot;
    total_reciprocal = 0
    for i, res in enumerate(results):
        if ground_truth[i] in res:
            rank = res.index(ground_truth[i]) + 1  # 0-based -&gt; 1-based
            total_reciprocal += 1 / rank
        else:
            total_reciprocal += 0
    return total_reciprocal / len(results)

# 예시
results = [[2, 5, 3], [1, 4, 0], [8, 6, 7]]
ground_truth = [5, 1, 6]

mrr = compute_mrr(results, ground_truth)
print(f&quot;MRR: {mrr:.4f}&quot;)</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (5) - 유사도 측정]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-5-%EC%9C%A0%EC%82%AC%EB%8F%84-%EC%B8%A1%EC%A0%95</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-5-%EC%9C%A0%EC%82%AC%EB%8F%84-%EC%B8%A1%EC%A0%95</guid>
            <pubDate>Thu, 08 May 2025 08:28:57 GMT</pubDate>
            <description><![CDATA[<p>두 데이터 간의 <strong>유사성을 평가하는 방법</strong></p>
<ul>
<li>머신러닝, 정보 검색, 자연어 처리 등 다양한 분야에서 활용</li>
<li>데이터 간의 관계를 수치화할 때 유용</li>
</ul>
<hr>
<h2 id="코사인-유사도-cosine-similarity">코사인 유사도, cosine similarity</h2>
<p>두 벡터 사이의 각도를 기준으로 유사도를 측정하는 방식.</p>
<p>→ 두 벡터가 이루는 각도가 작을수록(즉, 방향이 비슷할수록) 유사도가 높음.</p>
<p><strong>수식</strong>:</p>
<p>공식</p>
<p>$$
Cosine Similarity= \frac{A \cdot B}{|A| \times |B|}
$$</p>
<p>$$
A⋅B
$$</p>
<p>두 벡터의 내적</p>
<p>$$
∥A∥,∥B∥
$$</p>
<p>각 벡터의 크기 (Euclidean norm)</p>
<hr>
<p><strong>&lt;예제&gt;</strong></p>
<ul>
<li>A = [1, 2, 3], B = [2, 3, 4] 라는 두 벡터가 주어졌을 때</li>
</ul>
<ol>
<li><strong>내적 계산</strong></li>
</ol>
<p>$$
A⋅B=(1×2)+(2×3)+(3×4)=2+6+12=20
$$</p>
<ol>
<li><strong>벡터 크기 계산</strong></li>
</ol>
<p>$$
|A| = \sqrt{1^2 + 2^2 + 3^2} = \sqrt{14}, \quad |B| = \sqrt{2^2 + 3^2 + 4^2} = \sqrt{29}
$$</p>
<ol>
<li><strong>Cosine Similarity 계산</strong></li>
</ol>
<p>$$
\text{Cosine Similarity} = \frac{20}{\sqrt{14} \times \sqrt{29}} \approx 0.99
$$</p>
<p>→ <strong>1에 가까울수록 유사한 벡터임을 의미</strong></p>
<hr>
<p><strong>&lt;활용 분야&gt;</strong></p>
<ul>
<li>문서 간 유사도 비교 (예: 뉴스 기사 추천)</li>
<li>추천 시스템 (예: 영화 추천)</li>
<li>검색 엔진 (예: 사용자 검색어와 문서 간 유사도 평가)</li>
</ul>
<hr>
<h2 id="유클리드-거리">유클리드 거리</h2>
<p>두 점(벡터) 사이의 직선 거리를 측정하는 방법으로, 쉽게 말해 두 점이 얼마나 떨어져 있는지를 표시</p>
<p>$$
\text{Euclidean Distance} = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2 + \ldots}
$$</p>
<ul>
<li>각 차원의 차이를 제곱하여 더한 후, 제곱근을 구함</li>
</ul>
<hr>
<p><strong>&lt;예제&gt;</strong></p>
<ul>
<li><p>두 개의 점 A와 B 사이의 유클리드 거리</p>
<p>  A(1,2) 와 B(4,6)</p>
</li>
<li><p>각 차원의 계산</p>
</li>
</ul>
<p>$$
(4-1)^2 = 9, (6-2)^2 = 16
$$</p>
<ul>
<li>합산 후 제곱근 계산</li>
</ul>
<p>$$
\sqrt{9 + 16} = \sqrt{25} = 5
$$</p>
<p>→ 두 점 사이의 거리는 <strong>5</strong></p>
<hr>
<p><strong>&lt;활용 예&gt;</strong></p>
<ul>
<li>이미지 검색: 색상이나 패턴이 유사한 이미지 찾기</li>
<li>클러스터링: K-means 알고리즘에서 데이터를 군집화할 때</li>
<li>추천 시스템: 사용자와 아이템 간의 거리 측정</li>
</ul>
<hr>
<h2 id="기타-유사도-측정-방법">기타 유사도 측정 방법</h2>
<h3 id="자카드-유사도-jaccard-similarity">자카드 유사도 (Jaccard Similarity)</h3>
<ul>
<li><strong>집합(Set) 간의 유사도</strong>를 비교하는 방법</li>
<li><strong>교집합과 합집합의 비율</strong>을 사용</li>
</ul>
<p>$$
\text{Jaccard Similarity} = \frac{|A \cap B|}{|A \cup B|}
$$</p>
<ul>
<li><p>예시:</p>
<p>  A = {사과, 바나나, 오렌지}</p>
<p>  B = {바나나, 오렌지, 수박}</p>
<p>  $$
  → 유사도  = \frac{2}{4} = 0.5
  $$</p>
</li>
<li><p><strong>활용 분야</strong>:</p>
<ul>
<li>텍스트 중복 탐지</li>
<li>사용자 취향 비교</li>
</ul>
</li>
</ul>
<hr>
<h3 id="마할라노비스-거리-mahalanobis-distance">마할라노비스 거리 (Mahalanobis Distance)</h3>
<ul>
<li><strong>데이터의 분산과 공분산을 고려한</strong> 거리 측정 방식</li>
<li>데이터가 서로 다른 분포를 가질 때, <strong>유클리드 거리보다 더 신뢰</strong>할 수 있는 방식</li>
</ul>
<p>$$
D_M(A, B) = \sqrt{(A - B)^T S^{-1} (A - B)}
$$</p>
<ul>
<li>여기서</li>
</ul>
<p>$$
S^{-1}
$$</p>
<p>은 <strong>공분산 행렬의 역행렬</strong></p>
<ul>
<li><strong>활용 분야</strong>:<ul>
<li>이상치 탐지</li>
<li>다변량 데이터 분석</li>
</ul>
</li>
</ul>
<hr>
<h3 id="내적-유사도-dot-product-similarity">내적 유사도 (Dot Product Similarity)</h3>
<ul>
<li>두 벡터의 <strong>내적(Dot Product)</strong>을 계산하여 유사도를 측정하는 방법</li>
</ul>
<p>$$
A \cdot B = x_1 y_1 + x_2 y_2 + \cdots + x_n y_n
$$</p>
<ul>
<li><strong>내적 값이 클수록</strong> 두 벡터가 비슷한 방향을 가짐을 의미</li>
<li><strong>활용 예시</strong><ul>
<li>신경망 가중치 적용 (딥러닝)</li>
<li>추천 시스템 (사용자 선호도 예측)</li>
</ul>
</li>
</ul>
<hr>
<h3 id="맨해튼-거리-manhattan-distance">맨해튼 거리 (Manhattan Distance)</h3>
<ul>
<li>각 차원의 차이의 <strong>절댓값</strong>을 더해서 거리를 측정하는 방식</li>
<li>“격자 무늬 거리”라고도 하며, <strong>도시 블록처럼</strong> 수직·수평 방향으로만 이동하는 거리 방식과 유사</li>
</ul>
<p>$$
\text{Manhattan Distance} = |x_1 - x_2| + |y_1 - y_2| + \cdots
$$</p>
<ul>
<li><p>예시:</p>
<p>  A(1,2) 와 B(4,6)의 맨해튼 거리</p>
<p>  $$
  |4 - 1| + |6 - 2| = 3 + 4 = 7
  $$</p>
</li>
<li><p><strong>활용 예시</strong></p>
<ul>
<li>네트워크 라우팅 (최적 경로 찾기)</li>
<li>주식 데이터 비교 (가격 변화량 분석)</li>
</ul>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/84bee0d0-4888-45a1-a2ac-592caedbdd12/image.png" alt=""></p>
<blockquote>
<p>유사도 측정 방식은 상황에 따라 다르게 적용되니 데이터의 특징과 목적에 따라 적절한 방식 선택</p>
</blockquote>
<hr>
<h3 id="공분산-행렬-covariance-matrix">공분산 행렬, Covariance Matrix</h3>
<ul>
<li>여러 변수 간의 <strong>공분산(Covariance)</strong> 값을 정리한 행렬</li>
<li>공분산은 두 변수 간의 <strong>관계</strong>를 나타내는 값<ul>
<li><strong>양수</strong>: 양의 상관관계 (함께 증가)</li>
<li><strong>음수</strong>: 음의 상관관계 (한쪽 증가, 한쪽 감소)</li>
<li><strong>0</strong>: 관계 없음</li>
</ul>
</li>
<li>데이터의 <strong>분포 특성</strong>을 분석할 때 사용</li>
<li>활용 분야:<ul>
<li>PCA(주성분 분석)</li>
<li>머신러닝</li>
<li>통계분석</li>
<li>금융공학 등</li>
</ul>
</li>
</ul>
<hr>
<p><strong>&lt;정의 및 계산식&gt;</strong></p>
<ul>
<li>두 변수 XX 와 YY 의 공분산:</li>
</ul>
<p>$$
\text{Cov}(X, Y) = \frac{1}{n} \sum_{i=1}^{n} (X_i - \bar{X})(Y_i - \bar{Y})
$$</p>
<ul>
<li>설명:<ul>
<li>n: 데이터 개수</li>
<li>X_i, Y_i: 각 X와 Y 변수의 값</li>
<li>각 X와 Y의 평균</li>
</ul>
</li>
<li>의미:<ul>
<li>X 증가, Y 증가 → 공분산 &gt; 0 (양의 상관관계)</li>
<li>X 증가, Y 감소 → 공분산 &lt; 0 (음의 상관관계)</li>
<li>X와 Y가 서로 관계 없음 → 공분산 = 0</li>
</ul>
</li>
</ul>
<hr>
<p><strong>【활용】</strong></p>
<ul>
<li><strong>PCA (주성분 분석)</strong><ul>
<li>공분산 행렬을 사용하여 데이터의 주요 방향(주성분)을 찾고 차원 축소 수행</li>
</ul>
</li>
<li><strong>다변량 정규분포 분석</strong><ul>
<li>여러 개의 변수가 동시에 정규분포를 따를 때, 그 관계를 나타내는 데 사용</li>
</ul>
</li>
<li><strong>포트폴리오 최적화 (금융공학)</strong><ul>
<li>주식 간의 변동성을 분석하여 리스크를 최소화하는 투자 포트폴리오 구성</li>
</ul>
</li>
<li><strong>머신러닝 및 데이터 분석</strong><ul>
<li>데이터의 상관관계를 분석하고, 변수 선택(feature selection)에 활용</li>
</ul>
</li>
</ul>
<hr>
<p><strong>【Python 활용 예제】</strong></p>
<ul>
<li>Python에서는 <code>numpy</code> 라이브러리를 이용하여 쉽게 공분산 행렬 계산 가능</li>
</ul>
<pre><code class="language-python">import numpy as np

# 예제 데이터: 3개의 변수 (X, Y, Z)
data = np.array([
    [1, 2, 3],
    [2, 3, 5],
    [3, 4, 6],
    [4, 5, 6]
])

# 공분산 행렬 계산
cov_matrix = np.cov(data, rowvar=False)

print(&quot;공분산 행렬:\n&quot;, cov_matrix)
</code></pre>
<ul>
<li>결과:</li>
</ul>
<pre><code>공분산 행렬:
[[1.66 1.66 0.5 ]
 [1.66 1.66 1.0 ]
 [0.5  1.0  2.66]]
</code></pre><ul>
<li><strong>설명</strong><ul>
<li><strong>대각선</strong>: 각 변수의 분산</li>
<li><strong>나머지 값</strong>: 변수 간의 공분산</li>
</ul>
</li>
</ul>
<hr>
<table>
<thead>
<tr>
<th>구분</th>
<th>공분산 행렬</th>
<th>상관 행렬</th>
</tr>
</thead>
<tbody><tr>
<td>값의 범위</td>
<td>-∞ ~ +∞</td>
<td>-1 ~ +1</td>
</tr>
<tr>
<td>크기 영향</td>
<td>원래 데이터 크기에 따라 다름</td>
<td>크기와 단위에 영향을 받지 않음</td>
</tr>
<tr>
<td>계산 방식</td>
<td>공분산 값을 그대로 사용</td>
<td>공분산을 표준화(정규화)한 값 사용</td>
</tr>
<tr>
<td>활용</td>
<td>데이터의 분포와 관계 파악</td>
<td>변수 간의 강한/약한 상관관계 분석</td>
</tr>
</tbody></table>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (4) - 벡터 Indexing]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-4-%EB%B2%A1%ED%84%B0-Indexing</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-4-%EB%B2%A1%ED%84%B0-Indexing</guid>
            <pubDate>Thu, 08 May 2025 08:09:31 GMT</pubDate>
            <description><![CDATA[<h1 id="5-벡터-indexing">#5. 벡터 Indexing</h1>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/dbe24a9f-406d-4eb4-b49e-2c80bfb00fc8/image.png" alt=""></p>
<ul>
<li>데이터베이스에 벡터 데이터를 구조화된 인덱스에 담는 행위</li>
<li>추후 검색 성능을 고려하여 KNN이 아닌 <strong>ANN(Approximate Nearest Neighbor)</strong> 가능한 구조로 설계</li>
</ul>
<blockquote>
<p>목표: 검색 정확도 ↔ 검색 속도 간의 tradeoff 관계 최적화</p>
</blockquote>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1bc34610-7bab-4ad9-8c41-36a2ef064a7f/image.png" alt=""></p>
<blockquote>
<p>Quantinized(양자화) : 쪼개서,,,</p>
</blockquote>
<hr>
<h2 id="벡터-인덱싱">벡터 인덱싱</h2>
<p>벡터를 적절히 분류하고 저장하여, 유사한 벡터를 빠르게 찾음</p>
<ul>
<li>예시</li>
</ul>
<p>도서관에서 장르 별로 분류하고 원하는 장르에서 찾기</p>
<ul>
<li>종류</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/4372cab1-9a6d-4169-b190-a299935de91c/image.png" alt=""></p>
<hr>
<h3 id="hnsw-hierarchical-navigable-small-world">HNSW, Hierarchical Navigable Small World</h3>
<blockquote>
<p>최신 많이 시용하는 방법, 데이터가 수십만개 정도 되는 경우 효과적</p>
</blockquote>
<p>&lt;동작방식&gt;</p>
<ul>
<li><p>다층 네트워크 생성</p>
<ul>
<li>벡터 데이터를 여러 계층(Layer)으로 나눔</li>
<li>상위 계층에는 적은 수의 벡터(전략적 거점)가 배치됨</li>
<li>하위 계층에는 더 많은 벡터(세부적인 노드)가 배치됨</li>
</ul>
</li>
<li><p>빠른 검색</p>
<ul>
<li>먼저 상위 계층에서 대략적인 위치를 찾음</li>
<li>하위 계층으로 내려가면서 점점 더 정확한 벡터를 탐색</li>
<li>최종적으로 가장 유사한 벡터를 반환</li>
</ul>
</li>
</ul>
<p>&lt;장/단점&gt;</p>
<ul>
<li>장점<ul>
<li>검색 속도가 매우 빠름 (로그 시간 복잡도, O(log N))</li>
<li>높은 정확도를 유지함</li>
<li>최신 벡터를 쉽게 추가할 수 있음 (동적 업데이트 가능)</li>
</ul>
</li>
<li>단점<ul>
<li>인덱스를 만들 때 메모리를 많이 사용</li>
<li>특정 조건에서 속도가 느려질 수 있음</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>근사 최근접 이웃 검색(ANN: Approximate Nearest Neighbor)</strong>을 위해 사용되며, 그래프 기반 구조와 계층적 접근 방식으로 빠른 검색 성능을 제공</p>
</blockquote>
<hr>
<h3 id="ivf-inverted-file-index">IVF, Inverted File Index</h3>
<p>여러 그룹으로 나누고 필요한 그룹에서만 검색</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/09796db6-4014-4811-8238-dc68b2438a9e/image.png" alt=""></p>
<p>&lt;동작방식&gt;</p>
<ul>
<li><p>벡터를 여러 개의 그룹(버킷)으로 분리</p>
<ul>
<li><strong>K-means 알고리즘</strong>을 사용하여 유사한 벡터끼리 그룹화</li>
<li>각 그룹은 <strong>대표값(centroid, 중심점)</strong>을 가짐</li>
</ul>
</li>
<li><p>검색 시, 가장 유사한 그룹을 먼저 찾음</p>
<ul>
<li>전체 데이터를 검색하지 않고, 가장 유사한 그룹(버킷)만 탐색</li>
<li>해당 그룹 내에서 가장 가까운 벡터를 반환</li>
</ul>
</li>
<li><p>벡터 공간을 보로노이 다이어그램과 같이 나누어 서치 스페이스를 축소</p>
</li>
<li><p>쿼리 벡터와 centroid 간 거리 계산 후, 가장 가까운 centroid에 해당하는 공간 내 임베딩 벡터들과 거리 계산 수행</p>
</li>
</ul>
<p>&lt;장/단점&gt;</p>
<ul>
<li><p>장점</p>
<ul>
<li>전체 데이터베이스를 검색하지 않아서 속도가 빠름</li>
<li>대량의 벡터 데이터를 처리할 때 유리</li>
<li>메모리 사용량이 비교적 적음</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li>정확도가 HNSW보다 낮을 수 있음</li>
<li>그룹이 잘못 설정되면 검색 성능 저하 가능성 존재</li>
<li>새로운 벡터 추가 시 기존 그룹에 제대로 배치되지 않을 수 있음</li>
<li>공간을 형성하는 벡터가 많을수록 공간 나누는 작업의 속도가 느려짐</li>
</ul>
</li>
</ul>
<blockquote>
<p>속도는 빠를 수 있지만, 정확도가 낮을 수 있음 ⇒ <strong>PQ와 함께 사용함</strong></p>
</blockquote>
<hr>
<h3 id="pq-product-quantization">PQ, Product Quantization</h3>
<p>벡터를 여러 개의 작은 벡터로 나누고, 각 벡터를 압축하여 저장</p>
<p>&lt;동작방식&gt;</p>
<ul>
<li><p>벡터를 여러 개의 서브 벡터로 분리</p>
<ul>
<li>예: 128차원 벡터 → 4개의 32차원 벡터로 분할</li>
</ul>
</li>
<li><p>각 서브 벡터를 미리 정해둔 <strong>코드북(Codebook)</strong>에서 가장 가까운 값으로 매칭하여 저장</p>
<ul>
<li>&quot;비슷한 벡터를 대표하는 값&quot;을 사용하여 저장 공간 절감</li>
</ul>
</li>
<li><p>검색 시, 압축된 값만 비교하여 빠르게 유사도를 계산</p>
<ul>
<li>원본 벡터를 모두 비교하는 것보다 훨씬 빠름</li>
</ul>
</li>
</ul>
<blockquote>
<p>코드북(Codebook)은 <strong>서브 벡터들을 대표하는 기준 벡터(클러스터 중심)들의 집합으로, 유사한 벡터를 압축하여 표현할 때 참조되는 값들</strong></p>
</blockquote>
<p>&lt;장/단점&gt;</p>
<ul>
<li><p>장점</p>
<ul>
<li>벡터를 압축해서 저장하므로 메모리 사용량이 적음</li>
<li>대규모 데이터에서도 유사도 검색을 빠르게 수행 가능</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li>벡터를 압축하는 과정에서 정확도가 조금 떨어질 수 있음</li>
<li>너무 작은 차원으로 압축 시 원본 데이터의 특성을 잃을 수 있음</li>
</ul>
</li>
</ul>
<blockquote>
<p><strong>메모리 사용량이 적은 편</strong>이라 대규모 데이터에 적합함</p>
</blockquote>
<hr>
<h3 id="hnsw-ivf-pq-개념-요약">HNSW, IVF, PQ 개념 요약</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/24df0b21-d55f-4932-a57f-d0d8f64a31fd/image.png" alt=""></p>
<p>⇒ 하나만 고집해서 사용하는 것이 아닌, 여러 방법을 섞어서 사용</p>
<hr>
<h3 id="hash-index">Hash Index</h3>
<p>고차원 데이터는 그대로 두는데, 해시 테이블을 별도로 만들어서 </p>
<p>&lt;동작방식&gt;</p>
<ul>
<li><p>고차원 데이터를 저차원 해시코드로 변환하여 서칭 컴플렉시티 개선을 노리는 방식</p>
</li>
<li><p>일반적 해싱과 반대로, 벡터 인덱싱 시 <strong>비슷한 데이터끼리 해시 충돌이 나도록 하는 구조</strong></p>
</li>
<li><p>이때 사용되는 해싱 함수를 그대로 쿼리 벡터에 대해서도 적용시켜, 동일한 해시버킷에 위치한 벡터들에 대해서만 거리 계산 수행</p>
</li>
<li><p><strong>LSH(Locally Sensitive Hashing)</strong> 등이 여기에 해당</p>
</li>
</ul>
<p>&lt;장/단점&gt;</p>
<ul>
<li>장점<ul>
<li>빠른 검색 속도</li>
</ul>
</li>
<li>단점<ul>
<li>낮은 검색 정확도</li>
</ul>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8d16f1c0-9de5-44f3-98b1-9bc14110e86e/image.png" alt=""></p>
<blockquote>
<p>Query가 들어오면 Hash Index화 하고 유사함 Bucket으로 가서 유사한 Hash 값을 찾음</p>
</blockquote>
<hr>
<h3 id="tree-index">Tree Index</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/c902c114-4052-4552-8109-1dbb7d2da302/image.png" alt=""></p>
<p>&lt;동작방식&gt;</p>
<ul>
<li><p><strong>Binary Search Tree</strong> 구조를 사용하여 고차원 벡터 공간에서의 검색 속도 향상을 도모하는 방식</p>
</li>
<li><p>유사한 벡터들이 같은 서브트리 노드(혹은 공간)에 속하도록 하는 구조</p>
</li>
<li><p>검색 시, 해시버킷과 유사하게 쿼링 벡터가 속하는 서브트리 노드에 존재하는 다른 벡터들과의 거리만 계산하여 검색 속도 최적화</p>
</li>
<li><p><strong>Spotify Annoy</strong> 알고리즘이 여기에 해당</p>
</li>
</ul>
<p>&lt;장/단점&gt;</p>
<ul>
<li>장점<ul>
<li>빠른 검색 속도</li>
</ul>
</li>
<li>단점<ul>
<li>고차원 벡터에 대해서는 검색 정확도가 좋지 않다</li>
</ul>
</li>
</ul>
<hr>
<ul>
<li><p><strong>HNSW</strong>: 그래프를 따라 돌아다니며 &quot;지금보다 더 가까운 이웃은 없을까?&quot;를 반복적으로 묻는 방식</p>
</li>
<li><p><strong>Tree Index</strong>: &quot;이쪽 리프 노드면 이 근처에 있을 거야&quot;라고 트리를 타고 내려가는 방식</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>항목</th>
<th>HNSW</th>
<th>Tree Index (Annoy, KD-Tree 등)</th>
</tr>
</thead>
<tbody><tr>
<td><strong>기본 구조</strong></td>
<td>계층적 그래프 구조 (Small World Graph)</td>
<td>트리 구조 (Binary Tree, KD-Tree, Ball Tree 등)</td>
</tr>
<tr>
<td><strong>탐색 방식</strong></td>
<td>상위 계층에서 시작해 하위로 내려가며 점점 더 정확한 이웃을 탐색</td>
<td>트리의 리프 노드까지 탐색하여 근접한 후보 벡터 추출</td>
</tr>
<tr>
<td><strong>정확도</strong></td>
<td>매우 높음 (거의 정확 검색 수준에 근접)</td>
<td>비교적 낮음 (특히 고차원에서는 성능 급감)</td>
</tr>
<tr>
<td><strong>검색 속도</strong></td>
<td>빠름 (로그 시간 복잡도 O(log N))</td>
<td>빠름 (단, 차원 증가 시 느려질 수 있음 → &quot;차원의 저주&quot;)</td>
</tr>
<tr>
<td><strong>메모리 사용량</strong></td>
<td>높음 (그래프 전체를 메모리에 유지해야 함)</td>
<td>낮거나 중간 수준 (구현 방식에 따라 다름)</td>
</tr>
<tr>
<td><strong>구축 시간</strong></td>
<td>상대적으로 오래 걸림</td>
<td>빠르거나 중간 수준</td>
</tr>
<tr>
<td><strong>동적 업데이트</strong></td>
<td>가능 (벡터 삽입/삭제 지원)</td>
<td>대부분 불가능 또는 재구축 필요 (정적 인덱스가 많음)</td>
</tr>
<tr>
<td><strong>고차원 데이터 적합성</strong></td>
<td>매우 적합 (그래프 기반이 고차원에서도 잘 동작)</td>
<td>부적합 (고차원에서는 트리 구조 성능 급격히 하락)</td>
</tr>
<tr>
<td><strong>사용 예</strong></td>
<td>hnswlib, Faiss IndexHNSW</td>
<td>Spotify Annoy, scikit-learn KDTree/BallTree, Faiss IndexFlatTree</td>
</tr>
</tbody></table>
<hr>
<h3 id="graph-index">Graph Index</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/f907bc32-6112-4ceb-9a30-b21aa21febfb/image.png" alt=""></p>
<blockquote>
<p><strong>HNSW</strong>가 대표적임</p>
</blockquote>
<p>&lt;동작방식&gt;</p>
<ul>
<li><p>임베딩 벡터들을 그래프 구조로 구성하여, 임베딩 벡터를 노드로, 연결된 엣지를 벡터 간 거리로 표현</p>
</li>
<li><p>유사한 벡터끼리 엣지 커넥션이 더 잘 이루어지도록 설계</p>
</li>
<li><p><strong>HNSW(Hierarchical Navigable Small World) 알고리즘</strong>이 여기에 해당</p>
</li>
<li><p>여러 계층으로 그래프를 제작</p>
<ul>
<li>가장 밀도가 낮은 계층에서 랜덤한 노드로 시작하여, 해당 계층에서 가장 가까운 노드를 찾은 후 다음 계층으로 이동</li>
<li>최종적으로 원래 쿼리 벡터와 가장 가까운 이웃을 찾을 때까지 계층 탐색</li>
</ul>
</li>
</ul>
<p>&lt;장/단점&gt;</p>
<ul>
<li>장점<ul>
<li><strong>검색 속도도 빠르고 검색 성능도 빠르다</strong></li>
</ul>
</li>
<li>단점<ul>
<li>검색 그래프를 구성하는 방식에 따라 검색 성능이 의존적 (<strong>파라미터 튜닝 필요</strong>)</li>
</ul>
</li>
</ul>
<hr>
<h3 id="flat-indexingexhaustive-search">Flat Indexing(Exhaustive Search)</h3>
<p>모든 데이터를 하나하나 비교하는 방식</p>
<p>&lt;동작방식&gt;</p>
<ul>
<li><p>모든 데이터를 하나하나 비교하는 방식</p>
</li>
<li><p>벡터를 압축 없이 그대로 저장</p>
</li>
<li><p>검색할 때 모든 벡터를 하나씩 비교 (<strong>완전 탐색, brute-force search</strong>)</p>
</li>
<li><p>정확도가 높지만 속도가 느리고, 메모리를 많이 사용</p>
</li>
<li><p>사용 사례</p>
<ul>
<li>데이터 개수가 적거나, 정확도가 중요한 경우</li>
<li>의료 데이터 분석 (잘못된 결과가 나오면 안 되는 경우)</li>
<li>소규모 데이터에서 가장 가까운 벡터를 찾을 때</li>
</ul>
</li>
</ul>
<p>&lt;장/단점&gt;</p>
<ul>
<li>장점<ul>
<li>100% 정확한 검색 결과 (손실 없음)</li>
<li>추가적인 전처리 없이 사용 가능</li>
</ul>
</li>
<li>단점<ul>
<li>데이터가 많아질수록 속도가 느려짐</li>
<li>메모리 사용량이 많음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="quantized-인덱싱-양자화-방식">Quantized 인덱싱, 양자화 방식</h3>
<p>벡터를 압축하여 저장하고, 근사 검색을 수행하는 방식</p>
<ul>
<li>양자화</li>
</ul>
<p>벡터를 압축하여 더 적은 공간을 사용하고 검색 속도를 빠르게 하는 기법</p>
<table>
<thead>
<tr>
<th>방법</th>
<th>방식 설명</th>
<th>특징</th>
<th>활용 사례</th>
</tr>
</thead>
<tbody><tr>
<td><strong>PQ</strong>(Product Quantization, 제품 양자화)</td>
<td>벡터를 여러 작은 부분(서브벡터)으로 나눈 후 각각을 압축하여 저장</td>
<td>메모리를 크게 줄이면서도 높은 성능 유지</td>
<td>대규모 데이터에서 유사 이미지 검색</td>
</tr>
<tr>
<td><strong>IVF</strong>(Inverted File Index + Quantization)</td>
<td>데이터를 여러 그룹으로 나눈 후, 가까운 그룹에서만 검색</td>
<td>검색 속도는 빨라지지만 정확도가 약간 떨어질 수 있음</td>
<td>쇼핑몰 <strong>추천 시스템</strong>, 검색 엔진</td>
</tr>
<tr>
<td><strong>LSH</strong>(Locality-Sensitive Hashing)</td>
<td>비슷한 벡터끼리 같은 해시값을 부여하여 검색 속도를 높임</td>
<td>대규모 데이터에서 근사 검색할 때 유용</td>
<td>음성 인식, 근사 검색</td>
</tr>
</tbody></table>
<p>&lt;장점&gt;</p>
<ul>
<li><p>검색 속도가 빠름</p>
</li>
<li><p>메모리 사용량 절약 가능</p>
</li>
</ul>
<p>&lt;단점&gt;</p>
<ul>
<li><p>완벽한 검색이 아닌 <strong>근사 검색(Approximate Search)</strong></p>
<p>  → 정확도가 약간 낮을 수 있음</p>
</li>
</ul>
<p>&lt;사용 사례&gt;</p>
<ul>
<li><p>데이터가 많고 빠른 검색이 필요한 경우</p>
<ul>
<li><p>예) 수억 개의 상품 중 유사한 것을 추천하는 쇼핑몰 추천 시스템</p>
</li>
<li><p>예) 실시간 검색 시스템 (구글 이미지 검색, 영상 검색 등)</p>
</li>
</ul>
</li>
</ul>
<hr>
<p><img src="attachment:cfad33f9-cb61-45fd-8073-4ac7237aa48b:image.png" alt="image.png"></p>
<blockquote>
<p>정확도를 중요시 하면 <strong>Flat</strong>, 속도를 중요시 하면 <strong>Quantized</strong></p>
</blockquote>
<hr>
<h3 id="scalar-quantization-sq">Scalar Quantization, SQ</h3>
<p>벡터 인덱싱에서 벡터를 더 작은 크기로 변환하여 저장하는 기법</p>
<p>→ 벡터의 각 요소를 특정 범위의 정수값으로 변환(압축)하여 메모리를 절약하는 방법</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/ae87154e-696e-4223-b043-ae30852cc4c3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/2c705669-582c-4314-916b-022b4043358f/image.png" alt=""></p>
<table>
<thead>
<tr>
<th>사용 목적</th>
<th>SQ 사용 여부 및 이유</th>
</tr>
</thead>
<tbody><tr>
<td>정확도가 중요할 때</td>
<td>No❌ (SQ는 근사 검색 방식이므로 부적합)</td>
</tr>
<tr>
<td>대규모 벡터 데이터베이스</td>
<td>Yes ⭕ (메모리 절약 효과 있음)</td>
</tr>
<tr>
<td>빠른 검색이 필요할 때</td>
<td>Yes ⭕ (저장 공간이 작아져 연산 속도 향상)</td>
</tr>
<tr>
<td>딥러닝 모델 경량화</td>
<td>Yes ⭕ (모델 크기 감소 효과 있음)</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/7cd00772-7860-42a9-bc6f-da0e2f25de53/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/12e414e5-e296-49ed-b04a-f77fb9c9bb0a/image.png" alt=""></p>
<ul>
<li><p>모바일, 임베디드, Edge AI 환경에서 속도와 저장 공간을 최적화하기 위함</p>
</li>
<li><p>특히 int8은 양자화된 모델을 실행할 수 있는 TensorRT, ONNX Runtime, TFLite 등에서 활발히 사용</p>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0375e4ad-410b-424f-81a0-3af472a7d13d/image.png" alt=""></p>
<hr>
<h3 id="product-quantization-pq">Product Quantization, PQ</h3>
<p>대규모 벡터 데이터의 검색 속도를 높이고 메모리를 절약하는 인덱싱 기법 </p>
<blockquote>
<p>벡터 압축 후 근사 검색 수행</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/9db519a5-f5ef-4224-bc3b-650f219a2bc0/image.png" alt=""></p>
<p><strong>장점</strong></p>
<ul>
<li><p>메모리 절약 → 벡터를 압축하여 저장 가능</p>
</li>
<li><p>검색 속도 향상 → 근사 검색을 통해 빠르게 유사한 벡터 탐색</p>
</li>
<li><p>대규모 데이터에 적합 → 수억 개의 벡터도 효율적으로 저장 및 검색 가능</p>
</li>
</ul>
<p><strong>단점</strong></p>
<ul>
<li><p>정확도가 완전 탐색(Flat Indexing)보다 약간 낮음</p>
</li>
<li><p>적절한 <strong>코드북(Codebook) 크기 설정</strong>이 필요</p>
</li>
<li><p>고차원 벡터에서는 압축 과정이 복잡할 수 있음</p>
</li>
</ul>
<p><strong>언제 사용?</strong></p>
<ul>
<li><p>대규모 데이터에서 빠른 검색이 필요할 때</p>
</li>
<li><p>메모리를 절약하면서 유사 검색을 수행할 때</p>
</li>
<li><p>추천 시스템, 이미지 검색, 문서 검색 등에 활용</p>
</li>
</ul>
<p><strong>대표 활용 예</strong></p>
<ul>
<li><p>Google 이미지 검색</p>
</li>
<li><p>Netflix 추천 시스템</p>
</li>
<li><p>시기반 챗봇 검색 시스템</p>
</li>
<li><p>FAISS (Facebook AI Similarity Search)</p>
</li>
</ul>
<hr>
<p><strong>요약</strong> </p>
<blockquote>
<p>Product Quantization(PQ)는 대규모 데이터에서 메모리를 절약하고 빠르게 검색할 때 사용된다. 정확도가 약간 떨어질 수 있지만, 속도와 효율성을 크게 향상시킨다.</p>
</blockquote>
<hr>
<p>&lt;정리&gt;</p>
<ul>
<li><p><strong>Scalar Quantization</strong> 기법과 유사하게, 임베딩 벡터의 floating point 값을 8비트 integer로 변환하여 <strong>메모리 효율성을 높이는 기법</strong></p>
</li>
<li><p>이 방식에 몇 가지 추가 기술이 결합된 것이 바로 <strong>PQ (Product Quantization)</strong></p>
</li>
<li><p>원본 벡터를 <strong>n개의 청크 또는 서브벡터 단위로 분할</strong></p>
</li>
<li><p>각 서브벡터 단위로 <strong>K-means 클러스터링</strong>을 수행 (예: K = 256)</p>
</li>
<li><p>클러스터링 결과로 얻은 <strong>256개의 centroid</strong>를 서브벡터의 표현으로 사용하여 <strong>양자화(Quantization)</strong> 수행</p>
</li>
<li><p>새로운 쿼리 벡터가 들어오면 동일한 방식으로 서브벡터 단위로 나누고, 각 서브벡터별로 <strong>해당 centroid에 매핑</strong>하여 8비트 정수 형태로 변환</p>
</li>
<li><p>이후 거리 계산 시, <strong>메모리 효율성과 검색 속도 모두 향상</strong>되는 방식</p>
</li>
<li><p><strong>덜 쪼갤수록 압축률은 올라가지만 정확도가 낮아지고</strong>, <strong>더 많이 쪼개면 정확도는 올라가지만 압축률은 낮아지는</strong> <strong>trade-off 관계</strong> 존재</p>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/3d512205-10a2-41fc-9169-ae8ffd606767/image.png" alt=""></p>
<pre><code class="language-python">import faiss
import numpy as np

# 1. 1000개의 128차원 벡터 생성 (더미 데이터)
d = 128  # 벡터 차원
nb = 1000  # 데이터베이스 크기
np.random.seed(42)
data = np.random.random((nb, d)).astype(&#39;float32&#39;)

# 2. Product Quantization (PQ) 인덱스 생성
m = 8  # 서브벡터 개수
quantizer = faiss.IndexFlatL2(d)  # 기본 L2 거리 기반
index = faiss.IndexIVFPQ(quantizer, d, 10, m, 8)  # IVF + PQ 적용
index.train(data)  # 학습
index.add(data)    # 벡터 추가

# 3. 검색 수행
query = np.random.random((1, d)).astype(&#39;float32&#39;)
D, I = index.search(query, k=5)  # 가장 가까운 5개 검색

print(&quot;검색 결과 (Nearest Neighbors):&quot;, I)
print(&quot;거리 (Distances):&quot;, D)</code></pre>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Method</strong></td>
<td>인덱싱 알고리즘 설명</td>
</tr>
<tr>
<td><strong>Class name</strong></td>
<td>사용되는 FAISS 클래스 이름</td>
</tr>
<tr>
<td><strong>index_factory</strong></td>
<td><code>faiss.index_factory()</code>에서 문자열로 지정되는 인덱스명</td>
</tr>
<tr>
<td><strong>Main parameters</strong></td>
<td>인덱스 생성 시 필요한 주요 파라미터 (예: 벡터 차원 수 <code>d</code>, 클러스터 수 등)</td>
</tr>
<tr>
<td><strong>Bytes/vector</strong></td>
<td>각 벡터가 차지하는 메모리 바이트 수</td>
</tr>
<tr>
<td><strong>Exhaustive</strong></td>
<td>전체 검색 여부 (예: 정확도 100% 여부)</td>
</tr>
</tbody></table>
<blockquote>
<p>FAISS를 사용하면 쉽게 Product Quantization을 적용가능</p>
</blockquote>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[질문 기반 유사 문서 검색 서비스]]></title>
            <link>https://velog.io/@lyj_0316/%EC%A7%88%EB%AC%B8-%EA%B8%B0%EB%B0%98-%EC%9C%A0%EC%82%AC-%EB%AC%B8%EC%84%9C-%EA%B2%80%EC%83%89-%EC%84%9C%EB%B9%84%EC%8A%A4</link>
            <guid>https://velog.io/@lyj_0316/%EC%A7%88%EB%AC%B8-%EA%B8%B0%EB%B0%98-%EC%9C%A0%EC%82%AC-%EB%AC%B8%EC%84%9C-%EA%B2%80%EC%83%89-%EC%84%9C%EB%B9%84%EC%8A%A4</guid>
            <pubDate>Wed, 07 May 2025 07:33:29 GMT</pubDate>
            <description><![CDATA[<h1 id="1-유클리디안-정렬-→-코사인-점수">1. 유클리디안 정렬 → 코사인 점수</h1>
<pre><code class="language-python"># !pip install chromadb</code></pre>
<pre><code class="language-python">from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
import chromadb
from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction</code></pre>
<pre><code class="language-python"># 1. 문서 정의
docs = [
    &quot;Python is a programming language.&quot;,
    &quot;Pandas is a library for data analysis.&quot;,
    &quot;Transformers are used in NLP tasks.&quot;,
    &quot;Vector databases store high-dimensional embeddings.&quot;,
    &quot;ChromaDB supports fast vector search.&quot;
]</code></pre>
<pre><code class="language-python"># 2. Sentence-BERT 모델 로딩
model = SentenceTransformer(&#39;all-MiniLM-L6-v2&#39;)</code></pre>
<p>벡터DB화와 유사도를 측정하기 위한 실습이므로, <code>&#39;all-MiniLM-L6-v2&#39;</code> 모델을 사용함.</p>
<pre><code class="language-python"># 3. ChromaDB 클라이언트 생성
chroma_client = chromadb.Client()</code></pre>
<p><strong>ChromaDB의 클라이언트 객체</strong>를 생성하여, <strong>ChromaDB와 상호작용함.</strong></p>
<pre><code class="language-python"># 4. ChromaDB에 사용할 Sentence-BERT 기반 임베딩 함수 정의
embedding_function = SentenceTransformerEmbeddingFunction(model_name=&quot;all-MiniLM-L6-v2&quot;)</code></pre>
<p>ChromaDB가 내부적으로 문서나 쿼리를 벡터로 바꿀 때 사용할 <strong>임베딩 생성기</strong>를 지정</p>
<pre><code class="language-python">collection_name = &quot;qa-docs&quot;

# 기존 컬렉션이 존재하는지 확인
existing_collections = chroma_client.list_collections()
collection_names = [col.name for col in existing_collections]

if collection_name in collection_names:
    collection = chroma_client.get_collection(name=collection_name, embedding_function=embedding_function)
    print(&quot;vectorDB가 이미 존재합니다.&quot;)
else:
    collection = chroma_client.create_collection(name=collection_name, embedding_function=embedding_function)
    print(&quot;새로운 vectorDB를 생성합니다.&quot;)</code></pre>
<p> <strong>ChromaDB가 텍스트를 SBERT 기반 벡터로 변환할 수 있도록 다시 연결해주는 과정</strong></p>
<pre><code class="language-python"># 6. 쿼리 정의 및 임베딩
query = &quot;What is used in natural language processing?&quot;
query_embedding = model.encode([query])</code></pre>
<p>질문을 변수로 할당하고, 이를 기존 모델을 통해서 벡터화를 진행.</p>
<hr>
<pre><code class="language-python"># 7. ChromaDB에서 후보 문서 검색 (빠른 검색)
results = collection.query(
    query_texts=[query],
    n_results=3  # top-k 후보
)</code></pre>
<p>collection.query(...)를 통해서 주어진 쿼리 벡터(=질문)를 기반으로 <strong>가장 유사한 문서 3개를 반환</strong></p>
<table>
<thead>
<tr>
<th>구성 요소</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>collection.query(...)</code></td>
<td>주어진 쿼리 벡터(=질문)를 기반으로 <strong>가장 유사한 문서들을 반환</strong></td>
</tr>
<tr>
<td><code>query_texts=[query]</code></td>
<td>검색 기준이 될 자연어 문장 (이 경우 사용자가 입력한 질문)</td>
</tr>
<tr>
<td><code>n_results=3</code></td>
<td>유사도가 높은 상위 3개의 문서를 반환 (Top-K 검색)</td>
</tr>
</tbody></table>
<hr>
<h3 id="반환되는-결과-구조-results-변수">반환되는 결과 구조 (<code>results</code> 변수)</h3>
<pre><code class="language-python">{
  &#39;ids&#39;: [[&#39;doc2&#39;, &#39;doc4&#39;, &#39;doc1&#39;]],
  &#39;documents&#39;: [[...]],
  &#39;distances&#39;: [[...]]  # (L2 거리 or 유사도 기반 거리값)
}</code></pre>
<ul>
<li><code>documents[0]</code>: Top 3 유사 문장</li>
<li><code>distances[0]</code>: 각 문장과의 거리 값 (작을수록 유사함)</li>
<li><code>ids[0]</code>: 해당 문서의 ID 값</li>
</ul>
<hr>
<pre><code class="language-python"># 8. 후처리: cosine similarity 계산
print(&quot;query: &quot;, query)
for i in range(len(results[&#39;documents&#39;][0])):
    doc_text = results[&#39;documents&#39;][0][i]
    doc_embedding = model.encode([doc_text])
    sim_score = cosine_similarity(query_embedding, doc_embedding)[0][0]

    print(f&quot;\n[Top {i+1}] 문장: {doc_text}&quot;)
    print(f&quot;→ cosine similarity: {sim_score:.4f}&quot;)</code></pre>
<h3 id="왜-cosine-유사도를-다시-계산하나요">왜 cosine 유사도를 다시 계산하나요?</h3>
<table>
<thead>
<tr>
<th>이유</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>ChromaDB 기본은 L2 거리</td>
<td>SBERT에는 부적합</td>
</tr>
<tr>
<td>Cosine이 의미 유사성에 강함</td>
<td>SBERT는 cosine 유사도에 최적화</td>
</tr>
<tr>
<td>후처리로 정밀 비교 가능</td>
<td>후보 필터링 후 정확도 보완</td>
</tr>
</tbody></table>
<blockquote>
<p>query:  What is used in natural language processing?</p>
<p>[Top 1] 문장: Transformers are used in NLP tasks.
→ cosine similarity: 0.5670</p>
<p>[Top 2] 문장: Python is a programming language.
→ cosine similarity: 0.3393</p>
<p>[Top 3] 문장: Pandas is a library for data analysis.
→ cosine similarity: 0.2515</p>
</blockquote>
<aside>
💡 해당 코드의 문제점은 L2 거리 기반으로 먼저 랭킹을 매긴 뒤 cosine 유사도를 보는 구조로 정확한 의미 기반 정렬이 아니라고 생각된다. 

</aside>

<p>→ 따라서, 코사인 유사도를 통해서 문서의 유사도를 확인하는 코드를 다시 작성함</p>
<hr>
<h1 id="2-코사인-유사도를-통한-정렬">2. 코사인 유사도를 통한 정렬</h1>
<pre><code class="language-python"># 1. 문서 정의
docs = [
    &quot;Python is a programming language.&quot;,
    &quot;Pandas is a library for data analysis.&quot;,
    &quot;Transformers are used in NLP tasks.&quot;,
    &quot;Vector databases store high-dimensional embeddings.&quot;,
    &quot;ChromaDB supports fast vector search.&quot;
]
doc_ids = [f&quot;doc{i}&quot; for i in range(len(docs))]</code></pre>
<pre><code class="language-python"># 2. SBERT 모델 로딩
model = SentenceTransformer(&#39;all-MiniLM-L6-v2&#39;)</code></pre>
<pre><code class="language-python"># 3. ChromaDB 클라이언트 및 임베딩 함수 설정
chroma_client = chromadb.Client()
embedding_function = SentenceTransformerEmbeddingFunction(model_name=&quot;all-MiniLM-L6-v2&quot;)</code></pre>
<pre><code class="language-python">collection_name = &quot;qa-docs&quot;
existing_collections = [col.name for col in chroma_client.list_collections()]

# 컬렉션 불러오거나 생성
if collection_name in existing_collections:
    collection = chroma_client.get_collection(name=collection_name, embedding_function=embedding_function)
    print(&quot;기존 컬렉션을 불러왔습니다.&quot;)
else:
    collection = chroma_client.create_collection(name=collection_name, embedding_function=embedding_function)
    print(&quot;새 컬렉션을 생성했습니다.&quot;)

# 이미 저장된 문서 확인 (문장 기준으로 중복 제거)
existing_data = collection.get()
existing_docs = set(existing_data[&#39;documents&#39;])

# 새롭게 추가할 문장만 필터링
new_docs = [doc for doc in docs if doc not in existing_docs]
new_ids = [f&quot;doc{i}&quot; for i, doc in enumerate(docs) if doc not in existing_docs]

# 문서 추가
if new_docs:
    collection.add(documents=new_docs, ids=new_ids)
    print(f&quot;{len(new_docs)}개의 문서를 추가했습니다.&quot;)
else:
    print(&quot;추가할 문서가 없습니다.&quot;)
</code></pre>
<p>해당 코드를 통해서 컬렉션이 존재하면 기존의 컬렉션을 확인하고, 문서의 존재 여부를 확인하여 해당 문서가 없다는 새롭게 추가하도록 작성</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/14270a12-e34a-4ecd-923c-be8b961fc450/image.png" alt=""></p>
<pre><code class="language-python"># 5. 의미 검색 함수 (Chroma에서 벡터 꺼내서 직접 비교)
def semantic_search_cosine(query: str, collection, model: SentenceTransformer, top_n: int = 3):
    # query 임베딩
    query_embedding = model.encode([query])[0]

    # Chroma에서 문서 및 벡터 가져오기
    all_data = collection.get()
    doc_texts = all_data[&#39;documents&#39;]
    doc_ids = all_data[&#39;ids&#39;]
    doc_embeddings = model.encode(doc_texts)

    # cosine 유사도 계산
    similarities = cosine_similarity([query_embedding], doc_embeddings)[0]
    scored_docs = sorted(zip(doc_texts, similarities), key=lambda x: x[1], reverse=True)

    return scored_docs[:top_n]</code></pre>
<p>VectorDB의 각 문장의 벡터와 새로 입력되어 비교될 벡터의 유사도를 코사인 유사도를 기준으로 비교</p>
<pre><code class="language-python"># 6. 실행
query = &quot;What is used in natural language processing?&quot;
results = semantic_search_cosine(query, collection, model, top_n=3)

print(&quot;query:&quot;, query)
print()
for i, (doc, score) in enumerate(results, 1):
    print(f&quot;[Top {i}] 유사도 {score:.4f} → {doc}&quot;)</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b40bcff1-df03-4287-8ae4-74ad847b7b40/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Huggingface를 활용한 텍스트 벡터화]]></title>
            <link>https://velog.io/@lyj_0316/Huggingface%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B2%A1%ED%84%B0%ED%99%94</link>
            <guid>https://velog.io/@lyj_0316/Huggingface%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%ED%85%8D%EC%8A%A4%ED%8A%B8-%EB%B2%A1%ED%84%B0%ED%99%94</guid>
            <pubDate>Wed, 07 May 2025 07:30:45 GMT</pubDate>
            <description><![CDATA[<h1 id="1-bert-base-bert-base-uncased">1. BERT-base (bert-base-uncased)</h1>
<h3 id="1-필요-라이브러리-설치">1. 필요 라이브러리 설치</h3>
<pre><code class="language-bash">pip install transformers sentence-transformers scikit-learn matplotlib</code></pre>
<hr>
<h3 id="2-라이브러리-불러오기">2. 라이브러리 불러오기</h3>
<pre><code class="language-python">from transformers import AutoTokenizer, AutoModel
import torch
import numpy as np
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt</code></pre>
<hr>
<h3 id="3-bert-모델-로드">3. BERT 모델 로드</h3>
<blockquote>
<p>해당 텍스트들을 어떠한 용도로 사용할지 모르기 때문에, 범용성을 가지는 일반 Bert를 활용</p>
</blockquote>
<pre><code class="language-python"># 1. Hugging Face BERT (일반 BERT 사용)
# 해당 텍스트들을 어떠한 용도로 사용할지 모르기 때문에, 범용성을 가지는 일반 Bert를 활용
model_name = &#39;bert-base-uncased&#39;
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModel.from_pretrained(model_name)</code></pre>
<hr>
<h3 id="4-벡터화할-텍스트-데이터-정의">4. 벡터화할 텍스트 데이터 정의</h3>
<pre><code class="language-python"># 문장 리스트
sentences = [
    &quot;I love artificial intelligence.&quot;,
    &quot;Machine learning is fascinating.&quot;,
    &quot;Natural language processing is a subfield of AI.&quot;,
    &quot;Deep learning improves neural networks.&quot;,
    &quot;Transformers have changed AI forever.&quot;
]</code></pre>
<ul>
<li>문장 리스트로 구성된 입력 데이터</li>
</ul>
<hr>
<h3 id="5-텍스트-토크나이즈">5. 텍스트 토크나이즈</h3>
<pre><code class="language-python"># 2. 토큰화
encoded = tokenizer(sentences, padding=True, truncation=True, return_tensors=&#39;pt&#39;)</code></pre>
<ul>
<li><code>padding=True</code>: 문장 길이를 맞춤</li>
<li><code>truncation=True</code>: 최대 길이 초과 시 자름</li>
<li><code>return_tensors=&quot;pt&quot;</code>: PyTorch 텐서 형태로 반환</li>
</ul>
<hr>
<h3 id="6-bert-모델을-이용한-임베딩-추출">6. BERT 모델을 이용한 임베딩 추출</h3>
<pre><code class="language-python"># 3. 모델 통과
with torch.no_grad():
    output = model(**encoded)</code></pre>
<ul>
<li><code>torch.no_grad()</code>: 학습이 아닌 추론 모드</li>
</ul>
<hr>
<pre><code class="language-python"># 4. mean pooling 구현 : 문장의 의미를 더 잘 반영하도록 유도
def mean_pooling(model_output, attention_mask):
    token_embeddings = model_output.last_hidden_state
    input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
    sum_embeddings = (token_embeddings * input_mask_expanded).sum(1)
    sum_mask = input_mask_expanded.sum(1)
    sum_mask = torch.clamp(sum_mask, min=1e-9)  # 0 방지
    return sum_embeddings / sum_mask

embeddings = mean_pooling(output, encoded[&#39;attention_mask&#39;]).numpy()
print(embeddings.shape)</code></pre>
<blockquote>
<p>(5, 768)</p>
</blockquote>
<ul>
<li>모델 출력 (<code>model_output</code>)과 <code>attention_mask</code>를 받아서 평균 임베딩을 계산하는 함수.</li>
<li>분모가 0이 되는 것을 방지하기 위해 최소값 설정</li>
</ul>
<hr>
<pre><code class="language-python"># 5. PCA로 3차원 축소
pca = PCA(n_components=3)
reduced = pca.fit_transform(embeddings)</code></pre>
<ul>
<li><code>n_components=3</code>은 <strong>원래 임베딩 벡터(예: 768차원)</strong> 를 <strong>3차원으로 줄이겠다</strong>는 의미</li>
</ul>
<hr>
<pre><code class="language-python"># 6. PCA 시각화
fig = plt.figure(figsize=(10, 14))
ax = fig.add_subplot(111, projection=&#39;3d&#39;)
colors = [&#39;r&#39;, &#39;g&#39;, &#39;b&#39;, &#39;y&#39;, &#39;c&#39;]
for i, sentence in enumerate(sentences):
    ax.scatter(*reduced[i], c=colors[i], marker=&#39;o&#39;, s=100, label=sentences[i])
    ax.text(reduced[i][0]+0.2, reduced[i][1]+0.2, reduced[i][2]+0.2, f&quot;{i+1}&quot;, size=12, zorder=1, color=&#39;black&#39;)

ax.set_title(&quot;3D PCA of BERT Embeddings: bert-base-uncased + mean pooling&quot;)
ax.set_xlabel(&quot;PC1&quot;)
ax.set_ylabel(&quot;PC2&quot;)
ax.set_zlabel(&quot;PC3&quot;)
ax.legend()
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b53c64fa-e27a-4960-acff-d52a0f632bca/image.png" alt=""></p>
<hr>
<h1 id="2-sentence-bert">2. Sentence-BERT</h1>
<pre><code class="language-python">import torch
from transformers import BertTokenizer, BertModel, AutoTokenizer, AutoModel
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
# 1. 입력 문장
sentences = [
   &quot;I love artificial intelligence.&quot;,
   &quot;Machine learning is fascinating.&quot;,
   &quot;Natural language processing is a subfield of AI.&quot;,
   &quot;Deep learning improves neural networks.&quot;,
   &quot;Transformers have changed AI forever.&quot;
]
# 2. BERT-base (순수 BERT) 준비
bert_tokenizer = BertTokenizer.from_pretrained(&#39;bert-base-uncased&#39;)
bert_model = BertModel.from_pretrained(&#39;bert-base-uncased&#39;)
# 3. Sentence-BERT 준비
sbert_tokenizer = AutoTokenizer.from_pretrained(&#39;sentence-transformers/all-MiniLM-L6-v2&#39;)
sbert_model = AutoModel.from_pretrained(&#39;sentence-transformers/all-MiniLM-L6-v2&#39;)
# 4. BERT-base 임베딩 (CLS 토큰)
def get_bert_embeddings(sentences):
    embeddings = []
    for sentence in sentences:
        inputs = bert_tokenizer(sentence, return_tensors=&#39;pt&#39;, truncation=True, padding=True)
        with torch.no_grad():
            outputs = bert_model(**inputs)

        # mean pooling 적용
        token_embeddings = outputs.last_hidden_state  # [1, seq_len, hidden_size]
        attention_mask = inputs[&#39;attention_mask&#39;]     # [1, seq_len]
        input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()

        sum_embeddings = (token_embeddings * input_mask_expanded).sum(1)
        sum_mask = input_mask_expanded.sum(1)
        mean_pooled = sum_embeddings / torch.clamp(sum_mask, min=1e-9)

        embeddings.append(mean_pooled.squeeze(0).numpy())

    return np.array(embeddings)

# 5. Sentence-BERT 임베딩 (CLS 토큰)
def get_sbert_embeddings(sentences):
   inputs = sbert_tokenizer(sentences, return_tensors=&#39;pt&#39;, padding=True, truncation=True)
   with torch.no_grad():
       outputs = sbert_model(**inputs)
   cls_embeddings = outputs.last_hidden_state[:, 0, :] # (batch_size, hidden_size)
   return cls_embeddings.numpy()
# 6. 임베딩 추출
bert_embeddings = get_bert_embeddings(sentences)
sbert_embeddings = get_sbert_embeddings(sentences)
# 7. PCA로 3D 축소
pca_bert = PCA(n_components=3)
pca_sbert = PCA(n_components=3)
bert_3d = pca_bert.fit_transform(bert_embeddings)
sbert_3d = pca_sbert.fit_transform(sbert_embeddings)
# 8. 3D 시각화
fig = plt.figure(figsize=(16, 7))
# BERT 결과
ax1 = fig.add_subplot(121, projection=&#39;3d&#39;)
for i, sentence in enumerate(sentences):
   x, y, z = bert_3d[i]
   ax1.scatter(x, y, z, label=f&quot;{i+1}&quot;)
   ax1.text(x, y, z, f&#39;{i+1}&#39;, fontsize=9)
ax1.set_title(&quot;BERT-base (bert-base-uncased) Embeddings&quot;)
ax1.set_xlabel(&#39;PCA1&#39;)
ax1.set_ylabel(&#39;PCA2&#39;)
ax1.set_zlabel(&#39;PCA3&#39;)
# Sentence-BERT 결과
ax2 = fig.add_subplot(122, projection=&#39;3d&#39;)
for i, sentence in enumerate(sentences):
   x, y, z = sbert_3d[i]
   ax2.scatter(x, y, z, label=f&quot;{i+1}&quot;)
   ax2.text(x, y, z, f&#39;{i+1}&#39;, fontsize=9)
ax2.set_title(&quot;Sentence-BERT (all-MiniLM-L6-v2) Embeddings&quot;)
ax2.set_xlabel(&#39;PCA1&#39;)
ax2.set_ylabel(&#39;PCA2&#39;)
ax2.set_zlabel(&#39;PCA3&#39;)
plt.tight_layout()
plt.show()</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/faa3e647-218b-4732-b4bf-375b3da047dd/image.png" alt=""></p>
<p>BERT-base (<code>bert-base-uncased</code>)에서 <code>[CLS]</code> 토큰은 분류 태스크용이라 <strong>문장 의미를 잘 표현하지 못하는 문제점이 존재합니다.</strong> 따라서 문장 간의 유사도를 비교하는 데에 있어서 성능이 떨어집니다.</p>
<p>⇒ Sentence-BERT를 활용하여 학습 과정 자체가 의미 기반으로 진행되어, 문자의 의미를 내포하는 데에 더욱 효과적입니다.
⇒ 또한, 이러한 문제점을 해결하기 위해  실습 과정에서 BERT-base (<code>bert-base-uncased</code>)에 mean-pooling을 적용하여 문장의 의미를 더 잘 표현하도록 유도하였습니다.</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (3) - 벡터 Embedding 기초]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-3-%EB%B2%A1%ED%84%B0-Embedding-%EA%B8%B0%EC%B4%88</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-3-%EB%B2%A1%ED%84%B0-Embedding-%EA%B8%B0%EC%B4%88</guid>
            <pubDate>Wed, 07 May 2025 07:26:58 GMT</pubDate>
            <description><![CDATA[<h1 id="벡터-db-소개">벡터 DB 소개</h1>
<h3 id="벡터-db-정의">벡터 DB 정의</h3>
<blockquote>
<p>&quot;고차원 벡터 데이터를 효율적으로 저장, 관리, 검색하기 위해 설계된 데이터베이스&quot;</p>
</blockquote>
<hr>
<h3 id="특징-및-설명">특징 및 설명</h3>
<ul>
<li>텍스트, 이미지, 오디오 등의 데이터를 임베딩(벡터화)하여 저장하고, 관리하며, 검색 기능을 제공하는 <strong>임베딩 벡터 전용 DB</strong></li>
<li>고차원(벡터 차원 수)의 공간(인덱스)에 임베디드 벡터를 인덱싱하여 저장하는 방식</li>
</ul>
<hr>
<h3 id="주요-기능">주요 기능</h3>
<ul>
<li><strong>입력 Query와 가장 가까운 이웃</strong>을 찾아주는 방식 사용</li>
<li><strong>ANN (Approximate Nearest Neighbor)</strong> 기반 알고리즘으로 검색 효율성 향상</li>
<li>기본적인 <strong>CRUD (Create, Read, Update, Delete)</strong> 지원</li>
<li>벡터 DB 서비스 제공자마다 서로 다른 인덱싱 및 검색 알고리즘 방식 사용</li>
</ul>
<hr>
<h3 id="처리-단계">처리 단계</h3>
<ol>
<li><strong>Indexing</strong></li>
<li><strong>Querying</strong></li>
</ol>
<ul>
<li><p>이외에도 검색 성능을 높이기 위한 추가 단계:</p>
<ul>
<li><p>Loading</p>
</li>
<li><p>Transforming</p>
</li>
<li><p>Post-Processing</p>
<p>  (→ 벡터 DB가 자체적으로 지원하거나 외부에서 처리)</p>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="목적">목적</h3>
<ul>
<li><strong>비정형 데이터를 벡터화</strong>하여</li>
<li><strong>유사한 데이터를 빠르게 찾을 수 있도록 설계된 시스템</strong></li>
</ul>
<hr>
<h2 id="주요-특징---확장성">주요 특징 - 확장성</h2>
<h3 id="기존-db와-벡터-db의-차이">기존 DB와 벡터 DB의 차이</h3>
<table>
<thead>
<tr>
<th>확장 방식</th>
<th>전통적 RDB</th>
<th>벡터 DB</th>
</tr>
</thead>
<tbody><tr>
<td><strong>Scale-up</strong> (수직 확장)</td>
<td>서버 성능을 업그레이드</td>
<td>성능 개선 한계 존재</td>
</tr>
<tr>
<td><strong>Scale-out</strong> (수평 확장)</td>
<td>어려움 (데이터 분할, 샤딩 필요)</td>
<td>클러스터를 통해 쉽게 확장 가능</td>
</tr>
</tbody></table>
<hr>
<h3 id="벡터-db의-수평-확장-방식">벡터 DB의 수평 확장 방식</h3>
<ul>
<li><strong>Sharding (샤딩)</strong><ul>
<li>벡터 데이터를 여러 노드에 분산 저장</li>
<li>예: 10억 개의 벡터를 10개 노드에 1억 개씩 배치</li>
</ul>
</li>
<li><strong>Distributed Indexing (분산 인덱싱)</strong><ul>
<li>검색 시 여러 노드에서 병렬로 처리하여 속도 향상</li>
<li>예: HNSW + IVF를 혼합 적용 가능</li>
</ul>
</li>
<li><strong>Load Balancing (부하 분산)</strong><ul>
<li>대량의 검색 요청을 균등하게 분배하여 성능 유지</li>
<li>예: 여러 개의 검색 서버가 동시에 요청 처리</li>
</ul>
</li>
</ul>
<hr>
<h3 id="활용-사례">활용 사례</h3>
<ul>
<li>AI 기반 이미지 검색 서비스<ul>
<li>수억 개 이미지 저장 및 검색</li>
</ul>
</li>
<li>대규모 추천 시스템<ul>
<li>예: Netflix, Amazon 등의 제품 추천 시스템</li>
</ul>
</li>
</ul>
<hr>
<h2 id="주요-특징---메타데이터-통합-관리-기능">주요 특징 - 메타데이터 통합 관리 기능</h2>
<h3 id="메타데이터란">메타데이터란?</h3>
<ul>
<li><strong>벡터와 함께 저장되어 검색 결과에 대한 추가 정보를 제공하는 데이터</strong></li>
<li>벡터 데이터 자체는 숫자(좌표)로 표현되기 때문에, 실제 의미를 설명할 <strong>부가 정보</strong>가 필요함</li>
</ul>
<hr>
<h3 id="예시">예시</h3>
<table>
<thead>
<tr>
<th>벡터 데이터</th>
<th>메타데이터 (추가 정보)</th>
</tr>
</thead>
<tbody><tr>
<td>[0.2, 0.8, -0.5]</td>
<td>&quot;이미지 파일: cat.jpg, 업로드 날짜: 2025-03-18&quot;</td>
</tr>
<tr>
<td>[0.7, -0.2, 0.4]</td>
<td>&quot;논문 제목: AI in Healthcare, 저자: Dr. Kim&quot;</td>
</tr>
</tbody></table>
<hr>
<h3 id="활용-사례-1">활용 사례</h3>
<ul>
<li><strong>AI 검색엔진</strong>: 사용자 입력 텍스트와 유사한 문서를 찾은 후 제목, 저자, 링크 제공</li>
<li><strong>전자상거래 추천 시스템</strong>: 유사한 제품 추천 시 상품명, 가격, 브랜드 등 함께 표시</li>
<li><strong>의료 데이터 분석</strong>: 환자 유사도 검색 시 환자 ID, 병원, 진료 기록 등과 연계</li>
</ul>
<hr>
<h3 id="메타데이터를-활용한-향상된-검색">메타데이터를 활용한 향상된 검색</h3>
<ul>
<li>벡터 검색 이후, <strong>필터링(Query Filtering)</strong> 가능</li>
<li>예: &#39;강아지 이미지&#39; 검색 결과 중 <strong>최근 1년 이내 업로드된 데이터만 조회</strong></li>
</ul>
<hr>
<h2 id="주요-특징---동적-데이터-업데이트-지원">주요 특징 - 동적 데이터 업데이트 지원</h2>
<h3 id="기존-rdb의-문제점">기존 RDB의 문제점</h3>
<ul>
<li>새로운 데이터를 추가할 때 <strong>전체 인덱스를 다시 생성해야 함</strong><ul>
<li>→ 처리 속도 느림</li>
</ul>
</li>
<li>벡터 데이터는 고차원 공간에 위치해 있기 때문에 위치가 바뀌면 <strong>업데이트가 어려움</strong></li>
</ul>
<hr>
<h3 id="벡터-db에서의-동적-업데이트-방식">벡터 DB에서의 동적 업데이트 방식</h3>
<ol>
<li><strong>Incremental Indexing (점진적 인덱싱)</strong><ul>
<li>전체 인덱스를 재구성하지 않고 <strong>기존 인덱스에 새 데이터를 추가</strong></li>
<li>예: HNSW 방식에서 새로운 노드를 기존 구조에 연결</li>
</ul>
</li>
<li><strong>Lazy Update (지연 업데이트)</strong><ul>
<li>벡터를 <strong>즉시 반영하지 않고</strong>, 일정 시간 후 일괄 업데이트(batch)</li>
<li>검색 성능 유지하면서 <strong>동적 데이터 반영 가능</strong></li>
</ul>
</li>
<li><strong>Delete &amp; Rebuild (삭제 후 재구성)</strong><ul>
<li>일정 시간마다 불필요한 벡터를 삭제하고 인덱스를 재구성하여 <strong>최적화 유지</strong></li>
</ul>
</li>
</ol>
<hr>
<h3 id="활용-사례-2">활용 사례</h3>
<ul>
<li><strong>실시간 감성 분석</strong>: SNS에서 사용자 감정(긍정/부정)을 업데이트하여 최신 트렌드 반영</li>
<li><strong>보안 시스템 (얼굴 인식)</strong>: 새로운 얼굴 벡터를 실시간으로 추가하여 보안 강화</li>
<li><strong>뉴스 추천 시스템</strong>: 새로운 기사가 추가되면 즉시 벡터화하여 추천 시스템에 반영</li>
</ul>
<hr>
<h2 id="벡터-db의-중요성">벡터 DB의 중요성</h2>
<ol>
<li><p><strong>대용량 데이터도 빠르게 검색 가능</strong></p>
<ul>
<li><p>고속 검색을 위한 알고리즘 활용:</p>
<p>  예) HNSW, IVF, PQ 등</p>
</li>
</ul>
</li>
<li><p><strong>메타데이터 통합 관리</strong></p>
<ul>
<li>검색 결과에 <strong>부가 정보를 함께 제공</strong>하여 더 풍부한 결과 도출 가능</li>
</ul>
</li>
<li><p><strong>실시간 데이터 업데이트 지원</strong></p>
<ul>
<li>새로운 데이터가 추가되면 <strong>즉시 반영 가능</strong>, 최신 상태 유지</li>
</ul>
</li>
</ol>
<hr>
<h3 id="벡터-db는-ai-시대의-필수-기술">벡터 DB는 AI 시대의 필수 기술</h3>
<ul>
<li>OpenAI, Google, Facebook 등에서 사용하는 핵심 기술</li>
<li>AI 모델을 활용한 다양한 서비스에 적용됨<ul>
<li>예) 추천 시스템, 보안, 검색, 자연어 처리(NLP), 의료 AI 등</li>
</ul>
</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1c6e776d-59c4-4347-ac2f-723a296159d8/image.png" alt=""></p>
<hr>
<h1 id="3-벡터와-벡터-공간">#3. 벡터와 벡터 공간</h1>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/f10b5da1-11ca-4a0c-9b11-cbdb92e4ed30/image.png" alt=""></p>
<hr>
<h3 id="유클리드-거리-euclidean-distance">유클리드 거리 (Euclidean Distance)</h3>
<ul>
<li>가장 기본적인 거리 측정 방식</li>
<li>두 벡터 간의 직선 거리(피타고라스 정리 기반)를 계산</li>
<li>저차원(2D, 3D)에서는 효과적이지만, <strong>차원이 증가할수록 성능이 저하</strong></li>
</ul>
<p>공식:</p>
<p>$$
d(a,b)= \sqrt{(a_1 - b_1)^2 + (a_2 - b_2)^2 + \cdots + (a_n - b_n)^2}
$$</p>
<hr>
<h3 id="고차원에서의-문제점">고차원에서의 문제점</h3>
<ol>
<li><strong>차원의 저주 (Curse of Dimensionality)</strong><ul>
<li>차원이 높아질수록 벡터 간 거리가 균등하게 증가</li>
<li>→ 거리 기반 검색의 효용이 떨어짐</li>
<li>→ 데이터가 희소해지고, 유사한 벡터를 찾기 어려워짐</li>
</ul>
</li>
<li><strong>유사한 벡터 간 거리 차이가 작아짐</strong><ul>
<li>고차원 공간에서는 대부분의 점들이 서로 비슷한 거리를 가지게 되어, <strong>분별력이 낮아짐</strong></li>
</ul>
</li>
</ol>
<hr>
<h3 id="해결-방법-코사인-유사도-cosine-similarity">해결 방법: 코사인 유사도 (Cosine Similarity)</h3>
<ul>
<li>벡터 간의 방향(각도)를 비교하여 유사도를 측정</li>
<li><strong>방향</strong>이 중요한 경우에 효과적 (예: 자연어 처리에서 단어 벡터)</li>
</ul>
<p>공식:</p>
<p>$$
cos⁡(θ) = \frac{\mathbf{a} \cdot \mathbf{b}}{|\mathbf{a}| |\mathbf{b}|}
$$</p>
<ul>
<li>0도 (동일 방향): 유사도 = 1</li>
<li>90도 (직각): 유사도 ≈ 0</li>
<li>180도 (반대 방향): 유사도 = -1</li>
</ul>
<hr>
<h3 id="요약">요약</h3>
<ul>
<li>고차원 공간에서는 <strong>유클리드 거리보다 코사인 유사도</strong>가 더 적합한 경우가 많음</li>
<li>특히, <strong>단어 임베딩</strong>이나 <strong>BERT 등의 자연어 처리 벡터</strong>에서는 <strong>방향 정보</strong>가 중요</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/cea76a98-5e71-49ec-8f73-faf4fd97498c/image.png" alt=""></p>
<hr>
<h2 id="벡터-db">벡터 DB</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d6f5cde1-2e15-4cbd-a2b8-25b751ee933e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/5fcd4f3b-4bcf-492e-9fd7-a7fa1f820f15/image.png" alt=""></p>
<blockquote>
<p>쿼리가 들어오면 Index를 비교</p>
</blockquote>
<hr>
<h3 id="전체-프로세스">전체 프로세스</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0f34bd97-84be-4b56-b898-1d5980bfb8aa/image.png" alt=""></p>
<hr>
<h3 id="관계형-vs-벡터-db">관계형 VS 벡터 DB</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/429fda41-eae8-402d-a88c-13a13f7d4700/image.png" alt=""></p>
<hr>
<h1 id="벡터-embedding-기초">벡터 Embedding 기초</h1>
<p>단어, 문장, 이미지 같은 데이터를 숫자로 변환하는 과정</p>
<hr>
<h3 id="비유-도시-위치">비유: 도시 위치</h3>
<ul>
<li>우리가 살고 있는 도시는 <strong>비슷한 지역끼리 가까운 위치</strong>에 배치되어 있음<ul>
<li>서울 vs. 부산 → 같은 나라, <strong>비슷한 카테고리</strong></li>
<li>서울 vs. 도쿄 → <strong>가깝지만 다른 나라</strong>, 유사성 존재</li>
<li>서울 vs. 고양이 → <strong>완전히 무관</strong>, 관련 없음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="벡터-임베딩과의-연관성">벡터 임베딩과의 연관성</h3>
<ul>
<li><strong>벡터 임베딩도 같은 원리</strong><ul>
<li>비슷한 의미를 가진 단어나 이미지끼리는 <strong>가까운 숫자 벡터로 변환</strong></li>
</ul>
</li>
</ul>
<hr>
<h3 id="벡터-임베딩의-목적">벡터 임베딩의 목적</h3>
<ul>
<li>텍스트, 이미지, 소리 등 <strong>비정형 데이터</strong>를 숫자로 표현하는 과정</li>
<li>컴퓨터가 의미를 이해하고, 이를 통해 <strong>검색</strong>, <strong>추천</strong>, <strong>번역</strong> 등에 활용</li>
</ul>
<p>요약하자면, 벡터 임베딩은 <strong>의미가 비슷한 데이터들을 공간상에서 가깝게 위치시키는 방식</strong>이며, 이를 통해 AI는 인간처럼 유사성을 판단할 수 있게 됩니다.</p>
<hr>
<h2 id="word2vec-→-bert">word2vec → BERT</h2>
<h3 id="word2vec-2013">Word2Vec (2013)</h3>
<ul>
<li><strong>아이디어</strong><ul>
<li>&quot;비슷한 의미의 단어들은 벡터 공간에서 가깝게 위치할 것&quot;</li>
<li>단어를 숫자로 변환하여 의미를 벡터화</li>
</ul>
</li>
<li><strong>특징</strong><ul>
<li>단어를 <strong>고정된 벡터</strong>로 표현 (문맥 고려하지 않음)</li>
<li>문맥 이해 부족 → 예: “bank”가 은행인지, 강변인지 구분 불가</li>
</ul>
</li>
<li><strong>예시 벡터</strong></li>
</ul>
<pre><code>| 단어 | Word2Vec 벡터 예시 |
| --- | --- |
| king | [0.2, 0.5, 0.8] |
| queen | [0.3, 0.6, 0.6] |
| apple | [0.8, 0.1, 0.2] |</code></pre><ul>
<li><strong>장점</strong><ul>
<li>연산 가능: &quot;king - man + woman = queen&quot;과 같은 관계 유추 가능</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/6a5606ff-b41b-4d74-a793-9d96008ff7bc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/032035c1-a506-4c83-9f33-58372b53fa3c/image.png" alt=""></p>
<blockquote>
<p>해당 연산이 답은 “일본”</p>
</blockquote>
<hr>
<h3 id="bert-2018-google">BERT (2018, Google)</h3>
<ul>
<li><p><strong>개요</strong></p>
<ul>
<li>Word2Vec의 한계를 개선한 최신 기법</li>
<li>문맥을 반영하여 <strong>단어의 의미를 더 정교하게 임베딩</strong></li>
</ul>
</li>
<li><p><strong>특징</strong></p>
<ul>
<li><p>Transformer 기반 모델</p>
</li>
<li><p>문장의 <strong>양방향 문맥</strong>을 활용하여 단어의 의미 파악</p>
</li>
<li><p>예: &quot;나는 은행(bank)에서 돈을 찾았다.&quot; → 금융</p>
<p>  &quot;강둑 은행(bank)에 앉아 있었다.&quot; → 강변</p>
<p>  → 문맥에 따라 의미를 정확히 구분 가능</p>
</li>
</ul>
</li>
<li><p><strong>활용</strong></p>
<ul>
<li>문장 의미 파악, 검색, 챗봇, AI 번역 등 다양한 NLP 응용에 활용</li>
</ul>
</li>
</ul>
<hr>
<h3 id="핵심-비교-요약">핵심 비교 요약</h3>
<table>
<thead>
<tr>
<th>항목</th>
<th>Word2Vec</th>
<th>BERT</th>
</tr>
</thead>
<tbody><tr>
<td>문맥 반영</td>
<td>안 함</td>
<td>함</td>
</tr>
<tr>
<td>벡터 표현</td>
<td>단어당 고정</td>
<td>문장에 따라 달라짐</td>
</tr>
<tr>
<td>기반 모델</td>
<td>간단한 신경망</td>
<td>Transformer 구조</td>
</tr>
<tr>
<td>활용 분야</td>
<td>단어 유사성, 관계 유추</td>
<td>검색, 번역, 질문응답 등 넓음</td>
</tr>
</tbody></table>
<hr>
<h2 id="word2vec-학습-메커니즘">Word2vec 학습 메커니즘</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d34666f2-391c-4182-a90a-6f8253e91f5e/image.png" alt=""></p>
<h3 id="cbow-continuous-bag-of-words">CBOW (Continuous Bag of Words)</h3>
<ul>
<li><p><strong>개념</strong>:</p>
<p>  문맥(Context) 단어를 보고 중심 단어(Target Word)를 예측하는 방식</p>
<p>  예: &quot;나는 맛있는 피자를 먹었다.&quot;</p>
<ul>
<li><p>중심 단어: &quot;피자&quot;</p>
</li>
<li><p>주변 단어: [&quot;나는&quot;, &quot;맛있는&quot;, &quot;먹었다&quot;]</p>
<p>  → 입력: [&quot;나는&quot;, &quot;맛있는&quot;, &quot;먹었다&quot;] → 출력: &quot;피자&quot;</p>
</li>
</ul>
</li>
<li><p><strong>구조</strong>:</p>
<p>  입력(주변 단어) → 신경망 학습 → 출력(중심 단어 예측)</p>
</li>
<li><p><strong>특징</strong>:</p>
<ul>
<li>학습 속도가 빠름</li>
<li>자주 등장하는 단어 예측에 유리</li>
<li>문맥을 고려한 예측 가능</li>
</ul>
</li>
</ul>
<hr>
<h3 id="skip-gram">Skip-Gram</h3>
<ul>
<li><p><strong>개념</strong>:</p>
<p>  중심 단어(Target Word)를 보고 주변 단어(Context Words)를 예측하는 방식</p>
<p>  예: &quot;나는 맛있는 피자를 먹었다.&quot;</p>
<ul>
<li><p>중심 단어: &quot;피자&quot;</p>
</li>
<li><p>주변 단어: [&quot;나는&quot;, &quot;맛있는&quot;, &quot;먹었다&quot;]</p>
<p>  → 입력: &quot;피자&quot; → 출력: [&quot;나는&quot;, &quot;맛있는&quot;, &quot;먹었다&quot;]</p>
</li>
</ul>
</li>
<li><p><strong>구조</strong>:</p>
<p>  입력(중심 단어) → 신경망 학습 → 출력(주변 단어 예측)</p>
</li>
<li><p><strong>특징</strong>:</p>
<ul>
<li>희귀 단어 학습에 강함</li>
<li>CBOW보다 학습 속도는 느림</li>
<li>데이터가 적을 때도 성능이 좋음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="요약-비교">요약 비교</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1e7c87f8-a176-40c2-8563-390f60c88681/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/5a845ef2-78a8-43fb-8c19-8ca851ed28de/image.png" alt=""></p>
<table>
<thead>
<tr>
<th>항목</th>
<th>CBOW</th>
<th>Skip-Gram</th>
</tr>
</thead>
<tbody><tr>
<td>입력</td>
<td>주변 단어</td>
<td>중심 단어</td>
</tr>
<tr>
<td>출력</td>
<td>중심 단어</td>
<td>주변 단어들</td>
</tr>
<tr>
<td>학습 속도</td>
<td>빠름</td>
<td>느림</td>
</tr>
<tr>
<td>특징</td>
<td>자주 쓰는 단어 학습에 유리</td>
<td>희귀 단어 학습에 유리</td>
</tr>
<tr>
<td>데이터 요구</td>
<td>데이터 많을 때 성능 좋음</td>
<td>데이터 적을 때도 잘 작동</td>
</tr>
</tbody></table>
<hr>
<h3 id="윈도우-크기와-문맥context">윈도우 크기와 문맥(Context)</h3>
<ul>
<li><p><strong>윈도우 크기 2 라면</strong>:</p>
<ul>
<li><p>중심 단어 기준으로 <strong>앞쪽 2개, 뒤쪽 2개의 단어</strong>를 문맥으로 보는 것을 의미</p>
</li>
<li><p>예: 중심 단어가 &quot;fox&quot;일 때</p>
<p>  → 문장: <em>the quick brown fox jumps over the lazy dog</em></p>
<p>  → 주변 단어: [&quot;quick&quot;, &quot;brown&quot;, &quot;jumps&quot;, &quot;over&quot;]</p>
</li>
</ul>
</li>
<li><p><strong>CBOW 모델</strong>:</p>
<p>  주변 단어를 보고 중심 단어를 예측</p>
</li>
<li><p><strong>Skip-Gram 모델</strong>:</p>
<p>  중심 단어를 보고 주변 단어를 예측</p>
</li>
<li><p>윈도우 크기가 <strong>n</strong>이라면, 주변 단어 수는 총 <strong>2n개</strong></p>
</li>
</ul>
<hr>
<h3 id="정의">정의</h3>
<p>문장 전체에 슬라이딩 윈도우를 적용하여 학습용 데이터를 만드는 과정을</p>
<p><strong>슬라이딩 윈도우(sliding window)</strong> 라고 부름.</p>
<hr>
<h2 id="word2vec의-한계점">Word2Vec의 한계점</h2>
<h3 id="1-문맥-무시">1. 문맥 무시</h3>
<ul>
<li><p>같은 단어라도 <strong>문맥에 따라 의미가 달라질 수 있음</strong></p>
<p>  → 기존 임베딩은 이를 고려하지 않음</p>
</li>
<li><p>예시:</p>
<ul>
<li><p>&quot;단풍잎이 시뻘겋다.&quot;</p>
</li>
<li><p>&quot;얼굴이 시뻘겋다.&quot;</p>
<p>  (같은 단어 &quot;시뻘겋다&quot;지만 의미 다름)</p>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-다의성-해결-불가">2. 다의성 해결 불가</h3>
<ul>
<li><p>같은 단어인데도 <strong>여러 의미(다의어)를 가지는 경우</strong> 하나의 벡터로만 표현됨</p>
</li>
<li><p>예시:</p>
<ul>
<li><p>&quot;모자(cap)&quot; → 모자(의류), 모자(엄마와 아들)</p>
<p>  → 의미 구분 불가</p>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="3-장기-의존성-문제">3. 장기 의존성 문제</h3>
<ul>
<li><p>기존 모델은 <strong>근처 단어에만 의존</strong>하여 학습함</p>
</li>
<li><p>멀리 떨어져 있어도 <strong>의미적으로 연관된 단어 간의 관계</strong>를 반영하지 못함</p>
</li>
<li><p>예시:</p>
<ul>
<li><p>&quot;나는 많은 나라를 여행했고,</p>
<p>  그 중 프랑스는 내가 좋아하는 나라 중 하나였다.&quot;</p>
<p>  → &quot;프랑스&quot;와 &quot;좋아하는 나라&quot; 사이의 연관성 반영 어려움</p>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="이미지-임베딩--cnn-기반-특성-추출">이미지 임베딩 : CNN 기반 특성 추출</h2>
<h3 id="cnn-합성곱-신경망-convolutional-neural-network">CNN (합성곱 신경망, Convolutional Neural Network)</h3>
<h3 id="1-cnn의-개념">1. CNN의 개념</h3>
<ul>
<li>CNN은 사람이 이미지를 볼 때, 먼저 큰 특징(예: 얼굴, 배경)을 보고, 점차 세부적인 특징(예: 눈, 입, 턱)을 인식하는 방식과 유사한 구조로 설계된 딥러닝 모델이다.</li>
</ul>
<h3 id="2-cnn의-핵심-과정">2. CNN의 핵심 과정</h3>
<ul>
<li><p><strong>Conv Layer (합성곱 층)</strong></p>
<p>  필터를 사용하여 이미지에서 엣지, 모양 등 중요한 패턴을 추출한다.</p>
</li>
<li><p><strong>Pooling Layer (풀링 층)</strong></p>
<p>  정보를 압축하여 연산 속도를 높이고, 불필요한 부분을 제거한다.</p>
</li>
<li><p><strong>Fully Connected Layer (완전 연결 층)</strong></p>
<p>  벡터화된 정보를 바탕으로 객체(강아지, 고양이, 사람 등)를 분류한다.</p>
</li>
</ul>
<h3 id="3-활용-방식">3. 활용 방식</h3>
<ul>
<li>CNN은 이미지를 숫자 벡터로 변환하여, 유사한 이미지끼리 벡터 간의 거리로 비교할 수 있도록 한다.</li>
<li>예: 얼굴 인식 시스템에서는 비슷한 얼굴일수록 유사한 벡터 값을 갖게 되어, 이를 기반으로 얼굴을 매칭한다.</li>
</ul>
<hr>
<h2 id="멀티모달-임베딩-텍스트--이미지-결합">멀티모달 임베딩 (텍스트 + 이미지 결합)</h2>
<h3 id="멀티모달-multimodal">멀티모달 (Multimodal)</h3>
<h3 id="1-개념">1. 개념</h3>
<ul>
<li><p>여러 형태의 데이터를 동시에 이해할 수 있는 AI 모델</p>
<p>  예: 텍스트, 이미지, 음성 등을 함께 처리</p>
</li>
<li><p>예: ChatGPT 같은 AI가 &quot;고양이&quot;라는 텍스트를 입력받고 실제 고양이 이미지를 찾아낼 수 있는 기능</p>
</li>
</ul>
<hr>
<h3 id="예시-및-적용-사례">예시 및 적용 사례</h3>
<h3 id="clip-openai">CLIP (OpenAI)</h3>
<ul>
<li>텍스트(예: 설명)와 이미지(예: 사진)를 동일한 벡터 공간에 배치</li>
<li>예: &quot;개&quot;라는 단어를 입력하면 개와 관련된 이미지 벡터를 가까운 위치로 매칭시킴</li>
</ul>
<h3 id="dall·e-openai">DALL·E (OpenAI)</h3>
<ul>
<li>텍스트로 설명한 내용을 바탕으로 AI가 이미지를 생성</li>
</ul>
<hr>
<h3 id="멀티모달-임베딩-방식의-예">멀티모달 임베딩 방식의 예</h3>
<ol>
<li>텍스트: &quot;바닷가에서 노는 강아지&quot;</li>
<li>이미지 벡터: 실제 바닷가에서 노는 강아지 사진</li>
<li>벡터 비교: 텍스트 벡터와 이미지 벡터 간의 거리를 계산해 가까운 것을 매칭</li>
</ol>
<p>→ 검색 엔진에서 &quot;강아지&quot;라고 검색하면 강아지 이미지가 자동으로 나오는 원리와 유사</p>
<hr>
<h2 id="정리-벡터-임베딩-기초">정리: 벡터 임베딩 기초</h2>
<h3 id="1-벡터-임베딩이란">1. 벡터 임베딩이란?</h3>
<ul>
<li>데이터를 숫자로 변환하여 AI가 이해할 수 있도록 하는 과정</li>
</ul>
<hr>
<h3 id="2-텍스트-임베딩-word2vec-→-bert">2. 텍스트 임베딩 (Word2Vec → BERT)</h3>
<ul>
<li>문맥을 이해하는 방식으로 발전</li>
<li>검색, 번역, 챗봇 등 다양한 자연어 처리 분야에서 활용됨</li>
</ul>
<hr>
<h3 id="3-이미지-임베딩-cnn-기반">3. 이미지 임베딩 (CNN 기반)</h3>
<ul>
<li>이미지의 특징을 벡터로 변환</li>
<li>검색, 분류, 추천 시스템 등에 사용됨</li>
</ul>
<hr>
<h3 id="4-멀티모달-임베딩-텍스트--이미지-결합">4. 멀티모달 임베딩 (텍스트 + 이미지 결합)</h3>
<ul>
<li>AI가 텍스트와 이미지를 동시에 이해하도록 하는 기술</li>
<li>대표 예: CLIP, DALL·E 등</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/617742b5-a5a7-4e57-8b32-53142f916fe0/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (2) - 개요]]></title>
            <link>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-2-%EA%B0%9C%EC%9A%94</link>
            <guid>https://velog.io/@lyj_0316/%EB%B2%A1%ED%84%B0-DB-2-%EA%B0%9C%EC%9A%94</guid>
            <pubDate>Wed, 07 May 2025 02:07:50 GMT</pubDate>
            <description><![CDATA[<h1 id="벡터-db-개요">벡터 DB 개요</h1>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/10b21e9b-22b5-4b44-a2ab-6c98b17b384b/image.png" alt=""></p>
<p>생성형 AI가 발전하면서 환각 없는 생성형 콘텐츠의 중요성이 확대됐고, 환각을 최소화하는 방안으로 RAG가 각광받고 있습니다.</p>
<p>또한, RAG를 위해서는 벡터 DB가 반드시 필요합니다.</p>
<hr>
<h3 id="전통적인-데이터베이스-vs-벡터-데이터베이스-비교">전통적인 데이터베이스 vs 벡터 데이터베이스 비교</h3>
<table>
<thead>
<tr>
<th><strong>특징</strong></th>
<th><strong>전통적인 데이터베이스 (RDB, NoSQL)</strong></th>
<th><strong>벡터 데이터베이스 (벡터 DB)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>데이터 타입</strong></td>
<td>정형 데이터 (숫자, 문자열, 테이블)</td>
<td>비정형 데이터 (이미지, 음성, 텍스트)</td>
</tr>
<tr>
<td><strong>기본 연산</strong></td>
<td>CRUD (Create, Read, Update, Delete)</td>
<td>유사도 검색 (Nearest Neighbor Search)</td>
</tr>
<tr>
<td><strong>인덱싱 방식</strong></td>
<td>B-Tree, Hash Index</td>
<td>HNSW, IVF, PQ 등</td>
</tr>
<tr>
<td><strong>쿼리 방식</strong></td>
<td>SQL, NoSQL 쿼리</td>
<td>벡터 유사도 검색 (Cosine Similarity, Euclidean Distance)</td>
</tr>
<tr>
<td><strong>응용 분야</strong></td>
<td>전통적 Biz. Application (ERP, CRM, 금융)</td>
<td>AI 검색, 추천 시스템, 이미지/음성 검색</td>
</tr>
</tbody></table>
<hr>
<h3 id="요약-설명">요약 설명</h3>
<ul>
<li><p>전통적인 데이터베이스는 <strong>‘정확한 값을 찾는 데 강함’</strong></p>
</li>
<li><p>벡터 데이터베이스는 <strong>‘비슷한 것을 찾는 데 강함’</strong></p>
</li>
</ul>
<hr>
<h3 id="참고-knn-검색-vs-ann-검색">[참고] KNN 검색 vs. ANN 검색</h3>
<table>
<thead>
<tr>
<th><strong>비교 항목</strong></th>
<th><strong>KNN (K-Nearest Neighbors)</strong></th>
<th><strong>ANN (Approximate Nearest Neighbors)</strong></th>
</tr>
</thead>
<tbody><tr>
<td><strong>정의</strong></td>
<td>주어진 입력 벡터에 대해 가장 가까운 K개의 데이터를 찾아 분류 또는 회귀 수행</td>
<td>정확도보다는 <strong>속도와 효율성</strong>을 우선하여 근사적으로 최근접 이웃을 찾는 알고리즘</td>
</tr>
<tr>
<td><strong>기본 개념</strong></td>
<td>유클리디안 거리 등으로 거리 기반의 <strong>정확한</strong> 최근접 이웃 계산</td>
<td>효율적인 검색을 위해 인덱스 구조나 해싱 등을 사용하여 빠르게 근사 계산</td>
</tr>
<tr>
<td><strong>정확도</strong></td>
<td>매우 정확하지만 계산량이 많고 느림</td>
<td><strong>약간의 정확도 손실</strong>이 있으나 <strong>속도가 빠름</strong></td>
</tr>
<tr>
<td><strong>속도 및 성능</strong></td>
<td>느림 (특히 대규모 데이터에서는 매우 느림)</td>
<td><strong>매우 빠름</strong> (특히 고차원 대용량 데이터에서 <strong>성능 우수</strong>)</td>
</tr>
<tr>
<td><strong>메모리 사용량</strong></td>
<td>전체 데이터를 저장해야 하므로 큼</td>
<td>인덱스만 저장하므로 <strong>상대적으로 작음</strong></td>
</tr>
<tr>
<td><strong>확장성</strong></td>
<td>낮음 – 데이터가 많아질수록 속도 급격히 저하</td>
<td><strong>높음 – 수십억 개 벡터도 실시간 검색 가능</strong></td>
</tr>
<tr>
<td><strong>활용 분야</strong></td>
<td>- 분류(Classification)   - 회귀(Regression)  - 추천 시스템  - 이상 탐지</td>
<td>- <strong>대규모 이미지 검색</strong>  - <strong>추천 시스템</strong>  - 문서 유사도 검색  - 임베딩 기반 검색 엔진</td>
</tr>
<tr>
<td><strong>적합한 데이터</strong></td>
<td><strong>소규모, 고정된 데이터셋</strong></td>
<td><strong>대규모, 고차원 임베딩 데이터셋</strong></td>
</tr>
</tbody></table>
<hr>
<h3 id="요약">요약</h3>
<ul>
<li><p><strong>KNN</strong>: 정확도는 높지만 속도와 확장성이 떨어짐. 소규모 데이터에 적합</p>
</li>
<li><p><strong>ANN</strong>: 근사값을 이용하여 빠른 검색 가능. 대규모 벡터 검색에 적합</p>
</li>
</ul>
<hr>
<h2 id="벡터-데이터베이스의-필요성">벡터 데이터베이스의 필요성</h2>
<h3 id="기존-데이터베이스의-한계">기존 데이터베이스의 한계</h3>
<ul>
<li><p>숫자나 텍스트(예: &quot;홍길동&quot;) 같은 <strong>구조화된 데이터</strong> 저장·검색에는 최적화되어 있음</p>
</li>
<li><p>이미지, 음성, 문장 의미 같은 <strong>비정형 데이터 검색은 어려움</strong></p>
</li>
<li><p>이미지, 영상, 음성, 텍스트 등 <strong>비정형 데이터의 확산</strong>으로 기존 관계형 DB만으로는 한계</p>
<ul>
<li>SNS, 쇼핑, 스트리밍 플랫폼에서 비정형 데이터 활용 증가</li>
</ul>
</li>
<li><p>ChatGPT, DALL·E, Stable Diffusion 등 <strong>생성형 AI</strong> 발전</p>
</li>
<li><p>이미지 검색, 음성 인식, 추천 시스템 등에는 고급 검색 필요</p>
</li>
<li><p>전통적인 데이터베이스에서는 유사도 검색의 <strong>비효율성</strong></p>
<p>  → <strong>벡터 DB 필요성 대두</strong></p>
</li>
</ul>
<hr>
<h3 id="벡터-데이터베이스가-해결하는-문제">벡터 데이터베이스가 해결하는 문제</h3>
<ul>
<li><p>데이터를 <strong>숫자 벡터(좌표)</strong>로 변환하여 저장하고</p>
<p>  <strong>&quot;비슷한 것&quot;을 쉽게 찾을 수 있음</strong></p>
</li>
<li><p>활용 예시:</p>
<ul>
<li><p>이미지 검색: “이 사진이랑 비슷한 사진 찾아줘!”</p>
</li>
<li><p>음성 인식: “이 사람 목소리랑 비슷한 사람 찾아줘!”</p>
</li>
<li><p>추천 시스템: “내가 좋아할 만한 음악 추천해줘!”</p>
</li>
</ul>
</li>
</ul>
<hr>
<h2 id="이미지에서의-vectordb">이미지에서의 VectorDB</h2>
<h3 id="1-이미지-임베딩벡터화-속도">1. <strong>이미지 임베딩(벡터화)</strong> 속도</h3>
<ul>
<li><p>자율주행 카메라에서 들어오는 영상 프레임을 실시간 벡터로 바꾸려면, <strong>경량화된 모델</strong> 또는 <strong>하드웨어 가속</strong>이 필수입니다.</p>
</li>
<li><p><strong>해결책</strong>:</p>
<ul>
<li><p>ONNX, TensorRT로 <strong>딥러닝 모델 경량화 및 최적화</strong></p>
</li>
<li><p>GPU/TPU 또는 <strong>엣지 디바이스(NVIDIA Jetson, Coral 등)</strong> 활용</p>
</li>
<li><p>딥러닝 모델을 <strong>Batch 처리</strong>하여 처리 효율 향상</p>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="2-벡터-유사도-검색-속도">2. <strong>벡터 유사도 검색 속도</strong></h3>
<ul>
<li><p>벡터 DB는 수천만 개의 벡터 중에서 유사한 벡터를 빠르게 찾아야 함</p>
</li>
<li><p><strong>해결책</strong>:</p>
<ul>
<li><strong>ANN (Approximate Nearest Neighbor)</strong> 알고리즘 사용 (예: HNSW, IVF)</li>
<li>벡터 DB에서 <strong>search latency를 10ms 이하</strong>로 줄이는 기술 확보</li>
<li><strong>Memory-mapped storage, RAM caching, quantization(PQ)</strong> 기법 활용</li>
</ul>
</li>
</ul>
<hr>
<h3 id="3-동시성-및-시스템-아키텍처-최적화">3. <strong>동시성 및 시스템 아키텍처 최적화</strong></h3>
<ul>
<li><p>실시간 시스템은 단일 질의 성능뿐만 아니라 <strong>동시 다수 요청 처리</strong> 능력도 중요</p>
</li>
<li><p><strong>해결책</strong>:</p>
<ul>
<li>마이크로서비스 기반으로 벡터화/검색 분리 (Embedding 서버 ↔ Vector DB 서버)</li>
<li>실시간 스트림 프레임워크 (Kafka, ROS 등)와 연계</li>
<li><strong>벡터 DB는 미리 인덱싱</strong>된 데이터로만 검색하고, 새 벡터는 배치로 업데이트</li>
</ul>
</li>
</ul>
<hr>
<h3 id="실제-사용-예시">실제 사용 예시</h3>
<table>
<thead>
<tr>
<th>분야</th>
<th>사용 방식</th>
</tr>
</thead>
<tbody><tr>
<td>Tesla, Waymo</td>
<td>실시간 영상에서 객체 인식 → 특징 벡터화 → 유사 장면 비교 및 판단</td>
</tr>
<tr>
<td>Amazon Go</td>
<td>영상 기반 사용자 행동 벡터화 → 행동 패턴과 유사도 비교</td>
</tr>
<tr>
<td>스마트 CCTV</td>
<td>얼굴 인식 결과를 벡터로 변환 → 유사 인물 탐지</td>
</tr>
</tbody></table>
<hr>
<h3 id="결론">결론</h3>
<ul>
<li><p>실시간 유사도 검색은 <strong>가능하지만 고성능 하드웨어 + 최적화된 아키텍처 + 효율적인 알고리즘</strong>이 전제 조건입니다.</p>
</li>
<li><p>자율주행처럼 <strong>수밀리초 수준의 응답 시간</strong>이 요구되는 환경에서도 벡터 DB는 적극 활용되고 있습니다.</p>
</li>
</ul>
<hr>
<h2 id="벡터와-벡터공간">벡터와 벡터공간</h2>
<h3 id="벡터란">벡터란?</h3>
<ul>
<li><strong>벡터</strong>: 여러 개의 <strong>숫자</strong>로 이루어진 배열</li>
<li><strong>예시</strong><ul>
<li>1차원 벡터: <code>[5]</code></li>
<li>2차원 벡터: <code>[3, 4]</code></li>
<li>3차원 벡터: <code>[2, 5, 1]</code></li>
</ul>
</li>
<li><strong>활용 예시</strong><ul>
<li>위치 좌표: <code>[x, y] = [3, 4]</code> (지도상의 위치)</li>
<li>색상 정보: <code>[R, G, B] = [255, 0, 0]</code> (빨간색)</li>
</ul>
</li>
</ul>
<blockquote>
<p>벡터는 숫자로 이루어진 데이터의 표현 방식</p>
</blockquote>
<hr>
<h3 id="고차원-벡터-공간이란">고차원 벡터 공간이란?</h3>
<ul>
<li><p>벡터의 차원이 많아지면 <strong>고차원 벡터 공간</strong>이 됨</p>
</li>
<li><p>예: 텍스트를 벡터로 바꾸면</p>
<p>  → <code>[0.2, 0.8, 0.5, 0.1, …]</code> 형태가 됨</p>
</li>
<li><p>이런 방식으로 텍스트, 이미지, 음성 등을 <strong>벡터로 변환</strong> 가능</p>
</li>
</ul>
<hr>
<h3 id="벡터화-vectorization란">벡터화 (Vectorization)란?</h3>
<ul>
<li>텍스트, 이미지, 오디오 등의 데이터를 <strong>벡터(숫자 배열)</strong>로 변환하는 과정</li>
</ul>
<hr>
<h3 id="벡터-임베딩-embedding이란">벡터 임베딩 (Embedding)이란?</h3>
<ul>
<li>데이터를 <strong>의미가 보존된 숫자 벡터</strong>로 변환하는 방법</li>
<li>AI가 이해할 수 있도록 데이터를 표현하는 과정</li>
</ul>
<blockquote>
<p>벡터 임베딩은 데이터를 숫자로 변환하는 중요한 과정</p>
</blockquote>
<hr>
<h3 id="벡터화-방법-예시">벡터화 방법 예시</h3>
<ol>
<li><strong>텍스트 → 벡터</strong><ul>
<li><code>Word2Vec</code>: 단어의 의미를 숫자로 표현</li>
<li><code>BERT</code>: 문장의 의미까지 이해할 수 있도록 표현</li>
</ul>
</li>
<li><strong>이미지 → 벡터</strong><ul>
<li><code>CNN(합성곱 신경망)</code>을 이용해 이미지의 특징을 벡터로 변환</li>
</ul>
</li>
<li><strong>오디오 → 벡터</strong><ul>
<li><code>MFCC</code>, <code>Wave2Vec</code> 등을 이용하여 음성을 벡터로 변환</li>
</ul>
</li>
</ol>
<hr>
<h2 id="bert">BERT</h2>
<h3 id="bert란">BERT란?</h3>
<ul>
<li><p><strong>BERT</strong> (Bidirectional Encoder Representations from Transformers)는</p>
<p>  <strong>자연어 처리(NLP)</strong>를 위한 인공지능 모델</p>
</li>
<li><p>구글에서 개발</p>
</li>
<li><p><strong>문장의 맥락을 양방향(Bidirectional)</strong> 으로 이해하는 것이 특징</p>
</li>
</ul>
<hr>
<h3 id="bert의-특징">BERT의 특징</h3>
<ol>
<li><p><strong>양방향 이해</strong></p>
<ul>
<li>기존 모델은 왼쪽 → 오른쪽 또는 오른쪽 → 왼쪽 한 방향만 학습</li>
<li>BERT는 <strong>양방향</strong>으로 문장을 학습 → 문장 전체의 맥락을 더 정확히 파악 가능</li>
</ul>
</li>
<li><p><strong>문맥 이해 능력</strong></p>
<ul>
<li><p>예:</p>
<p>  &quot;나는 은행에 갔다.&quot; → 금융기관인지, 강변인지 <strong>문맥으로 구분 가능</strong></p>
<p>  &quot;나는 은행에서 돈을 찾았다.&quot; → &quot;금융기관&quot;으로 해석</p>
</li>
</ul>
</li>
<li><p><strong>사전 훈련 후 미세 조정 (Fine-tuning)</strong></p>
<ul>
<li>대량의 텍스트로 기본 학습 후</li>
<li>특정 작업(감성 분석, 번역 등)에 맞춰 <strong>세부 조정 가능</strong></li>
</ul>
</li>
</ol>
<hr>
<h3 id="bert의-활용-사례">BERT의 활용 사례</h3>
<ul>
<li><p><strong>검색 엔진</strong></p>
<p>  → 검색 결과의 정확도 향상 (예: 구글 검색)</p>
</li>
<li><p><strong>챗봇</strong></p>
<p>  → 질문의 맥락을 이해하고 더 정확한 답변 제공</p>
</li>
<li><p><strong>문장 의미 분석</strong></p>
<p>  → 문장의 긍정/부정 감정 분석, 질문-답변 시스템 등에 활용</p>
</li>
</ul>
<hr>
<h3 id="bert-간단한-실습-예제-hugging-face-사용">BERT 간단한 실습 예제 (Hugging Face 사용)</h3>
<h3 id="1-라이브러리-임포트">1. 라이브러리 임포트</h3>
<pre><code class="language-python">from transformers import BertTokenizer, BertModel</code></pre>
<h3 id="2-bert-토크나이저-불러오기">2. BERT 토크나이저 불러오기</h3>
<pre><code class="language-python">tokenizer = BertTokenizer.from_pretrained(&quot;bert-base-uncased&quot;)</code></pre>
<h3 id="3-예제-문장-정의">3. 예제 문장 정의</h3>
<pre><code class="language-python">text = &quot;I love natural language processing.&quot;</code></pre>
<h3 id="4-문장을-토큰화">4. 문장을 토큰화</h3>
<pre><code class="language-python">tokens = tokenizer.tokenize(text)
print(tokens)</code></pre>
<h3 id="5-토큰을-인덱스로-변환">5. 토큰을 인덱스로 변환</h3>
<pre><code class="language-python">input_ids = tokenizer.encode(text, add_special_tokens=True)
print(input_ids)</code></pre>
<p>Hugging Face의 <code>transformers</code> 라이브러리를 사용하면 BERT 모델을 쉽게 불러와 문장을 토큰화하고, 모델이 이해할 수 있는 입력 형식으로 변환할 수 있습니다.</p>
<hr>
<h2 id="mfcc-mel-frequency-cepsrtal-coefficients">MFCC, Mel-Frequency Cepsrtal Coefficients</h2>
<h3 id="mfcc란">MFCC란?</h3>
<ul>
<li>음성 신호를 숫자로 변환(음성 벡터화)하는 기술</li>
<li>사람의 청각 특성을 반영하여 음성 데이터를 분석하는 데 유용</li>
</ul>
<hr>
<h3 id="mfcc-원리-및-음성-처리-과정">MFCC 원리 및 음성 처리 과정</h3>
<h3 id="원리">원리</h3>
<ul>
<li>사람의 귀는 주파수가 낮은 소리에 더 민감함</li>
<li>이러한 청각 특성을 반영해 음성을 분석</li>
</ul>
<h3 id="음성-처리-과정">음성 처리 과정</h3>
<ol>
<li>음성을 작은 조각(Frame)으로 나눔</li>
<li>각 조각을 푸리에 변환(Fourier Transform)하여 주파수 분석</li>
<li>Mel 필터 적용 (인간 청각에 맞게 변환)</li>
<li>Cepstrum 분석 (중요한 특징을 추출하여 벡터화)</li>
</ol>
<p>→ 이 과정을 통해 음성을 숫자로 변환</p>
<hr>
<h3 id="활용-사례">활용 사례</h3>
<ul>
<li><strong>음성 인식</strong><ul>
<li>예: &quot;Siri, 오늘 날씨 어때?&quot;</li>
</ul>
</li>
<li><strong>음성 감정 분석</strong><ul>
<li>사람의 감정을 분석해 상담 서비스에 활용</li>
</ul>
</li>
<li><strong>음성 인증 시스템</strong><ul>
<li>예: 은행 콜센터 등에서 목소리로 본인 확인</li>
</ul>
</li>
</ul>
<hr>
<h3 id="mfcc-실습-python---librosa-라이브러리-사용">MFCC 실습 (Python - librosa 라이브러리 사용)</h3>
<h3 id="1-라이브러리-임포트-1">1. 라이브러리 임포트</h3>
<pre><code class="language-python">import librosa
import librosa.display
import numpy as np
import matplotlib.pyplot as plt</code></pre>
<h3 id="2-음성-파일-로드">2. 음성 파일 로드</h3>
<pre><code class="language-python">audio_file = &quot;example.wav&quot;
y, sr = librosa.load(audio_file, sr=22050)</code></pre>
<ul>
<li><code>y</code>: 음성 신호</li>
<li><code>sr</code>: 샘플링 레이트 (22050Hz)</li>
</ul>
<h3 id="3-mfcc-특징-추출">3. MFCC 특징 추출</h3>
<pre><code class="language-python">mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)</code></pre>
<ul>
<li>13개의 MFCC 계수를 추출</li>
</ul>
<h3 id="4-mfcc-시각화">4. MFCC 시각화</h3>
<pre><code class="language-python">plt.figure(figsize=(10, 4))
librosa.display.specshow(mfccs, x_axis=&quot;time&quot;)
plt.colorbar()
plt.title(&quot;MFCC&quot;)
plt.show()</code></pre>
<ul>
<li>MFCC 결과를 시간에 따라 시각화</li>
</ul>
<hr>
<h3 id="요약-1">요약</h3>
<ul>
<li>음성 데이터를 MFCC로 변환하고</li>
<li>변환된 결과를 시각화하여 분석에 활용</li>
</ul>
<hr>
<h2 id="wave2vec">Wave2Vec</h2>
<h3 id="wave2vec-개요">Wave2Vec 개요</h3>
<p><strong>설명</strong></p>
<ul>
<li>텍스트 레이블 없이도 음성 학습이 가능한 딥러닝 모델</li>
<li>Facebook AI 연구팀이 개발</li>
</ul>
<hr>
<h3 id="주요-특징">주요 특징</h3>
<ol>
<li><strong>비지도 학습(Self-Supervised Learning)</strong><ul>
<li>Wave2Vec은 음성 데이터만으로 사전 학습 진행</li>
<li>레이블이 없는 대량의 음성 데이터로도 학습 가능</li>
</ul>
</li>
<li><strong>음성을 직접 벡터로 변환</strong><ul>
<li>기존 방식(MFCC 등)은 중간 처리 과정이 필요</li>
<li>Wave2Vec은 원본 음성(Waveform)을 바로 벡터로 변환 가능</li>
</ul>
</li>
<li><strong>적은 데이터로도 뛰어난 성능</strong><ul>
<li>기존 모델은 많은 데이터가 필요했으나</li>
<li>Wave2Vec은 적은 데이터로도 높은 정확도 가능</li>
</ul>
</li>
</ol>
<hr>
<h3 id="활용-사례-1">활용 사례</h3>
<ul>
<li><strong>자동 음성 인식 (ASR, Automatic Speech Recognition)</strong><ul>
<li>예: AI 비서, 콜센터 자동화</li>
</ul>
</li>
<li><strong>자연어 처리와 결합</strong><ul>
<li>음성을 텍스트로 변환 후 감정 분석 등 가능</li>
</ul>
</li>
<li><strong>다국어 음성 인식</strong><ul>
<li>적은 데이터로 다양한 언어 학습 가능</li>
</ul>
</li>
</ul>
<hr>
<h3 id="wave2vec-실습-예제-hugging-face-사용">Wave2Vec 실습 예제 (Hugging Face 사용)</h3>
<h3 id="1-라이브러리-임포트-2">1. 라이브러리 임포트</h3>
<pre><code class="language-python">from transformers import Wav2Vec2Processor, Wav2Vec2ForCTC
import torch
import librosa</code></pre>
<h3 id="2-wave2vec-모델-불러오기">2. Wave2Vec 모델 불러오기</h3>
<pre><code class="language-python">processor = Wav2Vec2Processor.from_pretrained(&quot;facebook/wav2vec2-large-960h&quot;)
model = Wav2Vec2ForCTC.from_pretrained(&quot;facebook/wav2vec2-large-960h&quot;)</code></pre>
<h3 id="3-음성-파일-로드">3. 음성 파일 로드</h3>
<pre><code class="language-python">audio_file = &quot;example.wav&quot;
y, sr = librosa.load(audio_file, sr=16000)</code></pre>
<h3 id="4-음성을-모델-입력-형식으로-변환">4. 음성을 모델 입력 형식으로 변환</h3>
<pre><code class="language-python">input_values = processor(y, return_tensors=&quot;pt&quot;, sampling_rate=16000).input_values</code></pre>
<h3 id="5-모델-예측-수행">5. 모델 예측 수행</h3>
<pre><code class="language-python">with torch.no_grad():
    logits = model(input_values).logits</code></pre>
<h3 id="6-예측값을-텍스트로-변환">6. 예측값을 텍스트로 변환</h3>
<pre><code class="language-python">predicted_ids = torch.argmax(logits, dim=-1)
transcription = processor.batch_decode(predicted_ids)[0]
print(transcription)</code></pre>
<hr>
<h3 id="요약-2">요약</h3>
<ul>
<li>음성 파일을 불러와 Wave2Vec 모델에 입력</li>
<li>음성을 텍스트로 변환하여 자동 음성 인식 구현 가능</li>
</ul>
<hr>
<h2 id="hugging-face">Hugging Face</h2>
<h3 id="hugging-face-개요">Hugging Face 개요</h3>
<ul>
<li>자연어 처리(NLP) 분야에서 유명한 AI 스타트업이자 오픈소스 커뮤니티</li>
<li>AI 모델을 쉽게 사용할 수 있도록 다양한 도구와 라이브러리를 제공</li>
</ul>
<hr>
<h3 id="주요-서비스-및-제품---transformers">주요 서비스 및 제품 - Transformers</h3>
<ul>
<li><strong>Transformers 라이브러리</strong><ul>
<li>Hugging Face에서 제공하는 가장 유명한 오픈소스 라이브러리</li>
<li>다양한 사전 학습(pre-trained) 모델을 쉽게 사용할 수 있음</li>
<li>주요 모델 예시:<ul>
<li>BERT, GPT, T5, BART, RoBERTa, XLM-R 등</li>
</ul>
</li>
<li>이 라이브러리를 통해 NLP 모델을 쉽게 로드, 훈련, 평가, 추론 가능</li>
</ul>
</li>
</ul>
<hr>
<h3 id="예시-코드">예시 코드</h3>
<pre><code class="language-python">from transformers import pipeline

# 사전 학습된 모델을 사용한 감정 분석
classifier = pipeline(&#39;sentiment-analysis&#39;)
result = classifier(&quot;I love using Hugging Face!&quot;)
print(result)</code></pre>
<ul>
<li>Hugging Face의 사전 학습된 감정 분석 모델을 사용하여 주어진 텍스트의 감정을 분석</li>
</ul>
<hr>
<h3 id="주요-서비스-및-제품---hugging-face-hub">주요 서비스 및 제품 - Hugging Face Hub</h3>
<ul>
<li><strong>Hugging Face Hub</strong><ul>
<li>수천 개의 AI 모델과 데이터셋을 호스팅하는 플랫폼</li>
<li>다양한 모델을 다운로드하거나 자신만의 모델을 업로드 가능</li>
<li>텍스트, 이미지, 음성 등 여러 가지 유형의 모델과 다양한 언어를 지원</li>
<li>개발자들은 공개된 모델을 직접 사용하거나, 자신만의 모델을 공유할 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="주요-서비스-및-제품---datasets">주요 서비스 및 제품 - Datasets</h3>
<ul>
<li><strong>Hugging Face Datasets</strong><ul>
<li>수백 가지의 NLP 중심 데이터셋을 포함한 라이브러리 제공</li>
<li>데이터를 쉽게 로드, 변환, 분석할 수 있음</li>
<li>예시 데이터셋:<ul>
<li>SQuAD</li>
<li>GLUE</li>
<li>CoNLL-03</li>
</ul>
</li>
</ul>
</li>
</ul>
<hr>
<h3 id="주요-서비스-및-제품---autonlp-및-automl">주요 서비스 및 제품 - AutoNLP 및 AutoML</h3>
<ul>
<li><strong>AutoNLP</strong><ul>
<li>자동화된 NLP 모델 훈련과 최적화를 위한 서비스</li>
<li>프로그래밍 경험이 없어도 인터페이스를 통해 모델을 쉽게 훈련시키고 사용할 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h3 id="hugging-face--핵심-특징">Hugging Face – 핵심 특징</h3>
<h3 id="1-오픈-소스">1. 오픈 소스</h3>
<ul>
<li>Hugging Face의 Transformers 라이브러리는 완전 오픈 소스로 누구나 무료로 사용 가능</li>
<li>코드와 모델은 GitHub에 공개되어 있어, 누구나 자신의 모델을 업로드하거나 기여 가능</li>
</ul>
<h3 id="2-다양한-사전-학습-모델-pre-trained">2. 다양한 사전 학습 모델 (Pre-trained)</h3>
<ul>
<li>다양한 사전 학습된 모델을 통해 AI 연구자와 개발자들이 이미 학습된 모델을 기반으로 빠르게 실험 및 적용 가능</li>
<li>많은 데이터로 학습된 고성능 모델이며, 텍스트 분석, 요약, 번역, 감정 분석 등 다양한 작업 가능</li>
</ul>
<h3 id="3-편리한-사용">3. 편리한 사용</h3>
<ul>
<li>간단한 API와 파이프라인을 통해 복잡한 모델도 손쉽게 사용 가능</li>
<li>예: <code>pipeline</code> 함수를 쓰면 감정 분석, 텍스트 요약, 질의응답 시스템 등을 쉽게 구현할 수 있음</li>
</ul>
<h3 id="4-협업-및-커뮤니티">4. 협업 및 커뮤니티</h3>
<ul>
<li>AI 커뮤니티가 잘 활성화되어 있어 여러 연구자들이 모델을 공유하고 협업 체계가 잘 구성되어 있음</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[벡터 DB (1) - 개발 환경 설정]]></title>
            <link>https://velog.io/@lyj_0316/%EC%83%9D%EC%84%B1%ED%98%95-AI-%EB%B2%A1%ED%84%B0-DB-1</link>
            <guid>https://velog.io/@lyj_0316/%EC%83%9D%EC%84%B1%ED%98%95-AI-%EB%B2%A1%ED%84%B0-DB-1</guid>
            <pubDate>Wed, 07 May 2025 01:59:23 GMT</pubDate>
            <description><![CDATA[<h1 id="벡터-db-개발-환경-설정">벡터 DB 개발 환경 설정</h1>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/eee8c95f-cd8e-4404-85b0-f3856085a20a/image.png" alt=""></p>
<hr>
<h3 id="python-설치-및-확인">Python 설치 및 확인</h3>
<ol>
<li><p><strong>Python 버전 확인 명령어</strong></p>
<pre><code class="language-bash"> python --version
 또는
 python3 --version
</code></pre>
</li>
<li><p><strong>Python 다운로드 링크</strong></p>
<p> <a href="https://www.python.org/downloads/release/python-31010/">https://www.python.org/downloads/release/python-31010/</a></p>
</li>
<li><p><strong>설치 시 주의 사항</strong></p>
<p> 설치 시 &quot;Add Python to PATH&quot; 옵션 체크 필수</p>
</li>
<li><p><strong>설치 완료 후 확인 방법</strong></p>
<p> VSCode에서 다음 명령어로 설치 확인</p>
<pre><code class="language-bash"> python --version
</code></pre>
</li>
</ol>
<hr>
<h3 id="벡터-db-실행을-위한-필수-라이브러리-설치">벡터 DB 실행을 위한 필수 라이브러리 설치</h3>
<ul>
<li><p><strong>설치 명령어</strong></p>
<pre><code class="language-bash">  pip install faiss-cpu weaviate-client pymilvus pinecone-client
</code></pre>
</li>
<li><p><strong>설치된 라이브러리 예제 코드</strong></p>
<pre><code class="language-python">
  import faiss
  import weaviate
  import pymilvus
  import pinecone

  print(&quot;벡터 DB 라이브러리 설치 완료!&quot;)</code></pre>
</li>
<li><p>참고: faiss, milvus, weaviate, pinecone 등은 일반적으로 벡터 데이터베이스를 실행할 때 사용하는 대표적인 라이브러리들입니다.</p>
</li>
</ul>
<hr>
<h2 id="chromadb-환경설정">ChromaDB 환경설정</h2>
<h3 id="windows-환경에서-chromadb-설치-절차">Windows 환경에서 ChromaDB 설치 절차</h3>
<blockquote>
<p>필수 요구 사항 : Python 3.10.x 권장 + pip 최신 버전 + 가상환경(Virtual Environment) 사용</p>
</blockquote>
<ol>
<li><p><strong>Python 버전 확인</strong></p>
<pre><code class="language-bash"> python --version</code></pre>
</li>
<li><p><strong>pip 최신 버전으로 업데이트</strong></p>
<pre><code class="language-bash"> python -m pip install --upgrade pip</code></pre>
</li>
<li><p><strong>가상환경 생성 및 활성화 (venv 사용)</strong></p>
<pre><code class="language-bash"> python -m venv chromadb_env
 .\chromadb_env\Scripts\Activate</code></pre>
</li>
<li><p><strong>ChromaDB 설치</strong></p>
<pre><code class="language-bash"> pip install chromadb</code></pre>
</li>
</ol>
<hr>
<h3 id="【-chroma-db-인덱싱--검색-예제-】">【 Chroma DB 인덱싱 &amp; 검색 예제 】</h3>
<pre><code class="language-python">import chromadb

# Chroma DB 인스턴스 생성
chroma_client = chromadb.PersistentClient(path=&quot;./chroma_db&quot;)

# 컬렉션 생성 (벡터를 저장할 공간)
collection = chroma_client.get_or_create_collection(name=&quot;test_collection&quot;)

# 데이터 추가 (텍스트와 벡터)
collection.add(
    documents=[&quot;Hello World&quot;, &quot;Artificial Intelligence&quot;, &quot;벡터 Databases are cool!&quot;],
    metadatas=[{&quot;source&quot;: &quot;A&quot;}, {&quot;source&quot;: &quot;B&quot;}, {&quot;source&quot;: &quot;C&quot;}],
    ids=[&quot;doc1&quot;, &quot;doc2&quot;, &quot;doc3&quot;]
)

# 검색 테스트 (유사한 문서 찾기)
results = collection.query(
    query_texts=[&quot;AI&quot;],
    n_results=2
)

print(&quot;검색 결과:&quot;, results)</code></pre>
<ul>
<li>벡터 삽입 및 검색이 정상적으로 동작하는지 확인</li>
</ul>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8508f176-162f-47bd-833d-4321b7705edb/image.png" alt=""></p>
<hr>
<h3 id="chromadb-collection">ChromaDB Collection</h3>
<p><strong>벡터 DB Collection = RDB 테이블 = 엑셀 시트…</strong></p>
<ul>
<li><p>Collection은 RDB의 테이블과 같은 역할로 데이터를 저장할 수 있는 저장소</p>
</li>
<li><p>벡터 데이터와 그와 관련된 메타데이터를 논리적으로 그룹화한 데이터 집합</p>
</li>
</ul>
<hr>
<h3 id="구성요소">구성요소</h3>
<p><strong>벡터, 메타데이터, ID = RDB 테이블 컬럼…</strong></p>
<ul>
<li><p><strong>벡터(Vector)</strong>: 컬렉션에 저장되는 고차원 벡터 값, 각 데이터의 임베딩(embedding) 정보</p>
</li>
<li><p><strong>ID</strong>: 각 벡터의 고유한 식별자, 이름 등을 통해 특정 벡터를 조회하거나 업데이트 가능</p>
</li>
<li><p><strong>메타데이터(Metadata)</strong>: 벡터에 추가로 연결된 정보로, JSON 형식의 데이터</p>
<p>  (예: 한국어 위키의 각 제목, 작성자 등)</p>
</li>
<li><p><strong>문서(Document)</strong>: 컬렉션에서 추가적으로 저장되는 문서 형식의 데이터</p>
</li>
<li><p><strong>URI</strong>: 컬렉션에 추가적으로 저장하기 어려운 이미지나 음성 등의 데이터 경로</p>
</li>
</ul>
<hr>
<h3 id="list_collections">list_collections</h3>
<ul>
<li><p><code>client.count_collections()</code></p>
<p>  → Collection 개수 조회</p>
</li>
<li><p><code>client.list_collections()</code></p>
<p>  → Collection 목록 조회</p>
</li>
</ul>
<hr>
<h3 id="delete_collection">delete_collection</h3>
<ul>
<li><p><code>client.delete_collection(name=&quot;height_weight&quot;)</code></p>
<p>  → Collection 삭제</p>
<p>  → 해당 Collection이 존재하지 않으면 오류 발생</p>
</li>
</ul>
<hr>
<h3 id="【-get_or_create_collection-】">【 get_or_create_collection 】</h3>
<pre><code class="language-python">client.get_or_create_collection(
    name=&quot;chroma_tutorial&quot;,
    metadata={
        &quot;hnsw:space&quot;: &quot;cosine&quot;
    }
)</code></pre>
<ul>
<li><p><strong>Collection 생성 또는 조회</strong></p>
<p>  해당 이름의 Collection이 없으면 생성, 있으면 그대로 조회</p>
</li>
<li><p><strong>검색 방식 설정</strong></p>
<p>  <code>&quot;hnsw:space&quot;</code> 옵션을 통해 <code>l2</code>, <code>ip</code>, <code>cosine</code> 등 검색 방법 지정 가능</p>
</li>
</ul>
<hr>
<h3 id="metadatahnswspace-cosine-설명"><code>metadata={&quot;hnsw:space&quot;: &quot;cosine&quot;}</code> 설명</h3>
<p>이 설정은 <strong>HNSW(탐색 알고리즘)</strong>를 사용할 때 어떤 <strong>거리 측정 방식</strong>(search metric)을 사용할지를 지정합니다.</p>
<table>
<thead>
<tr>
<th>값</th>
<th>의미</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>&quot;l2&quot;</code></td>
<td>L2 거리 (유클리드 거리)</td>
<td>두 벡터 간의 직선 거리로, 물리적 거리 기반 비교</td>
</tr>
<tr>
<td><code>&quot;ip&quot;</code></td>
<td>Inner Product (내적)</td>
<td>값이 클수록 유사하다고 판단. 보통 정규화된 벡터에 사용</td>
</tr>
<tr>
<td><code>&quot;cosine&quot;</code></td>
<td>코사인 유사도</td>
<td>각도 기반의 유사도, 값이 클수록 방향이 유사 (0도 → 완전 유사)</td>
</tr>
</tbody></table>
<hr>
<h3 id="【-add-】">【 Add 】</h3>
<pre><code class="language-python">collection.add(
    ids=id_list,
    embeddings=embedding_list,
    metadatas=metadata_list,
    documents=doc_list,
    uris=uri_list
)
</code></pre>
<p>각 인자의 의미:</p>
<ul>
<li><p><code>ids=id_list</code></p>
<p>  → 유일한 구분자. <strong>중복 입력 불가</strong></p>
</li>
<li><p><code>embeddings=embedding_list</code></p>
<p>  → <strong>특정 벡터 목록</strong>. 고차원 임베딩 벡터들을 직접 지정</p>
</li>
<li><p><code>metadatas=metadata_list</code></p>
<p>  → <strong>원본 데이터의 메타데이터</strong>. Dict 형식으로 입력 (예: 출처, 카테고리 등)</p>
</li>
<li><p><code>documents=doc_list</code></p>
<p>  → <strong>특정 벡터를 생성하기 위한 문서 텍스트</strong></p>
</li>
<li><p><code>uris=uri_list</code></p>
<p>  → 이미지, 음성 등과 같이 <strong>컬렉션에 직접 저장하기 어려운 데이터의 경로</strong></p>
</li>
</ul>
<p>이 중 최소한 <code>ids</code>와 <code>documents</code> 또는 <code>embeddings</code>는 필수입니다. 둘 다 없으면 벡터 추가가 불가능합니다.</p>
<hr>
<h3 id="【-get-】">【 GET 】</h3>
<pre><code class="language-python">collection.count()
</code></pre>
<p>→ 데이터 개수 조회</p>
<pre><code class="language-python">collection.get(
    offset=0,              # 데이터 시작 위치
    limit=3,               # 조회할 데이터 개수
    where={&quot;키&quot;: {&quot;$gte&quot;: 170}},           # Metadata 검색 조건
    where_document={&quot;$contains&quot;: &quot;name&quot;}  # Document 검색 조건
)
</code></pre>
<hr>
<h3 id="where-document-조건">Where Document 조건</h3>
<ul>
<li><code>$contains</code> : 문자열 포함</li>
<li><code>$not_contains</code> : 문자열 포함하지 않음</li>
<li><code>$and</code> : and 조건</li>
<li><code>$or</code> : or 조건</li>
</ul>
<hr>
<h3 id="where-조건">Where 조건</h3>
<ul>
<li><code>$eq</code> : 동일 (문자열, 정수, 부동 소수점)</li>
<li><code>$ne</code> : 동일하지 않음</li>
<li><code>$gt</code> : 큼 (정수, 부동 소수점)</li>
<li><code>$gte</code> : 크거나 같음</li>
<li><code>$lt</code> : 작음</li>
<li><code>$lte</code> : 작거나 같음</li>
</ul>
<hr>
<h3 id="【-query-】">【 Query 】</h3>
<pre><code class="language-python">collection.query(
    [183, 78],                          # 유사도를 검색할 특정 벡터
    where={&quot;키&quot;: {&quot;$gte&quot;: 170}},       # Metadata 검색 조건
    where_document=None,               # Document 검색 조건
    n_results=11,                      # 조회할 데이터 개수
    include=[&#39;metadatas&#39;, &#39;embeddings&#39;]  # 검색 결과에 포함시킬 필드
)</code></pre>
<hr>
<h3 id="【-delete-】">【 DELETE 】</h3>
<pre><code class="language-python">collection.delete(
    ids=None,                                     # 삭제할 데이터 ID
    where={&quot;키&quot;: {&quot;$lte&quot;: 170}},                  # 삭제할 Metadata 조건
    where_document={&quot;$contains&quot;: &quot;name&quot;}          # 삭제할 Document 조건
)
</code></pre>
<h3 id="각-인자-설명">각 인자 설명</h3>
<ul>
<li><code>ids</code> : 삭제할 벡터의 ID 목록. <code>None</code>이면 ID 조건 없이 삭제</li>
<li><code>where</code> : 메타데이터를 기준으로 삭제할 조건 지정</li>
<li><code>where_document</code> : 문서 내용을 기준으로 삭제할 조건 지정</li>
</ul>
<p>이 함수는 조건에 일치하는 데이터만 삭제하며, ID, 메타데이터, 문서 중 하나 이상으로 삭제 조건을 줄 수 있습니다.</p>
<hr>
<h2 id="postgresql--pg벡터">PostgreSQL + pg벡터</h2>
<h3 id="1-postgresql-설치">1. PostgreSQL 설치</h3>
<pre><code class="language-bash">sudo apt -y install postgresql
sudo apt -y install postgresql-server-dev-all gcc make
</code></pre>
<h3 id="2-postgresql-실행">2. PostgreSQL 실행</h3>
<pre><code class="language-bash">sudo service postgresql start
</code></pre>
<h3 id="3-관리자-비밀번호-설정">3. 관리자 비밀번호 설정</h3>
<pre><code class="language-bash">sudo -u postgres psql -U postgres -c &quot;ALTER USER postgres PASSWORD &#39;postgres&#39;;&quot;
</code></pre>
<p>위 명령어들은 Ubuntu 등 Debian 기반 리눅스 환경에서 PostgreSQL을 설치하고 기본 설정을 하는 데 사용됩니다.</p>
<hr>
<h3 id="pg벡터-설치-방법">pg벡터 설치 방법</h3>
<h3 id="1-pg벡터란">1. pg벡터란?</h3>
<ul>
<li>PostgreSQL에서 <strong>벡터 검색 기능을 추가해주는 확장 플러그인</strong></li>
<li>벡터 데이터를 저장하고 <strong>유사성 검색</strong> 가능</li>
</ul>
<hr>
<h3 id="2-소스-코드-다운로드-및-설치">2. 소스 코드 다운로드 및 설치</h3>
<pre><code class="language-bash">git clone https://github.com/pgvector/pgvector.git
cd pgvector
make
sudo make install</code></pre>
<hr>
<h3 id="3-pg벡터-플러그인-활성화">3. pg벡터 플러그인 활성화</h3>
<pre><code class="language-sql">CREATE EXTENSION IF NOT EXISTS vector;</code></pre>
<p>위 단계를 따라 하면 PostgreSQL에서 벡터 유사도 검색을 수행할 수 있습니다.</p>
<hr>
<h2 id="벡터-테이블-생성">벡터 테이블 생성</h2>
<h3 id="【-sql-create-table-】">【 SQL: Create Table 】</h3>
<pre><code class="language-sql">CREATE TABLE IF NOT EXISTS height_weight (
    username varchar(64) NOT NULL,     -- 기존 RDB 필드
    height real NOT NULL,
    weight real NOT NULL,
    embedding vector(2) NOT NULL       -- 2차원 벡터를 저장할 수 있는 필드
);</code></pre>
<h3 id="설명">설명</h3>
<ul>
<li><code>username</code>, <code>height</code>, <code>weight</code>는 일반적인 관계형 데이터베이스(RDB) 필드</li>
<li><code>embedding vector(2)</code>는 <strong>pgvector</strong> 확장을 통해 사용 가능한 <strong>2차원 벡터 필드</strong><ul>
<li>예: <code>[180.0, 75.0]</code> 같은 벡터를 저장</li>
</ul>
</li>
</ul>
<hr>
<h3 id="【-sql-insert-】">【 SQL: INSERT 】</h3>
<pre><code class="language-sql">INSERT INTO height_weight VALUES (
    &#39;hong&#39;,           -- 기존 RDB 입력과 동일
    176.7,
    72.2,
    &#39;[176.7, 72.2]&#39;   -- 벡터 입력 형식은 string 형식
);</code></pre>
<h3 id="설명-1">설명</h3>
<ul>
<li><code>username</code>, <code>height</code>, <code>weight</code>는 일반적인 RDB 필드 값</li>
<li><code>embedding</code> 필드에는 <strong>문자열 형태의 벡터</strong>를 입력 (예: <code>&#39;[값1, 값2]&#39;</code>)</li>
<li><code>pgvector</code> 확장을 통해 벡터 형태로 저장됨</li>
</ul>
<hr>
<h3 id="【-sql-select-】">【 SQL: SELECT 】</h3>
<pre><code class="language-sql">SELECT * FROM height_weight
WHERE height &gt; 177
ORDER BY embedding &lt;-&gt; &#39;[183,78]&#39;
LIMIT 11;
</code></pre>
<h3 id="설명-2">설명</h3>
<ul>
<li><p><code>WHERE height &gt; 177</code></p>
<p>  → 기존 RDB 조건과 동일하게 사용 가능</p>
</li>
<li><p><code>ORDER BY embedding &lt;-&gt; &#39;[183,78]&#39;</code></p>
<p>  → <strong>embedding 벡터 필드를 기준으로 유사도 정렬</strong></p>
</li>
</ul>
<h3 id="벡터-유사도-연산자-종류">벡터 유사도 연산자 종류</h3>
<table>
<thead>
<tr>
<th>연산자</th>
<th>의미</th>
</tr>
</thead>
<tbody><tr>
<td><code>&lt;-&gt;</code></td>
<td>L2 거리 (유클리드 거리)</td>
</tr>
<tr>
<td><code>&lt;+&gt;</code></td>
<td>L1 거리 (맨해튼 거리)</td>
</tr>
<tr>
<td><code>&lt;#&gt;</code></td>
<td>Dot-product (내적)</td>
</tr>
<tr>
<td><code>&lt;=&gt;</code></td>
<td>Cosine similarity (코사인 유사도)</td>
</tr>
</tbody></table>
<p>위 쿼리는 pgvector를 사용하는 PostgreSQL에서 <strong>벡터 기반 최근접 이웃(NN) 검색</strong>을 수행하는 대표적인 방식입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터분석 mini project (2) 신약 독성 예측]]></title>
            <link>https://velog.io/@lyj_0316/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-mini-project-2-%EC%8B%A0%EC%95%BD-%EB%8F%85%EC%84%B1-%EC%98%88%EC%B8%A1</link>
            <guid>https://velog.io/@lyj_0316/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-mini-project-2-%EC%8B%A0%EC%95%BD-%EB%8F%85%EC%84%B1-%EC%98%88%EC%B8%A1</guid>
            <pubDate>Fri, 02 May 2025 15:10:56 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>들어가기에 앞서 SMILE 화학식 코드에 대해서 유용한 라이브러리를 알개되었다 <br></p>
</blockquote>
<h2 id="rdkit">RDKit</h2>
<p>RDKit이라는 라이브러리로, SMILES ↔ 분자 객체(Mol) 변환이 가능하며, 다양한 분자 지문(fingerprint), 분자 지표(descriptor) 계산을 할 수 있다.</p>
<pre><code>from rdkit import Chem
mol = Chem.MolFromSmiles(&#39;CCO&#39;)        # SMILES → 분자 객체
smi = Chem.MolToSmiles(mol)            # 분자 객체 → SMILES
fp = Chem.RDKFingerprint(mol)          # 분자 지문 생성</code></pre><pre><code>smiles_list = [
    &#39;CCOc1ccc(CC(=O)O)cc1&#39;,  # 아세트아닐리드 유사
    &#39;CCN(CC)CCOC(=O)c1ccccc1&#39;,  # 베타 차단제 유사
    &#39;C1=CC=C2C(=C1)C=CC=C2&#39;,     # 나프탈렌 (비약물)
]

for mol, smi in zip(mols, smiles_list):
    if mol is None:
        continue
    mw    = Descriptors.ExactMolWt(mol)       # 정확한 분자량
    logp  = Crippen.MolLogP(mol)              # clogP
    qed_s = QED.qed(mol)                      # QED score (0~1)
    results.append((smi, mw, logp, qed_s))</code></pre><p>위의 코드와 같이 스마일 코드를 입력하면, 분자량과 Fingerprint 정보 등을 알 수 있는 유용한 라이브러리이다.</p>
<hr>
<p>데이터 분석을 진행하는 과정에서, 내가 진행했던 코드가 사라져 다른 팀원분들의 코드를 참고하였다.</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/520b14cb-b4b7-4122-bf2c-1350687a4fa5/image.png" alt=""></p>
<p>나의 코드는 위의 이미지와 같이 train에 대해서 0.830 정도의 점수가 나왔지만 테스트에서 0.82 정도로 다소 낮은 점수가 나왔다...</p>
<hr>
<h2 id="데이터-로딩-및-피처-정의">데이터 로딩 및 피처 정의</h2>
<p>환경은 GPU를 사용하기 위해서 구글 코랩을 사용하였다.</p>
<pre><code># 1. 데이터 로딩
train = pd.read_csv(&#39;/content/drive/MyDrive/train.csv&#39;)
test  = pd.read_csv(&#39;/content/drive/MyDrive/predict_input.csv&#39;)

# 2. 피처 정의
feature_cols = [col for col in train.columns if col.startswith((&#39;ecfp_&#39;, &#39;fcfp_&#39;, &#39;ptfp_&#39;))]
meta_cols    = [&#39;MolWt&#39;, &#39;clogp&#39;, &#39;sa_score&#39;, &#39;qed&#39;]</code></pre><p>&#39;ecfp_&#39;, &#39;fcfp_&#39;, &#39;ptfp_&#39; 의 Fingerprint 정보를 별도로 분리하였다.</p>
<pre><code>ecfp_cols = [c for c in feature_cols if c.startswith(&quot;ecfp_&quot;)]
fcfp_cols = [c for c in feature_cols if c.startswith(&quot;fcfp_&quot;)]
ptfp_cols = [c for c in feature_cols if c.startswith(&quot;ptfp_&quot;)]</code></pre><pre><code># 3. 학습 데이터 구성
X_train = train[feature_cols + meta_cols].copy()
X_train[&#39;ecfp_sum&#39;] = train[ecfp_cols].sum(axis=1)
X_train[&#39;fcfp_sum&#39;] = train[fcfp_cols].sum(axis=1)
X_train[&#39;ptfp_sum&#39;] = train[ptfp_cols].sum(axis=1)
y_train = train[&#39;label&#39;]

# 4. 테스트 데이터 구성
X_test = test[feature_cols + meta_cols].copy()
X_test[&#39;ecfp_sum&#39;] = test[ecfp_cols].sum(axis=1)
X_test[&#39;fcfp_sum&#39;] = test[fcfp_cols].sum(axis=1)
X_test[&#39;ptfp_sum&#39;] = test[ptfp_cols].sum(axis=1)</code></pre><p>여기서 좋은 아이디어라고 생각했던 코드인데, 앞서 EDA과정을 통해 fingerprint 데이터가 중요 feature인 점을 확인하였지만, column의 수가 너무 많아 이를 적용하면 모델의 성능이 저하될 위험이 있었다. </p>
<p>위의 코드와 같이 같은 fingerptint 컬럼끼리의 정보를 합친 파생변수를 만들고, 이에 대하여 randomforest의 importance를 구해보았더니 파생변수의 중요도가 매우 높게 나옴을 확인할 수 있었다. </p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/894b871f-1411-4cdd-8bd4-0ad05c7ef7d4/image.PNG" alt=""></p>
<hr>
<pre><code># 5. Train/Validation 분할
X_train, X_val, y_train, y_val = train_test_split(
    X_train, y_train,
    test_size=0.2,
    stratify=y_train,
    random_state=42
)

# 6. SMOTE 오버샘플링
smote = SMOTE(random_state=42)
X_train_over, y_train_over = smote.fit_resample(X_train, y_train)</code></pre><p>해당 데이터는 8300개 가량의 sample을 가지고 있었고 이는 데이터를 학습시키는 데에 굉장히 부족했다. </p>
<p>따라서 SMOTE 방법론을 활용해서 불균형 데이터에 대해서 데이터를 증강시키는 데에 활용하여 모델의 성능을 높이는 참신한 아이디어였다.</p>
<p>기본적으로도 라벨 1에 대한 score가 높이 나왔는데, 해당 방법을 통해서 confusion matrix에 대해 균형을 맞출 수 있었다</p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d511fa05-aac1-4df0-aed4-8c273f3b8125/image.png" alt=""></p>
<p>이에 대하여 다음과 같이 모델을 구축하였고, </p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/da4b831f-d430-4a95-afb3-8abe653ebf8e/image.png" alt=""></p>
<p>해당 코드는 검증용 데이터에서는 0.8218을 테스트 데이터에서는 0.831에 가까운 좋은 성능을 보였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터분석 mini project (1) EDA]]></title>
            <link>https://velog.io/@lyj_0316/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-mini-project-1-EDA</link>
            <guid>https://velog.io/@lyj_0316/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B6%84%EC%84%9D-mini-project-1-EDA</guid>
            <pubDate>Fri, 02 May 2025 14:28:29 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0dd3eefb-3f25-49f7-86d0-ac388c4d3ce2/image.png" alt=""></p>
<p>해당 미니 프로젝트는 실제로 sk 내에서 진행했던 경진대회? 느낌의 프로젝트이다.</p>
<p>위의 표와 같이 데이터는 총 3078개의 Column으로 이루어져 있었고, 데이터의 총 수는 약 8300개 가량이었다. </p>
<blockquote>
<p>데이터의 수가 매우 적으며, 차원의 수가 매우 많은 데이터의 특성을 가짐</p>
</blockquote>
<hr>
<p>아래와 같이 세 개의 표로 정리할 수 있다.</p>
<table>
<thead>
<tr>
<th>구분</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>총 샘플 수 (행)</td>
<td>8,349개</td>
</tr>
<tr>
<td>총 변수 수 (열)</td>
<td>3,078개</td>
</tr>
</tbody></table>
<hr>
<table>
<thead>
<tr>
<th>구분</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>SMILES</td>
<td>분자의 화학 구조를 문자열로 표현한 정보 (문자형 object)</td>
</tr>
<tr>
<td>Fingerprint</td>
<td>ecfp_, fcfp_, ptfp_로 시작하는 이진 벡터 (총 3,072개, 각 1,024개씩)</td>
</tr>
<tr>
<td>특성 변수</td>
<td>MolWt, clogp, sa_score, qed (분자량, 지용성, SA 점수, QED) – 연속형 (float64)</td>
</tr>
<tr>
<td>라벨</td>
<td>label – 예측 대상(예: 독성 여부)로 추정 (int64 또는 범주형)</td>
</tr>
</tbody></table>
<hr>
<table>
<thead>
<tr>
<th>이름</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>ECFP</strong> (Extended Connectivity Fingerprint)</td>
<td>분자의 부분 구조에 대한 정보<br>원자 간 연결관계 기반의 구조적 특징</td>
</tr>
<tr>
<td><strong>FCFP</strong> (Functional-Class Fingerprint)</td>
<td>원자의 기능적 역할에 초점<br>화학적 성질 ·,작용기 기반 기능적 특징</td>
</tr>
<tr>
<td><strong>PTFP</strong> (Pattern Fingerprint)</td>
<td>분자 내 특정 서브패턴의 존재 여부 표현<br>미리 정의된 패턴 유무를 이진 벡터로 표시</td>
</tr>
</tbody></table>
<hr>
<p>2초 동안 생각함</p>
<table>
<thead>
<tr>
<th>이름</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>MolWt</strong> (Molecular Weight)</td>
<td>- 분자를 구성하는 원자 질량의 총합<br>- 값이 클수록 분자가 무거움</td>
</tr>
<tr>
<td><strong>clogP</strong> (LogP)</td>
<td>- 지용성(LogP) 지표<br>- 값이 클수록 지질막 투과성이 높고 흡수가 잘됨</td>
</tr>
<tr>
<td><strong>sa_score</strong> (Synthetic Accessibility Score)</td>
<td>- 분자의 합성 용이성을 1~10 점수로 표현<br>- 점수가 높을수록 합성 난이도 높음</td>
</tr>
<tr>
<td><strong>qed</strong> (Quantitative Estimate of Drug-likeness)</td>
<td>- 약물 유사도 점수 (0~1)<br>- 값이 높을수록 약물처럼 생김, 비독성일 가능성 ↑</td>
</tr>
</tbody></table>
<hr>
<h2 id="1-기초통계분석">1. 기초통계분석</h2>
<h4 id="결측치">결측치</h4>
<pre><code>print(train.isnull().sum().sum())</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/a739a22a-4136-4118-a70a-4e34eb5f3a99/image.png" alt=""></p>
<p>위의 이미지와 같이 결측치는 존재하지 않았다.</p>
<hr>
<h4 id="데이터-정보info--describe">데이터 정보(Info &amp; Describe)</h4>
<p>처음에는 위에서 나왔던 3가지의 Fingerprint 를 제외하고 float 타입의 4가지 컬럼에 집중해서 EDA를 진행하고자 하였다.</p>
<pre><code>print(train.iloc[:, 3073:].info())</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/3ff1f5ef-9e2f-42f1-895f-77e69f90c5fe/image.png" alt=""></p>
<p>인덱싱 과정을 통해서 MolWt, clogp, sa_score, qed 컬럼이 수치형으로 이루어져 있음을 확인할 수 있었다.</p>
<pre><code>print(train.iloc[:, 3073:].describe())</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/d096b201-04ce-4fb8-8237-63d2f9495c8a/image.png" alt=""></p>
<ul>
<li>전체 데이터프레임에서 <strong>수치형 특성 컬럼들만 선택</strong>한 후 요약하였다.</li>
<li>해당 자료는 라벨 별로 확인할 수 없기에 라벨 별로 기초통계량을 구하는 방향으로 진행하였다.</li>
</ul>
<hr>
<h4 id="라벨을-기준으로-컬럼-별-통계평균-표준편차-최솟값-최댓값">라벨을 기준으로 컬럼 별 통계(평균, 표준편차, 최솟값, 최댓값)</h4>
<blockquote>
<p>이상치 탐지 및 예측 모델링을 위해, label(0: 독성, 1: 비독성) 별로,
 주요 수치형 변수(MolWt, clogp, sa_score, qed)의 평균값 분포를 비교하였다.</p>
</blockquote>
<pre><code>agg_result = train.iloc[:, 3073:].groupby(&#39;label&#39;).agg([&#39;mean&#39;, &#39;std&#39;, &#39;min&#39;, &#39;max&#39;])
display(agg_result)</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/74c6604b-d2fc-4f80-84db-1977163d89fe/image.png" alt=""></p>
<hr>
<h4 id="컬럼-별-평균값-시각화">컬럼 별 평균값 시각화</h4>
<pre><code># 평균만 계산
agg_result = train.iloc[:, 3073:].groupby(&#39;label&#39;).mean().reset_index()

# 시각화할 컬럼 목록 (label 제외)
mean_columns = agg_result.columns.drop(&#39;label&#39;)

# 시각화
agg_result.plot(x=&#39;label&#39;, y=mean_columns, kind=&#39;bar&#39;, figsize=(14, 6))
plt.title(&#39;Mean Values of All Numerical Columns by Label&#39;)
plt.ylabel(&#39;mean&#39;)
plt.xlabel(&#39;label&#39;)
plt.xticks(rotation=0)
plt.legend(title=&#39;column&#39;, bbox_to_anchor=(1.05, 1), loc=&#39;upper left&#39;)  # 범례 바깥으로
plt.tight_layout()
plt.show()</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/a9d86c38-576c-4d41-ae0b-6cbba91cee61/image.png" alt=""></p>
<p>MolWt 컬럼의 수치가 커 비교가 쉽지 않았기에, 이를 각 컬럼 별로 다시 시각화하였다.</p>
<hr>
<h4 id="각-컬럼-별-label-간-평균-차이">각 컬럼 별 Label 간 평균 차이</h4>
<pre><code>for col in mean_columns:
    plt.figure(figsize=(6, 4))

    # 막대그래프
    sns.barplot(data=agg_result, x=&#39;label&#39;, y=col, palette=[&#39;#1f77b4&#39;, &#39;#ff7f0e&#39;])

    # 범례 수동 추가
    blue_patch = mpatches.Patch(color=&#39;#1f77b4&#39;, label=&#39;label 0&#39;)
    orange_patch = mpatches.Patch(color=&#39;#ff7f0e&#39;, label=&#39;label 1&#39;)
    plt.legend(handles=[blue_patch, orange_patch],
               title=&#39;Label&#39;,
               loc=&#39;center left&#39;,
               bbox_to_anchor=(1.0, 0.5))  # 오른쪽 바깥에 위치

    # 그래프 설정
    plt.title(f&#39;{col} mean&#39;)
    plt.ylabel(col)
    plt.xlabel(&#39;label&#39;)
    plt.tight_layout()
    plt.show()
</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/a9cc2fb6-f0f3-4b82-8c54-e66c350ad1f3/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/57cf3b65-2134-4630-843a-fd4e9a1f5edf/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/fe09c9a6-96f7-4ec5-8b37-cef48e4547b4/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/04f8b871-867f-454c-ae8f-19b7940f0610/image.png" alt=""></p>
<p>라벨 별로 각 컬럼의 평균값을 비교해 보았을 때, cloup를 제외하고 큰 차이가 없음을 확인할 수 있었다.</p>
<hr>
<pre><code># 컬럼 별 평균값을 표로 출력
print(&quot;Mean Values Table:&quot;)
display(agg_result)</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/3e8db88e-11a0-4398-af0c-1c469fa68bd8/image.png" alt=""></p>
<hr>
<h4 id="컬럼-별-이상치-탐지">컬럼 별 이상치 탐지</h4>
<pre><code>import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches  # 범례용 패치

# Numeric columns only
numeric_cols = train.columns[3073:]

# Boxplot for each column by label
for col in numeric_cols[:-1]:  # 마지막 컬럼 제외
    plt.figure(figsize=(6, 4))

    # Boxplot with custom colors
    sns.boxplot(x=&#39;label&#39;, y=col, data=train, palette={&quot;0&quot;: &#39;#1f77b4&#39;, &quot;1&quot;: &#39;#ff7f0e&#39;})

    # 범례 수동 추가 (오른쪽 바깥으로)
    blue_patch = mpatches.Patch(color=&#39;#1f77b4&#39;, label=&#39;label 0&#39;)
    orange_patch = mpatches.Patch(color=&#39;#ff7f0e&#39;, label=&#39;label 1&#39;)
    plt.legend(handles=[blue_patch, orange_patch], title=&#39;Label&#39;, loc=&#39;center left&#39;, bbox_to_anchor=(1.02, 0.5))

    # 라벨 및 제목 설정
    plt.title(f&#39;{col} - Boxplot by label&#39;)
    plt.xlabel(&#39;label&#39;)
    plt.ylabel(col)
    plt.tight_layout()
    plt.show()
</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/19ee04a7-f5d1-4a74-a960-6ccd93b215f6/image.png" alt=""></p>
<ol>
<li>MolWt (분자량)</li>
</ol>
<ul>
<li>전반적으로 분포 유사</li>
<li><strong>비독성 화합물의 분자량이 약간 더 큼</strong></li>
<li>매우 큰 분자(outlier)는 양쪽 모두 존재</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1b7a0337-a1ad-4deb-bf81-22e44343d746/image.png" alt=""></p>
<ol start="2">
<li>clogp (분배계수)</li>
</ol>
<ul>
<li><strong>독성 있는 화합물의 clogp가 더 높음</strong></li>
<li>일부 label=0은 <strong>8~10 이상 outlier</strong> 존재</li>
<li>clogp는 지용성 → <strong>흡수성, 체내 분포에 영향</strong></li>
</ul>
<blockquote>
<p>차후 target과의 상관관계의 분석 필요성</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/11526c4e-de4b-48e8-817c-a0158250fb44/image.png" alt=""></p>
<ol start="3">
<li>sa_score (합성 용이성 점수)</li>
</ol>
<ul>
<li><strong>label=0이 평균적으로 약간 높음</strong></li>
<li>sa_score는 <strong>1에 가까울수록 합성 쉬움</strong>, <strong>10에 가까우면 어려움</strong></li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1aef251f-343e-49dc-85f9-79e09ef80a5e/image.png" alt=""></p>
<ol start="4">
<li>qed</li>
</ol>
<ul>
<li><strong>label=1 (비독성) 쪽의 qed 값이 더 높음</strong></li>
<li><strong>약물 유사성이 높을수록 비독성일 가능성↑</strong></li>
<li>qed는 <strong>약물로 적합한 분자 구조 유사도</strong>를 나타냄</li>
</ul>
<hr>
<h4 id="컬럼-별-이상치-개수">컬럼 별 이상치 개수</h4>
<pre><code>
# 수치형 컬럼만 선택 (3074번째 이후)
numeric_df = train.iloc[:, 3073:-1]

# 이상치 개수 저장용 딕셔너리
outlier_counts = {}

# 각 컬럼별 이상치 계산 (IQR 기준)
for col in numeric_df.columns:
    Q1 = numeric_df[col].quantile(0.25)
    Q3 = numeric_df[col].quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR

    outlier_count = ((numeric_df[col] &lt; lower) | (numeric_df[col] &gt; upper)).sum()
    outlier_counts[col] = outlier_count

# 결과를 데이터프레임으로 변환
outlier_df = pd.DataFrame(list(outlier_counts.items()), columns=[&#39;column&#39;, &#39;outlier_count&#39;])
outlier_df = outlier_df.sort_values(by=&#39;outlier_count&#39;, ascending=False).reset_index(drop=True)

# 출력
from IPython.display import display
print(&quot;Outlier Count per Column:&quot;)
display(outlier_df)</code></pre><p><img src="https://velog.velcdn.com/images/lyj_0316/post/70d86272-f81c-4829-95e4-e7c52ead8787/image.png" alt=""></p>
<hr>
<h4 id="proportion">proportion</h4>
<p>독성 물질과 비독성 물질의 비율</p>
<blockquote>
<p>label
toxic        0.544017
non-toxic    0.455983
Name: proportion, dtype: float64</p>
</blockquote>
<p>독성 물질(toxic)과 비독성 물질(non-toxic)의 샘플 수가 대체로 균형 있게 분포하고 있다.</p>
<hr>
<h2 id="2-분포-시각화">2. 분포 시각화</h2>
<p>히스토그램, KDE를 통한 분포 시각화.</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/16496f0c-9718-43a3-b7ef-71b1940550c7/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/263e4f2e-7a24-4e76-ada7-5060dd392e65/image.png" alt=""></p>
<p>4개의 column에 대해서 위와 같이 정규분포와 비슷한 형태의 분포가 나왔으며, 라벨별로 차이를 두더라도 큰 차이를 확인하기 힘들었다</p>
<hr>
<h2 id="3-상관관계-분석">3. 상관관계 분석</h2>
<h3 id="상관계수"><strong>상관계수</strong></h3>
<p>3077개의 칼럼 중 대부분이 MoleCular Fingerprint Data와 관련 된 칼럼이고, 4개만이 다른 정보를 담고 있는 칼럼이라, 상대적으로 중요한 정보를 담고 있는 칼럼이라고 생각하고, </p>
<p>우선 독성(label 칼럼에 0,1로 표기됨)과의 상관관계를 뽑아보았다.</p>
<hr>
<h4 id="상관관계-히트맵">상관관계 히트맵</h4>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/bcc81bf0-99f4-4485-848b-937310f4a66c/image.png" alt=""></p>
<hr>
<h4 id="산점도로-개별-관계-시각화">산점도로 개별 관계 시각화</h4>
<p>히트맵에서는 상관계수가 낮아도, 비선형 관계나 분포 차이가 있을 수 있으므로 산점도를 통해 시각적으로 확인</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b775ec5b-389b-4e08-9363-84cd2f19f795/image.png" alt=""></p>
<ul>
<li><p><strong>MolWt(분자량) - qed(약물 유사성)</strong></p>
<p>  분자량이 클수록 약물 유사성(qed)은 낮아지는 경향이 뚜렷하며, 이 영역에 독성 화합물이 더 많이 분포하지만, 독성과 비독성을 명확히 구분짓지는 못함</p>
</li>
<li><p><strong>clogp(분배계수) - qed(약물 유사성)</strong></p>
<p>  일부 높은 clogp, 낮은 qed 조합에서 독성이 다소 많음, 독성 여부와 뚜렷한 구분은 어려움</p>
</li>
<li><p><strong>MolWt(분자량) - clogp(분배계수)</strong></p>
<p>  중간 정도의 양의 상관관계가 있으나, 독성/비독성 간 뚜렷한 구분은 없음</p>
</li>
<li><p><strong>sa_score(합성가능성)</strong></p>
<p>  sa_score는 전반적으로 다른 변수들과 독성 간 구분력이 약하며, 분포 차이가 뚜렷하진 않음</p>
</li>
</ul>
<blockquote>
<p>즉, 처음 생각과는 달리 뒤 4개의 column은 라벨을 결정하는 데에 큰 영향을 주지 못했다.<br></p>
</blockquote>
<ul>
<li>원인(도메인 지식 부족)</li>
</ul>
<p>화학·독성 분야 도메인 지식 없이 “분자량이 크면 독성이 높다” 등 단순 가설에 의존하였고, 분자의 독성 여부는 합성 용이성(sa_score)이나 약물 유사도(qed)만으로 설명하기 어려움이 존재</p>
<ul>
<li>배운 점</li>
</ul>
<p>도메인 전문가의 인사이트 없이 단순 메타 특성만으로는 복잡한 화학·독성 현상을 포착하기 어려움</p>
<p>모델링 전, 각 피처가 실제로 어떤 메커니즘과 연관되는지 충분히 검토해야 함</p>
<p>구조적 fingerprint 정보가 화학 데이터 분석에서 핵심임을 인지하고, 필요시 물리·화학 특성은 보조 피처로 활용할 것</p>
<hr>
<blockquote>
<p>이러한 부분을 느끼고 나서 FingerPrint에 집중하기 시작하였다</p>
</blockquote>
<h3 id="pca-t-sne-umap">PCA, t-SNE, UMAP</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/29206cc9-3681-4bf8-9b4a-dfbfe1f68bfb/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/e8d10a97-2de6-4bea-be35-e19f5eb20e95/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/e4dbb767-d846-4061-8450-a4afcfdfa40d/image.png" alt=""></p>
<p>Fingerprint 데이터를 2차원으로 차원 축소</p>
<ul>
<li><strong>PCA (Principal Component Analysis):</strong><ul>
<li><code>PCA</code> 모델을 생성하고, 스케일링된 Fingerprint 데이터를 2개의 주성분으로 차원 축소 .(<code>fit_transform</code>).</li>
<li>축소된 2차원 데이터를 <code>visualize_embedding</code> 함수를 사용하여 <code>label</code>에 따라 색깔을 구분하여 산점도로 시각화.</li>
<li>첫 번째와 두 번째 주성분이 설명하는 분산 비율을 출력하여 전체 데이터의 구조를 얼마나 잘 보존하고 있는지 확인하였다.</li>
</ul>
</li>
<li><strong>t-SNE (t-distributed Stochastic Neighbor Embedding):</strong><ul>
<li><code>TSNE</code> 모델을 생성하고, 스케일링된 Fingerprint 데이터를 2차원으로 비선형 차원 축소 (<code>fit_transform</code>). <code>perplexity</code>와 <code>n_iter</code> 등의 파라미터가 설정됨.</li>
<li>축소된 2차원 데이터를 <code>visualize_embedding</code> 함수를 사용하여 시각화.</li>
</ul>
</li>
<li><strong>UMAP (Uniform Manifold Approximation and Projection):</strong><ul>
<li><code>umap.UMAP</code> 모델을 생성하고, 스케일링된 Fingerprint 데이터를 2차원으로 비선형 차원 축소. (<code>fit_transform</code>). <code>n_neighbors</code>와 <code>min_dist</code> 등의 파라미터가 설정됨.</li>
<li>축소된 2차원 데이터를 <code>visualize_embedding</code> 함수를 사용하여 시각화.</li>
</ul>
</li>
</ul>
<h3 id="결론">결론</h3>
<p>⇒ 뚜렷한 군집은 보이지 않음</p>
<hr>
<h4 id="finger-print-종류별-umap-분석-결과">Finger Print 종류별 UMAP 분석 결과</h4>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/05f31c01-6b1e-4faf-9503-251380c29e85/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/ca84bc0c-3a56-4e58-95b6-7321904b722a/image.png" alt="">
<img src="https://velog.velcdn.com/images/lyj_0316/post/2b560b65-d463-418b-bcdf-c69e1f81dd14/image.png" alt=""></p>
<table>
<thead>
<tr>
<th>Fingerprint 유형</th>
<th>시각적 분포</th>
<th>해석</th>
</tr>
</thead>
<tbody><tr>
<td><strong>ECFP</strong></td>
<td>중앙 밀집, 색상 섞여 있음</td>
<td>독성/비독성 화합물이 <strong>혼합된 클러스터</strong>를 형성 → <strong>구분 어려움</strong></td>
</tr>
<tr>
<td><strong>FCFP</strong></td>
<td>ECFP와 매우 유사한 패턴</td>
<td>마찬가지로 <strong>독성 여부에 따른 뚜렷한 군집 없음</strong></td>
</tr>
<tr>
<td><strong>PTFP</strong></td>
<td>상대적으로 중앙 집중, 바깥에 분산된 소수 점들</td>
<td>약간 더 <strong>희미한 구분 가능성</strong>이 보이지만 여전히 뚜렷하지 않음</td>
</tr>
</tbody></table>
<hr>
<h4 id="각-fingerprint-feature에-대한-독성-비율">각 Fingerprint Feature에 대한 독성 비율</h4>
<h5 id="구조의-존재에-따른-독성-영향-하위-20">구조의 존재에 따른 독성 영향 하위 20</h5>
<table>
<thead>
<tr>
<th>Index</th>
<th>Feature</th>
<th>Total Count</th>
<th>non-Toxic Count</th>
<th>non-Toxic Ratio</th>
</tr>
</thead>
<tbody><tr>
<td>1902</td>
<td>fcfp_878</td>
<td>64</td>
<td>59</td>
<td>0.9219</td>
</tr>
<tr>
<td>1144</td>
<td>fcfp_120</td>
<td>12</td>
<td>11</td>
<td>0.9167</td>
</tr>
<tr>
<td>1242</td>
<td>fcfp_218</td>
<td>22</td>
<td>20</td>
<td>0.9091</td>
</tr>
<tr>
<td>1134</td>
<td>fcfp_110</td>
<td>195</td>
<td>177</td>
<td>0.9077</td>
</tr>
<tr>
<td>1127</td>
<td>fcfp_103</td>
<td>56</td>
<td>50</td>
<td>0.8929</td>
</tr>
<tr>
<td>1346</td>
<td>fcfp_322</td>
<td>223</td>
<td>199</td>
<td>0.8924</td>
</tr>
<tr>
<td>1069</td>
<td>fcfp_45</td>
<td>65</td>
<td>58</td>
<td>0.8923</td>
</tr>
<tr>
<td>1873</td>
<td>fcfp_849</td>
<td>36</td>
<td>32</td>
<td>0.8889</td>
</tr>
<tr>
<td>1225</td>
<td>fcfp_201</td>
<td>17</td>
<td>15</td>
<td>0.8824</td>
</tr>
<tr>
<td>1549</td>
<td>fcfp_525</td>
<td>108</td>
<td>95</td>
<td>0.8796</td>
</tr>
<tr>
<td>1835</td>
<td>fcfp_811</td>
<td>113</td>
<td>99</td>
<td>0.8761</td>
</tr>
<tr>
<td>663</td>
<td>ecfp_663</td>
<td>205</td>
<td>178</td>
<td>0.8683</td>
</tr>
<tr>
<td>2961</td>
<td>ptfp_913</td>
<td>91</td>
<td>79</td>
<td>0.8681</td>
</tr>
<tr>
<td>1408</td>
<td>fcfp_384</td>
<td>30</td>
<td>26</td>
<td>0.8667</td>
</tr>
<tr>
<td>1091</td>
<td>fcfp_67</td>
<td>132</td>
<td>114</td>
<td>0.8636</td>
</tr>
<tr>
<td>1449</td>
<td>fcfp_425</td>
<td>71</td>
<td>61</td>
<td>0.8592</td>
</tr>
<tr>
<td>553</td>
<td>ecfp_553</td>
<td>211</td>
<td>181</td>
<td>0.8578</td>
</tr>
<tr>
<td>1320</td>
<td>fcfp_296</td>
<td>14</td>
<td>12</td>
<td>0.8571</td>
</tr>
<tr>
<td>2805</td>
<td>ptfp_757</td>
<td>28</td>
<td>24</td>
<td>0.8571</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/25ba3984-ad36-495f-81d1-53fcdd78fd3a/image.png" alt=""></p>
<hr>
<h5 id="구조의-존재에-따른-독성-영향-상위-20">구조의 존재에 따른 독성 영향 상위 20</h5>
<table>
<thead>
<tr>
<th>Index</th>
<th>Feature</th>
<th>Total Count</th>
<th>non-Toxic Count</th>
<th>non-Toxic Ratio</th>
</tr>
</thead>
<tbody><tr>
<td>1538</td>
<td>fcfp_514</td>
<td>73</td>
<td>3</td>
<td>0.0411</td>
</tr>
<tr>
<td>1295</td>
<td>fcfp_271</td>
<td>11</td>
<td>1</td>
<td>0.0909</td>
</tr>
<tr>
<td>1469</td>
<td>fcfp_445</td>
<td>275</td>
<td>30</td>
<td>0.1091</td>
</tr>
<tr>
<td>1170</td>
<td>fcfp_146</td>
<td>348</td>
<td>39</td>
<td>0.1121</td>
</tr>
<tr>
<td>1804</td>
<td>fcfp_780</td>
<td>87</td>
<td>16</td>
<td>0.1839</td>
</tr>
<tr>
<td>425</td>
<td>ecfp_425</td>
<td>455</td>
<td>88</td>
<td>0.1934</td>
</tr>
<tr>
<td>1550</td>
<td>fcfp_526</td>
<td>422</td>
<td>82</td>
<td>0.1943</td>
</tr>
<tr>
<td>1774</td>
<td>fcfp_750</td>
<td>40</td>
<td>8</td>
<td>0.2000</td>
</tr>
<tr>
<td>2553</td>
<td>ptfp_505</td>
<td>453</td>
<td>96</td>
<td>0.2119</td>
</tr>
<tr>
<td>1093</td>
<td>fcfp_69</td>
<td>27</td>
<td>6</td>
<td>0.2222</td>
</tr>
<tr>
<td>2332</td>
<td>ptfp_284</td>
<td>501</td>
<td>112</td>
<td>0.2236</td>
</tr>
<tr>
<td>1762</td>
<td>fcfp_738</td>
<td>40</td>
<td>9</td>
<td>0.2250</td>
</tr>
<tr>
<td>765</td>
<td>ecfp_765</td>
<td>474</td>
<td>107</td>
<td>0.2257</td>
</tr>
<tr>
<td>1317</td>
<td>fcfp_293</td>
<td>109</td>
<td>25</td>
<td>0.2294</td>
</tr>
<tr>
<td>1054</td>
<td>fcfp_30</td>
<td>106</td>
<td>25</td>
<td>0.2358</td>
</tr>
<tr>
<td>1514</td>
<td>fcfp_490</td>
<td>450</td>
<td>108</td>
<td>0.2400</td>
</tr>
<tr>
<td>1167</td>
<td>fcfp_143</td>
<td>404</td>
<td>97</td>
<td>0.2401</td>
</tr>
<tr>
<td>1627</td>
<td>fcfp_603</td>
<td>41</td>
<td>10</td>
<td>0.2439</td>
</tr>
<tr>
<td>2424</td>
<td>ptfp_376</td>
<td>583</td>
<td>143</td>
<td>0.2453</td>
</tr>
<tr>
<td>158</td>
<td>ecfp_158</td>
<td>530</td>
<td>132</td>
<td>0.2491</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b38eb79c-5ac9-4a23-b0d1-d26c58ba4166/image.png" alt=""></p>
<hr>
<h2 id="결론-1">결론</h2>
<p>이번 분석에서는 화합물의 독성 여부와 분자 특성 간의 관계를 탐색하였다.</p>
<p><code>MolWt</code>, <code>clogp</code>, <code>sa_score</code>, <code>qed</code> 네 가지 변수에 대해 KDE plot과 boxplot 등을 통해 분포를 비교하였으나, 독성 여부를 명확히 구분할 수 있는 뚜렷한 경향은 발견되지 않았다.</p>
<p>반면, fingerprint feature를 기준으로 분석한 결과, 특정 구조가 독성 화합물에서 매우 높은 비율로 등장하거나 거의 등장하지 않는 등, 독성과의 강한 상관성을 보이는 feature들이 다수 확인되었다.</p>
<p>결론적으로 수치형 특성보다는 fingerprint 기반 구조 정보가 독성 예측에 훨씬 유의미하므로, 향후 분석과 모델링은 <strong>fingerprint 중심으로 진행</strong>하는 것이 바람직하다고 판단된다.</p>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[쿠버네티스 심화]]></title>
            <link>https://velog.io/@lyj_0316/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EC%8B%AC%ED%99%94</link>
            <guid>https://velog.io/@lyj_0316/%EC%BF%A0%EB%B2%84%EB%84%A4%ED%8B%B0%EC%8A%A4-%EC%8B%AC%ED%99%94</guid>
            <pubDate>Wed, 23 Apr 2025 10:11:10 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>목표:  자신의 애플리케이션 프로그램을 Kubernetes 환경에 배포해서 운영 가능하도록 구성</p>
</blockquote>
<ul>
<li>경로를 변환</li>
</ul>
<pre><code class="language-powershell">cd shared-dir/collaboration </code></pre>
<ul>
<li>원격에 있는 파일을 local로 copy</li>
</ul>
<pre><code class="language-powershell">remote-cp -rf ./cloud  /config/workspace</code></pre>
<pre><code class="language-powershell">remote-cp -rf ./k8s-rbac  /config/workspace</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/47552ec0-48de-4dde-bbbc-9c6511d7ecb5/image.png" alt=""></p>
<pre><code class="language-powershell">ls -al</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0b77d239-0698-4e2b-b072-328beb9df3db/image.png" alt=""></p>
<blockquote>
<p>만약 workspace의 user가 root인 경우</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/66bd840b-fc47-4e03-8186-3a6ffd0cf702/image.png" alt=""></p>
<pre><code class="language-powershell">sudo chown -R 911:911</code></pre>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody><tr>
<td><code>-R</code></td>
<td><strong>재귀적(recursively)</strong> 변경 — 디렉토리일 경우 하위 모든 파일과 폴더 포함</td>
</tr>
<tr>
<td><code>911:911</code></td>
<td>소유자 ID(uid): 911, 그룹 ID(gid): 911 로 설정</td>
</tr>
</tbody></table>
<pre><code class="language-powershell">sudo chown -R 911:911 ./workspace</code></pre>
<p>해당 코드로 user를 변경</p>
<hr>
<h1 id="accounts">Accounts</h1>
<p>쿠버네티스 API server에 접속하는 주체(Subject)를 의미</p>
<h3 id="serviceaccount">ServiceAccount</h3>
<ul>
<li><p>Pod 또는 외부 서비스가 클러스터 리소스에 접근할 수 있게 해주는 K8s <strong>내장 계정</strong></p>
</li>
<li><p><strong>시스템 간 인증</strong>을 위한 계정</p>
</li>
<li><p>K8s <strong>리소스로 Namespace 안에 생성</strong></p>
</li>
<li><p>Pod 생성 시 <strong>default ServiceAccount가 자동 연결</strong></p>
</li>
</ul>
<hr>
<h3 id="user">User</h3>
<ul>
<li><p>사람이(Human) 사용하는 계정</p>
</li>
<li><p><code>kubectl CLI</code>, <code>k8s Dashboard</code>, 또는 API를 <strong>직접 호출</strong>해서 사용</p>
</li>
<li><p>K8s 자체에서는 <strong>미지원</strong>, <strong>외부 시스템과 연동</strong> 필요</p>
<p>  예: OIDC, x509 인증서, SSO, <code>alice@example.com</code>, <code>devops-admin</code></p>
</li>
</ul>
<hr>
<h3 id="group">Group</h3>
<ul>
<li><p>여러 User를 묶는 <strong>논리적 단위</strong></p>
</li>
<li><p>K8s 자체에서는 <strong>미지원</strong>, <strong>외부 시스템과 연동</strong> 필요</p>
</li>
</ul>
<hr>
<h2 id="service-account-중심-계정-관리">Service Account 중심 계정 관리</h2>
<p>kubernete 내에서는 다음과 같은 이유로 Service Account 중심으로 사용하며 User 와 User Group은 잘 사용하지 않음</p>
<blockquote>
<p>계정은 단순히 사용자를 구분하는 용도</p>
</blockquote>
<ol>
<li><p>Kubernetes가 직접 User/Group을 관리 미지원</p>
<ul>
<li><p>외부 인증 연동이 필요하며, 구성과 운영이 복잡</p>
</li>
<li><p>관리 포인트 증가</p>
</li>
</ul>
</li>
<li><p>자동화 환경에서는 사람이 직접 API를 호출하는 경우가 거의 없음</p>
<ul>
<li><p>대부분 앱이나 컨트롤러(예: ArgoCD, Tekton, Jenkins 등)가 자동으로 실행</p>
</li>
<li><p>자동화 앱이나 컨트롤러는 Pod로 동작하므로 ServiceAccount가 적합</p>
</li>
<li><p>kubectl 등을 활용한 접근 역시 Service Account로 생성해서 실행 가능</p>
</li>
</ul>
</li>
<li><p>RBAC이 ServiceAccount에 최적화되어 있음</p>
<ul>
<li><p>RoleBinding, ClusterRoleBinding 등에서 명확하게 ServiceAccount를 지정</p>
</li>
<li><p>Namespace 단위로 권한을 잘게 쪼개어 관리하기 용이</p>
</li>
</ul>
</li>
</ol>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/bc73a303-1644-4b85-b88a-c5cc2fab2cc4/image.png" alt=""></p>
<blockquote>
<p><strong>ServiceAccount</strong> 는 쿠버네티스 클러스터 내부에서 Pod나 서비스가 <strong>API 서버에 인증된 방식으로 접근할 수 있도록</strong> 만들어진 계정.</p>
<p>이를 위해 <strong>인증 수단</strong>으로 <strong>JWT(JSON Web Token)</strong> 형태의 <strong>ServiceAccount 토큰</strong>이 사용</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/4493aca4-9883-4288-88ac-8dd91dee4420/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/281188ee-c0b1-4ab5-88ab-8ba4eb03cda4/image.png" alt=""></p>
<pre><code class="language-powershell">k get sa</code></pre>
<ul>
<li><strong>default</strong></li>
</ul>
<p>자기 네임스페이스에 대한 접근 권한을 가질 수 있음</p>
<hr>
<h2 id="service-account-기반-api-server-통신-방식">Service Account 기반 API server 통신 방식</h2>
<ul>
<li><p>Service Account는 Token 발행을 위해 동일 이름을 자동 생성, 1.24 이후 버전에서는 수동 연결해서 Token 발행</p>
</li>
<li><p>Pod가 Service Acount 연결 시 아래 디렉토리에 token, ca.crt, namespace 파일 생성</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/09aa5d3a-4589-427a-a35c-fc5e2f8f2fd6/image.png" alt=""></p>
<h3 id="토큰-적용-순서">토큰 적용 순서</h3>
<ol>
<li><p>KubeConfig 환경변수 설정</p>
<p> config에 있는 토큰 값을 가져와서 담음</p>
</li>
<li><p>자기 홈 디렉토리 내 config에 있는 토큰을 가져옴</p>
</li>
<li><p>/var/run/…/serviceaccount 경로의 토큰을 가져옴</p>
</li>
</ol>
<hr>
<h2 id="실습-mounted-service-account-확인하기">[실습] mounted service account 확인하기</h2>
<pre><code class="language-powershell">kubectl get pod -n skala-practice</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/3d6d6cbc-9746-4ff3-8c82-8b7e0a8e0de5/image.png" alt=""></p>
<pre><code class="language-powershell">k exec -it collabo-shared-sts-0 -- /bin/bash</code></pre>
<p><strong>collabo-shared-sts-0</strong> Pod에 접속해서 bash 셸로 들어갈 수 있음.</p>
<pre><code class="language-powershell">cd /var/run/secrets/kubernetes.io/serviceaccount

ls</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/accea529-bf3d-4bd3-b09e-9f40c80696bc/image.png" alt=""></p>
<blockquote>
<p>ctrl d로 나갈 수 있음</p>
</blockquote>
<hr>
<h1 id="role-base-acess-control-rbac">Role-Base Acess Control (RBAC)</h1>
<h2 id="rbac-role-baed-access-control의-목적">RBAC (Role-baed Access Control)의 목적</h2>
<p>Kubernetes는 모든 리소스에 대한 처리는 <strong>kube API Server</strong> + <strong>ETCD Resource</strong> 에 대한 접근</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/2f0d75a4-f06c-497d-9a1b-5df75f0ce85b/image.png" alt=""></p>
<blockquote>
<p>모든 Action에 대해서 API Server를 활용해야 하므로, 통신을 위해선 <strong>RBAC</strong>을 사용해야 함</p>
</blockquote>
<hr>
<h2 id="rbac-role-baed-access-control">RBAC (Role-baed Access Control)</h2>
<p>역할 기반 접근 제어 (RBAC)는 사용자가 직접 권한을 받는 것이 아니라, 역할(Role)을 통해 접근 권한을 조절하는 방법</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/2e60200d-bb2e-4519-9c19-93f23cfadde2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/f404a32f-0b33-4f9c-abb6-85facb1bac35/image.png" alt=""></p>
<p><strong>ServiceAccount <code>skala-admin-sa</code>가 <code>namespace</code> 리소스를 조회할 권한이 없어서</strong> 생긴 문제</p>
<ul>
<li>skala-practice 네임스페이스 안의 skala-admin-sa 라는 ServiceAccount가 <strong>클러스터 수준(cluster scope)의 <code>namespaces</code> 리소스를 조회할 권한이 없음</strong></li>
</ul>
<hr>
<h2 id="role-정의">Role 정의</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1b3e8fea-11c5-4315-8cd9-c2854e10d14f/image.png" alt=""></p>
<p>api 그룹에 대한 path 내용도 담고 있음</p>
<ul>
<li>verbs: 어떤 권한을 줄 지를 표시</li>
</ul>
<p>⇒ Role은 namespace가 존재함</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/870a661e-d584-434b-a242-32eb80f48206/image.png" alt=""></p>
<p>⇒ ClusterRole은 namespace가 존재하지 X</p>
<hr>
<h3 id="role의-rules">Role의 Rules</h3>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0ce9049f-677f-4b1f-9c13-3f5d1d182722/image.png" alt=""></p>
<h2 id="rules-필드-설명-rbac-권한-설정"><code>rules</code> 필드 설명 (RBAC 권한 설정)</h2>
<p>RBAC의 <code>rules</code> 필드는 <code>Role</code> 또는 <code>ClusterRole</code> 안에서 사용되며, 권한을 정의합니다.</p>
<table>
<thead>
<tr>
<th>필드 이름</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>apiGroups</code></td>
<td>리소스가 속한 <strong>API 그룹</strong> 지정예: <code>&quot;&quot;</code>(core), <code>apps</code>, <code>rbac.authorization.k8s.io</code> 등</td>
</tr>
<tr>
<td><code>resources</code></td>
<td>권한을 부여할 <strong>리소스 종류</strong>예: <code>pods</code>, <code>deployments</code>, <code>configmaps</code></td>
</tr>
<tr>
<td><code>verbs</code></td>
<td>허용할 <strong>동작(행위)</strong>예: <code>get</code>, <code>list</code>, <code>watch</code>, <code>create</code>, <code>delete</code>, <code>update</code> 등</td>
</tr>
<tr>
<td><code>resourceNames</code></td>
<td>(선택) <strong>특정 리소스 이름에만 제한</strong>예: <code>[&quot;my-secret&quot;, &quot;my-pod&quot;]</code></td>
</tr>
<tr>
<td><code>nonResourceURLs</code></td>
<td>(선택) API 외부 URL 경로에 대한 권한 (예: <code>/metrics</code>, <code>/healthz</code>)→ <strong>보통 ClusterRole에서 사용</strong></td>
</tr>
</tbody></table>
<hr>
<h2 id="kubectl-api-resources-명령어-예시"><code>kubectl api-resources</code> 명령어 예시</h2>
<pre><code class="language-bash">kubectl api-resources</code></pre>
<p>이 명령어는 <strong>Kubernetes 클러스터에서 사용 가능한 모든 API 리소스 목록</strong>을 보여줍니다.</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/c532c9f9-3b38-4c7b-a2c8-b1238b663cc1/image.png" alt=""></p>
<table>
<thead>
<tr>
<th>필드</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><code>NAME</code></td>
<td>리소스 이름 (예: <code>pods</code>, <code>deployments</code>)</td>
</tr>
<tr>
<td><code>SHORTNAMES</code></td>
<td>줄임말 (예: <code>po</code> for pods, <code>deploy</code> for deployments)</td>
</tr>
<tr>
<td><code>APIGROUP</code></td>
<td>리소스가 속한 API 그룹<code>&quot;&quot;</code>이면 core API group</td>
</tr>
<tr>
<td><code>NAMESPACED</code></td>
<td>해당 리소스가 Namespace에 종속적인지 여부 (<code>true</code> or <code>false</code>)</td>
</tr>
</tbody></table>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/f8bb8e28-111b-4e86-ad87-1d0931f9fc8c/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b66cc81c-6dca-4eca-a8fd-7c724d84b432/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d903022d-fdbe-47c4-8177-ec7d6ccad33c/image.png" alt=""></p>
<pre><code class="language-powershell">k get sa
k get secret</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/9152c251-0f15-4602-94b4-0b975de6d920/image.png" alt=""></p>
<pre><code class="language-powershell">k get secret skala-admin-sa-token -o yaml</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e58b0c70-1974-464c-a2b5-71050199cdb3/image.png" alt=""></p>
<p><strong><code>skala-admin-sa-token</code></strong>이라는 이름의 시크릿(Secret) 리소스를 YAML 형식으로 출력</p>
<pre><code class="language-powershell">k get pod</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/5b51189c-8602-480c-95ab-7e98e9f38b01/image.png" alt=""></p>
<p>쿠버네티스(Kubernetes)에서 파드(Pod)의 목록과 상태를 조회하는 명령어</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/7fb8b949-8a96-4f38-87d6-8b524c2842c6/image.png" alt=""></p>
<pre><code class="language-yaml">apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  labels:
    amdp.io/app: skala25a-stock-api-wamdp
    amdp.io/profile: skala.skala-a
    argocd.argoproj.io/instance: skala25a-stock-api-wamdp.skala-a.skala
    cluster-tier: dev
  name: skala25a-stock-api-wamdp-pod-reader-skala-a
  namespace: skala-practice
rules:
- apiGroups:
  - &quot;&quot;
  resources:
  - pods
  - configmaps
  verbs:
  - get
  - watch
  - list # 목록을 볼 수 있음</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b285bffa-fb66-4819-96bd-28e572069583/image.png" alt=""></p>
<pre><code class="language-powershell">k get clusterrole admin -o yaml</code></pre>
<p>쿠버네티스 클러스터 내에 정의된 <strong><code>admin</code></strong>이라는 이름의 ClusterRole의 상세 정보를 YAML 형식으로 출력</p>
<pre><code class="language-powershell">k get --raw /metrics</code></pre>
<p>쿠버네티스 API 서버 또는 각 컴포넌트(예: kubelet, kube-scheduler, kube-controller-manager 등)가 노출하는 <em>Prometheus 형식의 시스템 메트릭</em>을 그대로 출력</p>
<hr>
<pre><code class="language-powershell">(RDE) &gt; kcns skala-argocd 
Context &quot;skala-edu-cluster&quot; modified.</code></pre>
<p><strong>쿠버네티스 환경에서 현재 작업 중인 네임스페이스를 <code>skala-argocd</code>로 전환하는 역할</strong></p>
<p>(= kubectl config set-context --current --namespace=skala-argocd)</p>
<hr>
<h1 id="namespace">Namespace</h1>
<blockquote>
<p>Namespace는 Kubernetes 클러스터 안에서 리소스들을 논리적으로 분리해주는 가상 공간.</p>
</blockquote>
<p>특정 리소스 자원을 나눠주는, 리소스를 각각의 분리된 영역으로 나누기 좋은 방법</p>
<p>(명시적 분리)</p>
<ul>
<li><p>여러 네임스페이스를 사용하면 복잡한 쿠버네티스 시스템을 더 작은 그룹으로 분할</p>
</li>
<li><p>멀티 테넌트(Multi-tenant) 환경을 분리하여 리소스를 생산, 개발, QA 환경 등으로 사용</p>
</li>
<li><p>리소스 이름은 네임스페이스 내에서만 고유 명칭 사용</p>
</li>
<li><p>현재 클러스터의 기본 네임스페이스 확인하기</p>
</li>
</ul>
<blockquote>
<p><strong>테넌트</strong>
: <strong>클라우드 인프라/서비스</strong> 제공 방식에서 소프트웨어 인스턴스(Software <strong>Instance)를</strong> 공유하는 <strong>사용자</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/81507937-ee33-4e31-82fa-73cf06a2f0fd/image.png" alt=""></p>
<blockquote>
<p>Namespace는 <strong>Kubernetes 리소스를 논리적으로 나누고 관리하는 컨테이너</strong> 역할을 하며, <strong>자원 분리와 보안, 조직화</strong>에 매우 유용</p>
</blockquote>
<hr>
<pre><code class="language-powershell">kubectlget pod -A. (full argument: --all-namespaces)</code></pre>
<p>전체 네임스페이스를 대상으로 kubectl을 실행하는 방법</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/de95c144-5c19-42bd-8ed0-f37d3e17226f/image.png" alt=""></p>
<hr>
<h1 id="pod">Pod</h1>
<p>Kubernetes는 Pod 단위로 라이프사이클을 관리하며, 컨테이너는 직접적인 관리를 하지 않는다</p>
<ul>
<li><p>컨테이너의 공동 배포된 그룹이며 쿠버네티스의 기본 빌딩 블록을 대표</p>
</li>
<li><p>쿠버네티스는 컨테이너를 개별적으로 배포하지 않고 컨테이너의 포드를 항상 배포하고 운영</p>
</li>
<li><p>일반적으로 포드는 단일 컨테이너만 포함하지만 다수의 컨테이너를 포함 할 수 있음</p>
</li>
<li><p>포드는 다수의 노드에 생성되지 않고 단일 노드에서만 실행</p>
</li>
<li><p>여러 프로세스를 실행하기 위해서는 컨테이너 당 단일 프로세스가 적합</p>
</li>
<li><p>다수의 프로세스를 제어하려면? -&gt; 다수의 컨테이너를 다룰 수 있는 그룹이 필요!</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/7c1d82e9-4259-4d32-8402-138295a681fc/image.png" alt=""></p>
<blockquote>
<p>컨테이너는 보통 하나의 Pod 안에서 함께 실행되며, <strong>같은 네트워크(IP), 같은 저장소(Volume)</strong>를 공유합니다.</p>
</blockquote>
<table>
<thead>
<tr>
<th>항목</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td><strong>같이 스케줄링</strong></td>
<td>Pod 안의 모든 컨테이너는 <strong>같은 노드에 같이 배치됨</strong></td>
</tr>
<tr>
<td><strong>같은 네트워크</strong></td>
<td>Pod 안의 컨테이너들은 <strong>같은 localhost(127.0.0.1)</strong> 로 통신 가능</td>
</tr>
<tr>
<td><strong>같은 Volume 사용 가능</strong></td>
<td>공유 볼륨으로 파일을 공유할 수 있음</td>
</tr>
<tr>
<td><strong>보통 하나의 컨테이너만 포함</strong></td>
<td>대부분 1 컨테이너 = 1 Pod (sidecar 쓰는 경우 제외)</td>
</tr>
</tbody></table>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/c672dda0-6d0c-4a7b-a64b-3577f415bce5/image.png" alt=""></p>
<h3 id="장점">장점</h3>
<ul>
<li><p>포드는 밀접하게 연관된 프로세스를 함께 실행하고 마치 하나의 환경에서 동작하는 것처럼 보임</p>
</li>
<li><p>그러나 동일한 환경을 제공하면서 다소 격리된 상태로 유지</p>
</li>
</ul>
<h3 id="동일한-포드의-컨테이너-사이의-부분-격리">동일한 포드의 컨테이너 사이의 부분 격리</h3>
<p>포드의 모든 컨테이너는 동일한 네트워크 및 리눅스 네임스페이스에서 실행</p>
<p>같은 호스트 이름 및 네트워크 인터페이스를 공유 (포트 충돌 가능성 있음)</p>
<p>포드의 모든 컨테이너는 동일한 IPC 네임스페이스 아래에서 실행되며 IPC를 통해 통신 가능</p>
<hr>
<h2 id="pod-네트워크-구조">POD 네트워크 구조</h2>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/15419fd6-253f-4ae5-bb6f-4f0de4546f29/image.png" alt=""></p>
<h3 id="plat-inter-pod-네트워크-구조">Plat Inter-Pod 네트워크 구조</h3>
<ul>
<li><p>쿠버네티스 클러스터의 모든 포드는 공유된 단일 플랫, 네트워크 주소 공간에 위치</p>
</li>
<li><p>파드 사이에는 NAT 게이트웨이가 존재 하지 않음</p>
<p>  ⇒ 모든 Pod는 고유한 IP를 갖고 있고, 클러스터 내부에서는 NAT 없이 직접 통신이 가능.</p>
</li>
<li><p>파드내 컨테이너 간 통신은 local host 기반을 통신하면 모든 자원을 공유</p>
</li>
</ul>
<hr>
<h3 id="pod-내-컨테이너-구성-방법">POD 내 컨테이너 구성 방법</h3>
<p>컨테이너를 포드 전체에 적절하게 구성하는 방법</p>
<ul>
<li><p>다수의 포드로 멀티티어 애플리케이션 분할하기</p>
</li>
<li><p>각각 스케일링이 가능한 포드로 분할하기</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/bcfb436c-ffa8-4939-8a63-921edd2edac0/image.png" alt=""></p>
<blockquote>
<p>front/back 단을 병렬로 띄우기 위해선 나누어서 구성</p>
</blockquote>
<p>: 둘 간의 communication 과정을 보고 결정하지만, 보통 main process는 나누어서 구성</p>
<hr>
<h3 id="port-forward">port-forward</h3>
<p>컨테이너에서 호스트로 포트 포워딩, <strong>로컬 PC ↔ 클러스터 내부 리소스</strong> 간에 직접 연결하는 유용한 디버깅 도구</p>
<ul>
<li><p>디버깅 혹은 다른 이유로 서비스를 거치지 않고 특정 포드와 통신하고 싶을 때 사용</p>
</li>
<li><p>kubectlport-forward 명령으로 수행</p>
</li>
<li><p>컨테이너 8888 포트를 pod의 8080 포트로 전달</p>
</li>
</ul>
<blockquote>
<p>Multi-Pod에 Port-forward 시 개별 IP</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/1c33631d-5ce1-4083-af3d-f30ee9774103/image.png" alt=""></p>
<pre><code class="language-powershell">kubectl port-forward pod/webserver-pod 8888:8080 –n {namespace}

bg

curl localhost:8888</code></pre>
<blockquote>
<p><code>kubectl port-forward</code>는 <strong>로컬 포트를 Kubernetes 리소스의 포트에 연결</strong>해서, 클러스터 내부 리소스를 <strong>외부에서 직접 접근 가능</strong>하게 해주는 도구.</p>
</blockquote>
<hr>
<h3 id="pod-yaml-구조">Pod yaml 구조</h3>
<p>Pod는 하나의 독자적인 실행 단위이며, kubernetes에서 관리하는 최소 단위</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/3032fc92-3d19-4d28-b5b0-ee9f210c6883/image.png" alt=""></p>
<hr>
<h1 id="pod-argument-전달">Pod Argument 전달</h1>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b425487d-4f02-4445-a5f8-66f856579cb8/image.png" alt=""></p>
<p>docker가 가지고 있는 arguments를 전달할 수 있음.</p>
<pre><code class="language-powershell">python3 fastserver.py --host 0.0.0.0 --port 8080</code></pre>
<hr>
<h1 id="init-containr">Init-Containr</h1>
<p>Pod의 실행되기 전 가장 먼저 초기에 실행되어 초기화 및 사전 작업을 수행하는 컨테이너로 Pod 내 포함</p>
<ul>
<li><p>Pod 실행 시 최초 실행되며, Init-container가 정상적으로 종료해야 하지만 다음 절차가 실행</p>
</li>
<li><p>Init-container가 일정 시간 이상 내에 정상 처리되지 않으면 재시작 정책에 따라 재시도</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/3cccd643-fe06-4e43-a454-bb9046b82562/image.png" alt=""></p>
<pre><code class="language-yaml">apiVersion: v1
kind: Pod
metadata:
  name: sk000-init-container-test
  namespace: skala-practice
  annotations:
    prometheus.io/scrape: &#39;true&#39;
    prometheus.io/port: &#39;8081&#39;
    prometheus.io/path: &#39;/actuator/prometheus&#39;
    update: ${ANNOTATION_UPDATE}
  labels:
    app: sk000-init-container-test
spec:
  initContainers:
  - name: check-active-enabled
    image: busybox
    command:
    - sh
    - -c
    - |
      timeout 300 sh -c &quot;
      while [ ! -f /root/active.enabled ]; do
        echo &#39;Waiting for active.enabled file...&#39;
        sleep 5
      done
      echo &#39;File active.enabled found. Initialization complete.&#39;
      &quot;
    volumeMounts:
    - name: root-volume
      mountPath: /root
  containers:
  - name: init-container-test
    image: amdp-registry.skala-ai.com/skala25a/sk000-webserver:2.0.0
    imagePullPolicy: Always
    env:
    - name: LOGGING_LEVEL
      value: DEBUG
    - name: USER_NAME
      value: sk000
  volumes:
  - name: root-volume
    emptyDir: {}
</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/4694fc86-55a5-42fb-bdfd-5dcc8006a59b/image.png" alt=""></p>
<hr>
<h2 id="실습-kubernetes-환경에서-배포를-실행">[실습] kubernetes 환경에서 배포를 실행</h2>
<h3 id="yaml을-생성한-후-생성된-pod-확인">yaml을 생성한 후 생성된 pod 확인</h3>
<ol>
<li><a href="http://env.properties">env.properties</a> 파일에 들어가서, USER_NAME=sk021 로 변경</li>
</ol>
<pre><code class="language-powershell">cicd.sh -y</code></pre>
<p><strong>중간에 묻는 질문 없이 자동으로 모든 과정을 진행</strong>하는 <strong>자동 확인 옵션</strong></p>
<pre><code class="language-powershell">k apply –f init-pod.yaml</code></pre>
<p>해당 YAML 파일을 기준으로 Kubernetes 리소스를 <strong>생성하거나 업데이트</strong>하는 명령어</p>
<pre><code class="language-powershell">k get pod –w</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b1b614c7-9303-46c3-8f87-9a348785d36a/image.png" alt=""></p>
<pre><code class="language-powershell"> k exec  -it sk021-init-container-test -c check-active-enabled -- /bin/sh

 / # cd /root
 ~ # ls
 ~ # touch active.enabled</code></pre>
<p>해당 pod 내 <code>check-active-enabled</code> 컨테이너에 셸로 접속</p>
<p><code>~ # touch active.enabled</code></p>
<p><code>active.enabled</code>라는 <strong>빈 파일을 생성</strong></p>
<blockquote>
<p><code>sk021-init-container-test</code>라는 Pod의 <code>check-active-enabled</code> 컨테이너 안에 접속해서 <code>/root/active.enabled</code>라는 <strong>상태 파일을 생성</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e5211bc1-46f5-4cea-a090-8518a7b91ecd/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8133cf8a-9be6-4095-ab9d-4375f5fbbe08/image.png" alt=""></p>
<ol>
<li>env.properties에서 자기 username으로 고치고</li>
</ol>
<pre><code class="language-powershell">sudo cicd.sh --all # -a or -build -push</code></pre>
<p><code>sudo cicd.sh --all</code>은 <strong>Docker 이미지 빌드부터 푸시, 배포까지의 전체 파이프라인을 자동으로 실행하는 스크립트</strong></p>
<hr>
<h3 id="init-container-동작-원리-요약"><code>Init Container</code> 동작 원리 요약</h3>
<ol>
<li><p><code>Init Container</code>는 메인 컨테이너보다 <strong>먼저 실행</strong>.</p>
</li>
<li><p>모든 <code>Init Container</code>가 <strong>성공적으로 종료(exit 0)</strong> 되어야 <strong>메인 컨테이너</strong>가 실행되고, Pod 전체가 <code>Running</code> 상태가 됨.</p>
</li>
<li><p>보통 <code>Init Container</code>는 특정 조건이나 파일 존재 등을 검사하고, 조건이 맞아야 끝나도록 설계됨.</p>
</li>
</ol>
<blockquote>
<p><code>init-container</code>의 목적은 어떤 조건이 충족될 때까지 기다리는 것이고, 그 조건이 <strong><code>/root/active.enabled</code> 존재 여부</strong>라면 <code>touch</code>로 조건을 만족시킴</p>
</blockquote>
<pre><code class="language-yaml">initContainers:
- name: check-active-enabled
  image: busybox
  command:
  - sh
  - -c
  - |
    timeout 300 sh -c &quot;
    while [ ! -f /root/active.enabled ]; do
      echo &#39;Waiting for active.enabled file...&#39;
      sleep 5
    done
    echo &#39;File active.enabled found. Initialization complete.&#39;
    &quot;</code></pre>
<blockquote>
<p>해당 코드는 init-pod.yaml 중 일부로 <strong>init-container가 실행되면서 <code>/root/active.enabled</code> 파일이 존재할 때까지 최대 5분(300초) 동안 대기</strong>한다는 의미</p>
</blockquote>
<table>
<thead>
<tr>
<th>항목</th>
<th>내용</th>
</tr>
</thead>
<tbody><tr>
<td>init-container 역할</td>
<td>특정 파일(<code>/root/active.enabled</code>)이 존재할 때까지 대기</td>
</tr>
<tr>
<td>동작 방식</td>
<td>쉘 루프로 감시, 파일 생기면 정상 종료</td>
</tr>
<tr>
<td>공유 방법</td>
<td><code>emptyDir</code>를 <code>/root</code>에 마운트해 다른 컨테이너와 공유</td>
</tr>
<tr>
<td>너의 행동 결과</td>
<td>예상대로 루프 종료 → Pod Running 상태</td>
</tr>
</tbody></table>
<hr>
<h1 id="sidecar-container">Sidecar container</h1>
<p>일반적으로 Pod는 주 컨테이너 와 지원 컨테이너인 한 개 이상의 side car 컨테이너로 이루어져 있다.</p>
<h3 id="pod-내-모든-컨테이너가-주-컨테이너로-구성하지-않는-이유">Pod 내 모든 컨테이너가 주 컨테이너로 구성하지 않는 이유</h3>
<ul>
<li><p>Pod내 컨테이너는 한 배를 탄 동지 죽어도 같이 죽고 살아도 같이 산다</p>
</li>
<li><p>Kubernetes의 핵심은 컨테이너의 탄력적 확장성 지원인데, Pod 내 컨테이너는 지원되지 않는다.</p>
</li>
</ul>
<blockquote>
<p>일반적으로 공통 기능을 옆에 같이 포함 (side car) 시켜서 컨테이너의 안정성, 네트워크, 로그, 모니터링, 자가 복구를 지원하도록 한다</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d06e2e23-72e0-47ae-925b-21804118e024/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8c9077fe-6f58-4618-9cf6-b8409b1d65fd/image.png" alt=""></p>
<h3 id="service-mesh-istio">service mesh istio</h3>
<p>service간 트래픽 연결을 그물망처럼 자유롭게 연결</p>
<ul>
<li>Pod 내 주 컨테이너로 들어오고 나가는 모든 트래픽을 side car container인 proxy가 모두 통제함으로써 유연하게 트래픽 제어</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/7c59cf0f-d37d-434c-8db1-073136608f05/image.png" alt=""></p>
<blockquote>
<p>외/내부의 모든 traffic을 관리할 수 있음
Traffic Flow Control &amp; Traffic Resilient</p>
</blockquote>
<hr>
<h1 id="replicaset">ReplicaSet</h1>
<p>ReplicaSet은 Kubernetes에서 지정한 수의 Pod 복제본을 항상 유지하도록 도와주는 컨트롤러</p>
<p>만약 어떤 Pod가 종료되거나 삭제되면, ReplicaSet이 자동으로 새로운 Pod를 생성해서 지정된 수를 유지</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/287e0c8d-0888-4fad-b91f-b9708baf72ee/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e903f6dc-c206-4833-821e-f48454ed7698/image.png" alt=""></p>
<ul>
<li><p>ReplicaSet을 사용자가 생성하지 않고 Deployment 적용 시 ReplicaSet Controller가 RepllicaSet을 자동 구성</p>
</li>
<li><p>Deployment는 여러 개의 ReplicasSet을 제공해서 버전 변화에 따라 Rolling Update 및 Rollback 실행</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/e25604f6-1bb1-44d2-bb72-12ab60734a86/image.png" alt=""></p>
<blockquote>
<p>Replicaset을 둬서, Rolling-update 역할(점진적 업데이트)을 할 수 있음</p>
</blockquote>
<h3 id="replicaset를-통한-rolling-update">ReplicaSet를 통한 Rolling Update</h3>
<ul>
<li><p>pod 이미지 업데이트 시 새로운 ReplicaSet이 만들어지고 Old 와 New Pod가 점진적 업데이트 (Rolling update) 지원</p>
</li>
<li><p>ReplicaSet의 선언적 정의는 Deployment 내에 포함되어 있음</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/af1e8075-a61d-4edc-85d8-c0f47b5e6bd8/image.png" alt=""></p>
<hr>
<h3 id="replicaset를-통한-rolling-update-2가지-정책">ReplicaSet를 통한 Rolling Update: 2가지 정책</h3>
<ol>
<li>maxSurge: (최대 넘침)</li>
</ol>
<p>Rolling Update 시 기존 desired replica 개수보다 추가로 생성될 수 있는 Pod = 일시적 넘침</p>
<ol start="2">
<li>maxUnavailable</li>
</ol>
<p>업데이트 중에 기존 desired replica 개수기준 동작하지 않아도 되는 Pod 수</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/8e704d33-94ec-4c84-b7eb-87b79b2a7456/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/56d54f9b-53e9-4f88-b7a3-a2bbe2975b83/image.png" alt=""></p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/d6fadce0-193d-4ec9-af2e-b58bddcad7fd/image.png" alt=""></p>
<p>maxSurge 만큼 넘친 다음에 항상 4개가 유지되도록 해서 멈춘 pod가 없게끔 설정</p>
<hr>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/7020deb7-5628-4206-a708-1fe509a697c7/image.png" alt=""></p>
<p>maxSurge 만큼 넘치지만, 최대 maxUnavailable만큼 비활성화될 수 있음</p>
<hr>
<h2 id="실습-rolling-update--roll-back">[실습] Rolling Update &amp; Roll back</h2>
<ol>
<li><a href="http://env.properties">env.properties</a> 수정</li>
</ol>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/cda792eb-bb4e-4d96-bcbb-b55834223c29/image.png" alt=""></p>
<ol>
<li>각 명령어를 버전을 바꿔가면서 해보기</li>
</ol>
<pre><code class="language-powershell">cicd.sh -y  </code></pre>
<pre><code class="language-powershell">kubectl apply -f deploy.yaml</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/67c12037-a0db-4394-8e28-20a5b6a8e011/image.png" alt=""></p>
<pre><code class="language-powershell">k describe replicaset sk021-replicaset-test-7bd98549cd</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/9ecb5217-ed4d-453f-afe5-95be803d31e7/image.png" alt=""></p>
<pre><code class="language-powershell">kubectl rollout history deploy sk021-replicaset-test </code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/b3a0ad94-23ef-481a-beb2-a4bd88f57fe1/image.png" alt=""></p>
<pre><code class="language-powershell">kubectl rollout history deploy sk021-replicaset-test --revision=3</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/cf76475d-4626-437f-a11f-3c0f8ea839cb/image.png" alt=""></p>
<pre><code class="language-powershell">(RDE) &gt; kubectl port-forward svc/sk021-replicaset-test 8080:8080</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/a7d25d7c-2b33-4c10-a1ad-8c1d59e8ce24/image.png" alt=""></p>
<ul>
<li>롤백</li>
</ul>
<pre><code class="language-powershell">(RDE) &gt; kubectl rollout undo deploy sk021-replicaset-test</code></pre>
<ul>
<li>롤백 확인</li>
</ul>
<pre><code class="language-powershell">(RDE) &gt; kubectl rollout history deploy sk021-replicaset-test --revision=4</code></pre>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0621cc2a-ec17-4526-905b-27c80f082e3e/image.png" alt=""></p>
<blockquote>
<p>undo를 통해서 정상적으로 rollback이 됨을 확인할 수 있음</p>
</blockquote>
<pre><code class="language-powershell">(⎈|skala-edu-cluster:skala-practice) ~/workspace/cloud/k8s-ddive/04.replicaset
(RDE) &gt; k get pod -l app=sk021-replicaset-test               
NAME                                     READY   STATUS             RESTARTS   AGE
sk021-replicaset-test-68fd9576bf-gjmbr   0/1     ImagePullBackOff   0          14m
sk021-replicaset-test-7bd98549cd-s4wzw   1/1     Running            0          44m

(⎈|skala-edu-cluster:skala-practice) ~/workspace/cloud/k8s-ddive/04.replicaset
(RDE) &gt; k delete pod sk021-replicaset-test-68fd9576bf-gjmbr  
pod &quot;sk021-replicaset-test-68fd9576bf-gjmbr&quot; deleted

(⎈|skala-edu-cluster:skala-practice) ~/workspace/cloud/k8s-ddive/04.replicaset
(RDE) &gt; k get pod -l app=sk021-replicaset-test         
NAME                                     READY   STATUS    RESTARTS   AGE
sk021-replicaset-test-68fd9576bf-z7jjq   1/1     Running   0          15s</code></pre>
<blockquote>
<p>Rollback을 했는데, Webserver에 1.0.0 버전이 없어서 오류가 발생
→ 해당 pod에는 오류가 생겨 정상적으로 작동하지 않고, 그 전의 pod를 죽이지 않고 그대로 유지
→ webserver에 우선적으로 1.0.0을 배포하고 오류가 있는 pod를 지우고 다시 실행해야 롤백한 버전이 정상적으로 웹에 뜸</p>
</blockquote>
<pre><code class="language-powershell">C:\Users\Administrator\Desktop\cloud_k8s\rde-launcher-1.2.2.add-jmeter\exec\rde-launcher-windows\config\workspace\cloud\container\05.webserver</code></pre>
<p>해당 경로에서 </p>
<pre><code class="language-powershell">docker login amdp-registry.skala-ai.com/skala25a</code></pre>
<p>아이디와 비밀번호를 입력한 후,</p>
<pre><code class="language-powershell">docker build --tag amdp-registry.skala-ai.com/skala25a/sk021-webserver:1.0.0 .</code></pre>
<pre><code class="language-powershell">docker push amdp-registry.skala-ai.com/skala25a/sk021-webserver:1.0.0</code></pre>
<p>해당 과정을 통해서 1.0.0 버전을 docker 로 push하여 webserver에 이미지를 올릴 수 있음</p>
<pre><code class="language-powershell">k port-forward deploy/sk021-replicaset-test --address 0.0.0.0 8080:8080</code></pre>
<hr>
<h1 id="deployment">Deployment</h1>
<p>Deployment는 여러 개의 Replicas를 관리하기 위한 ReplicaSet 상위 리소스</p>
<p>새로운 이미지를 가지는 동일한 Deployment를 배포하는 경우 기존 운영 중인 Replica Set Pod와 신규 버전 Replica Set Pod가 점진적 업데이트되는데, 이를 통합 관리하는 것이 Deployment</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/0f09d1b4-7662-4f81-b1d4-4cb51caf959f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/25ea3c71-fa8c-48a6-9c21-c9fc8020d7ff/image.png" alt=""></p>
<hr>
<h1 id="label-과-selector">label 과 Selector</h1>
<h2 id="label">Label</h2>
<p>k8s 리소스에 붙이는 Key-value 쌍의 <strong>메타데이터</strong>로, 리소스를 그룹화하기 위한 필터링 도구로 활용</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/770611c9-94de-49ad-a1e1-127430e34785/image.png" alt=""></p>
<p>⇒ 사용자가 리소스를 분류하거나 특정 그룹으로 묶는 데 사용예를 들어, 특정 애플리케이션, 환경, 또는 릴리즈 버전에 따라 리소스를 구분</p>
<blockquote>
<p>붙였다가 땔 수 있음.</p>
</blockquote>
<h2 id="selector">Selector</h2>
<p>특정 조건에 따라 Label을 가진 리소스를 선택하는 기능</p>
<p><img src="https://velog.velcdn.com/images/lyj_0316/post/a2ebcbd8-8bb8-44bf-94ab-0e3ef4a1e1dc/image.png" alt=""></p>
<p>⇒ Service, Deployment, 또는 다른 리소스가 Selector를 통해 특정 Label을 가진 리소스(예: Pod)를 타겟팅하거나 관리</p>
<hr>
<p><img src="blob:https://velog.io/ad2f7c9d-019e-46df-af7b-230ded56baa3" alt="업로드중.."></p>
<hr>
]]></description>
        </item>
    </channel>
</rss>