[LG U+ Why Not SW Camp 7기] 8월 2주차 회고

배형진·2025년 9월 2일

Why not SW 부트캠프

목록 보기
9/11
post-thumbnail

🔎 8월 2주차 학습 개요

이번 주는 웹/JSON/API 데이터를 수집해 MariaDB·DuckDB에 저장하고, Grafana·Metabase·Elastic Stack으로 시각화 및 모니터링을 경험했으며, 데이터 웨어하우스 구조(ODS·Fact·Mart)와 RAG 기반 벡터DB 활용 이론도 함께 학습하였다.


🗂️ 데이터 수집과 저장소 이론 정리

1. 데이터 수집 도구의 변화

  • 과거에는 Selenium 같은 브라우저 자동화 도구로 많이 연습했지만, 최근에는 Playwright 등 더 가볍고 안정적인 대안이 널리 쓰임
  • 또 하나 주목할 만한 도구가 Apache NiFi
    • 장점: UI 기반으로 쉽게 파이프라인을 구성할 수 있어 데이터 수집의 범용성이 높음
    • 단점: 세부 조정이 많고 대용량 데이터 처리 성능은 상대적으로 떨어짐

즉, 요즘은 상황에 맞춰 PlaywrightNiFi 같은 최신 도구들을 더 많이 활용한다는 점이 특징


2. 데이터 저장소와 활용

데이터를 저장할 때는 데이터의 성격에 맞는 저장소를 선택해야 한다

  • AWS에서 자주 쓰는 서비스
    • EC2: 가상 서버 (데이터 분석/처리 환경 직접 구성)
    • S3: 객체 스토리지 (로그, 이미지, 원본 데이터 저장에 최적화)
    • Athena: S3에 저장된 데이터를 SQL로 바로 분석 가능 → 데이터 웨어하우스 역할
  • 데이터 웨어하우스
    • 매우 큰 데이터베이스를 분석 목적에 맞게 최적화한 것
    • 탑다운 방식: 미리 스키마와 처리 방법을 설계하고 데이터를 쌓음
    • 대규모 데이터에서는 Snowflake 같은 클라우드 기반 DW가 자주 활용됨

3. 데이터 모델과 구조

데이터 웨어하우스에서는 여러 층위의 테이블 구조가 존재한다

  • ODS (Operational Data Store): 단기 저장소, 운영 데이터가 바로 들어옴
  • Fact Table: 수치 중심의 테이블 (매출액, 수량, 점수 등)
  • Market Data Mart: 특정 주제에 맞춰 가공된 테이블 → 분석 편의성을 위해 만듦

특징:

  • 마트 데이터는 삭제해도 상관없음 → 필요하면 Fact Table에서 다시 뽑아오면 되기 때문
  • 이 구조 덕분에 운영 데이터와 분석 데이터를 효율적으로 분리할 수 있음

4. 다양한 저장소가 필요한 이유

  • 데이터의 형태(정형·비정형), 처리 방식, 성능 요구사항에 따라 최적의 저장소가 다르다
  • 예를 들어:
    • 관계형 데이터 → MySQL, PostgreSQL
    • 빅데이터 분석 → Hadoop, Spark + Hive
    • 클라우드 데이터 분석 → S3 + Athena, Snowflake
    • 벡터 검색 → 벡터 DB (RAG에서 활용)

5. RAG와 벡터 데이터베이스

  • RAG (Retrieval Augmented Generation): LLM이 답변을 생성할 때, 벡터 DB에서 질문과 유사한 내용을 찾아 함께 입력해줌
  • 장점: 정확하고 문맥 맞는 답변을 얻을 수 있음
  • 즉, 저장소 선택은 단순히 보관 목적이 아니라 AI 모델 활용까지 고려하는 단계로 확장되고 있다

📚 주요 실습 내용 정리

1. 데이터 수집 및 저장

  • 웹 데이터 수집: 웹페이지 데이터를 크롤링하여 원하는 정보를 추출하고, 수집한 데이터를 MariaDB에 저장하는 과정을 실습
  • JSON & API 데이터 처리: JSON 파일을 불러오고, 외부 API를 통해 데이터를 수집하는 방법을 학습하여 다양한 소스의 데이터를 통합
  • DuckDB 활용: 로컬 환경에서 가볍게 사용할 수 있는 분석형 데이터베이스인 DuckDB를 사용해 데이터 처리 효율성을 경험

2. 데이터 시각화 및 모니터링

  • Grafana & Prometheus: 서버 자원 및 성능 지표를 모니터링하기 위해 Prometheus와 Windows Exporter를 설정하고, Grafana 대시보드에서 시각화
  • Metabase: 수집된 데이터를 쉽고 직관적으로 분석할 수 있는 BI 도구를 활용하여 SQL 기반 분석 및 차트 시각화를 수행
  • ElasticSearch: Elasticsearch와 Kibana를 이용하여 MariaDB에 적재된 데이터를 시각화하는 과정을 체험

