<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jiyoon_sw524.log</title>
        <link>https://velog.io/</link>
        <description>주니어 개발자</description>
        <lastBuildDate>Tue, 21 Jan 2025 12:05:54 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jiyoon_sw524.log</title>
            <url>https://velog.velcdn.com/images/jiyoon_sw524/profile/395e7dcb-bd19-4f14-9f63-cb4781609f68/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jiyoon_sw524.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jiyoon_sw524" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[AMPS: 소셜 미디어 마케팅 환경에서 다중 모달 주의 메커니즘을 활용한 숏폼의 인기 예측]]></title>
            <link>https://velog.io/@jiyoon_sw524/AMPS-%EC%86%8C%EC%85%9C-%EB%AF%B8%EB%94%94%EC%96%B4-%EB%A7%88%EC%BC%80%ED%8C%85-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EB%8B%A4%EC%A4%91-%EB%AA%A8%EB%8B%AC-%EC%A3%BC%EC%9D%98-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%88%8F%ED%8F%BC%EC%9D%98-%EC%9D%B8%EA%B8%B0-%EC%98%88%EC%B8%A1</link>
            <guid>https://velog.io/@jiyoon_sw524/AMPS-%EC%86%8C%EC%85%9C-%EB%AF%B8%EB%94%94%EC%96%B4-%EB%A7%88%EC%BC%80%ED%8C%85-%ED%99%98%EA%B2%BD%EC%97%90%EC%84%9C-%EB%8B%A4%EC%A4%91-%EB%AA%A8%EB%8B%AC-%EC%A3%BC%EC%9D%98-%EB%A9%94%EC%BB%A4%EB%8B%88%EC%A6%98%EC%9D%84-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%88%8F%ED%8F%BC%EC%9D%98-%EC%9D%B8%EA%B8%B0-%EC%98%88%EC%B8%A1</guid>
            <pubDate>Tue, 21 Jan 2025 12:05:54 GMT</pubDate>
            <description><![CDATA[<h1 id="연구-질문">연구 질문</h1>
<blockquote>
</blockquote>
<h4 id="rq1-누적-분포-함수cdf를-기반으로-한-인기-기준이-실제-환경에서도-적용-가능하고-효과적인가">RQ1. 누적 분포 함수(CDF)를 기반으로 한 인기 기준이 실제 환경에서도 적용 가능하고 효과적인가?</h4>
<h4 id="rq2-모달리티-내부intra-modal-및-모달리티-간inter-modal-관계는-인기-예측-모델의-효율성에-어떻게-영향을-미치는가">RQ2. 모달리티 내부(intra-modal) 및 모달리티 간(inter-modal) 관계는 인기 예측 모델의 효율성에 어떻게 영향을 미치는가?</h4>
<h4 id="rq3-전체-동영상-프레임을-활용하는-것이-짧은-동영상의-인기를-예측하는-데-어떤-영향을-미치는가">RQ3. 전체 동영상 프레임을 활용하는 것이 짧은 동영상의 인기를 예측하는 데 어떤 영향을 미치는가?</h4>
<h1 id="abstract">[abstract]</h1>
<p>TV에서 모바일로 콘텐츠 소비가 전환되면서 숏폼이 주요 콘텐츠 형식으로 부상하며 다양한 분야에서 큰 잠재력을 보이고 있습니다. 그러나 이들의 인기를 평가하기 위한 데이터셋과 확립된 기준의 부족은 실제 분포를 정확히 반영하는 데 어려움을 초래합니다. 이에 대응하여 본 연구는 새로운 데이터셋을 도입하고, 숏폼에 특화된 누적 분포 함수(CDF) 기반의 새로운 평가 기준을 제안합니다.</p>
<p>본 연구에서 제안한 모델인 <strong>AMPS(Attention-based Multi-modal Popularity prediction model of Short-form videos)</strong>는 이러한 동영상의 인기를 효과적으로 예측하도록 설계되었습니다. 특히, 길이가 1분 이내로 제한되는 <strong>YouTube Shorts를 대상</strong>으로, 전체 동영상 프레임을 활용한 종합적인 인기 예측 방식을 채택했습니다. AMPS는 BiLSTM, Self-Attention, 그리고 Co-Attention 메커니즘을 활용해 다양한 모달리티 간의 내적 및 상호 관계를 깊이 이해하도록 설계되었습니다. 전체 동영상 프레임 표현을 기반으로 하여 예측 정확도를 크게 향상시켰습니다.</p>
<p>기준 모델 및 기존 머신러닝 알고리즘과의 종합적인 평가 결과, AMPS는 G-Mean, 평균 F1-score, <strong>정확도(Accuracy)</strong>와 같은 지표에서 일관되게 우수한 성능을 보여줬습니다. 또한, 다른 공개 소셜 미디어 데이터셋과 비교했을 때, 본 연구에서 수집한 데이터셋과 AMPS는 지속적으로 더 나은 성능을 보여, 모델의 강력함과 신뢰성을 입증했습니다.</p>
<p>추가로, <strong>모듈 제거 실험(Ablation Study)</strong>을 통해 AMPS의 아키텍처가 효과적임을 입증했으며, 인기를 예측하는 데 있어 각각의 모달리티의 중요성을 강조했습니다.</p>
<h1 id="1-서론">1. 서론</h1>
<p>기존 연구들은 콘텐츠 인기를 예측하는 데 주목했지만, 짧은 동영상의 인기를 예측하기 위한 데이터셋과 연구는 현저히 부족합니다. 기존 연구 중 하나는 그래프 컨볼루션 네트워크(Graph Convolutional Networks, GCN)를 사용하여 짧은 동영상의 인기를 예측했지만(Zhang et al., 2020), 이 접근법은 주로 커뮤니티 기반 분석에 초점을 맞췄으며, <strong>짧은 동영상 내 특정 요소가 인기 형성에 미치는 영향</strong>을 자세히 조사하지 못했습니다.</p>
<p>기존 연구에서는 콘텐츠 인기를 예측하기 위해 이 지표는 인기 있는 동영상을 회귀 또는 분류하는 데 기준으로 사용되었습니다. 그러나 이러한 연구에서 설정한 인기 기준은 인기를 균등 비율이나 중간값을 사용하여 정규화했기 때문에 실제 인기 동영상의 분포를 반영하는 데 한계가 있었습니다.</p>
<p>인기 예측에서 <strong>모달리티 내부(intra-modal) 상호작용</strong>과 <strong>모달리티 간(inter-modal) 관계</strong>에 집중 했습니다. </p>
<ul>
<li>모달리티 내부 상호작용을 이해하면 각 모달리티 내에서 중요한 정보를 식별할 수 있음 </li>
<li>모달리티 간 상호작용을 활용하면 모달리티 간 보완적 강점을 활용할 수 있음.
<img src="https://velog.velcdn.com/images/jiyoon_sw524/post/c59ff676-788e-4ce4-be40-26696ac886a4/image.png" alt=""></li>
</ul>
<p>=&gt; 이러한 상호작용은 <strong>다중 모달리티를 통해 고차원적인 맥락 정보를 얻음</strong> </p>
<h3 id="amps-attention-based-multi-modal-popularity-prediction-of-short-form-videos-model">AMPS: Attention-based Multi-modal Popularity Prediction of Short-form videos Model</h3>
<blockquote>
<p>AMPS는 주의 메커니즘(Attention Mechanism)을 활용하여 다중 모달리티 전반의 고차원 맥락 정보를 이해하고 인기를 예측</p>
</blockquote>
<ul>
<li>Attention Mechanism: 딥러닝 모델이 입력 데이터 중에서 어떤 부분에 집중해야 하는지를 학습하는 방법. 입력 문장의 모든 단어를 동일한 가중치로 취급하지 않고, 출력 문장에서 특정 위치에 대응하는 입력 단어들에 더 많은 가중치를 부여하는 방법.</li>
<li>Self-Attention: 각 모달리티 내부에서 중요한 요소를 학습.</li>
<li>Co-Attention: 모달리티 간 상호작용을 학습하여, 텍스트-영상 간 보완적 정보를 효과적으로 통합.
=&gt; 단순히 모든 데이터를 균등하게 처리하는 것보다 효율적이고 정확한 예측 가능</li>
</ul>
<blockquote>
<p>BiLSTM과 Self-Attention 메커니즘을 통해 연속적인 비디오와 텍스트 모달리티 내에서 필수적인 정보와 패턴을 포착</p>
</blockquote>
<ol>
<li>BiLSTM(Bidirectional LSTM)의 역할
:과거와 미래의 정보를 모두 활용하여 예측하는 Long Short Term Memory(LSTM). LSTM이란 RNN(순환 신견망)의 한 종류로 순서가 중요한 시퀀스 데이터를 처리하기 위해 고안됨.</li>
</ol>
<ul>
<li>연속 데이터의 의존성 학습:<ul>
<li>비디오: 프레임 간 연속성을 학습하여 흐름(예: 움직임, 장면 전환)을 이해.</li>
<li>텍스트: 문장의 앞뒤 단어 간의 관계를 학습해 맥락을 파악.</li>
</ul>
</li>
<li>양방향 정보 활용:<ul>
<li>텍스트: 특정 단어의 의미를 이전 단어와 이후 단어로부터 모두 추론.</li>
<li>비디오: 현재 프레임의 의미를 이전/이후 프레임 정보를 통해 보강.</li>
</ul>
</li>
</ul>
<ol start="2">
<li>Self-Attention 메커니즘의 역할</li>
</ol>
<ul>
<li>중요도 학습:<ul>
<li>입력 데이터(예: 단어, 프레임)에서 어떤 요소가 중요한지 Attention Score를 통해 계산.</li>
<li>예: 텍스트에서 특정 단어가 중요한 감정이나 주제를 나타내거나, 비디오에서 특정 프레임이 주목할 만한 장면임을 강조.</li>
</ul>
</li>
<li>비연속적 의존성 학습:<ul>
<li>BiLSTM은 연속적인 의존성을 잘 학습하지만, Self-Attention은 비연속적 관계(예: 문장 처음과 끝 단어 간 관계)를 효과적으로 학습.</li>
<li>예: 동영상 초반의 프레임이 후반부의 중요한 내용과 연관될 경우 이를 학습.</li>
</ul>
</li>
</ul>
<p>결합 효과: BiLSTM이 시간적 순서를 학습하여 시퀀스 데이터의 구조적 맥락을 제공하고, Self-Attention이 이 데이터에서 중요한 부분에 더 초점을 맞춰 효율적이고 정밀한 정보 추출이 가능해집니다.</p>
<ol start="3">
<li><p>이 메커니즘이 인기와의 관계</p>
<p><strong>인기와 정보/패턴의 상관관계</strong></p>
</li>
</ol>
<ul>
<li><p>텍스트 모달리티:</p>
<ul>
<li>제목과 설명은 동영상의 핵심 내용을 전달하며, 클릭 유도(CTR, Click-Through Rate)와 연관</li>
<li>BiLSTM과 Self-Attention은 이 텍스트에서 주제, 감성, 키워드를 학습하여 인기를 좌우하는 요소를 도출.</li>
</ul>
</li>
<li><p>비디오 모달리티:</p>
<ul>
<li>동영상 내 특정 장면, 색감, 분위기 등은 사용자 반응(예: 시청 시간, 좋아요 수)에 큰 영향을 줍니다.</li>
<li>BiLSTM과 Self-Attention은 전체 프레임의 흐름과 중요한 장면을 학습하여 사용자의 선호도를 유추.</li>
</ul>
</li>
<li><p>연속적 패턴과 인기:</p>
<ul>
<li>동영상의 스토리라인, 장면 변화와 텍스트의 문맥적 연관성이 사용자 참여도(engagement)에 직결.</li>
<li>예: 부자연스러운 전환(텍스트-비디오 불일치)은 인기를 낮추고, 매끄러운 연결은 인기를 높이는 요인.</li>
</ul>
</li>
</ul>
<blockquote>
<p>Co-Attention 메커니즘은 이러한 모달리티 간 상호작용을 이해하는 데 도움을 줌</p>
</blockquote>
<h1 id="2-관련-연구">2. 관련 연구</h1>
<p>2.1 단일 모달 콘텐츠의 인기 예측
본 연구는 동영상의 내재적인 본질과 세부 특성을 포착하기 위해 딥러닝 특징 표현을 사용해 동영상을 나타내고자 합니다.</p>
<p>2.2 다중 모달 딥러닝 기반 예측 모델
본 연구는 짧은 동영상에 집중하여 전체 동영상 길이에 걸친 포괄적인 특징을 분석하고자 합니다. 제안된 모델은 동영상 콘텐츠 전체를 딥러닝 특징으로 나타내어 인기 예측 성능을 향상시키고자 합니다.</p>
<p>2.3 인기 점수를 활용한 예측
본 연구는 현실 세계에서 더 널리 적용 가능한 실용적인 인기 평가 방식을 제안하고자 합니다.</p>
<h1 id="3-youtube-shorts-데이터셋과-제안한-cdf-기반-인기-기준">3. YouTube Shorts 데이터셋과 제안한 CDF 기반 인기 기준</h1>
<p><strong>데이터셋에서 콘텐츠의 인기를 평가하고 정량화하기 위해</strong> 누적 분포 함수(CDF) 기반의 새로운 인기 기준을 제안
-&gt; 콘텐츠가 달성한 인기 수준을 평가하기 위한 기준점</p>
<h2 id="31-데이터-수집-방법론">3.1 데이터 수집 방법론</h2>
<p>데이터셋 = 동영상 콘텐츠 자체 + 관련 채널 정보에 대한 세부 내용</p>
<h2 id="32-데이터-설명">3.2 데이터 설명</h2>
<p>Shorts 메타데이터, 채널 메타데이터, 그리고 추가 데이터입니다.</p>
<ol>
<li><p>Shorts 메타데이터: </p>
<ul>
<li>비디오 ID(Video Id): 각 Shorts를 식별하는 고유 식별자.</li>
<li>썸네일 URL(Thumbnail Url): Shorts의 시각적 표현에 접근할 수 있는 링크.</li>
<li>게시 날짜(Published At): 동영상의 게시 날짜.</li>
<li>제목(Title), 설명(Description), 카테고리 ID(Category Id): 콘텐츠와 주제에 대한 정보를 제공.</li>
<li>조회수(Views Count), 좋아요 수(Likes Count), 댓글 수(Comments Count): 동영상의 인기와 사용자 상호작용에 관한 정보를 제공.</li>
</ul>
</li>
<li><p>채널 메타데이터:</p>
<ul>
<li>채널 ID(Channel Id): 각 채널을 고유하게 식별.</li>
<li>채널 제목(Channel Title), 구독자 수(Subscriber Count), 총 조회수(Total View Count), 총 동영상 수(Total Video Count): 채널별 특성을 나타냄.</li>
</ul>
</li>
<li><p>추가 데이터:</p>
<ul>
<li>수집 날짜(Collect Date), 일일 조회수(Views per day), 인기 점수(Popularity Score), 인기 여부(Popularity): 데이터셋에 추가적인 통찰을 제공.</li>
</ul>
</li>
</ol>
<hr>
<h2 id="33-인기-기준">3.3 인기 기준</h2>
<p>일반적으로 사용자는 YouTube에서 동영상을 선택해 시청하지만, YouTube Shorts는 플랫폼 추천 알고리즘에 주로 의존하여 사용자에게 노출됩니다. 또한, 연속적인 세로 형식으로 인해 사용자가 적극적으로 탐색하지 않더라도 짧은 동영상이 자연스럽게 노출됩니다.</p>
<p>따라서, 짧은 동영상의 인기를 측정하기 위해 특별히 설계된 새로운 기준을 제안합니다. 이 제안된 인기 기준은 YouTube Shorts의 인기 동향을 분석하고 예측하기 위한 핵심 메트릭으로 작용합니다. 이를 실현하기 위해, <strong>누적 분포 함수(CDF)</strong>를 정의 기준으로 사용하여 <strong>인기 점수(Popularity Score)</strong>라는 효과적인 메트릭을 설정했습니다.</p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/f5df9b78-557a-4a9c-9dc9-8e791fc9628f/image.png" alt=""></p>
<p>*<em>Fig. 2. 정규화된 인기 점수의 누적 분포 함수(CDF) 그래프. 빨간 선은 CDF 그래프에서 기울기가 1이 되는 지점을 나타냅니다. *</em></p>
<h3 id="331-인기-점수popularity-score">3.3.1 인기 점수(Popularity Score)</h3>
<p>본 연구에서는 실험 데이터셋에서 조회 수를 인기의 지표로 활용했다. 하지만 YouTube Shorts의 조회 수는 시간이 지남에 따라 누적되므로, 하루 평균 조회 수로 정제된 인기 점수를 도입했다. 이 인기 점수는 하루 평균 조회 수에 기반하며, 조회 수가 0인 동영상을 처리하기 위해 1을 추가하는 방식으로 보완했다. </p>
<p>기존에는 구독자 수가 높을수록 콘텐츠 품질에 관계없이 조회 수가 증가할 가능성이 있다는 가정 하에, 채널의 구독자 수를 통합하여 로그 정규화를 사용하는 방식을 사용하였다. 하지만 인기 있는 Shorts의 수가 덜 인기 있는 Shorts의 수보다 크게 많은 경우, 이러한 정규화 기법은 실제 데이터 분포에 적응하는 데 한계가 있었다. </p>
<p>이를 해결하기 위해 본 연구는 누적 분포 함수(CDF) 접근 방식을 채택했으며, 기존의 로그 정규화 대신 Min-Max 스케일러를 도입했다. </p>
<p>이후, 인기 점수 분포를 종합적으로 분석하여, 0.2를 초과하는 이상치를 제거했다. 이상치를 제거한 후, 데이터셋은 총 13,001개의 항목으로 정제되어 후속 분석을 위한 더 집중적이고 신뢰할 수 있는 데이터셋이 되었다.</p>
<ul>
<li>CDF 곡선에서 x = 0.2 이후로 급격히 변화하며, 분포의 꼬리가 길어지는 현상이 관찰됨 -&gt; 이는 극단적으로 높은 인기 점수를 가진 데이터가 존재함을 의미 -&gt; 해당 데이터는 일반적인 데이터와 다른 특성을 가지며, 분포에서 비정상적 변화를 유발함</li>
<li>이 비정상적 변화가 나타난 이유<ul>
<li>바이럴 콘텐츠의 존재 : 특정 동영상이 갑작스럽게 높은 조회수나 좋아요를 기록하며, 분포 상 극단값으로 나타남.</li>
<li>플랫폼 알고리즘의 영향 : 플랫폼 추천 알고리즘이 특정 콘텐츠를 과도하게 노출시켜 비정상적 인기 점수를 생성.</li>
<li>분포 왜곡 : 극단적인 점수는 전체 데이터를 대표하기보다는 특정 상황(예: 유명인 협업, 광고성 콘텐츠)의 결과일 가능성이 높음.</li>
</ul>
</li>
<li>CDF를 시각화한 결과, 인기 점수가 0.2를 초과하면 데이터의 분포에서 <strong>상위 15%</strong>에 속함을 확인</li>
<li>0.2를 초과하는 데이터가 상위 15%에 해당하는 이유는 CDF 분석 결과에서 해당 구간이 데이터 분포 상 극단적인 영역으로 나타났기 때문</li>
</ul>
<h3 id="332-누적-분포-함수cumulative-distribution-function-cdf">3.3.2 누적 분포 함수(Cumulative Distribution Function, CDF)</h3>
<ul>
<li><strong>누적 분포 함수(CDF)</strong>는 가설 검정과 관련된 임계값을 설정하는 강력한 도구로 사용</li>
<li>본 연구에서는 CDF를 사용해 데이터 분포를 시각화하고 데이터셋 내에 내재된 패턴을 탐구</li>
<li>연구 결과, 상위 15%의 Shorts 콘텐츠가 전체 Shorts 인기 점수의 85% 이상을 차지한다는 중요한 사실이 밝혀짐</li>
</ul>
<h1 id="4-amps-모델">4. AMPS 모델</h1>
<p>본 연구에서는 YouTube Shorts의 인기를 예측하기 위해 다양한 모달리티로부터 정보를 효과적으로 처리할 수 있도록 설계된 특징 추출 방법을 제시함. 이렇게 추출된 특징을 활용한 다중 모달 모델의 구성을 자세히 설명하며, 제안된 모델의 구조와 설계는 Fig. 3에 시각적으로 제시</p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/14f72e8c-2b6b-4a4f-a1c5-8b8eeeaf09ee/image.png" alt=""></p>
<p>*<em>Fig. 3. Attention 기반 다중 모달 단기 동영상 인기 예측 모델(AMPS)의 개요 *</em></p>
<ul>
<li>$V_T$는 제목(feature)  </li>
<li>$V_D$는 설명(feature)  </li>
<li>$V_M$은 메타데이터(feature)  </li>
<li>$U_V$, $U_T$, $U_D$는 각각 <strong>비디오, 제목, 설명</strong>의 <strong>특징 기술자(feature descriptor)</strong>  </li>
<li>BiLSTM(Self-Attention 포함)은 <strong>BiLSTM 및 Self-Att</strong>로 약칭됨  </li>
<li>Co-Attention 계층은 <strong>Co-ATT</strong>로 표기됨  </li>
<li>$U_{VT}$, $U_{DV}$, $U_{TD}$는 각각  <strong>비디오-제목</strong>,   <strong>비디오-설명</strong>,  <strong>제목-설명</strong>의 <strong>특징 기술자의 Co-Attention 계층 출력 벡터</strong>  </li>
<li>$U_{C1}$은 <strong>첫 번째 병합 계층(Merged layer)의 192차원 벡터를 8차원으로 축소한 벡터</strong>  </li>
<li>$U_{C2}$는 <strong>$V_M$과 병합된 16차원 벡터</strong>를 의미</li>
<li>마지막으로 <strong>분류기(Classifier)</strong>를 통해 <strong>인기 예측(0 또는 1)</strong> 수행</li>
</ul>
<p>AMPS 모델은 비디오, 텍스트(제목+설명), 메타데이터를 각각 처리한 후, <strong>모달리티 간 관계를 학습(Co-Attention)하여 종합적인 인기 예측을 수행하는 모델</strong>입니다.</p>
<h2 id="41-특징-추출">4.1 특징 추출</h2>
<p>다중 모달 데이터 소스(동영상, 텍스트, 메타데이터)로부터 정보를 추출하는 과정을 아래와 같이 단계별로 설명합니다.</p>
<h3 id="411-동영상-특징">4.1.1 동영상 특징</h3>
<ul>
<li>동영상 프레임으로부터 특징을 추출하며, 각 프레임은 224×224 크기로 조정된 후 인코더로 전달</li>
<li>특징 추출을 위해 ResNet50 모델을 사용. ResNet50은 <strong>Deep Residual Neural Network(ResNet)</strong>의 확장 버전으로, ResNet50의 두 번째 연결 계층에서 이미지 표현을 추출하여 각 프레임에 대해 2048차원의 특징 벡터를 생성</li>
<li>YouTube Shorts의 동영상 길이는 1분 이내로 다양한 분포를 가지지만, 모든 프레임의 정보를 활용하여 동영상 특징 벡터를 생성</li>
<li><strong>최종 동영상 임베딩은 모든 프레임에서 평균 벡터를 계산하여 동영상을 포괄적으로 표현</strong></li>
</ul>
<h3 id="412-텍스트-특징">4.1.2 텍스트 특징</h3>
<ul>
<li>텍스트 특징은 YouTube Shorts의 제목과 간단한 설명에서 추출됩니다. 이 텍스트는 Shorts의 주제를 나타내는 중요한 요소를 포함합니다.</li>
<li>텍스트 길이는 다양하지만, <strong>Bidirectional Encoder Representations from Transformers(BERT)</strong>의 sentence2vector 기능을 사용해 제목과 설명의 특징을 추출합니다(Kenton and Toutanova, 2019).</li>
<li>BERT는 자연어 처리(NLP) 작업에서 뛰어난 성능을 발휘하며, 텍스트 데이터로부터 특징 벡터를 생성하기 위한 이상적인 프레임워크입니다. 이를 통해 제목과 설명에 내재된 의미와 맥락 정보를 효과적으로 분석하고 표현할 수 있습니다.</li>
</ul>
<h3 id="413-메타데이터-특징">4.1.3 메타데이터 특징</h3>
<ul>
<li>채널 정보와 Shorts 정보와 관련된 4가지 메타데이터를 선택했습니다. 이는 이전 연구에서 성능 향상에 중요한 역할을 한 요소들입니다(Abousaleh et al., 2021; Meghawat et al., 2018; Li et al., 2016; Vasireddi et al., 2023).</li>
<li><strong>채널 메타데이터</strong>: 채널의 인기는 해당 채널에서 업로드한 Shorts의 인기와 강하게 상관관계를 가지므로, 동일 채널에서 업로드된 Shorts에 대해 균일한 값이 적용됩니다.</li>
<li><strong>동영상 메타데이터</strong>: 이전 연구에 따르면 맥락적인 콘텐츠 정보가 동영상의 인기 형성에 중요한 영향을 미칩니다(Abousaleh et al., 2021).</li>
</ul>
<p>모든 메타데이터에서 일관된 스케일링을 보장하고 이상치의 영향을 줄이기 위해 Robust Scaler를 사용하여 데이터를 정규화하고 더 일관적이고 균형 잡힌 데이터셋을 보장했습니다(deAmorim et al., 2023).</p>
<h4 id="채널-메타데이터">채널 메타데이터</h4>
<ul>
<li>구독자 수(Number of subscribers): 채널의 구독자 수.</li>
<li>총 조회수(Total views): 채널에 업로드된 모든 Shorts의 총 조회수.</li>
<li>총 동영상 수(Total videos): 채널이 업로드한 Shorts의 총 개수.</li>
<li>평균 조회수(Average views): 총 조회수를 Shorts 개수로 나눈 평균 조회수.</li>
</ul>
<h4 id="동영상-메타데이터">동영상 메타데이터</h4>
<ul>
<li>동영상 길이(Video length): 각 동영상의 길이는 1분 이내.</li>
<li>태그 수(Tag count): Shorts를 업로드한 사용자가 부여한 태그의 수.</li>
<li>제목 길이(Title length): Shorts 제목의 문자 수.</li>
<li>설명 길이(Description length): Shorts 설명의 문자 수.</li>
</ul>
<h2 id="42">4.2</h2>
<h1 id="5-experiments-and-results-실험-및-결과">5. Experiments and Results (실험 및 결과)</h1>
<p>이 섹션에서는 AMPS 모델의 실험 설정, 평가 방법, 기존 모델과의 성능 비교, 그리고 성분 분석(Ablation Study)을 통해 AMPS의 성능을 분석합니다.</p>
<hr>
<h2 id="51-experiments-실험-설정"><strong>5.1. Experiments (실험 설정)</strong></h2>
<h3 id="511-experimental-setup-실험-환경-및-데이터-설정"><strong>5.1.1. Experimental Setup (실험 환경 및 데이터 설정)</strong></h3>
<ul>
<li><p><strong>데이터셋 분할</strong>: </p>
<ul>
<li>학습(80%), 검증(10%), 테스트(10%)로 나누어 실험을 진행.</li>
<li>YouTube Shorts 데이터셋을 활용.</li>
<li>데이터 불균형(인기 있는 영상 15%, 인기 없는 영상 85%)을 해결하기 위해 <strong>SMOTE(Synthetic Minority Over-sampling Technique)</strong> 를 적용.</li>
<li>불균형 데이터 문제를 개선하기 위해 <strong>Binary Focal Cross-Entropy Loss</strong>를 활용하여 학습.</li>
</ul>
</li>
<li><p><strong>하이퍼파라미터 설정</strong>:</p>
<ul>
<li><strong>Optimizer</strong>: Adam (학습률 0.0001)</li>
<li><strong>손실 함수</strong>: Binary Focal Cross-Entropy Loss (α=0.25, γ=2.0)</li>
<li><strong>에포크(Epochs)</strong>: 최대 100회 학습, 하지만 Early Stopping(검증 손실이 10 에포크 동안 개선되지 않으면 중단) 적용.</li>
<li><strong>최적화 목표</strong>: 일반적으로 20~40 에포크 내에 수렴.</li>
</ul>
</li>
</ul>
<hr>
<h3 id="512-evaluation-metrics-성능-평가-지표"><strong>5.1.2. Evaluation Metrics (성능 평가 지표)</strong></h3>
<p>모델 성능을 평가하기 위해 다양한 분류 성능 지표를 사용:</p>
<ol>
<li><p><strong>Accuracy (정확도)</strong>
[
Accuracy = \frac{TP + TN}{TP + TN + FP + FN}
]</p>
<ul>
<li>전체 샘플 중 올바르게 분류된 샘플의 비율.</li>
</ul>
</li>
<li><p><strong>Precision (정밀도)</strong>
[
Precision = \frac{TP}{TP + FP}
]</p>
<ul>
<li>모델이 <strong>인기 영상(Popular)으로 분류한 샘플</strong> 중 실제로 인기 영상인 비율.</li>
</ul>
</li>
<li><p><strong>Recall (재현율)</strong>
[
Recall = \frac{TP}{TP + FN}
]</p>
<ul>
<li>실제 인기 영상 중 <strong>모델이 올바르게 분류한 비율</strong>.</li>
</ul>
</li>
<li><p><strong>F1-score</strong>
[
F1-score = 2 \times \frac{Precision \times Recall}{Precision + Recall}
]</p>
<ul>
<li>Precision과 Recall의 조화 평균으로, 불균형 데이터에서 유용한 지표.</li>
</ul>
</li>
<li><p><strong>G-Mean (Geometric Mean)</strong>
[
G-Mean = \sqrt{Sensitivity \times Specificity}
]</p>
<ul>
<li>데이터 불균형 문제를 해결하기 위한 성능 지표로, 양성 클래스(인기 영상)와 음성 클래스(비인기 영상)의 균형을 평가.</li>
</ul>
</li>
</ol>
<hr>
<h3 id="513-baseline-models-비교-모델-설정"><strong>5.1.3. Baseline Models (비교 모델 설정)</strong></h3>
<p>AMPS 모델과 비교할 기존 머신러닝 및 딥러닝 모델:</p>
<ul>
<li><p><strong>머신러닝 기반 모델</strong></p>
<ul>
<li><strong>SVC</strong> (Support Vector Classifier)</li>
<li><strong>SGDClassifier</strong> (Stochastic Gradient Descent)</li>
<li><strong>Decision Tree Classifier</strong> (DTC)</li>
<li><strong>Random Forest Classifier</strong> (RFC)</li>
</ul>
</li>
<li><p><strong>딥러닝 기반 모델</strong></p>
<ul>
<li><strong>VSCNN</strong> (Said et al., 2020) - 이미지 인기 예측 모델</li>
<li><strong>ViViD</strong> (Sarkar et al., 2023) - 비디오 조회수 예측 모델</li>
<li><strong>MMSPP</strong> (Gu, 2020) - 멀티모달 소셜 미디어 인기 예측 모델</li>
</ul>
</li>
</ul>
<p><strong>비교 실험 목표</strong>:</p>
<ul>
<li>기존 모델과의 성능 비교를 통해 AMPS의 강점을 검증.</li>
<li><strong>머신러닝 vs 딥러닝 기반 모델</strong>의 차이를 분석.</li>
</ul>
<hr>
<h3 id="514-comparative-datasets-비교-데이터셋-설정"><strong>5.1.4. Comparative Datasets (비교 데이터셋 설정)</strong></h3>
<p>추가적인 데이터셋을 활용하여 AMPS 모델의 일반화 성능을 평가:</p>
<ol>
<li><p><strong>IPPCD (Image Popularity Prediction Challenge Dataset)</strong></p>
<ul>
<li>SNS에서 공유된 <strong>이미지의 인기 예측</strong>을 위한 데이터셋.</li>
<li>30일 동안 누적된 조회수를 기준으로 인기 점수를 측정.</li>
<li>20,337개 항목 포함.</li>
</ul>
</li>
<li><p><strong>SMPD (Social Media Prediction Dataset)</strong></p>
<ul>
<li>다양한 소셜 미디어 게시물(이미지, 텍스트 포함)로 구성된 멀티모달 데이터셋.</li>
<li>약 486,000개 항목 중 ‘Social &amp; People’ 카테고리의 15,121개 샘플을 실험에 활용.</li>
</ul>
</li>
</ol>
<hr>
<h2 id="52-results-실험-결과"><strong>5.2. Results (실험 결과)</strong></h2>
<h3 id="521-comparison-with-baseline-models-기존-모델과의-비교"><strong>5.2.1. Comparison with Baseline Models (기존 모델과의 비교)</strong></h3>
<p><strong>주요 결과 요약</strong>:</p>
<ul>
<li>AMPS 모델이 <strong>모든 성능 지표(Accuracy, F1-score, G-Mean 등)에서 기존 모델을 능가</strong>.</li>
<li>특히, 데이터 불균형 문제를 해결하는 <strong>G-Mean과 F1-score에서 2~13% 향상</strong>.</li>
<li>머신러닝 모델(SVC, SGD 등)은 상대적으로 낮은 성능을 보임.</li>
<li><strong>딥러닝 모델 중에서도 AMPS 모델이 가장 높은 성능</strong>을 기록.</li>
</ul>
<p><strong>세부 성능 비교 (Table 2)</strong>
| Model | Accuracy | G-Mean | Avg-F1 |
|--------|---------|--------|--------|
| VSCNN | 76.5% | 40.2% | 74.6% |
| ViViD | 77.3% | 46.6% | 77.8% |
| MMSPP | 76.3% | 58.8% | 77.2% |
| <strong>AMPS (Ours)</strong> | <strong>79.7%</strong> | <strong>71.2%</strong> | <strong>81.2%</strong> |</p>
<hr>
<h3 id="522-comparison-with-comparative-datasets-다른-데이터셋과의-비교"><strong>5.2.2. Comparison with Comparative Datasets (다른 데이터셋과의 비교)</strong></h3>
<ul>
<li><strong>IPPCD 및 SMPD 데이터셋에서도 AMPS 모델이 최고 성능</strong>.</li>
<li>특히, IPPCD에서 <strong>78.1%의 정확도</strong>를 기록하며, 기존 모델 대비 2~22% 높은 성능을 보임.</li>
<li>SMPD에서도 <strong>76.5%의 정확도</strong>를 기록.</li>
</ul>
<hr>
<h3 id="523-ablation-study-성분-분석-연구"><strong>5.2.3. Ablation Study (성분 분석 연구)</strong></h3>
<p><strong>BiLSTM-SelfAttention과 Co-Attention의 효과 분석</strong></p>
<ul>
<li>AMPS의 BiLSTM + Self-Attention과 Co-Attention 구조가 <strong>성능 향상에 기여</strong>함을 입증.</li>
<li>BiLSTM과 Self-Attention을 제거하면 성능이 5~10% 하락.</li>
</ul>
<p><strong>모달리티 분석 (Table 6)</strong>:</p>
<ul>
<li><strong>텍스트(Text)와 영상(Video)를 함께 사용할 때 성능이 향상</strong>됨.</li>
<li><strong>모달리티를 모두 결합(멀티모달)</strong> 했을 때 가장 높은 성능 기록.</li>
</ul>
<hr>
<h2 id="6-discussion-and-conclusion-논의-및-결론"><strong>6. Discussion and Conclusion (논의 및 결론)</strong></h2>
<h3 id="61-연구-기여"><strong>6.1. 연구 기여</strong></h3>
<ol>
<li><strong>YouTube Shorts 기반 신규 데이터셋 구축</strong></li>
<li><strong>CDF 기반의 새로운 인기 평가 기준 제안</strong></li>
<li><strong>멀티모달 데이터를 활용한 BiLSTM + Co-Attention 기반 예측 모델 개발</strong></li>
<li><strong>기존 모델 대비 우수한 성능 입증</strong></li>
</ol>
<h3 id="62-실무적-시사점"><strong>6.2. 실무적 시사점</strong></h3>
<ul>
<li><strong>콘텐츠 제작자</strong>: 인기 있는 영상을 제작하는 전략을 수립하는 데 활용 가능.</li>
<li><strong>마케팅 전문가</strong>: SNS 콘텐츠 마케팅 전략에 적용 가능.</li>
<li><strong>추천 시스템</strong>: 개인 맞춤형 콘텐츠 추천 알고리즘 개발에 적용 가능.</li>
</ul>
<hr>
<h1 id="📌-결론">📌 결론</h1>
<p>AMPS 모델은 기존 인기 예측 모델 대비 <strong>멀티모달 데이터를 활용하여 예측 정확도를 향상</strong>시켰으며, <strong>데이터 불균형 문제를 해결</strong>하는 효과적인 방법을 제시함. 🚀</p>
<h1 id="6-결론">6. 결론</h1>
]]></description>
        </item>
        <item>
            <title><![CDATA[논문 읽기와 작성 방법 정리]]></title>
            <link>https://velog.io/@jiyoon_sw524/%EB%85%BC%EB%AC%B8-%EC%9D%BD%EA%B8%B0%EC%99%80-%EC%9E%91%EC%84%B1-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@jiyoon_sw524/%EB%85%BC%EB%AC%B8-%EC%9D%BD%EA%B8%B0%EC%99%80-%EC%9E%91%EC%84%B1-%EB%B0%A9%EB%B2%95-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Tue, 24 Dec 2024 02:44:10 GMT</pubDate>
            <description><![CDATA[<h3 id="논문-읽기-방법">논문 읽기 방법</h3>
<ol>
<li><p><strong>핵심 구조 파악</strong></p>
<ul>
<li><strong>동기(문제점)</strong>: 연구가 다루는 문제나 연구의 필요성.</li>
<li><strong>목표(목적)</strong>: 연구의 의도와 방향.</li>
<li><strong>방법</strong>: 연구가 구체적으로 무엇을, 어떻게 수행했는지.</li>
<li><strong>결론</strong>: 연구 결과와 의의.</li>
</ul>
</li>
<li><p><strong>논문에서 느껴야 할 점</strong></p>
<ul>
<li>문제를 어떻게 인지했는지.<ul>
<li>이런 문제점을 인지했구나~</li>
</ul>
</li>
<li>문제 해결을 위한 접근 방식.<ul>
<li>이 문제를 이렇게 풀면 좋겠다고 생각했구나~</li>
</ul>
</li>
<li>구체적인 해결 방법과 실행 과정.<ul>
<li>방법은 구체적으로 이렇게 했구나~</li>
</ul>
</li>
</ul>
</li>
</ol>
<h3 id="논문-작성-방법">논문 작성 방법</h3>
<ol>
<li><p><strong>관련 연구 분석</strong></p>
<ul>
<li>기존 연구와의 비교를 통해 배경 설명.</li>
<li>연구의 흐름과 각 접근 방식의 문제점 제시.</li>
<li>논문 주제를 ‘검색과 추론’으로 초점 맞춤.</li>
<li><strong>관련 연구 키워드</strong><ul>
<li>기존 검색 시스템과 추론 기반 시스템의 문제점. &lt;- llm/벡터DB와의 비교</li>
<li>새로운 시스템의 필요성.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>핵심 개념과 연구 방향</strong></p>
<ul>
<li><strong>KeyWord: 왜 &#39;검색과 추론&#39;이 가능한 시스템이 필요한가?</strong><ul>
<li>정보의 폭증 시대에 적합한 검색 및 추론 시스템 필요성.<ul>
<li>직접 읽는 책 -&gt; 전지 문서의 등장  -&gt; 이슈: 검색 (구글) -&gt; llm -&gt; RAG -&gt; graphRAG</li>
</ul>
</li>
<li>기존 검색(예: Google)의 한계를 극복하기 위한 접근.</li>
</ul>
</li>
<li><strong>도구(시스템)</strong><ul>
<li><strong>GraphRAG</strong>: 검색과 추론을 통합한 시스템의 구현.
  -&gt; 이렇게 할 수 있는 코어 시스템을 만든 것이다.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>논문 작성 시 유의사항</strong></p>
<ul>
<li><strong>목표를 분명히 제시</strong>: 제목에서부터 연구 방향을 명확히 드러내기.</li>
<li><strong>타당성과 동기 강조</strong>: 연구의 중요성과 필요성을 독자에게 납득시킬 수 있도록.</li>
</ul>
</li>
</ol>
<h3 id="연구의-설계와-구조-설명">연구의 설계와 구조 설명</h3>
<ol>
<li><p><strong>효율성과 단순함</strong></p>
<ul>
<li>장황한 설명은 지양하고, 효율적이라는 점을 명확히 정의.</li>
<li>예: &quot;효율적인 자동차&quot;는 &quot;효율적인 배터리&quot;에서 비롯됨.</li>
<li>빠르고 간편한 설계 철학:<ul>
<li>노 메뉴(No Menu) 채택 이유 설명.</li>
<li>로그인 방식 설계 배경과 필요성.</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>구현의 논리적 근거</strong></p>
<ul>
<li><strong>왜 이렇게 구현했는가?</strong><ul>
<li>구조를 설계한 이유와 근거를 논리적으로 제시.</li>
<li>시스템 요구사항과 이를 충족하기 위한 설계 철학 설명.</li>
<li>왜이렇게 구현했고 그래서 이런게 필요했고 이렇게 구조를 만들었다. 이렇게 만든 이유!</li>
</ul>
</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[WebRTC]]></title>
            <link>https://velog.io/@jiyoon_sw524/WebRTC</link>
            <guid>https://velog.io/@jiyoon_sw524/WebRTC</guid>
            <pubDate>Fri, 15 Nov 2024 12:39:28 GMT</pubDate>
            <description><![CDATA[<h1 id="webrtc와-react--socketio--flask-통신-구조">WebRTC와 React + Socket.io + Flask 통신 구조</h1>
<hr>
<h2 id="1-webrtc란">1. WebRTC란?</h2>
<p>WebRTC(Web Real-Time Communication)는 브라우저 간의 실시간 <strong>P2P 통신</strong>을 지원하는 기술입니다. 이를 통해 별도의 플러그인 없이 브라우저에서 실시간 오디오, 비디오, 데이터 통신을 가능하게 합니다.</p>
<hr>
<h2 id="2-webrtc의-핵심-요소">2. WebRTC의 핵심 요소</h2>
<h3 id="21-offer-answer-ice-candidate">2.1 Offer, Answer, ICE Candidate</h3>
<ul>
<li><p><strong>Offer</strong></p>
<ul>
<li>WebRTC 연결을 시작하려는 클라이언트가 생성하는 초기 요청 메시지입니다.</li>
<li>네트워크 정보와 미디어 정보(예: 비디오/오디오 설정)가 포함됩니다.</li>
</ul>
</li>
<li><p><strong>Answer</strong></p>
<ul>
<li>Offer를 받은 클라이언트가 응답으로 보내는 메시지입니다.</li>
<li>자신의 네트워크와 미디어 정보를 포함하여 연결을 수락합니다.</li>
</ul>
</li>
<li><p><strong>ICE Candidate</strong></p>
<ul>
<li>P2P 연결을 최적화하기 위해 네트워크 경로(IP 주소와 포트)를 제공하는 정보입니다.</li>
<li>여러 ICE Candidate를 교환하여 최적의 경로를 설정합니다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="3-signaling-서버">3. Signaling 서버</h2>
<h3 id="31-역할과-개념">3.1 역할과 개념</h3>
<ul>
<li><p><strong>Signaling 서버</strong>란?</p>
<ul>
<li>두 클라이언트(A와 B)가 WebRTC 연결을 시작하기 전에 서로의 연결 정보(Offer, Answer, ICE Candidate)를 교환하는 <strong>중간 다리 역할</strong>을 합니다.</li>
<li>실제 미디어 데이터(비디오, 오디오)는 Signaling 서버를 통하지 않고 브라우저 간 직접 전송됩니다.</li>
</ul>
</li>
<li><p><strong>Socket.io</strong>의 활용</p>
<ul>
<li>Signaling 서버 구현 시 자주 사용되는 실시간 통신 도구로, WebSocket 기반 데이터 교환을 간소화합니다.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="4-webrtc-통신-흐름">4. WebRTC 통신 흐름</h2>
<h3 id="41-react--socketio--flask의-통신-흐름">4.1 React + Socket.io + Flask의 통신 흐름</h3>
<p><strong>1. React 클라이언트와 Flask 서버 연결</strong></p>
<ul>
<li>각 클라이언트(A와 B)는 React에서 <code>socket.emit()</code>으로 메시지를 전송.</li>
<li>Flask는 <code>socketio.on()</code>으로 메시지를 수신 후 상대 클라이언트에게 전달.</li>
</ul>
<p><strong>2. Signaling 과정</strong></p>
<ul>
<li>A 클라이언트가 Offer를 생성하여 Flask 서버에 전송.</li>
<li>Flask가 클라이언트 B로 Offer를 전달.</li>
<li>클라이언트 B가 Answer를 생성해 Flask 서버에 전송.</li>
<li>Flask가 Answer를 클라이언트 A로 전달.</li>
<li>양쪽 클라이언트가 ICE Candidate를 주고받아 최적의 경로를 설정.</li>
</ul>
<p><strong>3. P2P 연결 완료</strong></p>
<ul>
<li>Signaling 이후 클라이언트 간 P2P 연결이 성립됩니다.</li>
<li>이후 데이터(비디오, 오디오, 메시지)는 서버를 거치지 않고 브라우저 간 직접 전송됩니다.</li>
</ul>
<hr>
<h2 id="5-p2p-통신">5. P2P 통신</h2>
<h3 id="51-rtcpeerconnection-p2p-통신의-중심">5.1 RTCPeerConnection: P2P 통신의 중심</h3>
<h4 id="--localdescription과-remotedescription">- LocalDescription과 RemoteDescription</h4>
<ul>
<li><strong>LocalDescription</strong><br> : 현재 클라이언트의 WebRTC 연결 상태(Offer 또는 Answer)를 나타냄.</li>
<li><strong>RemoteDescription</strong><br> : 상대방의 WebRTC 연결 상태(Offer 또는 Answer)를 나타냄.</li>
</ul>
<pre><code class="language-javascript">// Offer 생성 및 설정
const offer = await peerConnection.createOffer();
await peerConnection.setLocalDescription(offer);

// RemoteDescription 설정
await peerConnection.setRemoteDescription(offer);</code></pre>
<h4 id="--ice-candidate-교환">- ICE Candidate 교환</h4>
<ul>
<li>네트워크 경로(IP와 포트 정보)를 제공하여 방화벽과 NAT 문제를 해결.</li>
<li>최적의 경로 설정 후 P2P 데이터 전송 시작.</li>
</ul>
<hr>
<h3 id="52-p2p-데이터-전송-흐름">5.2 P2P 데이터 전송 흐름</h3>
<ul>
<li><p><strong>미디어 데이터 전송</strong>
 : WebRTC를 사용해 실시간 비디오 및 오디오 데이터를 전송.</p>
</li>
<li><p><strong>데이터 채널 전송</strong>
 : 텍스트 데이터, 파일 등 일반 데이터를 전송 가능.</p>
</li>
</ul>
<hr>
<h2 id="6-nat-및-방화벽-문제-해결">6. NAT 및 방화벽 문제 해결</h2>
<h3 id="61-stun-서버와-turn-서버">6.1 STUN 서버와 TURN 서버</h3>
<h4 id="--stun-서버">- <strong>STUN 서버</strong></h4>
<ul>
<li>공인 IP와 포트를 확인해 클라이언트 간 P2P 연결을 돕습니다.</li>
</ul>
<h4 id="--turn-서버">- <strong>TURN 서버</strong></h4>
<ul>
<li>P2P 연결이 불가능할 경우 데이터를 중계.</li>
<li>성능은 다소 저하될 수 있으나 연결이 항상 보장됩니다.</li>
</ul>
<pre><code class="language-javascript">const peerConnection = new RTCPeerConnection({
    iceServers: [
        { urls: &quot;stun:stun.l.google.com:19302&quot; },
        { urls: &quot;turn:turnserver.example.com&quot;, username: &quot;user&quot;, credential: &quot;pass&quot; },
    ],
});</code></pre>
<hr>
<h2 id="7-react--socketio--flask의-장점">7. React + Socket.io + Flask의 장점</h2>
<h4 id="--react">- <strong>React</strong></h4>
<ul>
<li>WebRTC를 UI와 연동하여 사용자 경험을 개선할 수 있습니다.</li>
<li>Electron을 통해 패드에서도 동일한 화면을 출력할 수 있습니다.</li>
</ul>
<h4 id="--socketio">- <strong>Socket.io</strong></h4>
<ul>
<li>브라우저 간 Offer/Answer/ICE Candidate 교환을 실시간으로 처리.</li>
<li>재연결 및 브라우저 호환성을 지원하여 안정적인 통신 가능.</li>
</ul>
<h4 id="--flask">- <strong>Flask</strong></h4>
<ul>
<li>GraphRAG 기능을 위한 백엔드 처리.</li>
<li>REST API와 Socket.io의 공존이 가능해 확장성 높은 아키텍처 구축 가능.</li>
</ul>
<hr>
<h2 id="8-react--socketio--flask-구현-예시">8. React + Socket.io + Flask 구현 예시</h2>
<h3 id="81-react-클라이언트-코드">8.1 React 클라이언트 코드</h3>
<pre><code class="language-javascript">import React, { useRef } from &quot;react&quot;;
import io from &quot;socket.io-client&quot;;

const socket = io(&quot;http://localhost:5000&quot;);

const WebRTCApp = () =&gt; {
  const localVideoRef = useRef(null);
  const remoteVideoRef = useRef(null);

  const startCall = async () =&gt; {
    const stream = await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
    localVideoRef.current.srcObject = stream;

    const peerConnection = new RTCPeerConnection({
      iceServers: [{ urls: &quot;stun:stun.l.google.com:19302&quot; }],
    });

    stream.getTracks().forEach((track) =&gt; peerConnection.addTrack(track, stream));

    const offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);
    socket.emit(&quot;offer&quot;, offer);

    socket.on(&quot;answer&quot;, async (answer) =&gt; {
      await peerConnection.setRemoteDescription(answer);
    });

    peerConnection.onicecandidate = (event) =&gt; {
      if (event.candidate) socket.emit(&quot;candidate&quot;, event.candidate);
    };

    socket.on(&quot;candidate&quot;, async (candidate) =&gt; {
      await peerConnection.addIceCandidate(candidate);
    });

    peerConnection.ontrack = (event) =&gt; {
      remoteVideoRef.current.srcObject = event.streams[0];
    };
  };

  return (
    &lt;div&gt;
      &lt;video ref={localVideoRef} autoPlay muted&gt;&lt;/video&gt;
      &lt;video ref={remoteVideoRef} autoPlay&gt;&lt;/video&gt;
      &lt;button onClick={startCall}&gt;Start Call&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default WebRTCApp;</code></pre>
<hr>
<h3 id="82-flask-서버-코드">8.2 Flask 서버 코드</h3>
<pre><code class="language-python">from flask import Flask
from flask_socketio import SocketIO

app = Flask(__name__)
socketio = SocketIO(app, cors_allowed_origins=&quot;*&quot;)

@app.route(&quot;/&quot;)
def index():
    return &quot;WebRTC Signaling Server is Running&quot;

@socketio.on(&quot;offer&quot;)
def handle_offer(data):
    socketio.emit(&quot;offer&quot;, data, broadcast=True)

@socketio.on(&quot;answer&quot;)
def handle_answer(data):
    socketio.emit(&quot;answer&quot;, data, broadcast=True)

@socketio.on(&quot;candidate&quot;)
def handle_candidate(data):
    socketio.emit(&quot;candidate&quot;, data, broadcast=True)

if __name__ == &quot;__main__&quot;:
    socketio.run(app, host=&quot;0.0.0.0&quot;, port=5000)</code></pre>
<hr>
<h2 id="9-결론">9. 결론</h2>
<p>React + Socket.io + Flask 조합은 WebRTC 프로젝트에 적합한 강력한 조합입니다.</p>
<ul>
<li><p><strong>확장성</strong><br>Signaling 서버로서 역할을 수행하며, React와 연동해 실시간 통신 구현.</p>
</li>
<li><p><strong>호환성</strong><br>Electron을 통해 패드에서도 동일한 화면 제공 가능.</p>
</li>
<li><p><strong>효율성</strong><br>Signaling 이후 P2P로 데이터 전송, 서버 부하 감소와 지연 시간 최소화.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React-Native]  React-Native 란?]]></title>
            <link>https://velog.io/@jiyoon_sw524/React-Native-React-Native-%EB%9E%80</link>
            <guid>https://velog.io/@jiyoon_sw524/React-Native-React-Native-%EB%9E%80</guid>
            <pubDate>Fri, 15 Nov 2024 06:58:11 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>본 게시글은 &#39;Nomad Coders&#39;의 강의를 듣고 작성하였습니다.</p>
</blockquote>
<p align="center">
  <img src="https://velog.velcdn.com/images/jiyoon_sw524/post/9d283c65-e00f-4096-98cf-09482c242a63/image.png" width="620">
</p>

<p>React Native의 기본 구조는 다음과 같이 설명할 수 있습니다:</p>
<ol>
<li><p><strong>JavaScript 및 Markup/Styling 레이어</strong>:</p>
<ul>
<li>React Native는 JavaScript를 기반으로 작동하며, UI를 정의하는 Markup(예: JSX)과 Styling(스타일링을 위한 CSS와 유사한 문법)을 포함합니다. 이 부분은 React의 표준적인 구성요소입니다.</li>
</ul>
</li>
<li><p><strong>React Native JS 모듈</strong>:</p>
<ul>
<li>JavaScript로 작성된 React Native 모듈은 React의 컴포넌트와 기능들을 활용하여 UI와 로직을 작성합니다.</li>
<li>이 모듈은 React Native가 제공하는 API와 연결됩니다.</li>
</ul>
</li>
<li><p><strong>JavaScript 인터프리터</strong>:</p>
<ul>
<li>JavaScript 코드는 인터프리터를 통해 실행되며, 이 인터프리터가 React Native의 핵심 역할을 합니다.</li>
<li>React Native는 주로 JavaScriptCore 또는 Hermes(React Native의 경량화된 JavaScript 엔진)를 사용하여 코드를 실행합니다.</li>
</ul>
</li>
<li><p><strong>React Native 네이티브 모듈</strong>:</p>
<ul>
<li>JavaScript 코드와 네이티브 코드(Android의 Java/Kotlin, iOS의 Swift/Objective-C) 간의 다리 역할을 합니다.</li>
<li>이 모듈을 통해 JavaScript가 네이티브 플랫폼 기능(예: 카메라, GPS)에 접근할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>플랫폼 API</strong>:</p>
<ul>
<li>플랫폼(API)은 React Native 네이티브 모듈을 통해 접근할 수 있는 기능들입니다. 예를 들어, Android의 Notification Manager 또는 iOS의 Core Location API와 같은 플랫폼 별 네이티브 API에 접근하여 다양한 기능을 구현합니다.</li>
</ul>
</li>
</ol>
<p>React Native는 JavaScript와 네이티브 코드 간의 브릿지(Bridge)를 중심으로 설계되었으며, 이를 통해 하나의 코드베이스로 Android와 iOS 모두를 지원할 수 있는 애플리케이션을 개발할 수 있습니다.</p>
<hr>
---

<h3 id="1-react-native는-운영체제와-어떻게-소통하는가">1. React Native는 운영체제와 어떻게 소통하는가?</h3>
<p>React Native는 운영체제와 소통하기 위해 <strong>Bridge(다리)</strong>의 역할을 합니다.  </p>
<ul>
<li>JavaScript 레벨에서 작성된 UI 및 로직은 React Native의 브릿지를 통해 Android나 iOS의 네이티브 API와 상호작용합니다.  </li>
<li>이를 통해 JavaScript 코드로 운영체제의 다양한 기능(예: 카메라, GPS, 네트워크 등)을 제어할 수 있습니다.  </li>
</ul>
<p>결론적으로 React Native는 개발자에게 네이티브 기능을 쉽게 사용할 수 있는 환경을 제공하며, 네이티브 코드와 JavaScript 코드 간의 매끄러운 통신을 지원합니다.</p>
<h3 id="2-apk와-ipa-파일의-차이점은">2. <code>.apk</code>와 <code>.ipa</code> 파일의 차이점은?</h3>
<p>React Native로 개발된 앱은 최종적으로 Android와 iOS에서 실행 가능한 파일 형태로 빌드됩니다.</p>
<ul>
<li><p><strong><code>.apk</code> (Android Package)</strong>:</p>
<ul>
<li>Android 기기에서 사용하는 애플리케이션 패키지 파일입니다.</li>
<li>앱 코드와 리소스, 메타데이터가 포함되어 있으며, 이를 설치하면 앱이 실행됩니다.</li>
</ul>
</li>
<li><p><strong><code>.ipa</code> (iOS App Store Package)</strong>:</p>
<ul>
<li>iOS 기기에서 사용하는 애플리케이션 패키지 파일입니다.</li>
<li>바이너리 코드와 리소스가 포함되어 있으며, 일반적으로 Apple App Store를 통해 배포됩니다.</li>
</ul>
</li>
</ul>
<p><code>.apk</code>는 Android, <code>.ipa</code>는 iOS 전용이라는 차이가 있으며, React Native는 하나의 코드베이스로 두 플랫폼을 모두 지원합니다.</p>
<br>

<hr>
<p align="center">
  <img src="https://velog.velcdn.com/images/jiyoon_sw524/post/00c92b48-113d-4d12-90b6-97776c4503c3/image.png" width="620">
</p>

<h3 id="1-react-native-통신-구조">1. React Native 통신 구조</h3>
<p>React와 React Native는 각각 웹과 네이티브 환경에서 컴포넌트를 렌더링하기 위해 다른 경로를 따릅니다.</p>
<ul>
<li><p><strong>React (웹 기반)</strong>:</p>
<ul>
<li>React 컴포넌트에서 작성된 JavaScript 코드는 ReactJS로 변환된 뒤, 브라우저의 DOM(Document Object Model)과 상호작용하여 웹 UI를 렌더링합니다.</li>
</ul>
</li>
<li><p><strong>React Native (모바일 기반)</strong>:</p>
<ul>
<li>React Native 컴포넌트에서 작성된 JavaScript 코드는 React Native 브릿지를 통해 Android와 iOS의 네이티브 API와 통신합니다.</li>
<li>브릿지(Bridge)는 JavaScript와 네이티브 코드 간의 다리 역할을 하며, 플랫폼별 UI(View)와 기능을 제어할 수 있게 합니다.</li>
</ul>
</li>
</ul>
<p>이 구조는 React Native가 하나의 JavaScript 코드로 Android와 iOS 모두에 맞는 네이티브 UI를 렌더링할 수 있게 하는 핵심 요소입니다.</p>
<hr>
<p align="center">
  <img src="https://velog.velcdn.com/images/jiyoon_sw524/post/093142bc-40c1-466b-ad2c-c52483641a88/image.png" width="620">
</p>


<h3 id="2-react-native-브릿지-동작-과정">2. React Native 브릿지 동작 과정</h3>
<p>React Native의 브릿지(Bridge)는 JavaScript 코드와 네이티브 코드 간의 데이터를 주고받기 위해 다음 단계를 따릅니다:</p>
<ol>
<li><p><strong>Native 이벤트 생성</strong>:</p>
<ul>
<li>네이티브 플랫폼(Android/iOS)에서 이벤트가 발생합니다. 예: 버튼 클릭, 센서 데이터 업데이트 등.</li>
</ul>
</li>
<li><p><strong>데이터 수집 및 알림 (Collect data and notify)</strong>:</p>
<ul>
<li>네이티브 이벤트의 데이터를 수집하여 브릿지로 전달합니다.</li>
</ul>
</li>
<li><p><strong>브릿지에서 직렬화 (Serialized payload)</strong>:</p>
<ul>
<li>브릿지가 네이티브 데이터를 직렬화하여 JavaScript 환경으로 보냅니다.</li>
</ul>
</li>
<li><p><strong>JavaScript에서 이벤트 처리 (Process event)</strong>:</p>
<ul>
<li>JavaScript 레이어에서 데이터를 기반으로 이벤트를 처리합니다.</li>
</ul>
</li>
<li><p><strong>네이티브 메서드 호출 또는 UI 업데이트 (Call native methods or update UI)</strong>:</p>
<ul>
<li>JavaScript에서 네이티브 메서드를 호출하거나 UI 변경 요청을 보냅니다.</li>
</ul>
</li>
<li><p><strong>직렬화된 응답 전송 (Serialized batched response)</strong>:</p>
<ul>
<li>요청에 대한 응답이 브릿지에서 직렬화됩니다.</li>
</ul>
</li>
<li><p><strong>명령 처리 (Process commands)</strong>:</p>
<ul>
<li>네이티브에서 명령을 처리하고 UI 업데이트에 필요한 작업을 실행합니다.</li>
</ul>
</li>
<li><p><strong>UI 업데이트 (Update UI)</strong>:</p>
<ul>
<li>네이티브 환경에서 UI를 업데이트하여 사용자에게 결과를 표시합니다.</li>
</ul>
</li>
</ol>
<p>이런 동작 방식은 React Native가 JavaScript 기반의 비즈니스 로직과 네이티브 플랫폼의 고유 기능을 원활하게 연결하도록 돕는 핵심 메커니즘입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React Native 실행 명령어]]></title>
            <link>https://velog.io/@jiyoon_sw524/React-Native-%EC%8B%A4%ED%96%89-%EB%AA%85%EB%A0%B9%EC%96%B4</link>
            <guid>https://velog.io/@jiyoon_sw524/React-Native-%EC%8B%A4%ED%96%89-%EB%AA%85%EB%A0%B9%EC%96%B4</guid>
            <pubDate>Fri, 15 Nov 2024 01:53:35 GMT</pubDate>
            <description><![CDATA[<p>React Native 프로젝트를 실행하는 명령어는 <code>package.json</code>의 scripts를 보면 알 수 있습니다:</p>
<pre><code class="language-5:13:package.json">  &quot;scripts&quot;: {
    &quot;start&quot;: &quot;expo start&quot;,
    &quot;reset-project&quot;: &quot;node ./scripts/reset-project.js&quot;,
    &quot;android&quot;: &quot;expo start --android&quot;,
    &quot;ios&quot;: &quot;expo start --ios&quot;,
    &quot;web&quot;: &quot;expo start --web&quot;,
    &quot;test&quot;: &quot;jest --watchAll&quot;,
    &quot;lint&quot;: &quot;expo lint&quot;
  },</code></pre>
<p>주요 실행 명령어들은 다음과 같습니다:</p>
<ol>
<li><p><strong>기본 실행</strong></p>
<pre><code class="language-bash">npm start
# 또는
npx expo start</code></pre>
</li>
<li><p><strong>Android에서 실행</strong></p>
<pre><code class="language-bash">npm run android
# 또는
npx expo start --android</code></pre>
</li>
<li><p><strong>iOS에서 실행</strong></p>
<pre><code class="language-bash">npm run ios
# 또는
npx expo start --ios</code></pre>
</li>
<li><p><strong>웹에서 실행</strong></p>
<pre><code class="language-bash">npm run web
# 또는
npx expo start --web</code></pre>
</li>
</ol>
<p>프로젝트를 실행하기 전에 먼저 의존성 패키지들을 설치해야 합니다:</p>
<pre><code class="language-bash">npm install</code></pre>
<p>실행하면 QR 코드가 터미널에 표시되며, 다음과 같은 옵션으로 앱을 실행할 수 있습니다:</p>
<ul>
<li>Expo Go 앱으로 QR코드 스캔</li>
<li>Android 에뮬레이터</li>
<li>iOS 시뮬레이터</li>
<li>웹 브라우저</li>
</ul>
<h3 id="npm-node-package-manager">npm (Node Package Manager)</h3>
<ul>
<li>패키지를 설치하고 관리하는 도구입니다</li>
<li><code>package.json</code>에 정의된 스크립트를 실행할 때 사용합니다</li>
<li>로컬에 설치된 패키지를 실행합니다</li>
</ul>
<p>예시:</p>
<pre><code class="language-bash">npm install expo-cli  # 패키지 설치
npm start            # package.json의 start 스크립트 실행</code></pre>
<h3 id="npx-node-package-execute">npx (Node Package Execute)</h3>
<ul>
<li>패키지를 설치하지 않고 일회성으로 실행할 수 있습니다</li>
<li>항상 최신 버전의 패키지를 실행합니다</li>
<li>로컬에 설치하지 않고도 패키지를 실행할 수 있습니다</li>
</ul>
<p>예시:</p>
<pre><code class="language-bash">npx expo start      # expo-cli를 설치하지 않고도 실행 가능</code></pre>
<p>주어진 <code>package.json</code>의 경우:</p>
<pre><code class="language-bash"># 두 명령어는 동일한 결과를 실행합니다
npm start
npx expo start</code></pre>
<p>npx를 사용하면:</p>
<ol>
<li>디스크 공간을 절약할 수 있습니다</li>
<li>항상 최신 버전을 사용할 수 있습니다</li>
<li>글로벌 설치가 필요 없습니다</li>
</ol>
<p>반면 npm은:</p>
<ol>
<li>프로젝트에 필요한 패키지를 관리합니다</li>
<li>특정 버전의 패키지를 유지할 수 있습니다</li>
<li>프로젝트의 의존성을 명확하게 관리할 수 있습니다</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[React] 포트번호 변경하는 방법]]></title>
            <link>https://velog.io/@jiyoon_sw524/React-%ED%8F%AC%ED%8A%B8%EB%B2%88%ED%98%B8-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@jiyoon_sw524/React-%ED%8F%AC%ED%8A%B8%EB%B2%88%ED%98%B8-%EB%B3%80%EA%B2%BD%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Fri, 20 Sep 2024 08:15:45 GMT</pubDate>
            <description><![CDATA[<h2 id="react-애플리케이션의-포트-번호-변경-및-외부-접속-설정">React 애플리케이션의 포트 번호 변경 및 외부 접속 설정</h2>
<p>React 애플리케이션은 기본적으로 <code>http://localhost:3000</code>에서 실행됩니다. 포트를 <strong>80</strong>으로 변경하고 외부에서 접속할 수 있도록 하려면 몇 가지 설정을 해야 합니다. 아래에서 필요한 과정을 설명하겠습니다.</p>
<h3 id="1-포트-변경">1. 포트 변경</h3>
<p>포트를 80으로 변경하기 위해서는 두 가지 옵션이 있습니다.</p>
<h4 id="11-packagejson에-설정-추가">1.1 <code>package.json</code>에 설정 추가</h4>
<p><code>react-scripts</code>를 사용 중인 경우, <code>package.json</code> 파일에서 다음과 같이 <code>start</code> 스크립트를 수정할 수 있습니다.</p>
<pre><code class="language-json">&quot;scripts&quot;: {
  &quot;start&quot;: &quot;PORT=80 react-scripts start&quot;
}</code></pre>
<p>하지만, <strong>Windows</strong> 환경에서는 이 방법이 작동하지 않습니다. Windows에서는 <code>cross-env</code>라는 패키지를 사용해야 합니다.</p>
<pre><code class="language-bash">npm install cross-env</code></pre>
<p>그런 다음 <code>package.json</code>에서 <code>start</code> 스크립트를 다음과 같이 수정합니다.</p>
<pre><code class="language-json">&quot;scripts&quot;: {
  &quot;start&quot;: &quot;cross-env PORT=80 react-scripts start&quot;
}</code></pre>
<h4 id="12-환경-변수-설정">1.2 환경 변수 설정</h4>
<p><code>PORT</code> 환경 변수를 직접 설정하는 방법도 있습니다. 이 방법은 운영체제에 따라 다릅니다.</p>
<ul>
<li><p><strong>Linux / macOS</strong>:</p>
<pre><code class="language-bash">PORT=80 npm start</code></pre>
</li>
<li><p><strong>Windows</strong> (PowerShell):</p>
<pre><code class="language-bash">$env:PORT=80; npm start</code></pre>
</li>
<li><p><strong>Windows</strong> (CMD):</p>
<pre><code class="language-cmd">set PORT=80 &amp;&amp; npm start</code></pre>
</li>
</ul>
<h3 id="2-외부에서-접속-가능하도록-설정">2. 외부에서 접속 가능하도록 설정</h3>
<p>기본적으로 <code>create-react-app</code>은 <code>localhost</code>에서만 애플리케이션을 실행합니다. 외부에서 접근할 수 있게 하려면 <code>package.json</code>에 다음 설정을 추가합니다.</p>
<pre><code class="language-json">&quot;scripts&quot;: {
  &quot;start&quot;: &quot;HOST=0.0.0.0 PORT=80 react-scripts start&quot;
}</code></pre>
<p>이렇게 하면 <code>0.0.0.0</code> 인터페이스에서 애플리케이션을 실행하므로, 외부에서 접속할 수 있습니다.</p>
<h3 id="3-포트-80은-루트-권한이-필요">3. 포트 80은 루트 권한이 필요</h3>
<p>Linux와 macOS에서 포트 80과 같은 낮은 번호의 포트를 사용하려면 <strong>루트 권한</strong>이 필요합니다. 그러므로 포트 80에서 애플리케이션을 실행하려면 <code>sudo</code> 명령을 사용해야 합니다.</p>
<pre><code class="language-bash">sudo PORT=80 npm start</code></pre>
<h3 id="4-프로덕션-환경에서는-nginxapache-사용-권장">4. 프로덕션 환경에서는 Nginx/Apache 사용 권장</h3>
<p>개발 환경에서 포트를 80으로 바꾸는 것은 가능하지만, 프로덕션 환경에서는 Nginx나 Apache 같은 <strong>리버스 프록시</strong> 서버를 사용하여 포트 80에서 들어오는 요청을 React 애플리케이션으로 프록시하는 것이 일반적입니다.</p>
<p>이 경우, React 애플리케이션은 기본적으로 포트 3000 또는 다른 포트에서 실행되며, Nginx가 포트 80에서 요청을 받고 이를 React 애플리케이션으로 전달하게 됩니다.</p>
<h4 id="41-nginx-설정-예시">4.1 Nginx 설정 예시</h4>
<pre><code class="language-nginx">server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://localhost:3000; # React 앱이 실행 중인 포트
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}</code></pre>
<p>Nginx는 포트 80에서 요청을 받고, React 애플리케이션은 포트 3000에서 실행되며 Nginx가 프록시 역할을 합니다.</p>
<hr>
<h2 id="url-접근">URL 접근</h2>
<p>포트 번호를 변경한 후에는, 다른 클라이언트가 애플리케이션에 접근하기 위해 브라우저의 URL 창에 <code>http://서버의-IP-주소:새-포트번호</code> 형식을 사용해야 합니다.</p>
<h4 id="예시">예시:</h4>
<pre><code>http://223.194.135.40:5000</code></pre><p>포트 번호가 <strong>80</strong>일 때는 <strong>HTTP 프로토콜의 기본 포트</strong>이기 때문에 URL에서 생략됩니다.</p>
<h3 id="1-서버의-ip-주소">1. 서버의 IP 주소</h3>
<p>서버가 인터넷에 연결되어 있고 공용 IP 주소를 가지고 있다면, 그 IP 주소를 사용해 접근할 수 있습니다.</p>
<h4 id="예시-1">예시:</h4>
<ul>
<li>서버의 IP 주소가 <code>123.456.789.101</code>이라면:<pre><code>http://123.456.789.101</code></pre></li>
</ul>
<p>포트를 80으로 설정했기 때문에 기본적으로 <code>http://123.456.789.101</code>로 접속하면 됩니다. 포트 80은 HTTP의 기본 포트이므로 따로 포트 번호를 입력할 필요가 없습니다.</p>
<h3 id="2-도메인-이름">2. 도메인 이름</h3>
<p>만약 도메인 이름이 설정되어 있다면, 클라이언트는 그 도메인을 사용해 접속할 수 있습니다.</p>
<h4 id="예시-2">예시:</h4>
<ul>
<li>서버에 <code>example.com</code>이라는 도메인이 설정되어 있다면:<pre><code>http://example.com</code></pre></li>
</ul>
<p>마찬가지로, 포트 80에서 실행 중이므로 포트 번호를 따로 입력하지 않아도 됩니다.</p>
<h3 id="3-내부-네트워크에서의-접근-로컬-네트워크">3. 내부 네트워크에서의 접근 (로컬 네트워크)</h3>
<p>만약 동일한 로컬 네트워크(예: 회사나 집의 Wi-Fi 네트워크)에 있는 다른 컴퓨터나 장치가 접근하려는 경우, 서버의 <strong>로컬 IP 주소</strong>를 사용해야 합니다.</p>
<h4 id="예시-3">예시:</h4>
<ul>
<li>로컬 네트워크에서 서버의 IP 주소가 <code>192.168.1.100</code>이라면:<pre><code>http://192.168.1.100</code></pre></li>
</ul>
<h3 id="4-서버-ip-주소-확인-방법">4. 서버 IP 주소 확인 방법</h3>
<h4 id="windows에서-ip-주소-확인-방법">Windows에서 IP 주소 확인 방법:</h4>
<ol>
<li>명령 프롬프트를 열고 <code>ipconfig</code> 명령을 입력합니다.</li>
<li>네트워크 어댑터 정보 중 &quot;IPv4 주소&quot;에 해당하는 IP 주소를 찾습니다.</li>
</ol>
<h4 id="linuxmacos에서-ip-주소-확인-방법">Linux/macOS에서 IP 주소 확인 방법:</h4>
<ol>
<li>터미널에서 <code>ifconfig</code> 명령을 입력하거나, <code>ip addr</code> 명령을 사용해 IP 주소를 확인할 수 있습니다.</li>
</ol>
<h3 id="5-포트-전달-포트-포워딩">5. 포트 전달 (포트 포워딩)</h3>
<p>만약 서버가 로컬 네트워크 내에 있고, 외부에서 접근할 수 있도록 하려면 <strong>포트 포워딩</strong> 설정을 해야 할 수 있습니다. 이는 주로 가정용 라우터에서 설정되며, 포트 80의 요청을 해당 서버로 전달하도록 라우터를 구성해야 합니다.</p>
<hr>
<h2 id="로컬-호스트localhost와-0000-인터페이스의-차이">로컬 호스트(<code>localhost</code>)와 <code>0.0.0.0</code> 인터페이스의 차이</h2>
<h3 id="1-로컬-호스트와-0000의-주요-차이점">1. 로컬 호스트와 <code>0.0.0.0</code>의 주요 차이점</h3>
<h4 id="11-localhost-127001">1.1 <code>localhost</code> (127.0.0.1)</h4>
<ul>
<li>본인 컴퓨터에서만 접근 가능.</li>
<li>다른 장치가 동일 네트워크에 있더라도, 해당 애플리케이션에 접속할 수 없음.</li>
<li>보안적인 이유로 개발 단계에서 주로 사용됨.</li>
</ul>
<h4 id="12-0000">1.2 <code>0.0.0.0</code></h4>
<ul>
<li>컴퓨터의 모든 네트워크 인터페이스에서 접속을 허용.</li>
<li>동일 네트워크에 있는 다른 장치나 외부 네트워크에서도 접속할 수 있음.</li>
<li>외부에서의 접근을 허용할 때 사용됨.</li>
</ul>
<h4 id="예시-4">예시</h4>
<ul>
<li><strong><code>localhost:3000</code>에서 실행</strong>: 본인 컴퓨터에서만 접근 가능. 다른 장치에서 접근 불가능.</li>
<li><strong><code>0.0.0.0:3000</code>에서 실행</strong>: 본인 컴퓨터뿐만 아니라 같은 네트워크에 연결된 다른 장치나, 공용 IP를 통해 인터넷을 통한 접속도 가능.</li>
</ul>
<h3 id="2-왜-0000을-사용하나요">2. 왜 <code>0.0.0.0</code>을 사용하나요?</h3>
<p><code>0.0.0.0</code>으로 설정하면 외부의 네트워크 장치들도 해당 서버에 접속할 수 있기 때문에, 개발 중에 여러 장치에서 테스트를 하거나 네트워크 환경에서 접근을 허용할 때 유용합니다.</p>
<h4 id="어떤-경우에-사용하는지-예시">어떤 경우에 사용하는지 예시:</h4>
<ol>
<li><p><strong>로컬 네트워크에서 다른 장치로부터 애플리케이션 테스트</strong></p>
<ul>
<li>예를 들어, React 애플리케이션을 <code>localhost</code>가 아닌 <code>0.0.0.0</code>에서 실행하면, 동일 네트워크에 있는 다른 컴퓨터나 스마트폰 등에서도 애플리케이션을 접속해볼 수 있습니다.</li>
</ul>
</li>
<li><p><strong>서버에서 애플리케이션 실행</strong></p>
<ul>
<li>프로덕션 환경에서 웹 애플리케이션을 서버에 배포한 후, <code>0.0.0.0</code>에서 실행하면 해당 서버에 접속할 수 있는 다른 클라이언트들도 애플리케이션을 사용할 수 있게 됩니다. 이 경우 <code>0.0.0.0</code>을 사용해 외부 트래픽을 허용합니다.</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이프라인 구축]]></title>
            <link>https://velog.io/@jiyoon_sw524/%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8-%EA%B5%AC%EC%B6%95</link>
            <guid>https://velog.io/@jiyoon_sw524/%ED%8C%8C%EC%9D%B4%ED%94%84%EB%9D%BC%EC%9D%B8-%EA%B5%AC%EC%B6%95</guid>
            <pubDate>Fri, 13 Sep 2024 04:59:15 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>목표</strong>: <strong>Neo4j</strong>와 <strong>GraphRAG</strong>를 통합하여 <strong>멀티모달 데이터</strong>(텍스트, 이미지, 동영상, 음성)를 효과적으로 <strong>관리</strong>하고 <strong>검색</strong>하며, 이를 통해 <strong>풍부하고 의미 있는 답변</strong>을 사용자에게 제공하는 시스템을 구축하는 것입니다.</p>
