개념 해설 · 2026-08-26

OWL 2 RL과 OWL 2 DL은 다른 질문에 답한다

SKOS와 PROV가 표현력을 아낀 이유를 따라가면, OWL 안의 두 계약이 나온다

ontologyknowledge-graph

SKOS가 broader/narrower를 rdfs:subClassOf로 정의하지 않고 일부러 비전이적으로 남겨둔 이유, PROV-O가 클래스는 OWL로 다 정의해두고도 스스로 OWL 2 RL 프로파일 안에 머무른 이유를 따라가 보니, 결론이 같은 자리로 모였다. 둘 다 OWL의 표현력을 전부 쓰지 않고 일부러 부분집합을 골랐다.

그 부분집합의 정체를 찾다 보니 OWL 2 자체가 이 문제에 이미 답을 갖고 있었다. OWL 2는 표현력과 계산 비용을 맞바꾼 여러 프로파일로 나뉘어 있고, RL과 DL은 그중 서로 다른 계약을 맺은 두 프로파일이다. RL은 규칙 엔진이 풀 수 있는 만큼만 표현하게 제한하고, DL은 Description Logic reasoner가 풀 수 있는 만큼 표현력을 열어둔다. 둘 다 OWL이지만, 하나는 "빠르고 예측 가능한 답"을 계약하고 다른 하나는 "정밀하지만 비용이 드는 답"을 계약한다. PROV-O가 스스로 RL에 묶인 이유도, SKOS가 subClassOf 대신 약한 관계를 쓴 이유도, 결국 이 두 계약 중 어느 쪽을 감당할 수 있느냐는 판단이었다.


1. RL이 다루는 추론은 사슬을 잇는 일이다

RL이 잘 다루는 건 subClassOf, subPropertyOf, domain, range, inverseOf, transitiveProperty처럼 관계를 앞으로 전파하는 규칙이다. 예를 들어 이런 사실이 있다고 하자.

Employee subClassOf Person
Person subClassOf Agent
Alice type Employee

여기서 "Alice type Person"과 "Alice type Agent"는 규칙 하나를 반복 적용해서 나온다.

x type A
A subClassOf B
----------------
x type B

이 규칙은 SQL의 재귀 쿼리나 Datalog, 일반적인 rule engine으로도 그대로 구현된다. 새로운 표현력을 더 이해할 필요가 없고, 사실이 늘어나도 같은 규칙을 계속 적용하면 된다. 그래서 RL은 대규모 ABox와 실시간 조회에 적합하다고 말한다. 규칙의 형태가 고정돼 있으니 성능도 미리 예측할 수 있다.

RL이 다루는 규칙 목록에는 domain·range 전파도 있다. "hasManager"라는 property의 domain이 Employee이고 range가 Employee라면, "Alice hasManager Bob"이라는 사실 하나에서 "Alice type Employee"와 "Bob type Employee"가 같이 따라 나온다. inverseOf도 마찬가지다. "hasManager"의 inverse가 "manages"로 선언돼 있으면, "Alice hasManager Bob"에서 "Bob manages Alice"가 자동으로 성립한다. 이런 규칙은 전부 "패턴이 보이면 결론을 하나 추가한다"는 형태를 벗어나지 않는다.


2. DL은 클래스를 논리식으로 정의한다

DL에서는 클래스 자체를 조건으로 정의할 수 있다. 이런 정의가 가능하다.

Parent ≡ Person AND (hasChild SOME Person)

이 정의가 있으면, 아래 사실만으로도

Alice type Person
Alice hasChild Bob
Bob type Person

reasoner는 "Alice type Parent"를 추론해낸다. Parent라는 클래스에 누가 속하는지 사람이 직접 정의하지 않아도, 논리식과 데이터를 맞대어 계산해낸다.

DL은 여기에 intersectionOf, unionOf, complementOf, someValuesFrom, allValuesFrom, cardinality, disjointWith 같은 구문을 더 지원한다. "Manager ≡ Employee AND (manages SOME Employee)" 같은 정의를 실제 판정 규칙으로 쓸 수 있는 이유다. RL의 규칙은 미리 정해진 패턴을 적용하는 일이고, DL의 추론은 논리식이 참인지 계산하는 일이다. 후자가 할 수 있는 일이 훨씬 많은 대신, 그 계산이 얼마나 걸릴지는 데이터가 커질수록 예측하기 어려워진다.


3. DL reasoner는 새 사실만 추가하지 않는다

