Cloudera
경력근거: Standardize successful patterns into repeatable reference architectures
※ 실제 산출물이 아닌 AI 예측 시안입니다.
Cloudera는 하이퍼스케일러급 데이터를 관리하는 고객사를 상대하고, 이 자리는 그 고객사에 들어가 AI 유스케이스를 빠르게 파일럿하면서 성공 패턴을 반복 가능한 레퍼런스로 남기는 일입니다. 데이터가 많다는 것은 무엇을 먼저 할지 고르는 일이 어려워진다는 뜻이라, 역할 사전과 요건표를 데이터로 두고 카탈로그와 대조하는 순간 그 두 표가 다음 고객사에서 그대로 재사용됩니다. 이 재사용 구조가 공고가 말하는 스타터 킷의 최소 형태이고, 고객사 카탈로그를 통째로 넘겨받아 시작하는 자리에서만 성립합니다. 공고 업무는 앱 프로토타이핑부터 멘토링까지 걸쳐 있는데 1주 범위에서 고를 수 있는 것은 하나라 착수 판정 축을 골랐습니다. 이 포트폴리오는 판단 기준을 데이터로 분리해 규칙으로 집행하고 근거를 남기는 기술을 보여줍니다. Cloudera 플랫폼 운영이나 고객사 업종 지식 자체의 전문성은 주장하지 않습니다. 그 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
성공한 패턴을 반복 가능한 레퍼런스 아키텍처와 스타터 킷으로 만드는 일이 업무에 있습니다. 유스케이스마다 어떤 데이터가 있어야 하는지를 표로 적어 두는 것이 그 표준화의 가장 앞자리입니다.
고객사에 들어가 AI 유스케이스를 빠르게 파일럿하는 것이 팀의 임무로 적혀 있습니다. 무엇부터 착수할지 고르는 판단이 그 속도를 가릅니다.
고객 리더에게 AI 로드맵과 유스케이스를 조언하고 기술 실무자부터 임원까지 상대하는 일이 업무입니다. 무엇이 지금 되고 무엇이 안 되는지를 근거와 함께 내놓는 것이 그 대화의 자료입니다.
고객사 데이터 카탈로그에서 내려받은 컬럼 인벤토리에 컬럼 역할 사전을 적용해 이름마다 역할을 붙이고, 유스케이스 요건표와 대조해 지금 착수할 수 있는 유스케이스와 무엇이 모자라 못 하는지를 요건별로 나눠 출력하고 고객 보고용 리포트를 남기는 CLI입니다. 유스케이스가 읽는 업무 도메인 안에서 필수 역할을 가장 많이 갖춘 테이블 하나를 골라 그 테이블 안에서만 판정하므로, 여신 요건을 주문 테이블로 채우는 짝은 나오지 않습니다.
전략 고객사에 처음 들어가 AI 로드맵을 함께 그리는 파견 엔지니어입니다. 무엇부터 하면 되냐는 질문에 답하려면 테이블 수천 개를 훑어야 하는데, 카탈로그를 내려받아 엑셀에서 컬럼 이름을 눈으로 찾다가 첫 주를 씁니다.
컬럼 이름을 역할로 옮기는 사전과 유스케이스마다 필요한 데이터를 적은 요건표가 있으면, 지금 무엇을 시작할 수 있는지는 사람이 카탈로그를 훑지 않아도 대조로 갈라집니다.
컬럼 인벤토리와 역할 사전, 유스케이스 요건표를 인자로 받아 요건별 판정을 터미널에 출력하고 고객 보고용 리포트를 떨구는 CLI입니다. 카탈로그에 직접 붙지 않고 내려받은 파일만 읽습니다.
요건 하나만 채우면 열리는 유스케이스를 먼저 뽑아, 어느 데이터를 먼저 확보하면 가장 많이 열리는지 보여주는 구성입니다.
유스케이스 요건표를 파일로 분리해 제조와 금융처럼 업종마다 다른 패턴을 같은 판정으로 돌리고, 판정 결과를 로드맵 문서에 붙일 수 있게 내보냅니다.
담당자가 인벤토리 50행과 사전, 요건표를 넣어 유스케이스마다 판정 테이블이 하나로 정해진 판정표와 고객 보고용 리포트가 나오는 것을 시연합니다.
결측·중복·표기흔들림·미매핑이 섞인 입력 30종을 넣어도 출력 형식이 깨지지 않고, 판정하지 못한 요건은 사유가 붙어 남습니다.
결측 비율이 비어 있는 컬럼은 충족으로 세지 않고 프로파일 누락으로 따로 답니다. 재지 못한 것을 통과로 만들지 않습니다.
판정과 손으로 만든 정답표를 맞춰 사유별로 어긋난 건을 셉니다. 단, 인벤토리와 정답을 모두 작성자가 만든 합성 기준이라 성능 측정이 아니라 데모 조건 동작입니다.
진짜 성능 검증은 여기서 멈춥니다. 위 수치는 더미데이터 자가채점이며, 실제 판정 정확도는 Cloudera 고객사의 실제 카탈로그와 실제 요건표가 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태까지 만듭니다.
수치는 합성 데이터 자가채점이라 성능 증명이 아닙니다. 면접에서는 데모 동작과 실검증 준비 상태로 솔직히 설명합니다.
잘 맞는 채점표는 그 자체로 증거가 아닙니다. 결측과 중복, 대소문자로 흔들린 테이블 표기, 사전이 못 맞춘 컬럼이 섞여 있어야 채점에 뜻이 생깁니다.
판정 테이블을 도메인 안에서 필수 역할 개수로 고르므로, 업무상 맞는 테이블이 아닌 쪽이 뽑힐 수 있습니다. 고른 테이블과 근거를 리포트에 적어 고객 담당자가 뒤집을 수 있게 둔 이유입니다.
역할 사전이 못 맞춘 컬럼은 요건이 없다고 나오지만 실제로는 있을 수 있습니다. 그 테이블에 남은 미매핑 컬럼을 함께 적어 사전을 채우면 열릴 후보인지 사람이 판단하게 합니다.
요건이 갖춰졌다고 해서 그 유스케이스가 성공한다고 단정할 수 없습니다. 데이터 품질과 업무 수용도는 이 도구가 보지 않으므로, 판정은 데이터가 있는지까지만 읽어야 합니다.
요건표와 역할 사전을 무엇으로 채울지는 이 도구의 범위 밖입니다. 유스케이스마다 어떤 데이터가 필요한지는 지난 프로젝트에서 얻은 패턴이고, 그 축적은 팀이 합니다.
도메인 태그와 컬럼 이름 규칙은 고객사마다 다릅니다. 태그가 비어 있거나 요건표의 도메인 이름과 다르게 붙은 고객사에서는 그 대응표를 데이터 담당자와 먼저 맞춰야 합니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
고객사 데이터 카탈로그에서 내려받은 컬럼 인벤토리입니다. 카탈로그가 실제로 내주는 것만 담아, 테이블에 붙은 업무 도메인 태그는 있지만 컬럼의 의미 역할은 들어 있지 않습니다. 테이블 표기가 스키마마다 대소문자로 흔들리고, 같은 자산 번호가 두 번 들어온 건과 프로파일러가 아직 재지 않아 결측 비율이 비어 있는 컬럼, 사전에 없는 축약 이름을 일부러 섞었습니다. 확보 기간은 테이블 속성이라 같은 테이블 행에는 같은 값이 반복됩니다.
| asset_no | table_raw | column_name | data_type | null_ratio | table_history_months | business_domain |
|---|---|---|---|---|---|---|
| AS-001 | sales.orders | customer_id | string | 0 | 36 | sales |
| AS-002 | sales.orders | ordered_at | timestamp | 0 | 36 | sales |
| AS-003 | Sales.Orders | amount | decimal | 0.02 | 36 | sales |
| AS-004 | SALES.ORDERS | channel | string | 0.41 | 36 | sales |
| AS-005 | sales.orders | product_id | string | 0 | 36 | sales |
아래 JSON Schema에 맞는 카탈로그 컬럼 인벤토리 행을 더 만들어 주세요. {"type":"object","properties":{"asset_no":{"type":"string"},"table_raw":{"type":"string"},"business_domain":{"type":"string"},"column_name":{"type":"string"},"data_type":{"type":"string"},"null_ratio":{"type":["number","null"]},"table_history_months":{"type":"integer"}},"required":["asset_no","table_raw","business_domain","column_name","data_type","null_ratio","table_history_months"]} asset_no는 AS-로 시작하는 일련번호이고, 같은 테이블의 행은 business_domain과 table_history_months가 같아야 합니다. business_domain은 카탈로그가 테이블에 붙인 업무 도메인 태그입니다. table_raw는 스키마.테이블 형태로 쓰되 일부는 대소문자를 흔들어 주세요. null_ratio는 0.0 이상 1.0 이하이고 열 행에 한 번쯤 null로 비워 주세요. column_name은 실무에서 쓰는 영문 스네이크 표기로 짓고, 열 행에 한 번쯤 collat_val처럼 사전에 없을 법한 축약 이름을 섞어 주세요.{"type":"object","properties":{"asset_no":{"type":"string"},"table_raw":{"type":"string"},"business_domain":{"type":"string"},"column_name":{"type":"string"},"data_type":{"type":"string"},"null_ratio":{"type":["number","null"]},"table_history_months":{"type":"integer"}},"required":["asset_no","table_raw","business_domain","column_name","data_type","null_ratio","table_history_months"]}컬럼 이름을 유스케이스 요건이 부르는 역할로 옮기는 사전입니다. 고객사 명명 규칙에 맞춰 갈아끼우는 자리이고, 여기에 없는 이름은 미매핑으로 남아 사람이 확인합니다.
| rule_no | role | name_pattern | data_type |
|---|---|---|---|
| RD-001 | customer_key | customer_id|cust_no|member_id | string |
| RD-002 | event_time | ordered_at|created_at|issued_at|measur… | timestamp |
| RD-003 | amount | amount|order_amount|invoice_amount | decimal |
| RD-004 | channel | channel|sales_channel | string |
| RD-005 | item_key | product_id|item_id|sku | string |
아래 JSON Schema에 맞는 컬럼 역할 사전 행을 더 만들어 주세요. {"type":"object","properties":{"rule_no":{"type":"string"},"role":{"type":"string"},"name_pattern":{"type":"string"},"data_type":{"type":"string"}},"required":["rule_no","role","name_pattern","data_type"]} rule_no는 RD-로 시작하는 일련번호이고 role은 영문 스네이크 표기의 역할 이름입니다. name_pattern은 그 역할로 볼 컬럼 이름 후보를 파이프로 이어 적고, data_type은 그 역할이 가져야 할 타입을 적어 주세요. 한 이름이 두 역할에 걸치지 않게 해 주세요.{"type":"object","properties":{"rule_no":{"type":"string"},"role":{"type":"string"},"name_pattern":{"type":"string"},"data_type":{"type":"string"}},"required":["rule_no","role","name_pattern","data_type"]}유스케이스마다 어느 도메인의 어떤 역할 데이터가 얼마나 있어야 착수 가능한지를 적은 요건표입니다. FDE 팀이 지난 프로젝트에서 얻은 패턴을 표로 남긴 것이고, 결측 허용치가 아직 정해지지 않은 요건을 일부러 섞었습니다.
| req_no | usecase_id | usecase_name | required_role | min_history_months | max_null_ratio | is_optional | source_domain |
|---|---|---|---|---|---|---|---|
| RQ-001 | churn_predict | 이탈 예측 | customer_key | 12 | 0.05 | false | sales |
| RQ-002 | churn_predict | 이탈 예측 | event_time | 12 | 0 | false | sales |
| RQ-003 | churn_predict | 이탈 예측 | amount | 12 | 0.1 | false | sales |
| RQ-004 | churn_predict | 이탈 예측 | channel | 12 | 0.2 | true | sales |
| RQ-005 | ticket_triage | 문의 자동 분류 | free_text | 6 | 0.1 | false | support |
아래 JSON Schema에 맞는 유스케이스 요건 행을 더 만들어 주세요. {"type":"object","properties":{"req_no":{"type":"string"},"usecase_id":{"type":"string"},"usecase_name":{"type":"string"},"source_domain":{"type":"string"},"required_role":{"type":"string"},"min_history_months":{"type":"integer"},"max_null_ratio":{"type":["number","null"]},"is_optional":{"type":"boolean"}},"required":["req_no","usecase_id","usecase_name","source_domain","required_role","min_history_months","max_null_ratio","is_optional"]} req_no는 RQ-로 시작하는 일련번호이고 한 usecase_id에 요건 두세 건이 붙습니다. required_role은 역할 사전의 role과 같은 표기를 쓰되 사전에 없는 역할도 하나쯤 섞어 주세요. max_null_ratio는 0.0 이상 1.0 이하이고 열 행에 한 번쯤 null로 비워 주세요. usecase_name은 한국어 명사구로 지어 주세요. source_domain은 그 유스케이스가 읽는 업무 도메인 태그이고 같은 usecase_id의 행은 값이 같아야 합니다.{"type":"object","properties":{"req_no":{"type":"string"},"usecase_id":{"type":"string"},"usecase_name":{"type":"string"},"source_domain":{"type":"string"},"required_role":{"type":"string"},"min_history_months":{"type":"integer"},"max_null_ratio":{"type":["number","null"]},"is_optional":{"type":"boolean"}},"required":["req_no","usecase_id","usecase_name","source_domain","required_role","min_history_months","max_null_ratio","is_optional"]}| Python | 세 입력 파일을 읽어 역할을 붙이고 대조 판정을 돌려 리포트를 만드는 본체입니다. |
| 데이터 카탈로그 | 판정의 입력이 나오는 곳입니다. 테이블·컬럼 이름과 타입, 프로파일러가 잰 결측 비율을 내보낸 파일을 받습니다. |
| Spark | 인벤토리에 결측 비율이 비어 있을 때 원본 테이블을 훑어 직접 재는 3주차 경로입니다. |
| Iceberg | 테이블의 확보 기간을 스냅샷 이력으로 확인하는 자리입니다. 요건의 최소 개월 수 판정에 씁니다. |
| RAG | 요건이 갖춰진 유스케이스 중 검색 기반 응답이 필요한 것을 표시해, 다음 단계 설계로 넘깁니다. |
| LLM | 사전이 역할을 못 붙인 컬럼에 역할 후보를 제시하는 보조입니다. 판정에는 쓰지 않습니다. |
✓ pass → 여기서 멈춰도 완결입니다. 더 키우려면 요건 하나만 채우면 열리는 유스케이스를 먼저 뽑습니다.
✓ pass → 우선순위까지가 한 덩어리입니다. 더 키우려면 요건표를 업종별로 분리합니다.
유스케이스 요건 하나가 지금 고객사 데이터로 충족되는지의 판정 결과입니다. 어느 테이블에서 봤는지와 모자라면 무엇이 모자란지를 근거와 함께 담습니다.
{"type":"object","properties":{"req_no":{"type":"string"},"usecase_id":{"type":"string"},"evaluated_table":{"type":["string","null"]},"verdict":{"type":"string","enum":["satisfied","role_not_found","role_unmapped","null_ratio_too_high","history_too_short","null_ratio_unknown","threshold_missing"]},"matched_column":{"type":["string","null"]},"matched_asset_no":{"type":["string","null"]},"observed_value":{"type":["number","null"]},"required_value":{"type":["number","null"]},"evidence":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"agg":{"type":["string","null"]},"value":{},"quote":{"type":["string","null"]}},"required":["field","value"]}},"next_action":{"type":"string"}},"required":["req_no","usecase_id","evaluated_table","verdict","matched_column","matched_asset_no","observed_value","required_value","evidence","next_action"]}[
{
"req_no": "RQ-001",
"usecase_id": "churn_predict",
"evaluated_table": "sales_orders",
"verdict": "satisfied",
"matched_column": "customer_id",
"matched_asset_no": "AS-001",
"observed_value": 0,
"required_value": 0.05,
"evidence": [
{
"field": "null_ratio",
"value": 0
},
{
"field": "max_null_ratio",
"value": 0.05
},
{
"field": "table_history_months",
"value": 36
},
{
"field": "asset_no",
"value": "AS-001"
}
],
"next_action": "요건을 충족합니다. 이탈 예측을 착수 후보에 올립니다."
},
{
"req_no": "RQ-003",
"usecase_id": "churn_predict",
"evaluated_table": "sales_orders",
"verdict": "satisfied",
"matched_column": "amount",
"matched_asset_no": "AS-003",
"observed_value": 0.02,
"required_value": 0.1,
"evidence": [
{
"field": "table_raw",
"value": "Sales.Orders",
"quote": "Sales.Orders"
},
{
"field": "null_ratio",
"value": 0.02
},
{
"field": "max_null_ratio",
"value": 0.1
},
{
"field": "asset_no",
"value": "AS-003"
},
{
"field": "asset_no",
"agg": "count",
"value": 2
}
],
"next_action": "요건을 충족합니다. 다만 AS-003이 두 번 들어와 앞 건으로만 판정했으니 인벤토리에서 뒤 건을 뺍니다."
},
{
"req_no": "RQ-004",
"usecase_id": "churn_predict",
"evaluated_table": "sales_orders",
"verdict": "null_ratio_too_high",
"matched_column": "channel",
"matched_asset_no": "AS-004",
"observed_value": 0.41,
"required_value": 0.2,
"evidence": [
{
"field": "table_raw",
"value": "SALES.ORDERS",
"quote": "SALES.ORDERS"
},
{
"field": "null_ratio",
"value": 0.41
},
{
"field": "max_null_ratio",
"value": 0.2
},
{
"field": "is_optional",
"value": true
},
{
"field": "asset_no",
"value": "AS-004"
}
],
"next_action": "결측이 허용치의 두 배입니다. 선택 요건이라 유입 경로 없이 먼저 시작할지 정합니다."
},
{
"req_no": "RQ-007",
"usecase_id": "ticket_triage",
"evaluated_table": "support_tickets",
"verdict": "history_too_short",
"matched_column": "customer_id",
"matched_asset_no": "AS-006",
"observed_value": 18,
"required_value": 24,
"evidence": [
{
"field": "table_history_months",
"value": 18
},
{
"field": "min_history_months",
"value": 24
},
{
"field": "asset_no",
"value": "AS-006"
}
],
"next_action": "문의 이력이 열여덟 달뿐입니다. 여섯 달 더 쌓이면 다시 봅니다."
},
{
"req_no": "RQ-009",
"usecase_id": "predictive_maint",
"evaluated_table": "iot_sensor_reads",
"verdict": "null_ratio_unknown",
"matched_column": "temperature",
"matched_asset_no": "AS-011",
"observed_value": null,
"required_value": 0.05,
"evidence": [
{
"field": "null_ratio",
"value": null
},
{
"field": "column_name",
"value": "temperature"
},
{
"field": "asset_no",
"value": "AS-011"
}
],
"next_action": "결측 비율이 아직 측정되지 않았습니다. 충족으로 세지 않고 프로파일링을 먼저 돌립니다."
},
{
"req_no": "RQ-010",
"usecase_id": "credit_risk",
"evaluated_table": "fin_invoices",
"verdict": "satisfied",
"matched_column": "customer_id",
"matched_asset_no": "AS-012",
"observed_value": 24,
"required_value": 24,
"evidence": [
{
"field": "table_history_months",
"value": 24
},
{
"field": "min_history_months",
"value": 24
},
{
"field": "null_ratio",
"value": 0
},
{
"field": "asset_no",
"value": "AS-012"
}
],
"next_action": "확보 기간이 요건과 정확히 같아 충족으로 봅니다. 이력이 더 필요하면 요건표의 최소 개월 수를 올립니다."
},
{
"req_no": "RQ-012",
"usecase_id": "credit_risk",
"evaluated_table": "fin_invoices",
"verdict": "role_unmapped",
"matched_column": null,
"matched_asset_no": null,
"observed_value": null,
"required_value": null,
"evidence": [
{
"field": "required_role",
"value": "collateral_value"
},
{
"field": "column_name",
"value": "collat_val"
},
{
"field": "asset_no",
"value": "AS-015"
}
],
"next_action": "담보 가액 역할이 붙은 컬럼이 없습니다. 같은 테이블에 역할을 못 붙인 collat_val이 있으니 사전에 넣을지 데이터 담당자에게 확인합니다."
},
{
"req_no": "RQ-014",
"usecase_id": "demand_forecast",
"evaluated_table": "sales_orders",
"verdict": "threshold_missing",
"matched_column": "channel",
"matched_asset_no": "AS-004",
"observed_value": 0.41,
"required_value": null,
"evidence": [
{
"field": "max_null_ratio",
"value": null
},
{
"field": "req_no",
"value": "RQ-014"
},
{
"field": "asset_no",
"value": "AS-004"
}
],
"next_action": "이 요건의 결측 허용치가 비어 있어 판정하지 않았습니다. 요건표를 먼저 채웁니다."
}
][자동 검증 · 1주차] 1. verdict가 enum 일곱 값 안에 있는지 확인합니다. 2. req_no·usecase_id·evaluated_table·verdict·matched_column·matched_asset_no·observed_value·required_value·evidence·next_action이 모두 있는지 확인합니다. 3. null_ratio가 0.0 이상 1.0 이하인지 확인합니다. 4. evaluated_table이 인벤토리의 테이블 표기에서 점을 밑줄로 바꿔 소문자로 모은 이름 목록 안에 있는지 확인합니다. 5. 같은 usecase_id의 판정이 모두 같은 evaluated_table을 가리키는지 확인합니다. 6. matched_asset_no가 인벤토리에 실재하는 자산 번호이고, 그 행의 테이블이 evaluated_table과 같으며 그 도메인 태그가 요건의 source_domain과 같은지 확인합니다. 7. evidence의 field가 세 입력 표의 컬럼에 실재하는지 확인합니다. 8. evidence의 quote가 그 행 table_raw의 일부인지 확인합니다. 9. 사유가 하나만 붙었는지 우선순위(역할 미매핑·역할 없음 → 이력 부족 → 결측 미측정 → 결측 초과 → 허용치 미정)로 확인합니다. 10. next_action이 존댓말로 끝나는지 확인합니다. [판정 규칙] 1. 유스케이스의 source_domain과 같은 도메인 태그가 붙은 테이블만 후보로 두고, 그중 필수 요건의 역할을 가장 많이 갖춘 테이블 하나를 골라 그 안에서만 판정합니다. 개수가 같으면 확보 기간이 긴 쪽을 고르고, 후보가 없으면 판정 테이블을 비운 채 역할 없음으로 답니다. 2. 요건의 역할이 그 테이블에 없을 때, 같은 테이블에 사전이 역할을 못 붙인 컬럼이 있으면 role_unmapped, 없으면 role_not_found로 가릅니다. 3. 같은 자산 번호가 두 번 들어오면 앞 건만 남기고 뒤 건은 적재 단계에서 사유와 함께 뺍니다. 중복은 판정 사유가 아닙니다. [수동 검증] 1. 유스케이스마다 고른 판정 테이블이 업무상 맞는 테이블인지 고객 담당자가 확인합니다. 2. 사전이 역할을 못 붙인 컬럼이 실제로 그 요건에 해당하는지 데이터 담당자가 확인합니다. [평가 러너 · 2주차] 1. 요건 하나만 모자란 유스케이스를 세어 어느 데이터를 먼저 확보하면 가장 많이 열리는지 나눕니다. 2. 인벤토리와 정답을 작성자가 만든 합성 기준이라 이 수치는 성능 측정이 아니라 데모 조건 동작입니다.
근거: Standardize successful patterns into repeatable reference architectures