스키마가 아니라 개념으로: 온톨로지로 데이터를 다루는 법
"올해 이직률이 가장 높은 부서는?"이라는 한 문장을 정확한 SQL로 바꾸려면, DB 스키마가 아니라 비즈니스 개념을 먼저 알아야 한다. 온톨로지 우선 설계로 자연어 데이터 조회 플랫폼 IRIS를 만든 이야기.

"올해 이직률이 가장 높은 부서는?" 임원이 던진 이 한 문장을, 데이터팀은 이렇게 번역해야 한다. employees 테이블에서 resignation_date가 올해인 행을 세고, department_id로 묶고, 각 부서의 재직 인원으로 나눠 비율을 구하고, 내림차순 정렬한다. 사람은 이 번역을 해낸다. "이직률"이 무슨 뜻인지, 어느 테이블의 어느 컬럼을 봐야 하는지 알고 있기 때문이다.
문제는 AI에게 DB 스키마만 던져주면 이 지식이 없다는 것이다. 스키마에는 resignation_date라는 컬럼명이 있을 뿐, "이직률"이라는 개념도, 그것이 이 컬럼과 연결된다는 사실도 적혀 있지 않다. 우리가 자연어 데이터 조회 플랫폼 IRIS를 만들며 가장 먼저 마주한 벽이 바로 이것이었다. 그리고 우리의 답은 온톨로지였다.
왜 자연어→SQL은 생각보다 어려운가
LLM에게 테이블 스키마를 전부 넣고 "이 질문을 SQL로 바꿔줘"라고 시키는 방식(Text-to-SQL)은 데모에서는 잘 동작한다. 하지만 실무에서는 세 가지 지점에서 무너진다.
- 어휘의 간극: 사용자는 "매출", "이직률", "우수 고객"이라 말하지만, DB에는
rev_amt,resignation_date,grade='A'같은 것만 있다. 사람의 말과 컬럼명 사이에는 번역이 필요하다. - 관계의 복잡성: "부서별"이라는 한 단어가 실제로는 두세 테이블의 조인을 요구한다. 어떤 경로로 조인해야 하는지는 스키마만 봐서는 유일하게 결정되지 않는다.
- 정확성의 요구: 틀린 숫자를 자신 있게 내놓는 분석 도구는 없느니만 못하다. 경영 의사결정이 걸린 질문에 "그럴듯한 SQL"은 실패다.
스키마는 데이터가 어떻게 저장되는지를 말해줄 뿐, 그 데이터가 무엇을 의미하는지는 말해주지 않는다. 이 의미의 공백을 메우는 것이 온톨로지의 역할이다.
온톨로지란 무엇인가
온톨로지(Ontology)는 원래 철학에서 "존재하는 것들과 그 관계에 대한 체계"를 뜻하는 말이다. 소프트웨어에서는 한 도메인의 개념·속성·관계를 명시적으로 기술한 지식 모델을 가리킨다.
쉽게 말하면 이렇다. 데이터베이스가 "직원 테이블에는 이름·부서ID·입사일 컬럼이 있다"고 말한다면, 온톨로지는 이렇게 말한다.
**직원(Employee)**은 하나의 **부서(Department)**에 속한다(belongs_to). 직원은 "사원", "임직원"이라고도 불린다. "이직"이란 직원의 재직 상태가 종료되는 것을 의미한다.
온톨로지는 개념에 **별칭(alias)**을 부여하고, 개념 사이의 관계를 정의하며, 사람의 언어와 데이터베이스의 구조를 잇는 다리를 놓는다. DB 스키마 위에 얹힌 **의미의 레이어(semantic layer)**인 셈이다.
온톨로지 우선 아키텍처
IRIS의 설계 철학은 한 문장으로 요약된다. DB 스키마가 아니라 비즈니스 개념이 SQL 생성을 주도한다. 이는 Palantir Gotham에서 영감을 받은 "온톨로지 우선(ontology-first)" 접근이다.
일반적인 Text-to-SQL이 질문 + 스키마 → SQL이라면, IRIS는 그 사이에 온톨로지를 끼워 넣는다.
질문 → [의미 해석] → 온톨로지의 개념·관계 → [매핑] → SQL
핵심 이점은 분리다. 비즈니스 개념(온톨로지)과 물리적 저장(스키마)이 분리되어 있으므로, 컬럼명이 바뀌어도 온톨로지의 매핑만 고치면 되고, 새로운 산업군에 진출할 때는 코드가 아니라 온톨로지만 새로 쓰면 된다. IRIS가 "DB 분석 → YAML 온톨로지 작성 → 배포"만으로 새 도메인에 2주 내 배포를 목표로 하는 이유가 여기에 있다.
YAML로 온톨로지를 정의한다
온톨로지가 거창하게 들리지만, IRIS에서는 사람이 읽고 쓸 수 있는 YAML 파일이다. 도메인 전문가가 개발자 없이도 개념을 정의하고 확장할 수 있도록 했다.
classes:
- name: Employee
table: employees
aliases: ["직원", "사원", "임직원"]
properties:
- name: department
column: department_id
join: departments.id
- name: is_resigned # "이직 여부"라는 개념
column: resignation_date
rule: "resignation_date IS NOT NULL"
이 몇 줄이 "이직", "부서", "임직원" 같은 사람의 언어를 실제 컬럼과 조인 경로, 계산 규칙에 연결한다. is_resigned처럼 컬럼에 직접 대응하지 않는 파생 개념도 규칙으로 정의할 수 있다. 온톨로지는 단순한 매핑표가 아니라 도메인의 규칙까지 담는 지식 베이스다.
8단계 파이프라인에서 온톨로지의 역할
IRIS에서 하나의 질문은 8단계 파이프라인을 지난다. 오케스트레이터 → 인텐트 파서 → 온톨로지 리졸버 → SQL 생성기 → SQL 검증기 → 쿼리 실행기 → 응답 포맷터 → 쿼리 로거.
온톨로지가 결정적으로 개입하는 곳은 세 번째 단계, 온톨로지 리졸버다. LLM이 파악한 질문 의도에서 비즈니스 개념을 추출하고, 이를 온톨로지에 조회해 실제 테이블·컬럼·조인 경로·계산 규칙으로 변환한다. SQL 생성기는 이 해석된 구조를 바탕으로 쿼리를 만들기 때문에, LLM이 스키마를 멋대로 추측하는 일이 크게 줄어든다.
여기에 안전장치가 더해진다. SQL 검증기는 화이트리스트 기반으로 허용된 패턴만 통과시키고, RBAC 5단계와 부서별 필터링, PII 마스킹으로 사용자가 권한 밖 데이터를 볼 수 없게 막는다. 정확성만큼이나 "보여도 되는 것만 보이게 하는" 통제가 중요하기 때문이다.
스스로 자라는 온톨로지
온톨로지의 가장 큰 약점은 초기 구축 비용이다. 세상의 모든 개념과 별칭을 처음부터 다 넣을 수는 없다. 그래서 IRIS의 온톨로지는 자기강화(self-reinforcing) 구조로 설계됐다.
- 사용자의 질문 중 온톨로지에 매칭되지 않은 것들을 자동으로 수집한다.
- 잘 동작한 질의는 골든 쿼리 라이브러리(100개 이상 큐레이션)에 축적된다.
- 사용 패턴을 바탕으로 새로운 별칭과 개념을 온톨로지에 자동 보강한다.
쓰면 쓸수록 온톨로지가 풍부해지고, 답할 수 있는 질문의 범위가 넓어진다. 처음엔 "이직률"을 못 알아듣더라도, 한 번 정의되면 그 뒤로는 계속 안다. 지식이 시스템 안에 축적되는 것이다.
왜 이 방식이 더 나은가
온톨로지 우선 설계의 진짜 가치는 주체의 이동에 있다.
기존 방식에서 데이터 질문에 답할 수 있는 사람은 SQL을 아는 개발자뿐이었다. 온톨로지가 있으면, 도메인을 가장 잘 아는 사람(인사팀, 재무팀, 현업 담당자)이 개념을 정의하고, 나머지 모두가 자연어로 질문한다. 데이터 접근의 병목이 사라진다.
그리고 이 구조는 확장에 강하다. 새 도메인이 들어오면 코드를 다시 짜는 게 아니라 온톨로지를 새로 기술한다. 인사 도메인에서 검증된 파이프라인이, 온톨로지만 갈아끼우면 물류나 커머스 도메인에서 그대로 돈다. 엔진은 하나, 지식은 도메인마다.
우리가 그리는 그림
Text-to-SQL은 "질문을 쿼리로 바꾸는 기술"이다. 하지만 우리가 진짜 만들고 싶은 것은 "조직의 지식을 코드가 아닌 개념으로 축적하는 시스템"이다.
온톨로지는 그 축적의 그릇이다. 개념과 관계와 규칙이 사람이 읽을 수 있는 형태로 쌓이고, 그 위에서 AI가 정확하게 질문에 답하며, 쓸수록 스스로 자란다. 스키마는 데이터가 어떻게 저장되는지를 말하지만, 온톨로지는 그 데이터가 조직에게 무엇을 의미하는지를 말한다. 우리는 후자가 AI 시대의 진짜 자산이라고 믿는다.