🎮 실습/과제 수행 및 문제 해결 과정

이번 주에 실습하면서 겪었던 어려움이나 궁금증의 해결 과정을 기록하였습니다

다음은 CSV를 duckDB로 불러오는 실습을 수행하면서 겪었던 어려움입니다

데이터 수집용 가상환경을 venv로 새로 만든 뒤 아래와 같이 csv를 먼저 판다스로 먼저 불러온 뒤 duckDB를 이용해 데이터를 추출하는 실습을 하였는데 실행 중에 알 수 없는 에러가 떴었습니다.

import duckdb
import os
import pandas as pd

# duckdb로 csv파일을 읽으면 에러가 발생하므로 pandas에서 먼저 읽어서 duckdb에 import,
print('a')
duck_con = duckdb.connect("c:/data/duck_smb.db")
print('b')
duck_con.execute("CREATE TABLE IF NOT EXISTS tb_smb_file AS SELECT * FROM read_csv('c:/data/smb_data/sejong.csv');")
duck_con.execute("DELETE FROM tb_smb_file;")

csv_path = 'c:/data/smb_data'
file_list = os.listdir( csv_path ) # 경로 내에 파일을 모두 불러옴
csv_file_list = [file for file in file_list if file.endswith('.csv')] # csv 확장자를 가진 파일로 새로운 리스트 생성

for csv_file_name in csv_file_list:
    csv_file_full = f'{csv_path}/{csv_file_name}'
    print(f'csv_file_name = {csv_file_full}')
    csv_df = pd.read_csv( csv_file_full )
    duck_con.execute("insert into tb_smb_file SELECT * FROM csv_df;")

print("csv loading complete")

duck_con.sql("SELECT addr1, addr2, addr3, cate3_nm, cnt FROM ( SELECT addr1, addr2, addr3, cate3_nm, cnt, RANK() OVER (PARTITION BY addr3 ORDER BY cnt DESC) AS t_rank FROM ( SELECT 시도명 as addr1, 시군구명 as addr2, 행정동명 as addr3, 상권업종소분류명 as cate3_nm, COUNT(상권업종소분류명) AS cnt FROM tb_smb_file GROUP BY addr1, addr2, addr3, cate3_nm ORDER BY cnt DESC ) temp_rank ) temp_rank2 WHERE t_rank=1 ORDER BY cnt DESC;").show()

어디서 에러가 발생한 지 명확하게 판단하기 위해 각 줄마다 print 문을 이용하여 어디서 에러가 나는지 체크를 해보았었는데 바로 첫번째 줄, duckDB를 연결하는 부분에서 문제가 발생했다는 것을 알 수 있었습니다.

a
PS C:\data>

이런식으로 터미널창에 출력이 되었는데 에러 메세지 자체가 보이지 않아 어떤 문제점인지 발견을 못하던중 다른 가상환경에서는 잘 동작하는 것을 보고 가상환경 충돌이 원인일 수 있겠다는 생각을 하였습니다.

실제로 먼저 만든 conda 환경안에 venv를 만드는 실수를 하여 가상환경 충돌로 인한 문제임을 venv환경을 삭제하고 다시 실행해봄으로써 알게 되었습니다.

이번 실습을 계기로 가상환경을 아예 분리해서 독립적으로 관리를 하는 것이 좋다는 사실을 배우게 되었습니다.


다음은 웹크롤링을 통해 데이터수집 실습을 수행하면서 새롭게 배운 점입니다

이번 데이터 수집 실습에서 URL과 데이터를 분리해서 관리하는 이유를 처음으로 명확히 이해할 수 있었다.

그동안은 단순히 데이터만 모으면 된다고 생각했는데, 강사님께서 설명해주신 내용을 통해 아래와 같은 장점을 새롭게 알게 되었다.

  • 출처 관리 → 데이터가 어디서 왔는지 추적 가능
  • 중복 방지 → 이미 같은 URL이 있다면 다시 수집하지 않음
  • 재수집 용이 → 원본 사이트가 수정되면 URL만 다시 호출해 최신화
  • 확장성 → URL 큐와 데이터 저장소를 분리하면 병렬 처리나 스케줄링이 쉬움

추가로 URL을 단순히 리스트로만 두는 게 아니라, 각 URL의 수집 상태(status)를 DB 컬럼으로 관리하는 방식도 배웠다.

# status : 1 수집처리대기
cur.execute(ready_update_sql, ('1', ready_seq_no))
conn.commit()

# status : 2 수집중
cur.execute(ready_update_sql, ('2', ready_seq_no))
conn.commit()

# status : 5 실패
cur.execute(ready_update_sql, ('5', ready_seq_no))
conn.commit()

# status : 9 수집완료
cur.execute(ready_update_sql, ('9', ready_seq_no))
conn.commit()

이와 같은 방식으로 크롤링 파이프라인이 어느 단계까지 진행됐는지 한눈에 파악할 수 있었다.

0개의 댓글