Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 99 additions & 53 deletions generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def encrypt_aes(raw_text):
DEFAULT_PASSWORD_HASH = bcrypt.hashpw(b"1234", bcrypt.gensalt()).decode('utf-8')

# --- 설정 및 상수 ---
SIZES = [10, 100, 10000, 50000, 100000]
SIZES = [10, 100, 1000, 10000, 50000, 100000]
OUTPUT_DIR = "dummy_data"

# 이름 생성을 위한 한국인 성/이름 풀
Expand Down Expand Up @@ -104,98 +104,145 @@ def run_generation(target_users):

# 1. 주소 데이터 생성 (가족 공유를 위해 회원 수의 80% 생성)
num_addresses = max(1, int(target_users * 0.8))
addresses = []
seen_address_key = set() # (province, city, street_address) 유니크 제약 준수
print(" - 주소 데이터 생성 중...")
with open(os.path.join(dir_path, 'address.csv'), 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['address_id', 'province', 'city', 'street_address', 'postal_code', 'created_at', 'updated_at'])
writer.writerow(['province', 'city', 'street_address', 'postal_code', 'created_at', 'updated_at'])

for i in range(1, num_addresses + 1):
prov = random.choice(list(ADDRESS_POOL.keys()))
city = random.choice(list(ADDRESS_POOL[prov].keys()))
street_base = random.choice(ADDRESS_POOL[prov][city])
street = f"{street_base} {random.randint(1, 150)}길 {random.randint(1, 99)}"
while True:
prov = random.choice(list(ADDRESS_POOL.keys()))
city = random.choice(list(ADDRESS_POOL[prov].keys()))
street_base = random.choice(ADDRESS_POOL[prov][city])
street = f"{street_base} {random.randint(1, 150)}길 {random.randint(1, 99)}"
key = (prov, city, street)
if key not in seen_address_key:
seen_address_key.add(key)
break
postal = f"{random.randint(10000, 69999)}"
now_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')

addresses.append(i) # address_id 저장
writer.writerow([i, prov, city, street, postal, now_str, now_str])

writer.writerow([prov, city, street, postal, now_str, now_str])

# 2. 회원 데이터 생성 (암호화 적용)
print(" - 회원 데이터 생성 중...")
used_emails = set()
used_phones = set()
used_providers = set() # 구글 소셜 로그인 ID 중복 방지용

subscriptions_to_create = [] # (member_id, [product_ids], start_date)

with open(os.path.join(dir_path, 'member.csv'), 'w', newline='', encoding='utf-8') as f:
writer = csv.writer(f)
writer.writerow(['member_id', 'address_id', 'provider_id', 'email', 'password', 'name', 'phone', 'birth_date', 'gender', 'join_date', 'created_at', 'updated_at', 'status_updated_at', 'status', 'type', 'role', 'membership'])
writer.writerow(['address_id', 'provider_id', 'email', 'password', 'name', 'phone', 'birth_date', 'gender', 'join_date', 'created_at', 'updated_at', 'status_updated_at', 'status', 'type', 'role', 'membership'])

for member_id in range(1, target_users + 1):
address_id = random.choice(addresses)

# 1) 원본 데이터 생성
# ----------------------------------------------------
# [A] 기본 정보 생성
# ----------------------------------------------------
raw_name = random.choice(LAST_NAMES) + random.choice(FIRST_NAMES)
encrypted_name = encrypt_aes(raw_name)

while True:
raw_phone = f"010-{random.randint(1000, 9999)}-{random.randint(1000, 9999)}"
if raw_phone not in used_phones:
used_phones.add(raw_phone)
break

while True:
email = f"user{member_id}_{random.randint(1000,9999)}@gmail.com"
if email not in used_emails:
used_emails.add(email)
break

# 2) 암호화 적용
encrypted_name = encrypt_aes(raw_name)
encrypted_phone = encrypt_aes(raw_phone)
hashed_password = DEFAULT_PASSWORD_HASH # 미리 만들어둔 BCrypt 해시 사용

birth_date = generate_random_date(date(1960, 1, 1), date(2010, 12, 31))
gender = random.choice(['M', 'F'])
join_date = get_weighted_join_date()
membership = random.choices(['VVIP', 'VIP', 'GOLD'], weights=[5, 15, 80], k=1)[0]
now_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
join_date = get_weighted_join_date()

# ----------------------------------------------------
# [B] 역할(Role) 결정 (CUSTOMER: 98.9%, COUNSELOR: 1%, ADMIN: 0.1%)
# ----------------------------------------------------
role = random.choices(['CUSTOMER', 'COUNSELOR', 'ADMIN'], weights=[98.9, 1.0, 0.1], k=1)[0]

writer.writerow([
member_id, address_id, '', email, hashed_password,
encrypted_name, encrypted_phone, birth_date, gender,
join_date, now_str, now_str, now_str, 'ACTIVE', 'FORM', 'CUSTOMER', membership
])

# 해당 회원의 구독 상품 결정 로직
my_products = []
my_products.append(random.choice(MOBILE_IDS)) # 모바일 1개 필수