OWL 2 DL reasoner가 하는 일은 triple을 늘리는 것 이상이다. 정합성 검사(consistency check)로 온톨로지 안에 모순이 있는지 보고, 만족가능성 검사(class satisfiability)로 어떤 클래스가 논리적으로 존재할 수 있는지 확인한다. 클래스 계층을 자동으로 계산하는 classification, 한 클래스가 다른 클래스의 하위 개념인지 판정하는 subsumption, 특정 인스턴스가 어떤 클래스에 속하는지 추론하는 instance checking도 여기 포함된다.

A disjointWith B
x type A
x type B

이 세 문장이 동시에 있으면 DL reasoner는 모순을 잡아낸다. 서로 배타적이라고 선언한 두 클래스에 같은 개체가 동시에 속해 있기 때문이다. RL 규칙 엔진은 이런 종류의 전역적인 모순 검사를 기본으로 하지 않는다. 규칙을 적용해서 나오는 결과만 볼 뿐, 결과들이 서로 모순인지는 별도로 확인해야 한다.


4. Agent runtime이 실제로 묻는 질문

Agent가 매 turn마다 묻는 질문을 적어보면 대개 이런 모양이다.

이 Entity의 상위 Type은 무엇인가?
이 Property의 domain/range는 무엇인가?
이 관계의 inverse는 무엇인가?
이 상태에서 다음 Action이 가능한가?

이 정도는 RDFS와 제한된 OWL 2 RL 규칙만으로 답이 나온다. 반면 "A AND (B SOME C) AND (D MIN 2 E) AND NOT F" 같은 복합 논리식을 매 turn마다 처음부터 풀어야 하는 경우는 실제로는 드물다. 그런 판정은 온톨로지를 설계하는 시점에 한 번 정리해두면, runtime에서는 이미 정리된 결과를 조회하는 것으로 충분하다.

그래서 파이프라인은 이런 순서가 관리하기 쉬웠다.

LLM → RDF 구조화 → SHACL Validation → OWL 2 RL/RDFS Reasoning → SPARQL → Agent Action

DL reasoner는 이 순서 밖, 온톨로지를 고칠 때 한 번 돌아가는 위치에 둔다.


5. 규칙을 테이블로 컴파일하면

RL 규칙은 결국 엣지 목록과 재귀적 순회로 옮겨진다. "Employee subClassOf Person, Person subClassOf Agent"는 이런 테이블이 된다.

subclass_edges
----------------
Employee | Person
Person   | Agent

이 테이블 위에서 recursive CTE를 돌리면 subClassOf의 전이적 폐포(closure)를 계산할 수 있다. TTL/OWL을 컴파일해서 정규화된 규칙으로 만들고, 그 규칙을 JSONL이나 Parquet로 저장한 뒤 DuckDB 같은 분석 엔진에 올려 추론을 돌리는 구조가 이래서 성립한다. 규칙마다 rule_id, input_fact_ids, output_fact를 같이 남기면, 어떤 사실이 어떤 규칙과 어떤 입력에서 나왔는지도 추적할 수 있다. reasoner가 블랙박스로 답만 던지는 대신, 추론 경로 자체가 감사 가능한 기록으로 남는다.


6. 지금 긋고 있는 경계

지금 온톨로지 스킬에 넣는 경계는 이렇다. Runtime에는 RDFS(subClassOf, subPropertyOf, domain, range)와 제한된 OWL RL(inverseOf, transitiveProperty, equivalentClass 일부)만 올린다. cardinality나 복합 클래스 정의 같은 DL 수준의 제약은 runtime에서 뺀다.

OWL DL은 설계·검증 단계에 남겨둔다. 온톨로지를 작성하고, DL reasoner로 정합성을 검사하고, 그 결과가 운영 가능한 RL 서브셋으로 걸러지면 그때 runtime에 배포한다. OWL 2 DL은 온톨로지를 정확하게 설계하고 검증하는 데 쓰고, OWL 2 RL은 그렇게 검증된 결과를 빠르고 결정론적으로 실행하는 데 쓴다는 역할 분리다.

아직 안 풀린 건 경계선에 있는 것들이다. equivalentClass는 두 클래스가 완전히 같다고 선언하는 것과, 조건을 걸어 논리적으로 같아지는 것 사이에 폭이 넓다. "AlternateName equivalentClass Alias"처럼 단순 동치 선언은 RL 규칙 하나로 충분히 처리된다. 반대로 "Manager equivalentClass (Employee AND manages SOME Employee)"처럼 조건부로 정의된 동치는 DL 없이는 판정 자체가 안 된다. 어디까지를 RL로 남기고 어디부터 DL 전용으로 뺄지는, 실제로 온톨로지 몇 개를 이 파이프라인에 태워보고 나서야 감이 잡힐 것 같다.