</blockquote>
<br>

<h2 id="1-시스템-구성-요소">1. <strong>시스템 구성 요소</strong></h2>
<h4 id="1-neo4j그래프-데이터베이스">1. Neo4j(그래프 데이터베이스)</h4>
<ul>
<li><strong>역할</strong>: 메타데이터 및 관계 데이터 저장</li>
<li><strong>저장 데이터</strong>:<ul>
<li>멀티모달 데이터의 메타데이터(파일 경로, 타임 스탬프 등)</li>
<li>스크립트 요약본</li>
<li>스크립트 원본 링크 (클라우드 또는 로컬 저장소 참조)</li>
<li>엔티티 간 관계 데이터</li>
</ul>
</li>
</ul>
<h4 id="2-graphrag그래프-기반-검색-및-분석-시스템">2. GraphRAG(그래프 기반 검색 및 분석 시스템)</h4>
<ul>
<li><strong>역할</strong>: 텍스트 데이터 분석 및 복잡한 쿼리 처리</li>
<li><strong>저장 데이터</strong>:<ul>
<li>분석된 텍스트 데이터 (Parquet 파일 형식)</li>
</ul>
</li>
</ul>
<ol start="3">
<li><p><strong>Parquet 파일</strong>:</p>
<ul>
<li><strong>역할</strong>: Parquet 파일은 대용량 텍스트 데이터를 효율적으로 저장하고, GraphRAG에서 신속한 검색과 분석에 활용할 수 있는 포맷입니다.</li>
</ul>
</li>
<li><p>벡터 데이터베이스 (예: Pinecone, Weaviate)</p>
<ul>
<li>역할: 대규모 임베딩 저장 및 유사도 검색</li>
<li>저장 데이터:텍스트, 이미지, 오디오 임베딩</li>
</ul>
</li>
<li><p>멀티모달 인코더 (ex. CLIP, Whisper)</p>
<ul>
<li>역할: 다양한 모달리티의 데이터를 벡터로 변환</li>
</ul>
</li>
<li><p>오케스트레이션 레이어</p>
<ul>
<li>역할: 전체 시스템 구성요소 간 조정 및 워크플로우 관리</li>
</ul>
</li>
</ol>
<hr>
<h3 id="2-데이터-처리-흐름">2. <strong>데이터 처리 흐름</strong></h3>
<ol>
<li><strong>데이터 입력 및 저장</strong>:</li>
</ol>
<ul>
<li>멀티모달 데이터 입력 (텍스트, 이미지, 비디오, 오디오)</li>
<li>각 모달리티별 전처리 (예: 비디오에서 프레임 추출, 오디오 전사)</li>
</ul>
<ol start="2">
<li><p><strong>텍스트 데이터의 분석 및 저장</strong>:</p>
<ul>
<li>제공된 텍스트 설명(예: 동영상 자막, 음성 전사본 등)을 GraphRAG를 통해 분석합니다. 이 분석된 텍스트 데이터는 Parquet 파일로 저장되어, 이후의 텍스트 기반 검색에 활용됩니다.</li>
</ul>
</li>
<li><p><strong>검색 및 분석</strong>:</p>
<ul>
<li><strong>Neo4j에서 초기 검색</strong>: 사용자가 특정 질문을 입력하면, Neo4j에서 먼저 메타데이터와 텍스트 설명을 기반으로 초기 검색을 수행합니다. 예를 들어, &quot;스크루지가 담배 피면서 브레이킹 댄스를 추는 장면&quot;과 같은 구체적인 장면을 검색할 수 있습니다.</li>
<li><strong>GraphRAG에서 추가 검색</strong>: Neo4j에서 필요한 정보를 찾지 못한 경우, GraphRAG에서 Parquet 파일에 저장된 텍스트 데이터를 사용해 추가적인 검색을 수행합니다. 이 과정에서 복잡한 텍스트 분석이 이루어지고, 질문에 대한 포괄적인 답변이 생성됩니다.</li>
</ul>
</li>
<li><p><strong>최종 응답 제공</strong>:</p>
<ul>
<li><strong>통합된 응답 생성</strong>: Neo4j와 GraphRAG에서 얻은 정보를 종합하여, 사용자가 요청한 정보(예: 특정 장면의 동영상 링크와 그 행동의 이유)를 제공할 수 있습니다. 이때, 동영상 링크와 함께 관련된 텍스트 설명이 제공됩니다.</li>
</ul>
</li>
</ol>
<hr>
<h3 id="3-시스템-최적화-및-추가-고려-사항">3. <strong>시스템 최적화 및 추가 고려 사항</strong></h3>
<ol>
<li><p><strong>데이터 용량 관리</strong>:</p>
<ul>
<li>Neo4j는 대규모 데이터셋에서 성능 저하가 발생할 수 있으므로, 샤딩, 클러스터링, 아카이빙 등을 통해 데이터 용량을 관리해야 합니다.</li>
</ul>
</li>
<li><p><strong>추가 파이프라인 구성</strong>:</p>
<ul>
<li>사용자가 요청한 정보를 더 쉽게 검색하고 제공하기 위해, GraphRAG에서 얻은 텍스트 데이터를 기반으로 Neo4j에서 역으로 검색하는 파이프라인을 추가할 수 있습니다. 이 경우, 사용자에게 자동으로 동영상 링크를 제공할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>시나리오별 최적화</strong>:</p>
<ul>
<li>텍스트 기반 질문은 GraphRAG에서 바로 처리하고, 멀티모달 데이터를 포함한 복잡한 질문은 Neo4j에서 메타데이터를 먼저 검색한 후, GraphRAG에서 추가적인 분석을 수행하는 방식으로 시스템을 최적화할 수 있습니다.</li>
</ul>
</li>
</ol>
<hr>
<h2 id="결론">결론</h2>
<p>이 통합 시스템은 Neo4j와 GraphRAG의 강점을 결합하여, 복잡한 멀티모달 데이터셋에서도 효율적인 검색과 분석을 가능하게 합니다. Parquet 파일을 활용한 사전 분석과 Neo4j의 관계 데이터 관리를 통해, 대규모 데이터에서도 사용자에게 의미 있는 응답을 제공할 수 있습니다. 이로 인해 다양한 데이터 유형을 효과적으로 처리하고, 사용자 경험을 향상시킬 수 있는 강력한 시스템이 완성됩니다.</p>
<h2 id="neo4j-데이터-용량-관리">neo4j 데이터 용량 관리</h2>
<p>Neo4j는 기본적으로 그래프 데이터베이스로, 관계 데이터 모델링에 강점을 가지고 있지만, 데이터 용량이 매우 커지면 성능 저하가 발생할 수 있습니다. 특히 노드, 관계, 속성이 많아질수록 쿼리 성능이 떨어질 가능성이 있습니다. 이를 해결하기 위한 몇 가지 전략은 다음과 같습니다:</p>
<h3 id="1-데이터-샤딩-및-분산-처리">1. <strong>데이터 샤딩 및 분산 처리</strong></h3>
<ul>
<li><strong>샤딩</strong>: 데이터를 여러 샤드(부분)로 나누어 저장하는 방법입니다. 각 샤드는 독립적인 데이터베이스 인스턴스에 저장되며, 이러한 샤드들이 결합되어 전체 데이터를 구성합니다. Neo4j 자체적으로 샤딩 기능을 지원하지 않지만, 이를 클러스터링 방식으로 구현할 수 있습니다.</li>
<li><strong>Neo4j 클러스터링</strong>: Neo4j는 클러스터링 기능을 제공하여 데이터베이스를 여러 노드로 분산시킬 수 있습니다. 클러스터링을 통해 데이터의 분산 저장 및 처리를 하여 성능을 향상시킬 수 있습니다. 이를 통해 더 많은 데이터를 처리할 수 있으며, 가용성과 내구성도 높일 수 있습니다.</li>
</ul>
<h3 id="2-데이터-아카이빙-및-백업">2. <strong>데이터 아카이빙 및 백업</strong></h3>
<ul>
<li><strong>아카이빙</strong>: 자주 사용되지 않는 오래된 데이터나 필요 시 복원 가능한 데이터를 아카이빙하여 메인 데이터베이스에서 분리합니다. 이를 통해 데이터베이스의 크기를 줄이고 성능을 최적화할 수 있습니다.</li>
<li><strong>백업 및 스냅샷</strong>: Neo4j에서 주기적으로 데이터를 백업하고, 스냅샷을 생성하여 장애 발생 시 데이터를 복구할 수 있도록 합니다. 이 방식으로 시스템 안정성을 유지하면서 데이터 양을 관리할 수 있습니다.</li>
</ul>
<h3 id="3-인덱싱-최적화">3. <strong>인덱싱 최적화</strong></h3>
<ul>
<li><strong>효율적인 인덱싱</strong>: Neo4j에서 필요한 인덱스를 적절히 설정하여 쿼리 성능을 최적화할 수 있습니다. 잘 설계된 인덱스는 쿼리 처리 속도를 크게 향상시킬 수 있습니다. 그러나 인덱스가 너무 많으면 성능에 부정적인 영향을 미칠 수 있으므로, 최적화된 인덱스 전략을 유지하는 것이 중요합니다.</li>
</ul>
<h3 id="4-데이터-파티셔닝">4. <strong>데이터 파티셔닝</strong></h3>
<ul>
<li><strong>수평 파티셔닝</strong>: 데이터를 논리적으로 나누어 여러 데이터베이스에 저장하는 방법입니다. 각 파티션은 독립적으로 쿼리되며, 필요한 경우 전체 데이터를 결합하여 사용할 수 있습니다. 이 방법은 데이터의 물리적 분리를 통해 성능을 최적화하는 데 유용합니다.</li>
</ul>
<h3 id="5-메모리-및-스토리지-확장">5. <strong>메모리 및 스토리지 확장</strong></h3>
<ul>
<li><strong>하드웨어 업그레이드</strong>: Neo4j의 성능 문제를 해결하기 위해서는 충분한 메모리와 빠른 디스크 I/O를 제공하는 하드웨어를 사용하는 것이 중요합니다. 특히 SSD와 같은 고속 스토리지를 사용하면 데이터 접근 속도가 크게 향상될 수 있습니다.</li>
<li><strong>메모리 캐시 조정</strong>: Neo4j에서 메모리 캐시 설정을 최적화하여 자주 접근하는 데이터를 메모리에 상주시켜 쿼리 성능을 향상시킬 수 있습니다.</li>
</ul>
<h1 id="한국어-모델">한국어 모델</h1>
<ol>
<li><strong><a href="https://aiopen.etri.re.kr/et5Model">한국어 이해생성 언어모델</a></strong>(ET5): 과학기술정보통신부와 IITP의 한국어 이해 및 생성이 가능한 언어모델</li>
<li><strong><a href="https://developers.kakao.com/product/kogpt">KoGPT API</a></strong></li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[Neo4j에 GraphRAG 결과 Parquet 파일 가져오기]]></title>
            <link>https://velog.io/@jiyoon_sw524/Neo4j%EC%97%90-GraphRAG-%EA%B2%B0%EA%B3%BC-Parquet-%ED%8C%8C%EC%9D%BC-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0</link>
            <guid>https://velog.io/@jiyoon_sw524/Neo4j%EC%97%90-GraphRAG-%EA%B2%B0%EA%B3%BC-Parquet-%ED%8C%8C%EC%9D%BC-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0</guid>
            <pubDate>Mon, 02 Sep 2024 15:51:06 GMT</pubDate>
            <description><![CDATA[<p>이 글은 GraphRAG 인덱싱 프로세스의 결과를 Neo4j 그래프 데이터베이스에 가져와 추가 처리, 분석 또는 시각화를 수행하는 절차를 작성하였습니다.</p>
<h3 id="어떻게-작동하나요">어떻게 작동하나요?</h3>
<p>인덱싱 프로세스의 출력 폴더에서 Parquet 파일을 로드하여 Pandas 데이터프레임에 불러옵니다. 그런 다음, 데이터를 Neo4j에 일괄 처리 방식으로 전송하여 노드와 관계를 생성하고 관련 속성을 추가합니다. 대부분의 엔터티에 대한 id 배열은 관계로 변환됩니다.
(예를 들어, 하나의 엔터티(노드)가 여러 다른 엔터티들과 연결될 때, 이 연결을 id 배열로 표현하여 각 엔터티(entity) 간의 관계를 명확하게 표현한다.)</p>
<p>모든 작업은 MERGE를 사용하므로 멱등성을 유지하며, 스크립트를 여러 번 실행해도 안전합니다.
(특정 노드나 관계를 데이터베이스에 존재하는지 확인하고, 존재하지 않으면 새로 생성하는 작업)</p>
<p><strong>데이터베이스를 정리</strong>해야 하는 경우, 다음 명령문을 실행하면 됩니다:</p>
<pre><code class="language-sql">MATCH (n)
CALL { WITH n DETACH DELETE n } IN TRANSACTIONS OF 25000 ROWS;</code></pre>
<br>

<pre><code class="language-python">&quot;&quot;&quot;DB 업데이트 메서드: 데이터프레임을 배치로 Neo4j에 삽입합니다.&quot;&quot;&quot;
    def batched_import(self, statement: str, df: pd.DataFrame, batch_size: int = 1000) -&gt; int:
        total = len(df)
        start_time = time.time()
        for start in range(0, total, batch_size):
            batch = df.iloc[start:min(start + batch_size, total)]
            with self.driver.session(database=os.getenv(&quot;NEO4J_DATABASE&quot;)) as session:
                session.run(&quot;UNWIND $rows AS row &quot; + statement, {&quot;rows&quot;: batch.to_dict(&#39;records&#39;)})
        elapsed_time = time.time() - start_time
        print(f&#39;Imported {total} rows in {elapsed_time:.2f} seconds.&#39;)
        return total</code></pre>
<p><br> <hr></p>
<h2 id="인덱스와-제약-조건">인덱스와 제약 조건</h2>
<p>Neo4j에서 인덱스는 그래프 쿼리의 시작점을 찾는 데만 사용됩니다. 예를 들어, 두 노드를 빠르게 찾아 연결하는 데 사용됩니다. 제약 조건은 중복을 방지하기 위해 존재하며, 주로 엔터티 유형의 ID에 대해 생성합니다.</p>
<p>우리는 일부 유형(메타데이터 유형, 마커 유형, 관계 유형을 나타내는 마커)을 실제 엔터티 유형과 구분하기 위해 앞뒤에 두 개의 밑줄(<code>__</code>)을 사용하여 마커로 사용합니다.</p>
<p>여기서 기본 관계 유형은 <code>RELATED</code>이지만, 설명이나 시작 및 끝 노드의 유형에서 실제 관계 유형을 추론할 수도 있습니다.</p>
<ul>
<li><code>__Entity__</code></li>
<li><code>__Document__</code></li>
<li><code>__Chunk__</code></li>
<li><code>__Community__</code></li>
<li><code>__Covariate__</code></li>
</ul>
<pre><code class="language-python">&quot;&quot;&quot;제약 조건 생성 메서드: 데이터베이스에 필요한 제약 조건을 생성합니다.&quot;&quot;&quot;
    def create_constraints(self):
        statements = &quot;&quot;&quot;
        create constraint chunk_id if not exists for (c:__Chunk__) require c.id is unique;
        create constraint document_id if not exists for (d:__Document__) require d.id is unique;
        create constraint entity_id if not exists for (c:__Community__) require c.community is unique;
        create constraint entity_id if not exists for (e:__Entity__) require e.id is unique;
        create constraint entity_title if not exists for (e:__Entity__) require e.name is unique;
        create constraint entity_title if not exists for (e:__Covariate__) require e.title is unique;
        create constraint related_id if not exists for ()-[rel:RELATED]-&gt;() require rel.id is unique;
        &quot;&quot;&quot;.split(&quot;;&quot;)

        for statement in statements:
            if len((statement or &quot;&quot;).strip()) &gt; 0:
                with self.driver.session(database=os.getenv(&quot;NEO4J_DATABASE&quot;)) as session:
                    session.run(statement)</code></pre>
<p><br> <hr></p>
<h2 id="import-process">Import Process</h2>
<h4 id="importing-the-documents">Importing the Documents</h4>
<p>문서에 대한 Parquet 파일을 로드하고, 각 문서의 ID를 사용하여 노드를 생성하며 제목 속성을 추가합니다. text_unit_ids를 저장할 필요는 없습니다. 왜냐하면 관계를 생성할 수 있고, 텍스트 내용이 청크에 포함되어 있기 때문입니다.</p>
<pre><code class="language-python">doc_df = pd.read_parquet(f&#39;{GRAPHRAG_FOLDER}/create_final_documents.parquet&#39;, columns=[&quot;id&quot;, &quot;title&quot;])
doc_df.head(2)</code></pre>
<br>

<h4 id="loading-text-units">Loading Text Units</h4>
<br>

<h1 id="최종본">최종본</h1>
<pre><code class="language-py">import os
from dotenv import load_dotenv
from neo4j import GraphDatabase
import pandas as pd
from typing import Dict, Any
import time

class EnvironmentLoader:
    @staticmethod
    def load_env_variables():
        load_dotenv()
        return {
            &quot;OPENAI_API_KEY&quot;: os.getenv(&quot;GRAPHRAG_API_KEY&quot;),
            &quot;NEO4J_URI&quot;: os.getenv(&quot;NEO4J_URI&quot;),
            &quot;NEO4J_USER&quot;: os.getenv(&quot;NEO4J_USER&quot;),
            &quot;NEO4J_PASSWORD&quot;: os.getenv(&quot;NEO4J_PASSWORD&quot;),
            &quot;NEO4J_DATABASE&quot;: os.getenv(&quot;NEO4J_DATABASE&quot;)
        }
class Neo4jClient:
    &quot;&quot;&quot;초기화 메서드: 환경 변수를 로드하고 Neo4j 드라이버를 설정합니다.&quot;&quot;&quot;
    def __init__(self, config: Dict[str, Any]):
        self.driver = GraphDatabase.driver(
            config[&quot;NEO4J_URI&quot;],
            auth=(config[&quot;NEO4J_USER&quot;], config[&quot;NEO4J_PASSWORD&quot;])
        )
        self.database = os.getenv(&quot;NEO4J_DATABASE&quot;)

    &quot;&quot;&quot;제약 조건 생성 메서드: 데이터베이스에 필요한 제약 조건을 생성합니다.&quot;&quot;&quot;
    def create_constraints(self):
        statements = &quot;&quot;&quot;
        create constraint chunk_id if not exists for (c:__Chunk__) require c.id is unique;
        create constraint document_id if not exists for (d:__Document__) require d.id is unique;
        create constraint entity_id if not exists for (c:__Community__) require c.community is unique;
        create constraint entity_id if not exists for (e:__Entity__) require e.id is unique;
        create constraint entity_title if not exists for (e:__Entity__) require e.name is unique;
        create constraint entity_title if not exists for (e:__Covariate__) require e.title is unique;
        create constraint related_id if not exists for ()-[rel:RELATED]-&gt;() require rel.id is unique;
        &quot;&quot;&quot;.strip().split(&quot;;&quot;)

        with self.driver.session(database=self.database) as session:
            for statement in statements:
                if statement.strip():  # 빈 문자열이 아닌 경우에만 실행
                    session.run(statement.strip())

    &quot;&quot;&quot;DB 쿼리 메서드: Cypher 쿼리를 실행하고 결과를 DataFrame으로 반환합니다.&quot;&quot;&quot;
    def db_query(self, cypher: str, params: Dict[str, Any] = {}) -&gt; pd.DataFrame:
        with self.driver.session(database=self.database) as session:
            result = session.run(cypher, parameters=params)
            return result.to_df()

    &quot;&quot;&quot;DB 업데이트 메서드: 데이터프레임을 배치로 Neo4j에 삽입합니다.&quot;&quot;&quot;
    def batched_import(self, statement: str, df: pd.DataFrame, batch_size: int = 1000) -&gt; int:
        total = len(df)
        records = df.to_dict(&#39;records&#39;)
        start_time = time.time()

        with self.driver.session(database=self.database) as session:
            for start in range(0, total, batch_size):
                batch = records[start:min(start + batch_size, total)]
                session.run(&quot;UNWIND $rows AS row &quot; + statement, {&quot;rows&quot;: batch})

        elapsed_time = time.time() - start_time
        print(f&#39;Imported {total} rows in {elapsed_time:.2f} seconds.&#39;)
        return total

    def import_doc(self, doc_df: pd.DataFrame) -&gt; int:
        statement = &quot;&quot;&quot;
        MERGE (d:__Document__ {id: row.id})
        SET d += row {.title}
        &quot;&quot;&quot;
        return self.batched_import(statement, doc_df)

    def __del__(self):
        if hasattr(self, &#39;driver&#39;):
            self.driver.close()

&quot;&quot;&quot;그래프 데이터를 Neo4j로 가져오는 클래스&quot;&quot;&quot;
class GraphRAGImporter:

    GRAPHRAG_FOLDER = &quot;/Users/jiyoon/Downloads/기술면접_KG/langGraphRAG_Neo/ragtest/output/20240904-215250/artifacts&quot;

    def __init__(self):
        config = EnvironmentLoader.load_env_variables()
        self.client = Neo4jClient(config)

    def import_documents(self):
        doc_df = pd.read_parquet(f&#39;{self.GRAPHRAG_FOLDER}/create_final_documents.parquet&#39;, columns=[&quot;id&quot;, &quot;title&quot;])
        return self.client.import_doc(doc_df)

    # __Chunk__ 노드의 토큰 수와 노드 수를 반환하는 쿼리
    def query_chunks(self):
        query = &quot;MATCH (n:__Chunk__) RETURN n.n_tokens as token_count, count(*) AS count&quot;
        return self.client.db_query(query)

    def import_text_units(self):
        text_df = pd.read_parquet(f&#39;{self.GRAPHRAG_FOLDER}/create_final_text_units.parquet&#39;,
                                columns=[&quot;id&quot;,&quot;text&quot;,&quot;n_tokens&quot;,&quot;document_ids&quot;])
        statement = &quot;&quot;&quot;
        MERGE (c:__Chunk__ {id: row.id})
        SET c += row {.text, .n_tokens}
        WITH c, row
        UNWIND row.document_ids AS document
        MATCH (d:__Document__ {id: document})
        MERGE (c)-[:PART_OF]-&gt;(d)
        &quot;&quot;&quot;
        return self.client.batched_import(statement, text_df)

    def import_entities(self):
        entity_df = pd.read_parquet(f&#39;{self.GRAPHRAG_FOLDER}/create_final_entities.parquet&#39;,
                                    columns=[&quot;name&quot;,&quot;type&quot;,&quot;description&quot;,&quot;human_readable_id&quot;,&quot;id&quot;,&quot;description_embedding&quot;,&quot;text_unit_ids&quot;])
        entity_statement = &quot;&quot;&quot;
        MERGE (e:__Entity__ {id:row.id})
        SET e += row {.human_readable_id, .description, name:replace(row.name,&#39;&quot;&#39;,&#39;&#39;)}
        WITH e, row
        CALL db.create.setNodeVectorProperty(e, &quot;description_embedding&quot;, row.description_embedding)
        CALL apoc.create.addLabels(e, case when coalesce(row.type,&quot;&quot;) = &quot;&quot; then [] else [apoc.text.upperCamelCase(replace(row.type,&#39;&quot;&#39;,&#39;&#39;))] end) yield node
        UNWIND row.text_unit_ids AS text_unit
        MATCH (c:__Chunk__ {id:text_unit})
        MERGE (c)-[:HAS_ENTITY]-&gt;(e)
        &quot;&quot;&quot;
        return self.client.batched_import(entity_statement, entity_df)

    def import_relationships(self):
        rel_df = pd.read_parquet(f&#39;{self.GRAPHRAG_FOLDER}/create_final_relationships.parquet&#39;, 
                                columns=[&quot;source&quot;,&quot;target&quot;,&quot;id&quot;,&quot;rank&quot;,&quot;weight&quot;,&quot;human_readable_id&quot;,&quot;description&quot;,&quot;text_unit_ids&quot;])
        rel_statement = &quot;&quot;&quot;
        MATCH (source:__Entity__ {name:replace(row.source,&#39;&quot;&#39;,&#39;&#39;)})
        MATCH (target:__Entity__ {name:replace(row.target,&#39;&quot;&#39;,&#39;&#39;)})
        // not necessary to merge on id as there is only one relationship per pair
        MERGE (source)-[rel:RELATED {id: row.id}]-&gt;(target)
        SET rel += row {.rank, .weight, .human_readable_id, .description, .text_unit_ids}
        RETURN count(*) as createdRels
        &quot;&quot;&quot;
        return self.client.batched_import(rel_statement, rel_df)

    def import_communities(self):
        community_df = pd.read_parquet(f&#39;{self.GRAPHRAG_FOLDER}/create_final_communities.parquet&#39;, 
                        columns=[&quot;id&quot;,&quot;level&quot;,&quot;title&quot;,&quot;text_unit_ids&quot;,&quot;relationship_ids&quot;])
        statement = &quot;&quot;&quot;
        MERGE (c:__Community__ {community:row.id})
        SET c += row {.level, .title}
        WITH *
        UNWIND row.relationship_ids as rel_id
        MATCH (start:__Entity__)-[:RELATED {id:rel_id}]-&gt;(end:__Entity__)
        MERGE (start)-[:IN_COMMUNITY]-&gt;(c)
        MERGE (end)-[:IN_COMMUNITY]-&gt;(c)
        RETURN count(distinct c) as createdCommunities
        &quot;&quot;&quot;
        return self.client.batched_import(statement, community_df)

    def import_community_reports(self):
        community_report_df = pd.read_parquet(f&#39;{self.GRAPHRAG_FOLDER}/create_final_community_reports.parquet&#39;,
                            columns=[&quot;id&quot;,&quot;community&quot;,&quot;level&quot;,&quot;title&quot;,&quot;summary&quot;, &quot;findings&quot;,&quot;rank&quot;,&quot;rank_explanation&quot;,&quot;full_content&quot;])
        community_statement = &quot;&quot;&quot;
        MERGE (c:__Community__ {community:row.community})
        SET c += row {.level, .title, .rank, .rank_explanation, .full_content, .summary}
        WITH c, row
        UNWIND range(0, size(row.findings)-1) AS finding_idx
        WITH c, row, finding_idx, row.findings[finding_idx] as finding
        MERGE (c)-[:HAS_FINDING]-&gt;(f:Finding {id:finding_idx})
        SET f += finding
        &quot;&quot;&quot;
        return self.client.batched_import(community_statement, community_report_df)

    def import_covariates(self):
        cov_df = pd.read_parquet(f&#39;{self.GRAPHRAG_FOLDER}/create_final_covariates.parquet&#39;)
        cov_statement = &quot;&quot;&quot;
        MERGE (c:__Covariate__ {id:row.id})
        SET c += apoc.map.clean(row, [&quot;text_unit_id&quot;, &quot;document_ids&quot;, &quot;n_tokens&quot;], [NULL, &quot;&quot;])
        WITH c, row
        MATCH (ch:__Chunk__ {id: row.text_unit_id})
        MERGE (ch)-[:HAS_COVARIATE]-&gt;(c)
        &quot;&quot;&quot;
        return self.client.batched_import(cov_statement, cov_df)


def main():
    importer = GraphRAGImporter()
    importer.client.create_constraints()

    imported_count = importer.import_documents()
    print(f&quot;Imported {imported_count} documents&quot;)

    # Importing other entities and relationships
    importer.import_text_units()
    importer.import_entities()
    importer.import_relationships()
    importer.import_communities()
    importer.import_community_reports()
    # importer.import_covariates()

    result_df = importer.query_chunks()
    print(result_df)

if __name__ == &quot;__main__&quot;:
    main()
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[GraphRAG와 Neo4j 연결 레이어층  만들기]]></title>
            <link>https://velog.io/@jiyoon_sw524/GraphRAG%EC%99%80-Neo4j-%EC%97%B0%EA%B2%B0-%EB%A0%88%EC%9D%B4%EC%96%B4%EC%B8%B5-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@jiyoon_sw524/GraphRAG%EC%99%80-Neo4j-%EC%97%B0%EA%B2%B0-%EB%A0%88%EC%9D%B4%EC%96%B4%EC%B8%B5-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Mon, 02 Sep 2024 12:25:45 GMT</pubDate>
            <description><![CDATA[<p>MS사의 GraphRAG와 Neo4j를 직접적으로 연결하는 공식적인 방법은 현재 없다. 그러나 두 시스템을 통합하여 자연스럽게 작동하게 만들 수 있는 몇 가지 방법을 알려주겠다:</p>
<h2 id="1-api-기반-통합">1. API 기반 통합</h2>
<p>GraphRAG는 REST API를 통해 접근할 수 있다. Neo4j 또한 HTTP API를 제공하기 때문에, 이를 활용하여 중간 레이어를 만들어 두 시스템을 연결할 수 있다.</p>
<pre><code class="language-python">from flask import Flask, request, jsonify
import requests
import py2neo

app = Flask(__name__)

# GraphRAG API 엔드포인트
GRAPHRAG_API = &quot;http://graphrag-endpoint/api&quot;

# Neo4j 연결
graph = py2neo.Graph(&quot;bolt://localhost:7687&quot;, auth=(&quot;neo4j&quot;, &quot;password&quot;))

@app.route(&#39;/query&#39;, methods=[&#39;POST&#39;])
def process_query():
    query = request.json[&#39;query&#39;]

    # GraphRAG에 쿼리 전송
    graphrag_response = requests.post(f&quot;{GRAPHRAG_API}/query&quot;, json={&#39;query&#39;: query})
    graphrag_result = graphrag_response.json()

    # GraphRAG 결과를 Neo4j에 저장
    for item in graphrag_result[&#39;items&#39;]:
        graph.run(&quot;CREATE (n:GraphRAGResult {content: $content})&quot;, content=item[&#39;content&#39;])

    # Neo4j에서 추가 정보 검색
    neo4j_result = graph.run(&quot;MATCH (n:GraphRAGResult) RETURN n&quot;).data()

    # 결과 통합
    combined_result = {
        &#39;graphrag&#39;: graphrag_result,
        &#39;neo4j&#39;: neo4j_result
    }

    return jsonify(combined_result)

if __name__ == &#39;__main__&#39;:
    app.run(debug=True)</code></pre>
<p><br> <hr></p>
<h2 id="2-이벤트-기반-통합">2. 이벤트 기반 통합</h2>
<p>Apache Kafka나 RabbitMQ와 같은 메시지 큐 시스템을 사용하여 GraphRAG와 Neo4j 사이의 이벤트 기반 통신을 구현할 수 있다.</p>
<pre><code class="language-python">from kafka import KafkaConsumer, KafkaProducer
from py2neo import Graph

# Kafka 설정
consumer = KafkaConsumer(&#39;graphrag_results&#39;, bootstrap_servers=[&#39;localhost:9092&#39;])
producer = KafkaProducer(bootstrap_servers=[&#39;localhost:9092&#39;])

# Neo4j 연결
graph = Graph(&quot;bolt://localhost:7687&quot;, auth=(&quot;neo4j&quot;, &quot;password&quot;))

for message in consumer:
    graphrag_result = message.value.decode()

    # GraphRAG 결과를 Neo4j에 저장
    graph.run(&quot;CREATE (n:GraphRAGResult {content: $content})&quot;, content=graphrag_result)

    # Neo4j에서 추가 정보 검색
    neo4j_result = graph.run(&quot;MATCH (n:GraphRAGResult) RETURN n&quot;).data()

    # 결과를 다른 Kafka 토픽으로 전송
    producer.send(&#39;combined_results&#39;, str(neo4j_result).encode())</code></pre>
<p><br> <hr></p>
<h2 id="3-데이터베이스-동기화">3. 데이터베이스 동기화</h2>
<p>GraphRAG의 결과를 주기적으로 Neo4j로 동기화하는 스크립트를 만들어 실행할 수 있다.</p>
<pre><code class="language-python">import schedule
import time
import requests
from py2neo import Graph

def sync_graphrag_to_neo4j():
    # GraphRAG API 엔드포인트
    GRAPHRAG_API = &quot;http://graphrag-endpoint/api&quot;

    # Neo4j 연결
    graph = Graph(&quot;bolt://localhost:7687&quot;, auth=(&quot;neo4j&quot;, &quot;password&quot;))

    # GraphRAG에서 최신 결과 가져오기
    response = requests.get(f&quot;{GRAPHRAG_API}/latest_results&quot;)
    graphrag_results = response.json()

    # Neo4j에 결과 저장 또는 업데이트
    for result in graphrag_results:
        graph.run(&quot;&quot;&quot;
        MERGE (n:GraphRAGResult {id: $id})
        SET n.content = $content, n.updated_at = datetime()
        &quot;&quot;&quot;, id=result[&#39;id&#39;], content=result[&#39;content&#39;])

# 매 시간마다 동기화 실행
schedule.every().hour.do(sync_graphrag_to_neo4j)

while True:
    schedule.run_pending()
    time.sleep(1)</code></pre>
<p>이러한 방법들을 통해 GraphRAG와 Neo4j를 더 자연스럽게 연결할 수 있다. 선택한 방법은 사용 사례, 데이터 볼륨, 실시간 요구 사항 등에 따라 달라질 수 있다. 각 방법은 장단점이 있으므로, 프로젝트의 요구 사항에 가장 적합한 접근 방식을 선택하시기 바란다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MS사의 graphRAG 톺아보기]]></title>
            <link>https://velog.io/@jiyoon_sw524/MS%EC%82%AC%EC%9D%98-graphRAG-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0</link>
            <guid>https://velog.io/@jiyoon_sw524/MS%EC%82%AC%EC%9D%98-graphRAG-%ED%86%BA%EC%95%84%EB%B3%B4%EA%B8%B0</guid>
            <pubDate>Wed, 28 Aug 2024 01:43:36 GMT</pubDate>
            <description><![CDATA[<h1 id="ms사의-graphrag에-대한-qa-✨">MS사의 GraphRAG에 대한 Q&amp;A ✨</h1>
<h2 id="1-전역-검색과-지역-검색을-분리해서-검색하는지-통합해서-답변을-내놓는지-🤔">1. 전역 검색과 지역 검색을 분리해서 검색하는지, 통합해서 답변을 내놓는지? 🤔</h2>
<p>GraphRAG에서는 <strong>전역 검색</strong>(Global Search)과 <strong>지역 검색</strong>(Local Search)이 별도로 제공됩니다. 각 검색 방식은 다음과 같은 특징이 있어요:</p>
<ul>
<li><strong>전역 검색</strong>: 코퍼스 전체를 대상으로 한 포괄적인 질문에 답하기 위해 사용됩니다. 이 방식은 커뮤니티 요약을 활용하여 전체적인 이해를 바탕으로 답변을 제공합니다.</li>
<li><strong>지역 검색</strong>: 특정 엔티티에 대한 질문에 답하는 데 사용됩니다. 엔티티와 연결된 이웃 노드 및 관련 개념들을 확장하여 답변하죠.</li>
</ul>
<p>이 두 가지 방식은 별도로 실행되며, 질문의 성격에 따라 적절한 검색 모드를 선택해서 사용해야 해요. 두 방식을 통합해서 하나의 답변을 내놓는 방식에 대해서는 명시적인 설명은 없지만, 사용자가 상황에 맞게 선택해야 할 것 같아요.</p>
<h3 id="11-그럼-사용자가-두-검색-방법을-선택하는-건가요-아니면-graphrag가-알아서-방법을-선택해주나요">1.1 그럼 사용자가 두 검색 방법을 선택하는 건가요, 아니면 GraphRAG가 알아서 방법을 선택해주나요?</h3>
<p>사용자가 검색 방식을 선택합니다.</p>
<h2 id="2-텍스트-임베딩이-정확히-뭐예요-인덱스와-임베딩의-차이가-뭔지-알려주세요-📚">2. 텍스트 임베딩이 정확히 뭐예요? 인덱스와 임베딩의 차이가 뭔지 알려주세요! 📚</h2>
<p>GraphRAG에서 텍스트 임베딩과 인덱스는 중요한 역할을 해요. 간단히 설명드릴게요:</p>
<ul>
<li><p><strong>텍스트 임베딩</strong>:</p>
<ul>
<li><strong>목적</strong>: 텍스트의 의미를 숫자 벡터로 변환해서 컴퓨터가 이해할 수 있게 만듭니다.</li>
<li><strong>방법</strong>: 텍스트를 고차원의 벡터로 변환하죠.</li>
<li><strong>사용</strong>: 주로 유사성 검색이나 클러스터링에 활용돼요.</li>
</ul>
</li>
<li><p><strong>인덱스</strong>:</p>
<ul>
<li><strong>목적</strong>: 데이터를 효율적으로 검색하고 접근할 수 있도록 구조화하는 데 있어요.</li>
<li><strong>방법</strong>: 텍스트를 분할하고, 엔티티 및 관계를 추출한 후 그래프 구조로 만듭니다.</li>
<li><strong>사용</strong>: 쿼리 시 관련 정보를 빠르게 찾고 접근하는 데 사용됩니다.</li>
</ul>
</li>
</ul>
<p>결론적으로, <strong>임베딩</strong>은 텍스트의 의미를 벡터로 표현하는 것이 주 목적이고, <strong>인덱스</strong>는 이를 포함한 전체 데이터를 구조화하는 데 목적이 있어요. GraphRAG에서는 텍스트 임베딩이 인덱싱 과정의 일부로 사용된다고 보면 됩니다.</p>
<h2 id="3-plaintext-input-data---이해가-잘-안-되네요-파일-패턴을-txt로-한다는-건가요-📝">3. Plaintext Input Data - 이해가 잘 안 되네요. 파일 패턴을 .txt로 한다는 건가요? 📝</h2>
<p>네, 맞아요! GraphRAG는 <strong>.txt 파일</strong>뿐만 아니라 다양한 텍스트 기반 파일 형식을 처리할 수 있어요. 지원되는 파일 형식은 다음과 같습니다:</p>
<ul>
<li><code>.txt</code> (텍스트 파일)</li>
<li><code>.md</code> (마크다운 파일)</li>
<li><code>.pdf</code> (PDF 문서)</li>
<li><code>.docx</code> (Microsoft Word 문서)</li>
<li><code>.html</code> (HTML 파일)</li>
<li><code>.csv</code> (CSV 파일)</li>
<li><code>.json</code> (JSON 파일)</li>
</ul>
<p>GraphRAG는 다양한 파일 형식을 처리할 수 있도록 설정 파일에서 <code>file_pattern</code> 매개변수를 조정할 수 있어요. 사용자 정의 데이터 로더를 통해 다른 파일 형식도 추가로 지원할 수 있습니다.</p>
<h3 id="31-graphrag가-처리할-수-있는-파일-형식은-어떻게-되나요">3.1 GraphRAG가 처리할 수 있는 파일 형식은 어떻게 되나요?</h3>
<p>GraphRAG는 위에 언급한 텍스트 기반 파일 형식을 모두 지원하며, 이 외에도 필요에 따라 추가적인 파일 형식을 지원하도록 설정할 수 있어요. 특히 텍스트 데이터는 주로 <code>.txt</code>, <code>.md</code>, <code>.pdf</code> 같은 형식으로 처리됩니다. 📂</p>
<h2 id="4-blob이-무슨-형식인가요-🗃️">4. blob이 무슨 형식인가요? 🗃️</h2>
<p>&quot;Blob&quot;은 &quot;Binary Large OBject&quot;의 약자로, <strong>대용량 바이너리 데이터를 저장</strong>하는 형식을 의미해요. GraphRAG에서는 주로 <strong>Azure Blob Storage</strong>와 관련이 있을 가능성이 큽니다.</p>
<p>Azure Blob Storage는 Microsoft Azure의 클라우드 저장소 솔루션으로, 다양한 비구조화 데이터를 저장할 수 있습니다. Blob 형식의 주요 특징은 다음과 같아요:</p>
<ul>
<li><strong>비구조화 데이터 저장</strong>: 텍스트 파일, 이미지, 비디오 등 다양한 데이터를 저장할 수 있어요.</li>
<li><strong>대용량 데이터 지원</strong>: 효율적으로 대량 데이터를 관리할 수 있습니다.</li>
<li><strong>확장성</strong>: 필요에 따라 저장 용량을 쉽게 확장 가능해요.</li>
<li><strong>HTTP/HTTPS 접근</strong>: 표준 프로토콜을 통해 데이터에 접근할 수 있어요.</li>
</ul>
<h3 id="41-graphrag의-input-data-형식은-어떻게-되나요">4.1 GraphRAG의 Input Data 형식은 어떻게 되나요?</h3>
<p>GraphRAG는 주로 <strong>텍스트 기반 데이터</strong>를 처리하도록 설계되었어요. 이미지, 비디오, 음성 등의 비텍스트 데이터를 직접적으로 처리하는 기능은 명시적으로 언급되어 있지 않지만, <strong>Azure Blob Storage</strong>를 통해 대량의 텍스트 데이터를 저장하고 접근할 수 있습니다.</p>
<p>비텍스트 데이터는 전처리를 통해 텍스트 형태로 변환한 후에야 활용이 가능합니다. 예를 들어, 이미지에 대한 설명을 텍스트로 변환하거나, 음성을 텍스트로 변환하여 처리하는 방식이 있죠. 📄🎥🎧</p>
<h2 id="5-index를-실행할-때-더-나은-결과를-얻을-수-있기-때문에-강력히-권장한다는데-인덱스가-뭘-해주길래요-🔍">5. Index를 실행할 때 더 나은 결과를 얻을 수 있기 때문에 강력히 권장한다는데, 인덱스가 뭘 해주길래요? 🔍</h2>
<p>인덱스는 GraphRAG에서 매우 중요한 역할을 해요. 인덱싱 과정에서 다음과 같은 작업이 이루어집니다:</p>
<ol>
<li><strong>텍스트 분할</strong>: 입력된 코퍼스를 관리 가능한 단위로 나눕니다.</li>
<li><strong>정보 추출</strong>: LLM을 사용하여 엔티티, 관계, 주요 내용을 추출합니다.</li>
<li><strong>그래프 구조화</strong>: 추출된 정보를 바탕으로 그래프 구조를 생성합니다.</li>
<li><strong>클러스터링</strong>: Leiden 알고리즘을 사용해 그래프를 계층적으로 클러스터링합니다.</li>
<li><strong>요약 생성</strong>: 각 클러스터와 구성요소에 대한 요약을 생성합니다.</li>
</ol>
<p>이 과정은 <strong>Auto Templating</strong>과 밀접하게 연관되어 있어요. 인덱싱을 통해 생성된 구조화된 정보와 요약은 템플릿 생성에 중요한 입력으로 사용될 수 있죠. 이렇게 인덱스를 실행하면 <strong>효율적인 검색</strong>, <strong>컨텍스트 이해</strong>, <strong>요약 활용</strong> 등이 가능해져 더 나은 결과를 얻을 수 있습니다.</p>
<h3 id="51-그러면-사용자가-자연어로-질문하면-이를-기반으로-auto-templating을-새로-작성해서-인덱싱된-정보들과-함께-프롬프트를-만들어-llm에-넘기면-답변을-주는-건가요-🧠">5.1 그러면 사용자가 자연어로 질문하면, 이를 기반으로 Auto Templating을 새로 작성해서 인덱싱된 정보들과 함께 프롬프트를 만들어 LLM에 넘기면 답변을 주는 건가요? 🧠</h3>
<p>네, 맞아요! GraphRAG의 작동 방식은 다음과 같아요:</p>
<ol>
<li>사용자가 자연어로 질문을 입력합니다.</li>
<li>이 질문을 분석하여 관련 엔티티와 관계를 추출합니다.</li>
<li>추출된 정보를 바탕으로 그래프 쿼리를 생성합니다.</li>
<li>이 쿼리를 사용해 지식 그래프에서 관련 정보를 검색합니다.</li>
<li>검색된 정보와 원래 질문을 결합하여 LLM에 전달할 프롬프트를 생성합니다.</li>
<li>LLM이 이 프롬프트를 바탕으로 답변을 생성합니다.</li>
</ol>
<p>Auto Templating은 질문의 의도와 구조에 따라 적절한 쿼리 템플릿을 선택하거나 생성하는 데 사용됩니다. 이 과정을 통해 사용자에게 자연스러운 답변을 제공합니다.</p>
<h3 id="52-관련-엔티티와-관계를-뽑을-때는-llm을-사용하는지-전체-과정을-설명해주세요-🚀">5.2 관련 엔티티와 관계를 뽑을 때는 LLM을 사용하는지, 전체 과정을 설명해주세요! 🚀</h3>
<p>GraphRAG의 전체 프로세스는 다음과 같습니다:</p>
<ol>
<li><p><strong>사용자 입력</strong>:</p>
<ul>
<li>사용자가 자연어로 질문을 입력합니다.</li>
</ul>
</li>
<li><p><strong>엔티티 및 관계 추출</strong>:</p>
<ul>
<li><strong>LLM</strong>을 사용하여 질문에서 엔티티와 관계를 추출합니다.</li>
<li>주로 사용하는 모델: <strong>GPT-3.5-turbo</strong> 또는 <strong>GPT-4</strong>.</li>
<li>사용 라이브러리: OpenAI API.</li>
</ul>
</li>
<li><p><strong>그래프 쿼리 생성</strong>:</p>
<ul>
<li>추출된 엔티티와 관계를 바탕으로 <strong>SPARQL 쿼리</strong>를 생성합니다.</li>
<li>사용 라이브러리: <strong>RDFLib</strong>.</li>
</ul>
</li>
<li><p><strong>지식 그래프 검색</strong>:</p>
<ul>
<li>생성된</li>
</ul>
<p>SPARQL 쿼리를 사용하여 지식 그래프에서 정보를 검색합니다.</p>
<ul>
<li>사용 기술: <strong>Apache Jena Fuseki</strong>.</li>
</ul>
</li>
<li><p><strong>프롬프트 생성</strong>:</p>
<ul>
<li>검색된 정보와 원래 질문을 결합하여 프롬프트를 생성합니다.</li>
<li>주로 Python 문자열 처리 기능을 사용.</li>
</ul>
</li>
<li><p><strong>LLM을 통한 답변 생성</strong>:</p>
<ul>
<li>생성된 프롬프트를 LLM에 입력하여 최종 답변을 생성합니다.</li>
<li>사용 모델: GPT-3.5-turbo 또는 GPT-4.</li>
<li>사용 라이브러리: OpenAI API.</li>
</ul>
</li>
<li><p><strong>사용자에게 답변 제공</strong>.</p>
</li>
</ol>
<p>이 과정에서 주요 사용 라이브러리는 <strong>LLM(OpenAI GPT 모델)</strong>, <strong>그래프 처리(RDFLib, NetworkX)</strong>, <strong>데이터 처리(Pandas, NumPy)</strong> 등이 포함됩니다.</p>
<h2 id="6-entity_extractiontxt에서-소스-타겟-엔티티-구별에-대해-해야-하는-이유와-반드시-행해야-하는지-확인이-필요합니다-엔티티를-뽑은-뒤-구분하는-것-같은데-맞나요-🧩">6. entity_extraction.txt에서 소스-타겟 엔티티 구별에 대해 해야 하는 이유와 반드시 행해야 하는지 확인이 필요합니다. 엔티티를 뽑은 뒤 구분하는 것 같은데 맞나요? 🧩</h2>
<p>소스-타겟 엔티티를 구별하는 작업은 <strong>반드시 필요한 단계</strong>입니다. 그 이유는:</p>
<ul>
<li><strong>관계 명확성</strong>: 엔티티 간의 관계 방향을 명확하게 이해하기 위해 필요합니다.</li>
<li><strong>쿼리 정확성</strong>: 정확한 그래프 쿼리 생성을 위해 필수적입니다.</li>
<li><strong>컨텍스트 유지</strong>: 질문의 의도를 정확히 파악하고 유지하는 데 도움이 됩니다.</li>
</ul>
<p>보통 모든 엔티티를 추출한 후 소스와 타겟을 구별하는 것이 일반적이지만, GraphRAG에서는 추출 과정에서 소스와 타겟을 동시에 식별하는 것이 중요합니다.</p>
<h3 id="61-그렇다면-entity_extractiontxt에서-소스-타겟-엔티티를-구별하는-작업은-사용자가-질문할-때-이뤄지나요-아니면-input-data를-받아서-parquet-파일을-만들-때인가요-🔍">6.1 그렇다면 entity_extraction.txt에서 소스-타겟 엔티티를 구별하는 작업은 사용자가 질문할 때 이뤄지나요? 아니면 input data를 받아서 Parquet 파일을 만들 때인가요? 🔍</h3>
<p>이 작업은 주로 <strong>입력 데이터를 처리하여 Parquet 파일을 만들 때</strong> 수행됩니다. 사용자의 질문 시에도 유사한 프로세스가 적용되지만, 주요 엔티티 추출 및 관계 설정은 데이터 준비 단계에서 이루어집니다. 전체 과정을 설명하자면:</p>
<ol>
<li><p><strong>데이터 수집</strong>:</p>
<ul>
<li>다양한 소스에서 데이터를 수집합니다.</li>
<li>사용 도구: 웹 스크래핑 도구(예: Beautiful Soup), API.</li>
</ul>
</li>
<li><p><strong>데이터 전처리</strong>:</p>
<ul>
<li>수집된 데이터를 정제하고 구조화합니다.</li>
<li>사용 라이브러리: Pandas, NumPy.</li>
</ul>
</li>
<li><p><strong>엔티티 추출</strong>:</p>
<ul>
<li><strong>LLM</strong>을 사용하여 텍스트에서 엔티티를 추출합니다.</li>
<li>사용 모델: GPT-3.5-turbo 또는 GPT-4.</li>
<li>사용 라이브러리: OpenAI API, spaCy(추가적인 NER 작업용).</li>
</ul>
</li>
<li><p><strong>관계 추출</strong>:</p>
<ul>
<li>추출된 엔티티 간의 관계를 식별합니다.</li>
<li>LLM과 규칙 기반 시스템을 결합하여 사용.</li>
</ul>
</li>
<li><p><strong>소스-타겟 엔티티 구별</strong>:</p>
<ul>
<li>관계의 방향성을 결정하여 소스와 타겟 엔티티를 구별합니다.</li>
<li>사용 기술: LLM, 구문 분석(Python의 NLTK 라이브러리 사용 가능).</li>
</ul>
</li>
<li><p><strong>그래프 구조 생성</strong>:</p>
<ul>
<li>추출된 엔티티와 관계를 바탕으로 그래프 구조를 생성합니다.</li>
<li>사용 라이브러리: NetworkX, RDFLib.</li>
</ul>
</li>
<li><p><strong>Parquet 파일 생성</strong>:</p>
<ul>
<li>그래프 데이터를 Parquet 형식으로 변환합니다.</li>
<li>사용 라이브러리: PyArrow 또는 Pandas.</li>
</ul>
</li>
</ol>
<p>이 과정에서 사용되는 주요 라이브러리는 <strong>LLM(OpenAI GPT 모델)</strong>, <strong>NLP 도구(spaCy, NLTK)</strong>, <strong>데이터 처리(Pandas, NumPy)</strong>, <strong>그래프 처리(NetworkX, RDFLib)</strong> 등이 포함됩니다. 생성된 Parquet 파일은 이후 GraphRAG 시스템에서 빠른 검색과 질의 응답에 사용됩니다.</p>
<h2 id="7-claim-extraction에서-엔티티-사양-클레임-설명-이게-뭔데-주어지나요-📄">7. Claim Extraction에서 엔티티 &quot;사양&quot;? 클레임 &quot;설명&quot;? 이게 뭔데 주어지나요? 📄</h2>
<p>Claim Extraction에서 중요한 개념들인데요:</p>
<ul>
<li><p><strong>엔티티 &quot;사양&quot;</strong>:</p>
<ul>
<li>특정 엔티티의 속성이나 특성을 나타내요. 예를 들어, 제품의 기술적 세부사항이나 특정 개념의 정의 등이 포함됩니다.</li>
</ul>
</li>
<li><p><strong>클레임 &quot;설명&quot;</strong>:</p>
<ul>
<li>클레임은 특정 주장이나 진술을 의미해요. &quot;설명&quot;은 이 클레임의 내용을 상세히 기술한 것으로, 주장의 근거나 세부 내용을 포함할 수 있습니다.</li>
</ul>
</li>
</ul>
<p>이들은 지식 그래프 구축 과정에서 엔티티 간의 관계를 더 명확하게 정의하고, 복잡한 정보를 구조화하는 데 사용됩니다.</p>
<h2 id="8-그래서-txt-파일들의-존재-이유는-무엇인가요-🤷♂️">8. 그래서 .txt 파일들의 존재 이유는 무엇인가요? 🤷‍♂️</h2>
<p>이 <code>.txt</code> 파일들은 GraphRAG 시스템의 다양한 구성 요소와 프로세스를 설정하고 관리하는 데 사용됩니다:</p>
<ul>
<li><strong>설정 파일</strong>: 시스템 파라미터, 모델 설정 등을 정의합니다.</li>
<li><strong>프롬프트 템플릿</strong>: LLM에 전달할 프롬프트의 기본 구조를 정의합니다.</li>
<li><strong>데이터 처리 지침</strong>: 엔티티 추출, 관계 정의 등의 규칙을 명시합니다.</li>
<li><strong>로깅 및 디버깅</strong>: 시스템 작동 중 발생하는 이벤트나 오류를 기록합니다.</li>
</ul>
<p>이러한 파일들은 시스템의 유연성을 높이고, 필요에 따라 쉽게 수정할 수 있도록 도와줍니다. 🛠️</p>
<h2 id="9-community_reporttxt의-의사결정자는-누군가요-뭐를-의미하는-거예요-🤷♀️">9. community_report.txt의 의사결정자는 누군가요? 뭐를 의미하는 거예요? 🤷‍♀️</h2>
<p><strong>&quot;의사결정자&quot;</strong>는 프로젝트나 조직 내에서 중요한 결정을 내리는 권한을 가진 개인이나 그룹을 의미해요.</p>
<ul>
<li><strong>역할</strong>:<ul>
<li>프로젝트의 방향 설정.</li>
<li>자원 할당 결정.</li>
<li>주요 전략적 결정 수행.</li>
</ul>
</li>
</ul>
<p>GraphRAG 맥락에서의 의사결정자는 시스템 구현에 관한 주요 결정을 내리는 사람들을 의미합니다. 데이터 사용, 모델 선택, 시스템 아키텍처 등에 관한 결정권자일 수 있으며, 이 파일은 그들에게 프로젝트의 진행 상황, 주요 결과, 향후 계획 등을 보고하는 데 사용될 수 있습니다.</p>
<hr>
<p>이렇게 정리된 내용을 바탕으로 MS사의 GraphRAG에 대해 더욱 명확하게 이해하실 수 있을 거예요! 궁금한 점이 있다면 언제든지 댓글로 남겨주세요! 😊</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[지식 그래프 사전 조사 (1)]]></title>
            <link>https://velog.io/@jiyoon_sw524/%EC%A7%80%EC%8B%9D-%EA%B7%B8%EB%9E%98%ED%94%84-%EC%82%AC%EC%A0%84-%EC%A1%B0%EC%82%AC-1</link>
            <guid>https://velog.io/@jiyoon_sw524/%EC%A7%80%EC%8B%9D-%EA%B7%B8%EB%9E%98%ED%94%84-%EC%82%AC%EC%A0%84-%EC%A1%B0%EC%82%AC-1</guid>
            <pubDate>Sun, 25 Aug 2024 13:38:38 GMT</pubDate>
            <description><![CDATA[<h3 id="지식그래프를-설계하는-4가지-단계">지식그래프를 설계하는 4가지 단계</h3>
<ol>
<li>지식그래프를 만드는 목적을 세우고, 데이터를 어떻게 사용할지 구조를 설계 한다.</li>
<li>데이터 전처리(자연어처리와 태깅 작업) 및 데이터에 대한 구조화 설계</li>
<li>모델링 - 데이터의 연결 관계를 적재하게 되고, 연결되어있는 정보를 통해서 예측 알고리즘을 활용하면 새로운 관계가 형성 된다.</li>
<li>형성된 지식그래프를 조회하고 이를 서비스하는 시각화 단계</li>
</ol>
<h1 id="domain-specific-knowledge-graphs-a-survey">Domain-specific knowledge Graphs: A survey</h1>
<blockquote>
<p>본 연구는 도메인 특정 KG에 대한 포괄적인 정의를 처음으로 제안하며, 7개의 지식 도메인에 관한 최첨단 접근법을 종합적으로 검토하고, KG의 품질 및 제한 사항을 점검한다. 또한, 현재 접근법의 한계를 분석하고, 기존 문헌의 문제를 해결하기 위한 향후 연구의 방향성을 제안함으로써 지식 그래프 구축의 중요성과 잠재력을 강조한다.</p>
</blockquote>
<br>

<h2 id="1-introduction">1. Introduction</h2>
<ul>
<li>도메인별 KG에 대한 적절한 평가 조치가 적용되었는가에 대한 의문을 제기하였다. </li>
<li><strong>지식의 동적 특성</strong>은 맥락적 상황과 높은 상관관계를 가지며, 개체를 설명하는 다양한 사실은 시간이 지남에 따라 변할 수 있어, 지식의 동적 특성을 무시한다면 KG가 나타내는 사실의 품질과 정확성을 떨어트린다는 문제를 제시하였다.</li>
<li>도메인 특정 KG의 <strong>포괄적인 정의</strong>를 제공하고, 7개의 도메인에서의 주요 KG 구성 접근법에 대한 분석한다. 각 사례의 KG가 <strong>어떻게</strong> 구축되었는지, KG 구축에 사용된 <strong>리소스</strong>, KG <strong>임베딩 기술의 통합</strong> 여부, KG 구축 접근법을 <strong>평가</strong>하는 데 사용된 척도, 각 접근법의 <strong>한계와 단점</strong>, 한계를 해결하기 위한 <strong>개선 사항, 권장 사항 및 기회</strong>를 제안하여 향후 연구를 위한 방향을 제시한다.</li>
</ul>
<br>

<h2 id="2-methodology---방법론">2. Methodology - 방법론</h2>
<ul>
<li>자기들 논문 이렇게 많이 찾아 보고, 요새 관련된 논문이 쏟아지고 있다.</li>
</ul>
<br>

<h2 id="3-preliminaries---근거_중요한-사전-작업과-관련-용어">3. Preliminaries - 근거_중요한 사전 작업과 관련 용어</h2>
<h3 id="31-generic-knowledge-graphs">3.1 Generic Knowledge Graphs</h3>
<ul>
<li>그냥 지식 그래프 설명</li>
</ul>
<h3 id="32-domain-specific-knowledge-graphs">3.2 Domain-specific Knowledge Graphs</h3>
<blockquote>
<p>&quot;도메인 지식 그래프는 특정 주제 영역(도메인)과 그 하위 영역을 명시적으로 개념화한 것입니다. 이 그래프는 의미적으로 상호 연관된 엔티티(개체)와 관계들로 표현됩니다.&quot;</p>
</blockquote>
<p>도메인에 독립적인 다양한 작업을 처리하기 위해 일반 및 오픈 월드 KG를 광범위하게 사용하고 있지만, 도메인별 문제를 해결하기 위해 도메인 코퍼스로부터 KG를 구축하는 것이 중요하다. 도메인별 KG는 도메인별 문제와 연관성이 있고 의미적으로 상호 연결된 애플리케이션을 가지고 있기 때문이다. </p>
<h3 id="33-knowledge-graph-construction">3.3 Knowledge Graph Construction</h3>
<p>KG 구축은 엔티티와 이들 간의 관계를 추출하는 과정이다.
<img src="https://velog.velcdn.com/images/jiyoon_sw524/post/e032f9dd-88c8-44fd-8c69-3d0ce0517baf/image.png" alt=""></p>
<h4 id="1-지식-추출-level">1) 지식 추출 level</h4>
<ul>
<li><p><strong>엔티티 추출</strong></p>
<ul>
<li><strong>Named Entity Recognition</strong> (NER, 이름있는 엔티티 인식): 개인, 조직, 위치, 이벤트 및 기타 엔티티를 (비)구조화된 데이터 소스에서 찾는 과정</li>
<li><strong>Named Entity Disambiguation</strong> (NED, 이름 있는 엔티티 비식별): 추론된 엔티티의 모호성을 제거하고 이를 실제 세계의 실제 엔티티에 매핑하는 작업</li>
<li><strong>Named Entity Linking</strong> (NEL, 이름 있는 엔티티 연결): 모호성이 제거된 엔티티에 고유한 IRI(국제화 리소스 식별자)를 할당하는 작업</li>
</ul>
</li>
<li><p><strong>관계 추출</strong>
: 식별되고 모호성이 제거된 엔티티 간의 의미적 관계를 발견하는 작업</p>
<ul>
<li>로컬 기반: 짧은 텍스트에서 관계 추론</li>
<li>글로벌 기발: 여러 로컬 관계를 연결하여 관계 추론<h4 id="2-지식-베이스-유형">2) 지식 베이스 유형</h4>
</li>
</ul>
</li>
<li><p><strong>스키마 기반</strong>(사전 정의된 온톨로지 사용):</p>
<ul>
<li>상향식(bottom-up): 온톨로지 구조를 통합하여 KG 구축 (ex. Wikipedia - DBpedia 사용)</li>
<li>하향식(top-down): 기본 구조화된 데이터에서 온톨로지 스키마를 추론하거나 웹 정보를 기반으로 분류 계층 구축</li>
</ul>
</li>
<li><p><strong>스키마 없는</strong>: 웹의 개방성에 의존하는 공개 정보 추출 기술 (ex. OpenIE)</p>
</li>
<li><p>하이브리드: 스키마 기반과 스키마 없는 접근법 혼합 (ex. KnowledgeVault, NELL)</p>
<h4 id="3-구축-방법">3) 구축 방법</h4>
<p>: 웹 및 기타 데이터 저장소와 저장소를 채굴하여 엔티티와 관계를 추론</p>
</li>
<li><p><strong>규칙(지식)</strong> 기반 접근법(Rule(Knowledge)-based) : 도메인 지식과 어휘 자원을 통합하여 도메인 전문가가 규칙(연관 규칙)을 설립</p>
</li>
<li><p><strong>반(비)지도 학습</strong> 기반 방법(Un(Semi-) Supervised): (반)지도 학습 기법 사용 
(ex. 조건부 확률장(CRF), 히든 마르코프 모델(HMM), 서포트 벡터 머신(SVM), 나이브 베이즈(NB), 로지스틱 회귀(LR), 의사결정 나무, 부트스트랩 방법 등)</p>
</li>
<li><p><strong>신경망</strong> 모델(Neural Networks): 특징을 추론하기 위해 신경망과 딥러닝을 통합하여 특징을 추론. 도메인에 독립적인 KG에 적합.
(ex.컨볼루션 신경망(CNN), 순환 신경망(RNN), 양방향 장기 기억망(BiLSTM))</p>
</li>
<li><p><strong>기성 NLP 도구</strong>(off-the-shelf): 상용/오픈 소스 도구로 텍스트 분석 및 엔티티와 관계 추출
(ex. spaCy, Stanford CoreNLP, AllenNLP, IBM Watson NLU)</p>
</li>
</ul>
<h3 id="34-knowledge-graph-embedding-kge">3.4 Knowledge Graph Embedding (KGE)</h3>
<ul>
<li><strong>정의</strong>: 지식 그래프의 구성 요소(엔티티와 관계)에 대한 특징 벡터 표현을 생성하는 과정</li>
<li><strong>목적</strong>: 수치적 기법을 적용하여 확장 가능하고 효과적인 결과를 도출</li>
<li><strong>장점</strong>: 전통적인 그래프 표현(ex. 인접 행렬)이 부적합한 복잡한 문제 해결</li>
<li><strong>활용</strong>: KG 완성, 엔티티 인식, 링크 기반 클러스터링 등의 문제를 해결</li>
<li><strong>KGE의 핵심 아이디어</strong>: KG의 각 엔티티와 각 관계에 대한 벡터를 생성한 후, 저차원 임베딩 벡터 공간에서 두 엔티티 간의 공간 거리를 측정하기 위해 점수 함수를 정의하는 것이다. </li>
<li><strong>목표</strong>: KG의 잠재적 의미를 포착하여 유사한 엔티티와 관계를 유사한 벡터로 표현하고, 의미적으로 연결되지 않은 것들은 분리되는 것</li>
<li><strong>KG 임베딩 학습 과정</strong>: 
1단계: 엔티티와 관계를 벡터로 변환하여 의미적 공간에 배치
2단계: 트리플에서 정보를 결합하기 위한 점수 함수나 모델별 함수 적용
3단계: KG 임베딩 과정에서 목표가 정의되고 최소화되는 최적화 절차를 손실 함수로 표현하여 적용</li>
<li><strong>KG 임베딩 모델</strong>
TransE: 엔티티와 관계를 동일한 저차원 의미 공간에서 벡터로 학습.
DistMult: RESCAL을 확장 및 단순화한 모델로, 관계를 단일 벡터로 인코딩.
ComplEx: DistMult를 확장하여 복소수 값 임베딩 도입.
HolE: RESCAL의 강점과 DistMult의 단순성을 결합한 모델.
ConvE: 다층 신경망을 사용하여 입력 엔티티와 관계 간의 상호작용을 해결.
ConvKB: 신경망을 활용하여 엔티티와 관계의 연결성을 학습.</li>
</ul>
<h3 id="35-knowledge-graph-evaluation평가">3.5 Knowledge Graph Evaluation(평가)</h3>
<h4 id="1-지식그래프-평가의-필요성">1) 지식그래프 평가의 필요성</h4>
<ul>
<li>문제: 대규모 지식 그래프(KG)의 확산은 포함된 지식(즉, 엔티티와 관계)의 품질, KG에 포함된 사실들이 실제 세계의 개념들을 정확하게 전달하는지 검증이 필요하다. 완전성과 정확성을 검증하는 것은 다양한 응용 프로그램에 KG가 얼마나 적합한지 평가하는 데 필수적이다. </li>
</ul>
<h2 id="4-domain-specific-kgs---7가지-영역에서-kg-구축-접근법-분석과-연국-결과와-확인된-연구-공백에-대한-논의">4. Domain-specific KGs - 7가지 영역에서 KG 구축 접근법 분석과 연국 결과와 확인된 연구 공백에 대한 논의</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[파이썬 프로젝트 가상 환경 설정 및 패키지 설치]]></title>
            <link>https://velog.io/@jiyoon_sw524/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B0%80%EC%83%81-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%8F-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EC%B9%98</link>
            <guid>https://velog.io/@jiyoon_sw524/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EA%B0%80%EC%83%81-%ED%99%98%EA%B2%BD-%EC%84%A4%EC%A0%95-%EB%B0%8F-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EC%B9%98</guid>
            <pubDate>Sun, 21 Jul 2024 23:13:54 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>이 가이드는 파이썬 프로젝트에서 가상 환경을 생성하고, requirements.txt 파일을 통해 필요한 패키지를 설치하는 과정이다. </p>
</blockquote>
<br>

<h2 id="1-requirementstxt-파일-생성-및-입력">1. requirements.txt 파일 생성 및 입력</h2>
<h4 id="11-터미널-열기">1.1. 터미널 열기</h4>
<p>터미널을 연다.</p>
<h4 id="12-프로젝트-디렉토리로-이동">1.2. 프로젝트 디렉토리로 이동</h4>
<p>프로젝트가 있는 디렉토리로 이동한다. 예를 들어, 프로젝트 디렉토리가 <code>~/Downloads/&lt;project&gt;</code>라면 다음 명령어를 사용한다.</p>
<pre><code class="language-sh">cd ~/Downloads/&lt;project&gt;</code></pre>
<h4 id="13-requirementstxt-파일-생성-및-내용-입력">1.3. requirements.txt 파일 생성 및 내용 입력</h4>
<p>다음 명령어를 사용하여 <code>requirements.txt</code> 파일을 생성하고, 편집기로 열어 내용을 입력한다.</p>
<pre><code class="language-sh">echo -e &quot;pandas\nrequests\nbeautifulsoup4\nPyMuPDF&quot; &gt; requirements.txt</code></pre>
<br>

<h2 id="2-가상-환경-생성-및-활성화">2. 가상 환경 생성 및 활성화</h2>
<h4 id="21-가상-환경-생성">2.1. 가상 환경 생성</h4>
<p>다음 명령어를 사용하여 가상 환경을 생성한다.</p>
<pre><code class="language-sh">python3 -m venv &lt;venv&gt;</code></pre>
<h4 id="22-가상-환경-활성화">2.2. 가상 환경 활성화</h4>
<p>다음 명령어를 사용하여 가상 환경을 활성화한다.</p>
<pre><code class="language-sh">source &lt;venv&gt;/bin/activate</code></pre>
<br>

<h2 id="3-requirementstxt-파일을-사용하여-패키지-설치">3. requirements.txt 파일을 사용하여 패키지 설치</h2>
<p>가상 환경이 활성화된 상태에서 다음 명령어를 사용하여 <code>requirements.txt</code> 파일에 명시된 모든 패키지를 설치한다.</p>
<pre><code class="language-sh">pip install -r requirements.txt</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[CH12 파일 입출력]]></title>
            <link>https://velog.io/@jiyoon_sw524/CH12-%ED%8C%8C%EC%9D%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5</link>
            <guid>https://velog.io/@jiyoon_sw524/CH12-%ED%8C%8C%EC%9D%BC-%EC%9E%85%EC%B6%9C%EB%A0%A5</guid>
            <pubDate>Wed, 12 Jun 2024 00:13:13 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프렌드-함수">1. 프렌드 함수</h2>
<h3 id="프렌드로-초대하는-3가지-유형">프렌드로 초대하는 3가지 유형</h3>
<br>

<h3 id="예시-코드---프렌드-함수-만들기-7-123">예시 코드 - 프렌드 함수 만들기 (7-1,2,3)</h3>
<pre><code class="language-cpp">
</code></pre>
<h2 id="2-연산자-중복">2. 연산자 중복</h2>
<br>

<h3 id="1-연산자-함수-형식">1) 연산자 함수 형식</h3>
<ol>
<li><p>클래스의 멤버 함수로 구현</p>
</li>
<li><p>외부 함수로 구현하고 클래스에 프렌드 함수로 선언</p>
<p> <strong><code>리턴타입 operator연산자(매개변수리스트);</code></strong></p>
 <br>

</li>
</ol>
<h3 id="2-이항-연산자-중복-와--연산자의-작성-사례">2) 이항 연산자 중복: +와 == 연산자의 작성 사례</h3>
<h4 id="클래스의-멤버-함수로-작성">클래스의 멤버 함수로 작성:</h4>
<pre><code class="language-cpp">
</code></pre>
<h4 id="외부-함수로-작성하고-클래스에-프렌드로-선언">외부 함수로 작성하고 클래스에 프렌드로 선언:</h4>
<pre><code class="language-cpp">

</code></pre>
<br>

<h3 id="3-이항-연산자-중복--연산자">3) 이항 연산자 중복: + 연산자</h3>
<h4 id="주요-코드-구조">주요 코드 구조</h4>
<pre><code class="language-cpp">

</code></pre>
<br>

]]></description>
        </item>
        <item>
            <title><![CDATA[CH11 입출력 시스템]]></title>
            <link>https://velog.io/@jiyoon_sw524/CH11-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%8B%9C%EC%8A%A4%ED%85%9C</link>
            <guid>https://velog.io/@jiyoon_sw524/CH11-%EC%9E%85%EC%B6%9C%EB%A0%A5-%EC%8B%9C%EC%8A%A4%ED%85%9C</guid>
            <pubDate>Wed, 12 Jun 2024 00:12:31 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프렌드-함수">1. 프렌드 함수</h2>
<h3 id="프렌드로-초대하는-3가지-유형">프렌드로 초대하는 3가지 유형</h3>
<br>

<h3 id="예시-코드---프렌드-함수-만들기-7-123">예시 코드 - 프렌드 함수 만들기 (7-1,2,3)</h3>
<pre><code class="language-cpp">
</code></pre>
<h2 id="2-연산자-중복">2. 연산자 중복</h2>
<br>

<h3 id="1-연산자-함수-형식">1) 연산자 함수 형식</h3>
<ol>
<li><p>클래스의 멤버 함수로 구현</p>
</li>
<li><p>외부 함수로 구현하고 클래스에 프렌드 함수로 선언</p>
<p> <strong><code>리턴타입 operator연산자(매개변수리스트);</code></strong></p>
 <br>

</li>
</ol>
<h3 id="2-이항-연산자-중복-와--연산자의-작성-사례">2) 이항 연산자 중복: +와 == 연산자의 작성 사례</h3>
<h4 id="클래스의-멤버-함수로-작성">클래스의 멤버 함수로 작성:</h4>
<pre><code class="language-cpp">
</code></pre>
<h4 id="외부-함수로-작성하고-클래스에-프렌드로-선언">외부 함수로 작성하고 클래스에 프렌드로 선언:</h4>
<pre><code class="language-cpp">

</code></pre>
<br>

<h3 id="3-이항-연산자-중복--연산자">3) 이항 연산자 중복: + 연산자</h3>
<h4 id="주요-코드-구조">주요 코드 구조</h4>
<pre><code class="language-cpp">

</code></pre>
<br>

]]></description>
        </item>
        <item>
            <title><![CDATA[CH10 템플릿과 STL(표준 템플릿 라이브러리)]]></title>
            <link>https://velog.io/@jiyoon_sw524/CH10-%ED%85%9C%ED%94%8C%EB%A6%BF%EA%B3%BC-STL%ED%91%9C%EC%A4%80-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@jiyoon_sw524/CH10-%ED%85%9C%ED%94%8C%EB%A6%BF%EA%B3%BC-STL%ED%91%9C%EC%A4%80-%ED%85%9C%ED%94%8C%EB%A6%BF-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Wed, 12 Jun 2024 00:11:27 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프렌드-함수">1. 프렌드 함수</h2>
<h3 id="프렌드로-초대하는-3가지-유형">프렌드로 초대하는 3가지 유형</h3>
<br>

<h3 id="예시-코드---프렌드-함수-만들기-7-123">예시 코드 - 프렌드 함수 만들기 (7-1,2,3)</h3>
<pre><code class="language-cpp">
</code></pre>
<h2 id="2-연산자-중복">2. 연산자 중복</h2>
<br>

<h3 id="1-연산자-함수-형식">1) 연산자 함수 형식</h3>
<ol>
<li><p>클래스의 멤버 함수로 구현</p>
</li>
<li><p>외부 함수로 구현하고 클래스에 프렌드 함수로 선언</p>
<p> <strong><code>리턴타입 operator연산자(매개변수리스트);</code></strong></p>
 <br>

</li>
</ol>
<h3 id="2-이항-연산자-중복-와--연산자의-작성-사례">2) 이항 연산자 중복: +와 == 연산자의 작성 사례</h3>
<h4 id="클래스의-멤버-함수로-작성">클래스의 멤버 함수로 작성:</h4>
<pre><code class="language-cpp">
</code></pre>
<h4 id="외부-함수로-작성하고-클래스에-프렌드로-선언">외부 함수로 작성하고 클래스에 프렌드로 선언:</h4>
<pre><code class="language-cpp">

</code></pre>
<br>

<h3 id="3-이항-연산자-중복--연산자">3) 이항 연산자 중복: + 연산자</h3>
<h4 id="주요-코드-구조">주요 코드 구조</h4>
<pre><code class="language-cpp">

</code></pre>
<br>

]]></description>
        </item>
        <item>
            <title><![CDATA[CH09 가상 함수와 추상 클래스]]></title>
            <link>https://velog.io/@jiyoon_sw524/CH09-%EA%B0%80%EC%83%81-%ED%95%A8%EC%88%98%EC%99%80-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4</link>
            <guid>https://velog.io/@jiyoon_sw524/CH09-%EA%B0%80%EC%83%81-%ED%95%A8%EC%88%98%EC%99%80-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4</guid>
            <pubDate>Wed, 12 Jun 2024 00:10:02 GMT</pubDate>
            <description><![CDATA[<h2 id="1-가상-함수와-함수-재정의">1. 가상 함수와 함수 재정의</h2>
<h3 id="1-정의">1) 정의</h3>
<h4 id="가상-함수">가상 함수</h4>
<ul>
<li><strong>가상 함수(virtual function)</strong>: <code>virtual</code> 키워드로 선언된 멤버 함수로, 함수 호출을 실행 시간까지 미루도록 지시하여 동적 바인딩을 가능하게 함.</li>
<li><strong>동적 바인딩</strong>: 실행 시간에 함수 호출을 결정, 이를 통해 다형성을 실현.</li>
</ul>
<h4 id="함수-오버라이딩">함수 오버라이딩</h4>
<ul>
<li><strong>함수 오버라이딩(function overriding)</strong>: 파생 클래스에서 기본 클래스의 <strong>가상 함수</strong>와 동일한 이름의 함수를 선언하여 기본 클래스의 가상 함수를 재정의하는 것. 파생 클래스에서 오버라이딩한 함수가 호출되도록 동적 바인딩.</li>
<li><strong>목적</strong>: 다형성을 제공하여, 파생 클래스의 객체를 통해 호출 시 파생 클래스의 함수를 실행.</li>
<li><strong>특징</strong><ul>
<li>가상 함수 이름 , 매개 변수 타입과 개수 , 리턴 타입이 모두 일치</li>
<li>파생 클래스에서  virtual 생략 가능 . virtual 지시어도 상속됨</li>
</ul>
</li>
</ul>
<h4 id="함수-재정의">함수 재정의</h4>
<ul>
<li><strong>함수 재정의</strong> : 가상 함수를 재정의 하는 것이 아니라 <code>virtual</code>을 쓰지 않은 함수를 재정의한 경우, 컴파일 시간에 결정되어 단순히 호출되도록 정적 바인딩.
<img src="https://velog.velcdn.com/images/jiyoon_sw524/post/0d59d383-8024-480d-8a5b-d7fa1f9c35e4/image.png" alt=""></li>
</ul>
<br>

<h3 id="2-예제-9-2--동적-바인딩과-정적-바인딩">2) 예제 9-2 : 동적 바인딩과 정적 바인딩</h3>
<pre><code class="language-cpp">class Base {
public:
    virtual void virtualFunc() { cout &lt;&lt; &quot;Base::virtualFunc() called&quot; &lt;&lt; endl; } // 가상 함수
    void nonVirtualFunc() { cout &lt;&lt; &quot;Base::nonVirtualFunc() called&quot; &lt;&lt; endl; }   // 비가상 함수
};

class Derived : public Base {
public:
    void virtualFunc() override { cout &lt;&lt; &quot;Derived::virtualFunc() called&quot; &lt;&lt; endl; } // 가상 함수 오버라이딩
    void nonVirtualFunc() { cout &lt;&lt; &quot;Derived::nonVirtualFunc() called&quot; &lt;&lt; endl; }    // 함수 재정의
};

int main() {
    Derived d;
    Base* pBase = &amp;d;  // 업캐스팅

    // 동적 바인딩: Derived 클래스의 가상 함수가 호출됨
    pBase-&gt;virtualFunc();  // 출력: Derived::virtualFunc() called

    // 정적 바인딩: Base 클래스의 비가상 함수가 호출됨
    pBase-&gt;nonVirtualFunc();  // 출력: Base::nonVirtualFunc() called

    return 0;
}
</code></pre>
<br>

<h3 id="3-예제--오버라이딩을-통한-다형성">3) 예제 : 오버라이딩을 통한 다형성</h3>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/f2f3bc39-9300-4330-bb91-36cde926f638/image.png" alt=""></p>
<br>

<h3 id="4-예제--기본-클래스에서-파생-클래스의-함수를-호출">4) 예제 : 기본 클래스에서 파생 클래스의 함수를 호출</h3>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/1439ccbe-fa90-4c06-8fe0-070d569757cd/image.png" alt=""></p>
<br>

<h3 id="5-점위-지정-연산자를-이용한-기본-클래스의-가상-함수-호출">5) 점위 지정 연산자(::)를 이용한 기본 클래스의 가상 함수 호출</h3>
<p><code>기본클래스::가상함수()</code>형태로 기본 클래스의 가상 함수를 정적 바인딩으로 호출. 참고로, 정적 바인딩은 컴파일 시간에 결정되는 것이고, 동적 바인딩은 실행 시간에 결정되는 것이다.</p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/df28878c-6056-4360-9ac2-7f471948d2e4/image.png" alt=""></p>
<p><br><hr></p>
<h3 id="3-가상-소멸자">3. 가상 소멸자</h3>
<h4 id="가상-소멸자의-필요성">가상 소멸자의 필요성</h4>
<ul>
<li><strong>가상 소멸자</strong>: 소멸자를 <code>virtual</code> 키워드로 선언하여 동적 바인딩을 통해 <strong>파생 클래스의 소멸자가 호출</strong>되도록 함.</li>
<li><strong>목적</strong>: 기본 클래스의 포인터를 통해 파생 클래스 객체를 삭제할 때, 파생 클래스의 소멸자가 호출되어야 <strong>리소스 누수를 방지</strong>할 수 있음.
<img src="https://velog.velcdn.com/images/jiyoon_sw524/post/c03ca885-e20c-486c-be0f-d8516ef680f1/image.png" alt=""></li>
</ul>
<pre><code class="language-cpp">class Base {
public:
    virtual ~Base() { cout &lt;&lt; &quot;~Base() called&quot; &lt;&lt; endl; }
};

class Derived : public Base {
public:
    ~Derived() { cout &lt;&lt; &quot;~Derived() called&quot; &lt;&lt; endl; }
};

int main() {
    Base* p = new Derived();
    delete p;  // ~Derived() -&gt; ~Base() 호출
}</code></pre>
<h3 id="4-추상-클래스와-순수-가상-함수">4. 추상 클래스와 순수 가상 함수</h3>
<h4 id="추상-클래스">추상 클래스</h4>
<ul>
<li><strong>추상 클래스</strong>: 최소 하나의 순수 가상 함수를 가진 클래스. 직접 객체를 생성할 수 없음.</li>
<li><strong>목적</strong>: 상속을 통해 파생 클래스에서 구현할 함수의 인터페이스를 제공.</li>
</ul>
<pre><code class="language-cpp">class Shape {
public:
    virtual void draw() = 0;  // 순수 가상 함수
};

class Circle : public Shape {
public:
    void draw() override { cout &lt;&lt; &quot;Circle&quot; &lt;&lt; endl; }
};

int main() {
    Shape* p = new Circle();
    p-&gt;draw();  // Circle 출력
    delete p;
}</code></pre>
<h3 id="5-예제">5. 예제</h3>
<h4 id="예제-9-1-파생-클래스에서-함수-재정의">예제 9-1: 파생 클래스에서 함수 재정의</h4>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

class Base {
public:
    void f() { cout &lt;&lt; &quot;Base::f() called&quot; &lt;&lt; endl; }
};

class Derived : public Base {
public:
    void f() { cout &lt;&lt; &quot;Derived::f() called&quot; &lt;&lt; endl; }
};

int main() {
    Derived d;
    d.f();  // Derived::f() 호출

    Base* pBase = &amp;d;  // 업캐스팅
    pBase-&gt;f();  // Base::f() 호출
}</code></pre>
<h4 id="예제-9-2-오버라이딩과-가상-함수-호출">예제 9-2: 오버라이딩과 가상 함수 호출</h4>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

class Base {
public:
    virtual void f() { cout &lt;&lt; &quot;Base::f() called&quot; &lt;&lt; endl; }
};

class Derived : public Base {
public:
    void f() override { cout &lt;&lt; &quot;Derived::f() called&quot; &lt;&lt; endl; }
};

int main() {
    Derived d;
    Base* pBase = &amp;d;  // 업캐스팅
    pBase-&gt;f();  // Derived::f() 호출 (동적 바인딩)
}</code></pre>
<h4 id="예제-9-3-상속이-반복되는-경우-가상-함수-호출">예제 9-3: 상속이 반복되는 경우 가상 함수 호출</h4>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

class Base {
public:
    virtual void f() { cout &lt;&lt; &quot;Base::f() called&quot; &lt;&lt; endl; }
};

class Derived : public Base {
public:
    void f() override { cout &lt;&lt; &quot;Derived::f() called&quot; &lt;&lt; endl; }
};

class GrandDerived : public Derived {
public:
    void f() override { cout &lt;&lt; &quot;GrandDerived::f() called&quot; &lt;&lt; endl; }
};

int main() {
    GrandDerived g;
    Base* pBase = &amp;g;
    Derived* pDerived = &amp;g;
    GrandDerived* pGrand = &amp;g;

    pBase-&gt;f();  // GrandDerived::f() 호출 (동적 바인딩)
    pDerived-&gt;f();  // GrandDerived::f() 호출 (동적 바인딩)
    pGrand-&gt;f();  // GrandDerived::f() 호출
}</code></pre>
<h4 id="예제-9-4-범위-지정-연산자를-이용한-기본-클래스의-가상-함수-호출">예제 9-4: 범위 지정 연산자(::)를 이용한 기본 클래스의 가상 함수 호출</h4>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

class Shape {
public:
    virtual void draw() { cout &lt;&lt; &quot;--Shape--&quot; &lt;&lt; endl; }
};

class Circle : public Shape {
public:
    void draw() override {
        Shape::draw();  // 기본 클래스의 draw() 호출
        cout &lt;&lt; &quot;Circle&quot; &lt;&lt; endl;
    }
};

int main() {
    Circle circle;
    Shape* pShape = &amp;circle;
    pShape-&gt;draw();  // --Shape--Circle 출력 (동적 바인딩)
    pShape-&gt;Shape::draw();  // --Shape-- 출력 (정적 바인딩)
}</code></pre>
<h4 id="예제-9-6-소멸자를-가상-함수로-선언">예제 9-6: 소멸자를 가상 함수로 선언</h4>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

class Base {
public:
    virtual ~Base() { cout &lt;&lt; &quot;~Base()&quot; &lt;&lt; endl; }
};

class Derived : public Base {
public:
    ~Derived() { cout &lt;&lt; &quot;~Derived()&quot; &lt;&lt; endl; }
};

int main() {
    Derived* dp = new Derived();
    Base* bp = new Derived();

    delete dp;  // ~Derived() -&gt; ~Base() 호출
    delete bp;  // ~Derived() -&gt; ~Base() 호출
}</code></pre>
<h4 id="예제-9-7-추상-클래스를-상속받는-파생-클래스-구현-연습">예제 9-7: 추상 클래스를 상속받는 파생 클래스 구현 연습</h4>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

class Calculator {
protected:
    int a, b;
    virtual int calc(int a, int b) = 0;  // 순수 가상 함수
public:
    void input() {
        cout &lt;&lt; &quot;정수 2개를 입력하세요&gt;&gt; &quot;;
        cin &gt;&gt; a &gt;&gt; b;
    }
    void run() {
        input();
        cout &lt;&lt; &quot;계산된 값은 &quot; &lt;&lt; calc(a, b) &lt;&lt; endl;
    }
};

class Adder : public Calculator {
protected:
    int calc(int a, int b) override {
        return a + b;
    }
};

class Subtractor : public Calculator {
protected:
    int calc(int a, int b) override {
        return a - b;
    }
};

int main() {
    Adder adder;
    Subtractor subtractor;

    adder.run();  // 덧셈 결과 출력
    subtractor.run();  // 뺄셈 결과 출력
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[CH08 상속]]></title>
            <link>https://velog.io/@jiyoon_sw524/CH08-%EC%83%81%EC%86%8D</link>
            <guid>https://velog.io/@jiyoon_sw524/CH08-%EC%83%81%EC%86%8D</guid>
            <pubDate>Wed, 12 Jun 2024 00:08:28 GMT</pubDate>
            <description><![CDATA[<h2 id="1-c-객체-지향-상속의-개념">1. C++ 객체 지향 상속의 개념</h2>
<ul>
<li><strong>상속의 정의</strong>: 클래스 사이에서 상속 관계를 정의하여 기본 클래스의 속성과 기능을 파생 클래스에 물려주는 것.</li>
<li><strong>기본 클래스(Base Class)</strong>: 상속해주는 클래스, 부모 클래스.</li>
<li><strong>파생 클래스(Derived Class)</strong>: 상속받는 클래스, 자식 클래스.</li>
<li><strong>상속의 목적</strong>: 클래스 재사용, 확장, 계층적 분류, 코드 간결화.</li>
</ul>
<br>

<h3 id="1-상속의-표현">1) 상속의 표현</h3>
<ul>
<li><p><strong>상속 선언</strong>: <code>class 파생클래스명 : 접근지정자 기본클래스명 { ... };</code></p>
<pre><code class="language-cpp">class Student : public Person { ... };
class StudentWorker : public Student { ... };</code></pre>
</li>
<li><p><strong>다중 상속</strong>: 다중 상속 시 기본 클래스의 멤버가 중복 상속될 수 있음.</p>
<pre><code class="language-cpp">  class BaseIO {        // 기본 클래스 정의
  };

  class In : virtual public BaseIO {    // In 클래스는 BaseIO 클래스를 가상 상속함
  };

  class Out : virtual public BaseIO {    // Out 클래스는 BaseIO 클래스를 가상 상속함
  };</code></pre>
</li>
</ul>
<h3 id="2-예제-8-1-point-클래스를-상속받는-colorpoint-클래스">2) 예제 8-1: Point 클래스를 상속받는 ColorPoint 클래스</h3>
<h4 id="상속의-특징">상속의 특징</h4>
<ul>
<li>파생 클래스의 객체는 기본 클래스의 멤버를 포함함</li>
<li>파생 클래스 객체를 통해 기본 클래스의 public 멤버와 파생 클래스의 멤버에 접근 가능.<img src="https://velog.velcdn.com/images/jiyoon_sw524/post/508694e8-f929-41e8-a275-1a84e5d5b73a/image.png" alt=""></li>
</ul>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &lt;string&gt;
using namespace std;

class Point {
    int x, y;
public:
    void set(int x, int y) { this-&gt;x = x; this-&gt;y = y; }
    void showPoint() { cout &lt;&lt; &quot;(&quot; &lt;&lt; x &lt;&lt; &quot;, &quot; &lt;&lt; y &lt;&lt; &quot;)&quot; &lt;&lt; endl; }
};

class ColorPoint : public Point {
    string color;
public:
    void setColor(string color) { this-&gt;color = color; }
    void showColorPoint() {
        cout &lt;&lt; color &lt;&lt; &quot;:&quot;;
        showPoint();        // 기본 클래스의 showPoint() 호출
    }
};

int main() {
    ColorPoint cp;         // 파생 클래스 객체 생성
    cp.set(3, 4);         // 기본 클래스의 멤버 함수 호출
    cp.setColor(&quot;Red&quot;); // 파생 클래스의 멤버 함수 호출
    cp.showColorPoint(); // 파생 클래스의 멤버 함수 호출
    return 0;
}</code></pre>
<p><br><hr></p>
<h2 id="2-상속과-객체-포인터">2. 상속과 객체 포인터</h2>
<h3 id="1-업-캐스팅-up-casting과-다운-캐스팅-down-casting">1) 업 캐스팅 (Up-Casting)과 다운 캐스팅 (Down-Casting)</h3>
<ul>
<li><strong>업 캐스팅</strong> : 파생 클래스 포인터가 기본 클래스 포인터로 치환되는 것.</li>
<li><strong>다운 캐스팅</strong> : 기본 클래스 포인터가 파생 클래스 포인터로 치환되는 것.<img src="https://velog.velcdn.com/images/jiyoon_sw524/post/930c0b94-180c-4e00-99c6-f209c210e07d/image.png" alt=""></li>
</ul>
<pre><code class="language-cpp">  int main() {
      ColorPoint cp;
      Point* pBase = &amp;cp; // 업 캐스팅
      pBase-&gt;set(3, 4);
      pBase-&gt;showPoint();
      pBase-&gt;showColorPoint();    //컴파일 오류. 기본 클래스만 접근 가능.

      ColorPoint *pDer;
      pDer = (ColorPoint *)pBase;    //다운캐스팅
      pDer -&gt; setColorPoint();        //정상 컴파일
  }</code></pre>
<h3 id="3-protected-접근-지정">3) protected 접근 지정</h3>
<ul>
<li><strong>private 멤버</strong>: 선언된 클래스 내에서만 접근 가능.</li>
<li><strong>public 멤버</strong>: 선언된 클래스 및 모든 외부 클래스에서 접근 가능.</li>
<li><strong>protected 멤버</strong>: 선언된 클래스 및 파생 클래스에서 접근 가능.</li>
</ul>
<h4 id="상속-시-접근-지정에-따른-멤버-접근-속성-변화">상속 시 접근 지정에 따른 멤버 접근 속성 변화</h4>
<ul>
<li><strong>public 상속</strong>: 기본 클래스의 protected, public 멤버를 그대로 계승.</li>
<li><strong>protected 상속</strong>: 기본 클래스의 protected, public 멤버를 protected로 계승.</li>
<li><strong>private 상속</strong>: 기본 클래스의 protected, public 멤버를 private으로 계승.</li>
</ul>
<pre><code class="language-cpp">class Point {
protected:
    int x, y;
public:
    void set(int x, int y) { this-&gt;x = x; this-&gt;y = y; }
    void showPoint() { cout &lt;&lt; &quot;(&quot; &lt;&lt; x &lt;&lt; &quot;, &quot; &lt;&lt; y &lt;&lt; &quot;)&quot; &lt;&lt; endl; }
};

class ColorPoint : public Point {
    string color;
public:
    void setColor(string color) { this-&gt;color = color; }
    void showColorPoint() {
        cout &lt;&lt; color &lt;&lt; &quot;:&quot;;
        showPoint();
    }
};

int main() {
    ColorPoint cp;
    cp.set(3, 4);
    cp.setColor(&quot;Red&quot;);
    cp.showColorPoint();
    return 0;
}</code></pre>
<p><br><hr></p>
<h2 id="3-상속-관계의-생성자와-소멸자-실행">3. 상속 관계의 생성자와 소멸자 실행</h2>
<h3 id="1-생성자-호출-관계-및-실행-순서">1) 생성자 호출 관계 및 실행 순서</h3>
<ul>
<li>파생 클래스의 객체 생성 : 기본 클래스의 생성자 -&gt; 파생 클래스의 생성자</li>
<li>파생 클래스의 객체 소멸 : 파생 클래스의 소멸자 -&gt; 기본 클래스의 소멸자</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/e894334f-084c-47b8-ac37-4ca19bcd5f69/image.png" alt=""></p>
<br>

<h3 id="2-파생-클래스의-생성자에서-명시적으로-기본-클래스의-생성자-선택">2) 파생 클래스의 생성자에서 명시적으로 기본 클래스의 생성자 선택</h3>
<blockquote>
<p>파생 클래스는 컴파일러에 의해 <strong>기본 클래스의 생성자를 자동으로 호출</strong>한다. 따라서 <strong>기본 클래스에 기본 생성자가 없으면 컴파일 오류가 발생</strong>한다. 또한, <strong>매개변수를 가진 파생 클래스</strong>도 기본 클래스의 기본 생성자를 호출하려고 시도하므로, 기본 클래스의 초기화가 필요할 수 있다. 이를 해결하기 위해 <strong>파생 클래스 생성자에서 명시적으로 기본 클래스의 생성자를 호출</strong>해야 한다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/23084c91-e544-42c5-927c-cd28b49e6a2f/image.png" alt=""></p>
<br>


<h3 id="3-예제-8-3-tv-widetv-smarttv-생성자-매개-변수-전달">3) 예제 8-3: TV, WideTV, SmartTV 생성자 매개 변수 전달<img src="https://velog.velcdn.com/images/jiyoon_sw524/post/2f8e1df8-c04f-4f0d-9242-73f0147a7293/image.png" alt=""></h3>
<p><br><hr></p>
<h2 id="4-다중-상속">4. 다중 상속</h2>
<ul>
<li>C++에서 클래스는 여러 개의 클래스로부터 상속받을 수 있음.</li>
<li>다중 상속을 선언하는 방법:</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/c429b77a-34ea-45b1-bd53-925437578e0b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인공지능]]></title>
            <link>https://velog.io/@jiyoon_sw524/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5</link>
            <guid>https://velog.io/@jiyoon_sw524/%EC%9D%B8%EA%B3%B5%EC%A7%80%EB%8A%A5</guid>
            <pubDate>Mon, 10 Jun 2024 22:17:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/7e6a5fe1-766c-47de-b39e-0f5e32f9fdef/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/ca6c796c-6821-4af1-b19b-befa08af80ab/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/7ccf16a4-95b3-4789-be16-8402ecdb8ee7/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/9783f5f1-e601-4935-bfb5-e4a8c4710dc7/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/fc0c9bbd-ac21-4bbe-aae8-7b64a035a050/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/cc44116f-f5ea-4156-aab5-ea9bde89a6bd/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/51cf462d-0509-431a-b93d-2694cdb1da8d/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[CH07 프렌드와 연산자 중복]]></title>
            <link>https://velog.io/@jiyoon_sw524/CH07-%ED%94%84%EB%A0%8C%EB%93%9C%EC%99%80-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%A4%91%EB%B3%B5</link>
            <guid>https://velog.io/@jiyoon_sw524/CH07-%ED%94%84%EB%A0%8C%EB%93%9C%EC%99%80-%EC%97%B0%EC%82%B0%EC%9E%90-%EC%A4%91%EB%B3%B5</guid>
            <pubDate>Sun, 09 Jun 2024 11:38:23 GMT</pubDate>
            <description><![CDATA[<h2 id="1-프렌드-함수">1. 프렌드 함수</h2>
<p>프렌드 함수는 클래스 외부에서 정의된 함수로, 해당 클래스의 private 및 protected 멤버에 접근할 수 있습니다. 프렌드 함수는 <code>friend</code> 키워드를 사용하여 선언합니다.</p>
<h3 id="프렌드로-초대하는-3가지-유형">프렌드로 초대하는 3가지 유형</h3>
<ol>
<li><p><strong>전역 함수</strong> : 객체를 사용하지 않고 호출</p>
<pre><code class="language-cpp">class Rect {
    friend bool equals(Rect r, Rect s);
};</code></pre>
</li>
<li><p><strong>특정 클래스 멤버 함수</strong> : 해당 클래스의 객체를 생성하여 호출</p>
<pre><code class="language-cpp">class Rect {
    friend bool RectManager::equals(Rect r, Rect s);
};</code></pre>
</li>
<li><p><strong>다른 클래스 전체</strong> : 해당 클래스의 객체를 생성하여 호출</p>
<pre><code class="language-cpp">class Rect {
    friend class RectManager;
};</code></pre>
<br>
### 예시 코드 - 프렌드 함수 만들기 (7-1,2,3)
```cpp
#include <iostream>
using namespace std;

</li>
</ol>
<p>// Rect 클래스의 전방 선언. Rect클래스가 선언되기 전에 먼저 참조되는 컴파일 오류를 막기 위한 선언문
class Rect;             </p>
<p>bool externalEquals(Rect r, Rect s);    // 외부(전역) 함수 선언</p>
<p>class RectManager {
public:
    bool memberEquals(Rect r, Rect s);  // 멤버 함수: 도형 크기 비교
    void copy(Rect&amp; dest, Rect&amp; src);   // 멤버 함수: 도형 복사
};</p>
<p>class Rect {
    int width, height;
public:
    Rect(int width, int height) : width(width), height(height) {}   // 생성자</p>
<pre><code>// 1. 외부 함수를 프렌드로 선언
friend bool externalEquals(Rect r, Rect s);

// 2. 특정 클래스 멤버 함수를 프렌드로 선언
friend bool RectManager::memberEquals(Rect r, Rect s);

// 3. 다른 클래스 전체를 프렌드로 선언
friend class RectManager;</code></pre><p>};</p>
<p>// 1. 외부 함수 정의
bool externalEquals(Rect r, Rect s) {
    return r.width == s.width &amp;&amp; r.height == s.height;  // private 멤버에 접근 가능
}</p>
<p>// 2. RectManager의 멤버 함수 정의
bool RectManager::memberEquals(Rect r, Rect s) {
    return r.width == s.width &amp;&amp; r.height == s.height;
}</p>
<p>// 3. RectManager의 멤버 함수 정의
void RectManager::copy(Rect&amp; dest, Rect&amp; src) {
    dest.width = src.width;
    dest.height = src.height;
}</p>
<p>int main() {
    Rect a(3, 4), b(4, 5);
    RectManager man;</p>
<pre><code>// 외부 함수 호출
if (externalEquals(a, b))
    cout &lt;&lt; &quot;externalEquals: equal&quot; &lt;&lt; endl;
else
    cout &lt;&lt; &quot;externalEquals: not equal&quot; &lt;&lt; endl;

// RectManager 멤버 함수 호출
if (man.memberEquals(a, b))
    cout &lt;&lt; &quot;memberEquals: equal&quot; &lt;&lt; endl;
else
    cout &lt;&lt; &quot;memberEquals: not equal&quot; &lt;&lt; endl;

// RectManager 멤버 함수 호출 (copy)
man.copy(b, a);
if (man.memberEquals(a, b))
    cout &lt;&lt; &quot;after copy: equal&quot; &lt;&lt; endl;
else
    cout &lt;&lt; &quot;after copy: not equal&quot; &lt;&lt; endl;

return 0;</code></pre><p>}</p>
<pre><code>
## 2. 연산자 중복

연산자 중복은 C++에서 기존 연산자에 새로운 의미를 부여하여 사용자 정의 타입에 대해 사용할 수 있도록 합니다. 이를 통해 코드의 가독성과 사용성을 높일 수 있습니다.
- C++에 **본래 있는 연산자만 중복 가능**
- **피연산자 타입이 다른 새로운 연산 정의**
- **연산자는 함수 형태로 구현**
- 반드시 클래스와 관계를 가짐
- 피연산자의 개수를 바꿀 수 없음
- 연산의 우선 순위 변경 불가
- 모든 연산자가 중복 가능하지 않음

&lt;br&gt;

### 1) 연산자 함수 형식
1. 클래스의 멤버 함수로 구현
2. 외부 함수로 구현하고 클래스에 프렌드 함수로 선언

    **`리턴타입 operator연산자(매개변수리스트);`**

    &lt;br&gt;

### 2) 이항 연산자 중복: +와 == 연산자의 작성 사례

#### 클래스의 멤버 함수로 작성:
```cpp
class Color {
public:
    Color operator+(Color op2);
    bool operator==(Color op2);
};</code></pre><h4 id="외부-함수로-작성하고-클래스에-프렌드로-선언">외부 함수로 작성하고 클래스에 프렌드로 선언:</h4>
<pre><code class="language-cpp">class Color {
public:
    friend Color operator+(Color op1, Color op2);
    friend bool operator==(Color op1, Color op2);
};</code></pre>
<br>

<h3 id="3-이항-연산자-중복--연산자">3) 이항 연산자 중복: + 연산자 <img src="https://velog.velcdn.com/images/jiyoon_sw524/post/c08915e3-d725-4558-b8aa-fc1e2fc682e1/image.png" alt=""></h3>
<h4 id="주요-코드-구조">주요 코드 구조</h4>
<pre><code class="language-cpp">class Power {
    int kick;
    int punch;
public:
    Power(int kick=0, int punch=0) : kick(kick), punch(punch) {}
    Power operator+(Power op2);  // + 연산자 함수 선언
};

//새로운 객체 &#39;tmp&#39;를 생성하여 두 객체의 값을 더해준다. 원래 객체는 수정되지 않고, 새로운 객체를 반환한다.
Power Power::operator+(Power op2) {
    Power tmp;
    tmp.kick = this-&gt;kick + op2.kick;  // kick 값 더하기
    tmp.punch = this-&gt;punch + op2.punch;  // punch 값 더하기
    return tmp;
}</code></pre>
<br>

<h3 id="4-단항-연산자-중복-전위와-후위--연산자">4) 단항 연산자 중복: 전위와 후위 ++ 연산자</h3>
<p>단항 연산자는 피연산자가 하나뿐인 연산자로, 연산자 중복 방식은 이항 연산자의 경우와 거의 유사합니다.</p>
<h4 id="단항-연산자-종류">단항 연산자 종류</h4>
<ul>
<li>전위 연산자 (prefix operator) : <code>++op</code>, <code>--op</code>, <code>!op</code>, <code>~op</code></li>
<li>후위 연산자 (postfix operator) : <code>op++</code>, <code>op--</code></li>
</ul>
<br>

<h4 id="전위--연산자">전위 ++ 연산자 <img src="https://velog.velcdn.com/images/jiyoon_sw524/post/fd452ef7-5099-4497-a1b4-f558d733f61b/image.png" alt=""></h4>
<pre><code class="language-cpp">class Power {
    int kick;
    int punch;
public:
    Power(int kick=0, int punch=0) : kick(kick), punch(punch) {}
    Power&amp; operator++();  // 전위 ++ 연산자 함수 선언.
};

// 리턴타입 : 레퍼런스
Power&amp; Power::operator++() {   
    kick++;
    punch++;
    return *this;  // 변경된 객체 자신을 반환
}

int main() {
    Power a(3,5), b;    //a=(3,5), b=(0,0)
    b=++a;                //a=(4,6), b=(4,6)
}</code></pre>
<br>

<h4 id="후위--연산자">후위 ++ 연산자 <img src="https://velog.velcdn.com/images/jiyoon_sw524/post/6f5d87b2-e2c5-41d4-946d-14ff6cc59e89/image.png" alt=""></h4>
<pre><code class="language-cpp">class Power {
    int kick;
    int punch;
public:
    Power(int kick=0, int punch=0) : kick(kick), punch(punch) {}
    Power operator++(int);  // 후위 ++ 연산자 함수 선언
};

Power Power::operator++(int) {
    Power tmp = *this;  // 증가 이전 객체 상태 저장
    kick++;
    punch++;
    return tmp;  // 증가 이전의 객체 반환
}

int main() {
    Power a(3,5), b;    //a=(3,5), b=(0,0)
    b = a++;            //a=(4,6), b=(3,5)
}</code></pre>
<p><br><hr></p>
<h3 id="5-2--a-덧셈을-위한--연산자-함수-작성">5) 2 + a 덧셈을 위한 + 연산자 함수 작성</h3>
<pre><code class="language-cpp">Power operator+(int op1, Power op2) {
    Power tmp;
    tmp.kick = op1 + op2.kick;  // kick 값 더하기
    tmp.punch = op1 + op2.punch;  // punch 값 더하기
    return tmp;
}</code></pre>
<h3 id="-연산자를-외부-프렌드-함수로-구현">+ 연산자를 외부 프렌드 함수로 구현</h3>
<pre><code class="language-cpp">Power operator+(Power op1, Power op2) {
    Power tmp;
    tmp.kick = op1.kick + op2.kick;  // kick 값 더하기
    tmp.punch = op1.punch + op2.punch;  // punch 값 더하기
    return tmp;
}</code></pre>
<h3 id="참조를-리턴하는--연산자-작성">참조를 리턴하는 &lt;&lt; 연산자 작성</h3>
<pre><code class="language-cpp">#include &lt;iostream&gt;
using namespace std;

class Power {
    int kick;
    int punch;
public:
    Power(int kick = 0, int punch = 0) : kick(kick), punch(punch) {}
    void show() {
        cout &lt;&lt; &quot;kick=&quot; &lt;&lt; kick &lt;&lt; &quot;, punch=&quot; &lt;&lt; punch &lt;&lt; endl;
    }
    Power&amp; operator&lt;&lt;(int n);  // &lt;&lt; 연산자 함수 선언
};

Power&amp; Power::operator&lt;&lt;(int n) {
    kick += n;  // kick 값에 n 더하기
    punch += n;  // punch 값에 n 더하기
    return *this;  // 변경된 객체 자신을 반환
}

int main() {
    Power a(1, 2);
    a &lt;&lt; 3 &lt;&lt; 5 &lt;&lt; 6;  // &lt;&lt; 연산자 사용
    a.show();  // 결과 출력
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[CH06 함수 중복과 static 멤버]]></title>
            <link>https://velog.io/@jiyoon_sw524/CH06-%ED%95%A8%EC%88%98-%EC%A4%91%EB%B3%B5%EA%B3%BC-static-%EB%A9%A4%EB%B2%84</link>
            <guid>https://velog.io/@jiyoon_sw524/CH06-%ED%95%A8%EC%88%98-%EC%A4%91%EB%B3%B5%EA%B3%BC-static-%EB%A9%A4%EB%B2%84</guid>
            <pubDate>Wed, 24 Apr 2024 23:09:23 GMT</pubDate>
            <description><![CDATA[<h3 id="함수-중복">함수 중복</h3>
<p>소멸자는 매개 변수를 가지지 않아, 중복 불가하다.</p>
<br>

<h1 id="디폴트-매개-변수">디폴트 매개 변수</h1>
<h3 id="제약-조건">제약 조건</h3>
<p>디폴트 매개 변수는 보통 매개 변수 앞에 선언될 수 없고, 끝 쪽에 몰려 선언되어야 한다. 
왜냐하면, 디폴트 매개 변수를 가지고 있는 함수의 호출문을 컴파일할 때, 컴파일러는 함수 호출문에 나열된 실인자 값들을 <strong>앞에서부터 순서대로</strong> 함수의 매개 변수에 전달하고, <strong>나머지는 디폴트 값으로 전달</strong>하기 때문이다. </p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/687d6509-a824-4190-b2fb-6905f60fa77b/image.png" alt=""></p>
<br>

<h3 id="디폴트-매개-변수를-가진-함수-선언-및-호출">디폴트 매개 변수를 가진 함수 선언 및 호출</h3>
<blockquote>
<p>선언부 또는 구현부에서 디폴트 매개 변수 선언을 해주면 된다. 하지만, 중복해서 작성하면 안 된다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/4139bcb7-a6aa-4c8f-bdcc-1ec87e4fc989/image.png" alt=""></p>
<br>

<h3 id="포인터-변수의-디폴트-값">포인터 변수의 디폴트 값</h3>
<pre><code class="language-cpp">void f(int *p = NULL);                //어떤 객체도 가리키지 않고 있음
void g(int x[] = NULL);                //어떠한 배열(주소) 가리키지 않고 있음
void h(const char *s = &quot;Hello&quot;);    //&quot;Hello&quot; 문자열을 가리킨

!!배열의 이름은 포인터이기 때문에, 다음 두 함수는 같은 함수로서, 공존할 수 없다!!
void f(int a[]);
void f(int* a);</code></pre>
<br>
<hr>
<br>


<h1 id="함수-중복의-모호성">함수 중복의 모호성</h1>
<h3 id="형-변환으로-인한-모호성">형 변환으로 인한 모호성</h3>
<p>함수의 매개 변수 타입과 호출 문의 실인자 타입이 일치하지 않는 경우, 컴파일러는 작은 타입 -&gt; 큰 타입으로 자동 형변환처리를 하는데, 이때 판정이 모호해지면 컴파일 오류를 발생시킨다. </p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/9881c761-18fb-42b2-a171-d5d558f7ab37/image.png" alt=""></p>
<h3 id="참조-매개-변수로-인한-모호성">참조 매개 변수로 인한 모호성</h3>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/3a67819d-35a4-4ce9-bbad-7370a6198ffc/image.png" alt=""></p>
<h3 id="디폴트-매개-변수로-인한-모호성">디폴트 매개 변수로 인한 모호성</h3>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/5abc997e-4c89-42d5-9896-15f985dfa1ca/image.png" alt=""></p>
<br>
<hr>
<br>


<h1 id="static-멤버">static 멤버</h1>
<h3 id="특징">특징</h3>
<ul>
<li><strong>생명 주기</strong> - 객체의 생성과 상관없이 프로그램이 시작할 때 생성되고 프로그램이 종료할 때 소멸된다</li>
<li><strong>사용 범위</strong> - 변수나 함수가 선언된 범위 내에서 사용. 전역 혹은 지역으로 구분</li>
<li>non-static 멤버는 클래스의 객체가 생성될 때 각 객체마다 별도로 생성되므로 인스턴스 멤버라 부르고, <strong>static 멤버</strong>는 클래스 당 하나만 생기고 모든 객체들이 공유하므로 <strong>클래스 멤버</strong>라고 부른다. </li>
<li><strong>static 멤버 함수는 오직 static 멤버들만 접근</strong><ul>
<li>static 멤버 함수가 접근할 수 있는 것 : static 멤버 함수, static 멤버 변수, 함수 내의 지역 변수</li>
<li>static 멤버 함수는 non-static 멤버에 접근 불가 
why? 객체가 생성되지 않은 시점에서 static 멤버 함수가 호출될 수 있기 때문</li>
<li>static 멤버 함수는 객체가 생기기 전부터 호출 가능하므로 this 사용 불가하다</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/28e14f6a-43e3-4256-b98e-ffca90e1032a/image.png" alt=""></p>
<br>

<h3 id="static-멤버-선언">static 멤버 선언</h3>
<p>static 멤버 변수는 외부에 전역 변수로 선언되어야 한다. </p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/8a513eec-dcb6-4a78-97ea-78cd8019ae3b/image.png" alt=""></p>
<br>

<h3 id="static-멤버-사용">static 멤버 사용</h3>
<blockquote>
<p>객체의 멤버로 접근 가능하고, 객체가 생기기 전부터 클래스명과 범위 지정 연산자(::)로도 접근 가능하다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/7bfb753b-b5aa-49c0-a176-bb43d8910263/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jiyoon_sw524/post/29c0c438-16b2-4cfa-a2b1-17e7839b3643/image.png" alt=""></p>
<br>

<h3 id="static의-주요-활용">static의 주요 활용</h3>
<blockquote>
<ul>
<li><strong>전역 변수나 전역 함수를 클래스에 캡슐화</strong><ul>
<li>전역 변수나 전역 함수를  static으로 선언하여 클래스 멤버로 선언</li>
<li>전역 변수나 전역 함수를 가능한 사용하지 않도록 </li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li><strong>객체 사이에 공유 변수를 만들고자 할 때</strong><ul>
<li>static 멤버를 선언하여 모든 객체들이 공유</li>
</ul>
</li>
</ul>
<br>
<br>
<hr>
<br>


<h1 id=""></h1>
<h3 id="-1"></h3>
<br>

<h3 id="-2"></h3>
<br>
<hr>
<br>

<h1 id="6-7">6-7</h1>
<blockquote>
<p> static 멤버를 가진 Random 클래스 완성하기</p>
</blockquote>
<h3 id="maincpp">main.cpp</h3>
<pre><code class="language-cpp">#include &lt;iostream&gt;
#include &quot;Random.h&quot;
using namespace std;

int main() {
    //Random::seed();         //static 함수는 클래스 이름으로 호출
    Random r;               
    r.seed();               //객체를 생성하지 않고도 seed 함수를 호출할 수 있다. 객체 생성 없이도 사용할 수 있는 함수를 static 함수로 선언한다.

    cout &lt;&lt; &quot;1에서 100까지 랜덤 정수 10개 출력&quot; &lt;&lt; endl;
    for (int i = 0; i &lt; 10; i++) {
        //int n = Random::nextInt();
        int n = r.nextInt(1, 100);
        cout &lt;&lt; n &lt;&lt; &#39; &#39;;
    }
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;알파벳 랜덤 10개 출력&quot; &lt;&lt; endl;
    for (int i = 0; i &lt; 10; i++) {
        char c = Random::nextAlphabet();
        cout &lt;&lt; c &lt;&lt; &#39; &#39;;
    }
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;실수 랜덤 10개 출력&quot; &lt;&lt; endl;
    for (int i = 0; i &lt; 10; i++) {
        double d = Random::nextDouble();
        cout &lt;&lt; d &lt;&lt; &#39; &#39;;
    }
    cout &lt;&lt; endl;
}</code></pre>
<h3 id="randomh-헤더-파일">Random.h 헤더 파일</h3>
<pre><code class="language-cpp">#ifndef RANDOM_H
#define RANDOM_H

#include &lt;cstdlib&gt;      //srand, rand 함수, RAND_MAX 상수 (32767) 포함
#include &lt;ctime&gt;        //time 함수 포함

class Random {
public:
    static void seed() {srand((unsigned)time(0));}
    static int nextInt(int min=0, int max=RAND_MAX); //디폴트 매개변수 사용하여 인수가 없을 때의 기본값 설정
    static char nextAlphabet();
    static double nextDouble();
};

#endif</code></pre>
<h3 id="randomcpp">Random.cpp</h3>
<pre><code class="language-cpp">#include &quot;Random.h&quot;

int Random::nextInt(int min, int max) {
    int range = max - min + 1;
    return rand() % range + min;
}

char Random::nextAlphabet() {
    int n = rand() % 26;
    if (rand() % 2 == 0) 
        return &#39;a&#39; + n;
    else 
        return &#39;A&#39; + n;

    /*
    return (char)(&#39;a&#39; + rand() % 52);   //소문자와 대문자를 둘 다 출력되지 않는다. 아스키코드가 연속적이지 않기 때문. &#39;a&#39;는 97, &#39;A&#39;는 65 임.
    */
}

double Random::nextDouble() {
    double d = ((double)rand()) / RAND_MAX; //한번 더 캐스팅을 해주어야 한다. 그렇지 않으면 정수 나누기 정수가 되어 0이 나온다.
    return d*100;
}</code></pre>
]]></description>
        </item>
    </channel>
</rss>