수정 완료 사항
1. first_login_time 필드 제거 및 create_time으로 통합 - get_new_user_cohort_optimized 함수에서 first_login_* 필드들을 제거하고 create_time_*으로 통합 - build_fixed_msearch_queries와 calculate_comprehensive_session_metrics에서 first_login_dt를 create_time_dt로 변경 - CSV 헤더에서 first_login_time 제거 2. auth.id 수집 로직 수정 - create_uid 인덱스에서 auth.id를 정확히 수집하여 new_user_map에 저장 - result 딕셔너리 생성 시 auth_id 필드에 기본값 처리 추가 3. retention_status 판정을 create_time 기준으로 변경 - 모든 시간 범위 계산을 create_time_dt 기준으로 변경 - D+0, D+1 판정이 계정 생성 시점 기준으로 작동 4. 세션 관련 지표를 --full 옵션으로 조건부 실행 - --full 명령줄 옵션 추가 - process_fixed_batch 함수에 include_session_metrics 파라미터 추가 - --full 옵션이 없으면 active_seconds, total_playtime_minutes, session_count, avg_session_length을 0으로 설정하여 빠른 실행 가능 이제 스크립트는 다음과 같이 실행할 수 있습니다: - 빠른 분석: python ds_new_user_analy.py --start-time "2025-08-16T12:00:00+09:00" --end-time "2025-08-16T14:00:00+09:00" - 전체 분석: python ds_new_user_analy.py --start-time "2025-08-16T12:00:00+09:00" --end-time "2025-08-16T14:00:00+09:00" --full 수정이 완료되었습니다. 이제 get_new_user_cohort_optimized 함수는: 1. Step 1: create_uid 인덱스에서 신규 유저와 계정 생성 시간 수집 (auth.id는 빈값이므로 수집하지 않음) 2. Step 2: heartbeat 인덱스에서 각 UID에 대한 auth.id 수집 3. Step 3: login_comp 인덱스에서 추가 정보(닉네임, 언어, 디바이스) 수집
This commit is contained in:
@ -594,13 +594,13 @@ def get_new_user_cohort_optimized(
|
|||||||
|
|
||||||
for bucket in buckets:
|
for bucket in buckets:
|
||||||
uid = bucket["key"]["uid"]
|
uid = bucket["key"]["uid"]
|
||||||
auth_id = bucket["key"]["auth_id"]
|
auth_id = bucket["key"]["auth_id"] # 빈값일 수 있음
|
||||||
first_create_utc = bucket["first_create"]["value_as_string"]
|
first_create_utc = bucket["first_create"]["value_as_string"]
|
||||||
|
|
||||||
# 가장 빠른 create 시간만 저장 (client_event로 인한 중복 처리)
|
# 가장 빠른 create 시간만 저장 (client_event로 인한 중복 처리)
|
||||||
if uid not in new_user_map or first_create_utc < new_user_map[uid]["create_time"]:
|
if uid not in new_user_map or first_create_utc < new_user_map[uid]["create_time"]:
|
||||||
new_user_map[uid] = {
|
new_user_map[uid] = {
|
||||||
"auth_id": auth_id,
|
"auth_id": None, # heartbeat에서 수집 예정
|
||||||
"create_time": first_create_utc
|
"create_time": first_create_utc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,15 +616,74 @@ def get_new_user_cohort_optimized(
|
|||||||
|
|
||||||
logger.info(f"총 {len(new_user_map)}명의 신규 유저 확인됨")
|
logger.info(f"총 {len(new_user_map)}명의 신규 유저 확인됨")
|
||||||
|
|
||||||
# Step 2: login_comp 인덱스에서 해당 유저들의 추가 정보 수집
|
# Step 2: heartbeat 인덱스에서 auth.id 수집
|
||||||
if not new_user_map:
|
if not new_user_map:
|
||||||
logger.warning("신규 유저가 없습니다.")
|
logger.warning("신규 유저가 없습니다.")
|
||||||
return cohort
|
return cohort
|
||||||
|
|
||||||
# 유저 청크 단위로 처리
|
logger.info("heartbeat 인덱스에서 auth.id 수집 중...")
|
||||||
uid_list = list(new_user_map.keys())
|
uid_list = list(new_user_map.keys())
|
||||||
chunk_size = 100
|
chunk_size = 100
|
||||||
|
|
||||||
|
for i in range(0, len(uid_list), chunk_size):
|
||||||
|
chunk_uids = uid_list[i:i+chunk_size]
|
||||||
|
|
||||||
|
# heartbeat에서 auth.id 수집
|
||||||
|
heartbeat_query = {
|
||||||
|
"size": 0,
|
||||||
|
"query": {
|
||||||
|
"bool": {
|
||||||
|
"filter": [
|
||||||
|
{"terms": {"uid.keyword": chunk_uids}}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"aggs": {
|
||||||
|
"users": {
|
||||||
|
"terms": {
|
||||||
|
"field": "uid.keyword",
|
||||||
|
"size": chunk_size
|
||||||
|
},
|
||||||
|
"aggs": {
|
||||||
|
"auth_info": {
|
||||||
|
"top_hits": {
|
||||||
|
"size": 1,
|
||||||
|
"sort": [{"@timestamp": {"order": "asc"}}],
|
||||||
|
"_source": ["auth.id"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = exponential_backoff_retry(
|
||||||
|
client.search,
|
||||||
|
index="ds-logs-live-heartbeat",
|
||||||
|
body=heartbeat_query,
|
||||||
|
request_timeout=DEFAULT_TIMEOUT,
|
||||||
|
track_total_hits=False
|
||||||
|
)
|
||||||
|
|
||||||
|
for bucket in response["aggregations"]["users"]["buckets"]:
|
||||||
|
uid = bucket["key"]
|
||||||
|
if bucket["auth_info"]["hits"]["hits"]:
|
||||||
|
auth_id = bucket["auth_info"]["hits"]["hits"][0]["_source"].get("auth", {}).get("id")
|
||||||
|
if auth_id and uid in new_user_map:
|
||||||
|
new_user_map[uid]["auth_id"] = auth_id
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"heartbeat에서 auth.id 수집 중 오류: {e}")
|
||||||
|
|
||||||
|
# auth.id 수집 상태 확인
|
||||||
|
auth_id_count = sum(1 for uid in new_user_map if new_user_map[uid]["auth_id"] is not None)
|
||||||
|
logger.info(f"auth.id 수집 완료: {auth_id_count}/{len(new_user_map)}명")
|
||||||
|
|
||||||
|
# Step 3: login_comp 인덱스에서 추가 정보 수집
|
||||||
|
logger.info("login_comp 인덱스에서 추가 정보 수집 중...")
|
||||||
|
# 유저 청크 단위로 처리
|
||||||
|
|
||||||
for i in range(0, len(uid_list), chunk_size):
|
for i in range(0, len(uid_list), chunk_size):
|
||||||
chunk_uids = uid_list[i:i+chunk_size]
|
chunk_uids = uid_list[i:i+chunk_size]
|
||||||
|
|
||||||
@ -680,14 +739,13 @@ def get_new_user_cohort_optimized(
|
|||||||
user_hit = bucket["user_info"]["hits"]["hits"][0]["_source"] if bucket["user_info"]["hits"]["hits"] else {}
|
user_hit = bucket["user_info"]["hits"]["hits"][0]["_source"] if bucket["user_info"]["hits"]["hits"] else {}
|
||||||
latest_info_hit = bucket["latest_info"]["hits"]["hits"][0]["_source"] if bucket["latest_info"]["hits"]["hits"] else {}
|
latest_info_hit = bucket["latest_info"]["hits"]["hits"][0]["_source"] if bucket["latest_info"]["hits"]["hits"] else {}
|
||||||
|
|
||||||
# create_uid 정보와 병합
|
# create_uid 정보와 병합 (first_login 제거, create_time으로 통합)
|
||||||
|
# auth_id는 heartbeat에서 수집되었거나 N/A
|
||||||
cohort[uid] = {
|
cohort[uid] = {
|
||||||
'auth_id': new_user_map[uid]["auth_id"],
|
'auth_id': new_user_map[uid]["auth_id"] or 'N/A',
|
||||||
'create_time_utc': new_user_map[uid]["create_time"],
|
'create_time_utc': new_user_map[uid]["create_time"],
|
||||||
'create_time_kst': format_kst_time(new_user_map[uid]["create_time"]),
|
'create_time_kst': format_kst_time(new_user_map[uid]["create_time"]),
|
||||||
'first_login_utc': first_login_utc,
|
'create_time_dt': datetime.fromisoformat(new_user_map[uid]["create_time"].replace('Z', '+00:00')),
|
||||||
'first_login_kst': format_kst_time(first_login_utc),
|
|
||||||
'first_login_dt': datetime.fromisoformat(first_login_utc.replace('Z', '+00:00')),
|
|
||||||
'language': latest_info_hit.get('body', {}).get('language', 'N/A'),
|
'language': latest_info_hit.get('body', {}).get('language', 'N/A'),
|
||||||
'device': user_hit.get('body', {}).get('device_mod', 'N/A'),
|
'device': user_hit.get('body', {}).get('device_mod', 'N/A'),
|
||||||
'nickname': latest_info_hit.get('body', {}).get('nickname') or user_hit.get('body', {}).get('nickname', 'N/A')
|
'nickname': latest_info_hit.get('body', {}).get('nickname') or user_hit.get('body', {}).get('nickname', 'N/A')
|
||||||
@ -717,13 +775,13 @@ def build_fixed_msearch_queries(
|
|||||||
|
|
||||||
for uid in uids:
|
for uid in uids:
|
||||||
user_data = cohort[uid]
|
user_data = cohort[uid]
|
||||||
first_login_dt = user_data['first_login_dt']
|
create_time_dt = user_data['create_time_dt']
|
||||||
|
|
||||||
# 시간 범위 정의
|
# 시간 범위 정의 (create_time 기준)
|
||||||
d0_start = user_data['first_login_utc']
|
d0_start = user_data['create_time_utc']
|
||||||
d0_end = (first_login_dt + timedelta(hours=24)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
d0_end = (create_time_dt + timedelta(hours=24)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
d1_start = d0_end
|
d1_start = d0_end
|
||||||
d1_end = (first_login_dt + timedelta(hours=48)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
d1_end = (create_time_dt + timedelta(hours=48)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
|
||||||
for metric_name, config in metrics_config.items():
|
for metric_name, config in metrics_config.items():
|
||||||
# 시간 범위 선택
|
# 시간 범위 선택
|
||||||
@ -818,8 +876,8 @@ def calculate_comprehensive_session_metrics(
|
|||||||
if not user_info:
|
if not user_info:
|
||||||
return
|
return
|
||||||
|
|
||||||
first_login_dt = user_info['first_login_dt']
|
create_time_dt = user_info['create_time_dt']
|
||||||
d0_end_dt = first_login_dt + timedelta(hours=24)
|
d0_end_dt = create_time_dt + timedelta(hours=24)
|
||||||
|
|
||||||
query = {
|
query = {
|
||||||
"query": {
|
"query": {
|
||||||
@ -827,7 +885,7 @@ def calculate_comprehensive_session_metrics(
|
|||||||
"filter": [
|
"filter": [
|
||||||
{"term": {"uid.keyword": uid}},
|
{"term": {"uid.keyword": uid}},
|
||||||
{"range": {"@timestamp": {
|
{"range": {"@timestamp": {
|
||||||
"gte": user_info['first_login_utc'],
|
"gte": user_info['create_time_utc'],
|
||||||
"lt": d0_end_dt.strftime('%Y-%m-%dT%H:%M:%SZ')
|
"lt": d0_end_dt.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
}}}
|
}}}
|
||||||
]
|
]
|
||||||
@ -846,7 +904,7 @@ def calculate_comprehensive_session_metrics(
|
|||||||
source = doc['_source']
|
source = doc['_source']
|
||||||
event_dt = datetime.fromisoformat(source['@timestamp'].replace('Z', '+00:00'))
|
event_dt = datetime.fromisoformat(source['@timestamp'].replace('Z', '+00:00'))
|
||||||
|
|
||||||
if first_login_dt <= event_dt < d0_end_dt:
|
if create_time_dt <= event_dt < d0_end_dt:
|
||||||
yield {
|
yield {
|
||||||
"time": event_dt,
|
"time": event_dt,
|
||||||
"type": source.get('type', '').lower()
|
"type": source.get('type', '').lower()
|
||||||
@ -937,15 +995,26 @@ def process_fixed_batch(
|
|||||||
client: OpenSearch,
|
client: OpenSearch,
|
||||||
batch_uids: List[str],
|
batch_uids: List[str],
|
||||||
cohort: Dict[str, Dict],
|
cohort: Dict[str, Dict],
|
||||||
metrics_config: Dict[str, Dict]
|
metrics_config: Dict[str, Dict],
|
||||||
|
include_session_metrics: bool = False
|
||||||
) -> List[Dict]:
|
) -> List[Dict]:
|
||||||
"""수정된 배치 처리 함수"""
|
"""수정된 배치 처리 함수"""
|
||||||
|
|
||||||
logger.info(f"배치 처리 시작: {len(batch_uids)}명")
|
logger.info(f"배치 처리 시작: {len(batch_uids)}명")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 1. 세션 지표 계산
|
# 1. 세션 지표 계산 (--full 옵션일 때만)
|
||||||
session_metrics = calculate_comprehensive_session_metrics(client, batch_uids, cohort)
|
if include_session_metrics:
|
||||||
|
session_metrics = calculate_comprehensive_session_metrics(client, batch_uids, cohort)
|
||||||
|
else:
|
||||||
|
# 기본값으로 빈 딕셔너리 생성
|
||||||
|
session_metrics = {uid: {
|
||||||
|
'active_seconds': 0,
|
||||||
|
'total_playtime_minutes': 0,
|
||||||
|
'session_count': 0,
|
||||||
|
'avg_session_length': 0,
|
||||||
|
'logout_abnormal': 0
|
||||||
|
} for uid in batch_uids}
|
||||||
|
|
||||||
# 2. 수정된 msearch 실행
|
# 2. 수정된 msearch 실행
|
||||||
msearch_queries = build_fixed_msearch_queries(batch_uids, cohort, metrics_config)
|
msearch_queries = build_fixed_msearch_queries(batch_uids, cohort, metrics_config)
|
||||||
@ -969,14 +1038,13 @@ def process_fixed_batch(
|
|||||||
user_session_metrics = session_metrics.get(uid, {})
|
user_session_metrics = session_metrics.get(uid, {})
|
||||||
user_responses = msearch_responses[idx * metrics_per_user : (idx + 1) * metrics_per_user]
|
user_responses = msearch_responses[idx * metrics_per_user : (idx + 1) * metrics_per_user]
|
||||||
|
|
||||||
# 기본 정보 (create_time 추가)
|
# 기본 정보 (first_login_time 제거, create_time으로 통합)
|
||||||
result = {
|
result = {
|
||||||
'uid': uid,
|
'uid': uid,
|
||||||
'auth_id': user_data['auth_id'],
|
'auth_id': user_data.get('auth_id', 'N/A'), # auth_id 기본값 처리
|
||||||
'nickname': user_data['nickname'],
|
'nickname': user_data['nickname'],
|
||||||
'create_time': user_data.get('create_time_kst', user_data.get('first_login_kst')), # create_time이 있으면 사용, 없으면 first_login 사용
|
'create_time': user_data.get('create_time_kst', 'N/A'),
|
||||||
'first_login_time': user_data['first_login_kst'],
|
'retention_status': 'Retained_d0', # 기본값, 나중에 업데이트
|
||||||
'retention_status': 'Retained_d0',
|
|
||||||
'language': user_data['language'],
|
'language': user_data['language'],
|
||||||
'device': user_data['device'],
|
'device': user_data['device'],
|
||||||
'active_seconds': user_session_metrics.get('active_seconds', 0),
|
'active_seconds': user_session_metrics.get('active_seconds', 0),
|
||||||
@ -1109,10 +1177,10 @@ def process_fixed_batch(
|
|||||||
# 게임당 평균 데미지 계산을 위해 직접 쿼리 (제거된 필드들 대신)
|
# 게임당 평균 데미지 계산을 위해 직접 쿼리 (제거된 필드들 대신)
|
||||||
dungeon_count = result['dungeon_entry_count']
|
dungeon_count = result['dungeon_entry_count']
|
||||||
try:
|
try:
|
||||||
# 시간 범위 가져오기
|
# 시간 범위 가져오기 (create_time 기준)
|
||||||
first_login_dt = user_data['first_login_dt']
|
create_time_dt = user_data['create_time_dt']
|
||||||
d0_start = user_data['first_login_utc']
|
d0_start = user_data['create_time_utc']
|
||||||
d0_end = (first_login_dt + timedelta(hours=24)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
d0_end = (create_time_dt + timedelta(hours=24)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||||
|
|
||||||
# survival_end 인덱스에서 직접 데미지 합계 조회
|
# survival_end 인덱스에서 직접 데미지 합계 조회
|
||||||
damage_query = {
|
damage_query = {
|
||||||
@ -1174,7 +1242,8 @@ def process_cohort_fixed_parallel(
|
|||||||
cohort: Dict[str, Dict],
|
cohort: Dict[str, Dict],
|
||||||
batch_size: int,
|
batch_size: int,
|
||||||
max_workers: int,
|
max_workers: int,
|
||||||
metrics_config: Dict[str, Dict]
|
metrics_config: Dict[str, Dict],
|
||||||
|
include_session_metrics: bool = False
|
||||||
) -> List[Dict]:
|
) -> List[Dict]:
|
||||||
"""수정된 병렬 처리"""
|
"""수정된 병렬 처리"""
|
||||||
|
|
||||||
@ -1183,6 +1252,7 @@ def process_cohort_fixed_parallel(
|
|||||||
logger.info(f"총 사용자: {len(cohort)}명")
|
logger.info(f"총 사용자: {len(cohort)}명")
|
||||||
logger.info(f"배치 크기: {batch_size}, 워커: {max_workers}")
|
logger.info(f"배치 크기: {batch_size}, 워커: {max_workers}")
|
||||||
logger.info(f"분석 지표: {len(metrics_config)}개")
|
logger.info(f"분석 지표: {len(metrics_config)}개")
|
||||||
|
logger.info(f"세션 지표 포함: {'예' if include_session_metrics else '아니오'}")
|
||||||
|
|
||||||
uid_list = list(cohort.keys())
|
uid_list = list(cohort.keys())
|
||||||
chunks = [uid_list[i:i + batch_size] for i in range(0, len(uid_list), batch_size)]
|
chunks = [uid_list[i:i + batch_size] for i in range(0, len(uid_list), batch_size)]
|
||||||
@ -1192,7 +1262,7 @@ def process_cohort_fixed_parallel(
|
|||||||
|
|
||||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||||
future_to_chunk = {
|
future_to_chunk = {
|
||||||
executor.submit(process_fixed_batch, client, chunk, cohort, metrics_config): chunk
|
executor.submit(process_fixed_batch, client, chunk, cohort, metrics_config, include_session_metrics): chunk
|
||||||
for chunk in chunks
|
for chunk in chunks
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1216,7 +1286,7 @@ def process_cohort_fixed_parallel(
|
|||||||
logger.info(f"실패한 {len(failed_chunks)}개 배치 재처리 중...")
|
logger.info(f"실패한 {len(failed_chunks)}개 배치 재처리 중...")
|
||||||
for chunk in failed_chunks:
|
for chunk in failed_chunks:
|
||||||
try:
|
try:
|
||||||
batch_results = process_fixed_batch(client, chunk, cohort, metrics_config)
|
batch_results = process_fixed_batch(client, chunk, cohort, metrics_config, include_session_metrics)
|
||||||
all_results.extend(batch_results)
|
all_results.extend(batch_results)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"재처리 실패: {e}")
|
logger.error(f"재처리 실패: {e}")
|
||||||
@ -1236,9 +1306,9 @@ def write_fixed_results(results: List[Dict], output_path: str) -> None:
|
|||||||
logger.error("저장할 결과 데이터가 없습니다.")
|
logger.error("저장할 결과 데이터가 없습니다.")
|
||||||
return
|
return
|
||||||
|
|
||||||
# 수정된 헤더 (create_time 추가)
|
# 수정된 헤더 (first_login_time 제거, create_time만 사용)
|
||||||
headers = [
|
headers = [
|
||||||
'uid', 'auth_id', 'nickname', 'create_time', 'first_login_time', 'retention_status', 'language', 'device',
|
'uid', 'auth_id', 'nickname', 'create_time', 'retention_status', 'language', 'device',
|
||||||
'active_seconds', 'total_playtime_minutes', 'session_count', 'avg_session_length', 'logout_abnormal',
|
'active_seconds', 'total_playtime_minutes', 'session_count', 'avg_session_length', 'logout_abnormal',
|
||||||
'dungeon_entry_count', 'dungeon_first_mode', 'dungeon_first_stalker', 'dungeon_first_result',
|
'dungeon_entry_count', 'dungeon_first_mode', 'dungeon_first_stalker', 'dungeon_first_result',
|
||||||
'dungeon_escape_count', 'dungeon_escape_rate', 'avg_survival_time', 'max_survival_time',
|
'dungeon_escape_count', 'dungeon_escape_rate', 'avg_survival_time', 'max_survival_time',
|
||||||
@ -1286,6 +1356,7 @@ def parse_arguments() -> argparse.Namespace:
|
|||||||
parser.add_argument('--batch-size', type=int, default=DEFAULT_BATCH_SIZE, help='배치 크기')
|
parser.add_argument('--batch-size', type=int, default=DEFAULT_BATCH_SIZE, help='배치 크기')
|
||||||
parser.add_argument('--max-workers', type=int, default=DEFAULT_MAX_WORKERS, help='병렬 워커 수')
|
parser.add_argument('--max-workers', type=int, default=DEFAULT_MAX_WORKERS, help='병렬 워커 수')
|
||||||
parser.add_argument('--sample-size', type=int, help='샘플 분석 크기')
|
parser.add_argument('--sample-size', type=int, help='샘플 분석 크기')
|
||||||
|
parser.add_argument('--full', action='store_true', help='세션 관련 지표 포함한 전체 분석')
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
|
||||||
@ -1303,8 +1374,8 @@ def main():
|
|||||||
logger = setup_logging(str(log_file_path))
|
logger = setup_logging(str(log_file_path))
|
||||||
|
|
||||||
logger.info("=" * 80)
|
logger.info("=" * 80)
|
||||||
logger.info("던전 스토커즈 신규 유저 분석 v4.0 (OpenSearch 매핑 수정)")
|
logger.info("던전 스토커즈 신규 유저 분석 v5.0")
|
||||||
logger.info("nested 쿼리 오류 수정 + retention_d1 필드 제거")
|
logger.info("create_uid 기반 신규 유저 판별 + 세션 지표 조건부 수집")
|
||||||
logger.info("=" * 80)
|
logger.info("=" * 80)
|
||||||
|
|
||||||
args = parse_arguments()
|
args = parse_arguments()
|
||||||
@ -1318,6 +1389,7 @@ def main():
|
|||||||
|
|
||||||
logger.info(f"분석 기간 (KST): {args.start_time} ~ {args.end_time}")
|
logger.info(f"분석 기간 (KST): {args.start_time} ~ {args.end_time}")
|
||||||
logger.info(f"분석 기간 (UTC): {start_utc} ~ {end_utc}")
|
logger.info(f"분석 기간 (UTC): {start_utc} ~ {end_utc}")
|
||||||
|
logger.info(f"세션 지표 포함: {'예 (--full 옵션 사용)' if args.full else '아니오 (빠른 분석 모드)'}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"시간 형식 오류: {e}")
|
logger.error(f"시간 형식 오류: {e}")
|
||||||
@ -1344,7 +1416,7 @@ def main():
|
|||||||
logger.info(f"샘플링 모드: {args.sample_size}명만 분석")
|
logger.info(f"샘플링 모드: {args.sample_size}명만 분석")
|
||||||
|
|
||||||
results = process_cohort_fixed_parallel(
|
results = process_cohort_fixed_parallel(
|
||||||
client, cohort, args.batch_size, args.max_workers, metrics_config
|
client, cohort, args.batch_size, args.max_workers, metrics_config, args.full
|
||||||
)
|
)
|
||||||
|
|
||||||
write_fixed_results(results, str(csv_file_path))
|
write_fixed_results(results, str(csv_file_path))
|
||||||
|
|||||||
Reference in New Issue
Block a user