if random.random() < 0.2: my_products.append(random.choice(TAB_WATCH_IDS))
if random.random() < 0.2: my_products.append(random.choice(IPTV_IDS))
if random.random() < 0.2: my_products.append(random.choice(INTERNET_IDS))
# ----------------------------------------------------
# [C] 상태(Status) 결정 (ACTIVE가 대부분, 나머지는 소수)
# ----------------------------------------------------
status = random.choices(['ACTIVE', 'PROCESSING', 'BANNED', 'DELETED'], weights=[90, 5, 3, 2], k=1)[0]

# ----------------------------------------------------
# [D] 가입 유형(Type) 및 인증 정보(Auth) 설정
# DDL: (type = 'FORM' AND password IS NOT NULL) OR (type <> 'FORM' AND provider_id IS NOT NULL)
# ----------------------------------------------------
# 관리자와 상담사는 무조건 FORM 가입으로 고정, 고객만 구글 로그인 20% 확률 부여
signup_type = 'FORM'
if role == 'CUSTOMER':
signup_type = random.choices(['FORM', 'GOOGLE'], weights=[80, 20], k=1)[0]

num_addons = random.randint(0, 4)
my_products.extend(random.sample(ADDON_IDS, num_addons))
provider_id = ''
hashed_password = ''

# 구독 시작일 (가입일 ~ 오늘 사이 언제든 가능)
sub_start = generate_random_date(join_date, date.today())
if signup_type == 'FORM':
hashed_password = DEFAULT_PASSWORD_HASH
else:
# GOOGLE 가입
while True:
pid = f"google_{random.randint(10000000, 99999999)}"
if pid not in used_providers:
used_providers.add(pid)
provider_id = pid
break

# ----------------------------------------------------
# [E] 고객 필수 정보(Customer Required Info) 설정
# DDL: role = 'CUSTOMER' 이면 폰, 생일, 성별, 주소, 멤버십 모두 NOT NULL
# ----------------------------------------------------
address_id = ''
encrypted_phone = ''
birth_date = ''
gender = ''
membership = ''

subscriptions_to_create.append((member_id, my_products, sub_start))
if role == 'CUSTOMER':
address_id = random.randint(1, num_addresses)

while True:
raw_phone = f"010-{random.randint(1000, 9999)}-{random.randint(1000, 9999)}"
if raw_phone not in used_phones:
used_phones.add(raw_phone)
break
encrypted_phone = encrypt_aes(raw_phone)

birth_date = generate_random_date(date(1960, 1, 1), date(2010, 12, 31))
gender = random.choice(['M', 'F'])
membership = random.choices(['VVIP', 'VIP', 'GOLD', 'BASIC'], weights=[5, 10, 35, 50], k=1)[0]

# 고객인 경우에만 요금제(구독) 생성 후보에 추가
my_products = []
my_products.append(random.choice(MOBILE_IDS)) # 모바일 1개 필수
if random.random() < 0.2: my_products.append(random.choice(TAB_WATCH_IDS))
if random.random() < 0.2: my_products.append(random.choice(IPTV_IDS))
if random.random() < 0.2: my_products.append(random.choice(INTERNET_IDS))
num_addons = random.randint(0, 4)
my_products.extend(random.sample(ADDON_IDS, num_addons))

sub_start = generate_random_date(join_date, date.today())
subscriptions_to_create.append((member_id, my_products, sub_start))

# ----------------------------------------------------
# CSV 쓰기
# ----------------------------------------------------
writer.writerow([
address_id, provider_id, email, hashed_password,
encrypted_name, encrypted_phone, birth_date, gender,
join_date, now_str, now_str, now_str, status, signup_type, role, membership
])

# 3. 구독 및 사용량 데이터 생성
print(" - 구독 및 월별 사용량 데이터 생성 중...")
sub_id = 1
usage_id = 1

with open(os.path.join(dir_path, 'subscription.csv'), 'w', newline='', encoding='utf-8') as f_sub, \
open(os.path.join(dir_path, 'usage_monthly.csv'), 'w', newline='', encoding='utf-8') as f_usage:

sub_writer = csv.writer(f_sub)
sub_writer.writerow(['subscription_id', 'member_id', 'product_id', 'start_date', 'end_date', 'status', 'created_at', 'updated_at'])
sub_writer.writerow(['member_id', 'product_id', 'start_date', 'end_date', 'status', 'created_at', 'updated_at'])

usage_writer = csv.writer(f_usage)
usage_writer.writerow(['usage_id', 'subscription_id', 'yyyymm', 'usage_details', 'created_at', 'updated_at'])
usage_writer.writerow(['subscription_id', 'yyyymm', 'usage_details', 'created_at', 'updated_at'])

now_str = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
recent_months = get_last_12_months()
Expand All @@ -206,7 +253,7 @@ def run_generation(target_users):

for p_id in p_ids:
# 3-1. 구독 데이터 작성
sub_writer.writerow([sub_id, member_id, p_id, start_date_str, '', True, now_str, now_str])
sub_writer.writerow([member_id, p_id, start_date_str, '', True, now_str, now_str])

# 3-2. 사용량 데이터 작성 (ADDON은 제외)
if p_id not in ADDON_IDS:
Expand Down Expand Up @@ -248,8 +295,7 @@ def run_generation(target_users):
}

usage_json = json.dumps(usage_details)
usage_writer.writerow([usage_id, sub_id, yyyymm, usage_json, now_str, now_str])
usage_id += 1
usage_writer.writerow([sub_id, yyyymm, usage_json, now_str, now_str])

sub_id += 1

Expand Down
Loading