SPARQL 1.2 RL

W3C 작업 초안

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/WD-sparql12-rl-20260826/
최신 게시 버전:
https://www.w3.org/TR/sparql12-rl/
최신 편집자 초안:
https://w3c.github.io/data-shapes/sparql12-rl/
이력:
https://www.w3.org/standards/history/sparql12-rl/
커밋 이력
테스트 스위트:
https://github.com/w3c/data-shapes/tree/gh-pages/shacl12-test-suite/tests/sparql-rl
편집자:
Robert David (Ontotext)
(KurrawongAI)
Andy Seaborne (Apache Software Foundation)
Simon Steyskal (Siemens AG)
피드백:
GitHub w3c/data-shapes (풀 리퀘스트, 새 이슈, 열린 이슈)

초록

이 문서는 RDF를 위한 Datalog 스타일의 규칙 언어인 SPARQL-RL을 정의한다.

SPARQL-RL은 일련의 규칙과 기본 데이터 RDF 그래프의 조합으로부터 새로운 RDF 데이터를 생성하는 추론을 제공한다. 또한 SPARQL과 유사한 텍스트 구문을 제공하며 일련의 규칙이 RDF 그래프에 대해 평가되는 방식을 정의한다.

문맥이 명확한 경우 SPARQL 규칙 언어는 간단히 SRL이라고 지칭할 수 있다.

이 명세는 데이터 셰이프 작업 그룹에서 발행한다.

이 문서의 상태

이 절에서는 이 문서가 발행된 시점의 상태를 설명한다. 현재 W3C 간행물 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있다.

이 문서는 데이터 셰이프 작업 그룹이 작업 초안으로 발행했으며, 권고안 트랙을 사용했다.

이 문서가 작업 초안으로 발행되었다고 해서 W3C와 그 회원들이 승인했음을 의미하지는 않는다.

이 문서는 초안이며 언제든지 다른 문서에 의해 갱신되거나 대체되거나 폐기될 수 있다. 이 문서를 진행 중인 작업 이외의 것으로 인용하는 것은 부적절하다. 향후 권고안의 후속 갱신에는 새로운 기능이 포함될 수 있다.

이 문서를 작성한 그룹은 다음에 따라 운영된다: W3C 특허 정책. W3C모든 특허 공개의 공개 목록을 그룹의 결과물과 관련하여 유지하며, 해당 페이지에는 특허 공개 지침도 포함되어 있다. 실제로 알고 있는 특허가 다음을 포함한다고 믿는 개인은 필수 청구항에 관한 정보를 다음에 따라 공개해야 한다: W3C 특허 정책 제6절.

이 문서에는 2025년 8월 18일 W3C 절차 문서가 적용된다.

SHACL 명세

이 명세는 SHACL 1.2 명세 모음의 일부이다. 이에 대한 자세한 소개는 SHACL 1.2 개요를 참조한다.

명세는 다음과 같다:

작업 초안:

SHACL 1.2 코어
SHACL의 코어를 정의한다
SHACL 1.2 SPARQL 확장
SHACL의 SPARQL 관련 확장을 정의한다
SHACL 1.2 노드 표현식
SHACL에서 포커스 노드와 값 노드를 도출하는 데 사용하는 표현식을 정의한다
SHACL 1.2 규칙
SHACL의 규칙 기반 추론 방법을 정의한다
SHACL 1.2 UI
사용자 인터페이스 생성에 SHACL을 사용하는 방법을 정의한다
SHACL 1.2 프로파일링
SHACL 데이터를 포함한 데이터 프로파일링에 SHACL을 사용하는 방법을 정의한다

작업 그룹 노트 초안:

SHACL 1.2 개요
SHACL 명세 모음을 개괄한다
SHACL 1.2 간결 구문
SHACL 개념을 표현하기 위한 RDF 구문을 정의한다
참고

구현자는 위 명세에 대한 적합성 수준의 일부를 SHACL 1.2 테스트 스위트의 테스트 사례에 모두 통과하여 확인할 수 있다. 하지만 테스트 스위트의 모든 테스트에 통과한다고 해서 명세에 완전히 적합함을 의미하지는 않는다. 이는 구현이 테스트 스위트에서 테스트한 측면에 적합하다는 것만 의미한다.

1. 소개

이 문서에서는 SPARQL-RL을 소개한다. SPARQL-RL은 선언적 규칙을 통해 기존 RDF 데이터에서 새로운 RDF 트리플을 도출하는 메커니즘이다. 이 문서는 규칙 기반 추론의 구문과 의미론을 정의한다.

SPARQL-RL 구현은 두 가지 연산을 제공한다. infer 연산은 주어진 기본 그래프에 규칙을 적용하고 규칙 실행으로 도출된 RDF 트리플을 포함하는 추론 그래프를 생성한다. 추론 그래프와 기본 그래프의 결합 여부는 선택 사항이며 사용자에게 맡긴다. query 연산은 주어진 목표 패턴을 규칙을 사용하여 기본 그래프에서 도출할 수 있는지 판단한다.

SPARQL-RL에서는 규칙 헤드의 트리플 템플릿에 사용할 수 있는 빈 노드를 비롯한 새로운 RDF 항을 사용할 수 있다.

SPARQL-RL은 실패에 의한 부정도 지원하며, 이는 규칙이 실행되는 순서에 따라 서로 다른 추론 그래프가 생성될 수 있다. 이를 방지하기 위해 규칙은 규칙 간에 하나의 암시적 순서를 설정하는 층화 기법을 사용하여 평가하며, 항상 동일한 추론 그래프가 생성되도록 보장한다.

1.1 용어

다음의 다른 명세는 이 문서에서 사용하는 기본 용어를 제공한다:

1.2 문서 규칙

이 문서의 RDF 데이터 예제에서는 RDF 1.2 Turtle [RDF12-TURTLE]을 사용한다.

이 문서에서는 다음 네임스페이스 접두사 바인딩을 사용한다:

접두사 네임스페이스
rdf: http://www.w3.org/1999/02/22-rdf-syntax-ns#
rdfs: http://www.w3.org/2000/01/rdf-schema#
srl: http://www.w3.org/ns/sparql-rl#
xsd: http://www.w3.org/2001/XMLSchema#
sparql: http://www.w3.org/ns/sparql#
ex: http://example/

문서 전체에 Turtle 형식의 RDF 그래프가 포함된 색상 구분 상자가 나타난다. 이러한 Turtle 문서 조각은 위에서 지정한 접두사 바인딩을 사용한다.

# 이 상자는 규칙을 나타낸다
# 이 상자는 입력 데이터를 나타낸다
# 이 상자는 추론된 데이터를 나타낸다

2. 적합성

비규범적이라고 표시된 절뿐만 아니라 이 명세의 모든 작성 지침, 도표, 예제 및 참고 사항은 비규범적이다. 이 명세의 그 밖의 모든 내용은 규범적이다.

이 문서의 핵심어 MAY, MUST, MUST NOTSHOULD는 여기에 표시된 것처럼 모두 대문자로 나타나는 경우에만 BCP 14 [RFC2119] [RFC8174] 에 설명된 대로 해석해야 한다.

이 명세는 다음 항목에 대한 적합성 기준을 정의한다:

적합한 SRL 문서RDF 문자열이며, 7. SPARQL-RL 문법에 정의된 RuleSet 생성 규칙으로 시작하는 문법을 준수한다.

참고

이 명세는 SPARQL-RL 프로세서가 부적합한 규칙 세트를 처리하는 방법을 정의하지 않는다.

3. SPARQL-RL

이 절은 비규범적이다.

SPARQL-RL은 기본 그래프규칙 집합이 주어지면 새로운 트리플을 추론한다. 평가 결과는 기본 그래프에 나타나지 않는 도출된 트리플을 포함하는 추론 그래프이다.

규칙에는 본문이라고 하는 패턴과 헤드라고 하는 결과 템플릿이 있다. 규칙은 본문이 결합된 기본 그래프 및 이 시점까지 실행하여 추론된 모든 트리플과 일치하도록 본문에 있는 변수의 값을 찾는 방식으로 실행된다. 그런 다음 이 값을 사용하여 규칙 헤드의 트리플 템플릿을 인스턴스화하고 새로운 추론 트리플을 생성한다.

규칙은 더 이상 트리플이 추론되지 않을 때까지 실행하며, 새로운 추론 트리플을 사용할 수 있게 됨에 따라 규칙을 두 번 이상 실행할 수 있다.

SPARQL-RL 실행은 규칙 실행 순서가 새로운 빈 노드를 포함한 새로운 RDF 항을 생성하거나 패턴의 부재를 테스트할 때 서로 다른 결과를 초래하지 않도록 정의된다. 즉, 규칙 실행 순서와 관계없이 동일한 추론 그래프가 생성된다.

SPARQL-RL에는 SPARQL 1.2 쿼리 언어에서 영감을 받은 사용자 친화적 구문이 있다. 규칙 집합 평가는 SPARQL과 유사한 요소를 포함하지만, 규칙 실행 순서와 관계없이 동일한 추론 그래프가 생성되도록 세부 사항에는 차이가 있다.

3.1 기본 패턴

이 절의 예제에서는 소프트웨어 구성 요소와 그 종속성을 설명한다. 프런트엔드는 애플리케이션 서버를 호출하고, 애플리케이션 서버는 알려진 취약점이 있는 데이터베이스를 쿼리한다.

첫 번째 예제에는 다음 데이터 그래프와 규칙 집합이 있다:

위의 규칙을 데이터에 적용하면 종속성 유형과 관계없이 :frontend:app에 종속되고 :app:db에 종속된다는 결론을 얻는다.

그런 다음 다른 규칙이 생성한 :dependsOn 트리플에 종속되는 규칙을 추가하여 :exposedTo 관계를 도출할 수 있다(아래의 4.3 규칙 종속성도 참조한다):

3.2 재귀

이전 절의 :exposedTo 규칙은 직접적인 종속성에만 도달한다. :frontend:db에 직접 종속되지 않으므로 :frontend에 대한 :exposedTo 트리플은 추론되지 않는다. 임의 길이의 종속성 체인을 따라 노출을 전파하기 위해 해당 규칙을 두 규칙으로 대체한다. 구성 요소는 자신이 가진 취약점에 노출되며, 직접적인 종속 대상이 노출된 모든 취약점에도 노출된다:

이전 예제와 비교하면 :db :exposedTo :vuln1이 추가된다. 즉, 데이터베이스가 자체 취약점에 노출된다. 또한 :frontend :exposedTo :vuln1도 추가된다. 체인이 아무리 길어도 노출이 종속성 체인을 통해 :frontend에 도달한다.

이 마지막 규칙은 재귀 규칙이다. 규칙의 본문이 규칙의 헤드에 종속된다.

3.3 필터링

규칙 본문의 표현식을 사용하여 본문 일치에서 변수의 값을 제한할 수 있다. 예를 들어 각 취약점의 심각도가 주어지면 심각한 취약점에 노출된 구성 요소에 상태를 지정할 수 있다:

FILTER는 표현식을 평가하고 표현식이 true로 평가되면 현재 변수 바인딩 집합을 유지하며, 표현식이 false로 평가되면 현재 변수 바인딩 집합을 버린다. 이는 SPARQL의 FILTER 연산과 동일하며 SPARQL-RL은 SPARQL과 동일한 함수 및 연산자 중 다수를 제공한다.

3.4 부정

부정을 사용하면 일치해서는 안 되는 패턴을 지정할 수 있다. 이를 "실패에 의한 부정"이라고 한다.

부정 요소를 평가하기 위해 규칙 평가 알고리즘은 부정 요소의 패턴과 일치하는 트리플을 생성할 수 있는 모든 규칙이 완료되도록 보장한다. 이를 층화라고 하며, 부정이 데이터에서 온 것이든 부정 요소에서 완료된 것이든 관련된 가능한 모든 트리플을 기반으로 하도록 보장한다. 부정을 포함하는 규칙은 이러한 트리플을 생성하는 규칙에 _종속된다_고 한다(아래의 4.3 규칙 종속성 참조).

3.5 할당 및 RDF 항 생성

할당을 사용하면 표현식의 결과를 규칙 본문의 변수에 할당할 수 있다. 이를 사용하여 데이터를 기반으로 새로운 RDF 항을 생성할 수 있다.

규칙 헤드에서 빈 노드를 사용할 수 있으며, 규칙 평가에서 트리플을 생성할 때마다 각각 새로운 고유 빈 노드를 생성한다.

할당이 관련된 규칙과 규칙 헤드에서 빈 노드를 생성하는 규칙은 일회 실행 규칙이다. 이러한 규칙은 자신이 종속된 데이터를 생성할 수 있는 모든 규칙이 실행된 후, 자신이 생성한 데이터에 종속된 모든 규칙이 실행되기 전에 실행된다. 규칙 헤드에 빈 노드가 관련된 규칙도 새로운 RDF 항을 생성하며 일회 실행 규칙이다.

이 조건은 이러한 규칙이 자신에게 다시 순환하여 무제한의 RDF 항을 생성하지 않도록 보장한다.

할당의 표현식을 평가할 때 오류가 발생하면, 할당이 현재 솔루션 매핑을 거부한다.

3.6 규칙 집합 가져오기

SPARQL-QL 규칙 집합은 다른 규칙 집합의 URL을 자신의 규칙 집합 가져오기에 포함하여 다른 규칙 집합을 통합할 수 있다. 이를 통해 규칙 집합 간에 공유하는 라이브러리로 규칙을 구성할 수 있다.

규칙 집합의 IMPORTS 문은 규칙 집합의 규칙을 평가하기 전에 처리한다. 가져오기 단계에서 가져온 규칙 집합에 자체 가져오기가 있으면 해당 가져오기도 재귀적으로 처리한다. 규칙 집합을 처리하는 동안 IMPORTS 문을 순회하면 순환 가져오기가 발생할 수 있다. 규칙 집합은 한 번만 가져오며, 가져오기 문 그래프의 순환은 무한 루프를 일으키지 않는다.

규칙 집합 가져오기 지원은 SRL 프로세서에서 선택 사항이다. 자세한 내용은 4.5 가져오기 처리를 참조한다.

3.7 데이터 블록

데이터 블록을 사용하면 RDF 트리플을 규칙 집합 평가에 직접 간결하게 제공할 수 있다. 데이터 블록의 트리플은 추론 그래프에 추가되며 규칙 본문에서 일치시키는 데 사용할 수 있다.

예를 들어 규칙 집합은 데이터에서 도출하는 대신 알려진 사실을 직접 단언한 상태로 제공할 수 있다:

참고

데이터 블록은 본문이 비어 있는 규칙과 동일하다. 어떠한 규칙도 평가하지 않고 해당 트리플이 추론 그래프의 일부가 된다.

3.8 규칙 집합 평가

규칙은 규칙 집합으로 구성된다. 규칙 집합과 데이터 그래프(기본 그래프)는 평가의 입력이다. 출력은 추론 그래프라고 하는 그래프이며, 데이터 그래프에 나타나지 않는 트리플의 집합이다.

평가 중에 한 규칙을 기반으로 추론한 트리플은 다른 규칙에서 일치시키는 데 사용할 수 있다. 규칙 집합 평가는 추론 그래프가 규칙 집합과 데이터 그래프의 입력에서 가능한 모든 트리플을 포함할 때까지 진행된다.

평가는 규칙 자체를 평가하기 전에 규칙 집합을 준비하는 두 단계로 시작한다:

  1. 지원되는 경우 입력 규칙 집합의 가져오기를 해석하여 가져온 모든 규칙 집합의 모든 규칙을 포함하는 규칙 집합을 구성한다. 프로세서는 가져오기를 허용할 수 없는 경우 오류를 알려야 한다 (4.5 가져오기 처리).
  2. 일관되고 예측 가능한 결과를 생성하도록 부정 요소할당 요소에 대해 층화를 계산한다(4.4.2 층화 알고리즘 층화에는 규칙 간 종속성 검사가 포함된다 (4.3.1 종속성 그래프).

규칙 집합의 준비가 완료되면 층화의 각 층을 순서대로 가져와 해당 층의 규칙을 완료될 때까지 평가한 다음 다음 층으로 이동하여 평가를 진행한다.

3.9 기초 데이터 일치

기초 데이터는 기본 그래프의 트리플이다. 규칙 집합 평가 중에는 추론된 트리플이 아닌 원본 트리플에 대해서만 패턴을 일치시켜야 할 수 있다.

이에 대한 예로 기본값 설정이 있다. 규칙은 기본 그래프에 값이 이미 포함되어 있는지 테스트하고, 그렇지 않으면 기본값을 계산할 수 있다.

NOT DATA를 사용하면 규칙 본문의 다른 부분이 추론된 트리플과 일치할 수 있다. 또한 규칙 본문 전체를 기본 그래프에 대해 일치시키기 위해 WHERE DATA를 사용할 수도 있다. 그러면 이러한 규칙은 기본 그래프의 일치 결과에만 의존한다.

4. SPARQL-RL 추상 구문

SPARQL-RL 추상 구문은 SPARQL-RL의 논리적 구조이다. 이는 SPARQL-RL의 실행 알고리즘을 정의하는 데 사용된다.

4.1 추상 구문의 요소

변수
변수는 트리플 패턴에서 가능한 RDF 항을 나타낸다. 변수는 표현식에서도 사용된다.
표현식
표현식은 함수 또는 함수형 형식이며, 인수는 RDF 항이다. 표현식은 솔루션 매핑에 관해 평가되며, 그 결과로 RDF 항을 제공한다. 표현식SPARQL 표현식SHACL 목록 매개변수 함수와 호환된다.
데이터 블록
데이터 블록은 트리플의 집합이다. 이러한 트리플은 추가 사실로 추론 그래프에 추가되며 추론 과정에 포함된다.
트리플 템플릿
트리플 템플릿은 각 요소가 변수 또는 RDF 항(트리플 항일 수 있음)인 3-튜플이다. 튜플의 두 번째 요소는 IRI 또는 변수여야 한다. 트리플 템플릿규칙 헤드에 나타나는 규칙이다.
트리플 패턴
트리플 패턴은 각 요소가 변수 또는 RDF 항(트리플 항일 수 있음)인 3-튜플이다. 튜플의 두 번째 요소는 IRI 또는 변수여야 한다.
필터 요소
필터 요소표현식이며 규칙 요소로 나타난다 이는 패턴 일치에서 변수의 값을 제한하는 데 사용된다.
트리플 패턴 요소
트리플 패턴 요소트리플 패턴이며, 규칙 요소로 나타난다.
부정 요소
부정 요소규칙 요소이다. 여기에는 트리플 패턴 요소필터 요소의 시퀀스로 구성된 부정 요소 본문이 있다.
할당 요소
할당 요소규칙 요소이며, 할당 변수라고 하는 변수할당 표현식이라고 하는 표현식으로 구성된 쌍이다.
규칙 요소
규칙 요소트리플 패턴 요소, 필터 요소, 부정 요소 또는 할당 요소 중 하나이다.
규칙 헤드
규칙 헤드트리플 템플릿의 시퀀스이다.
규칙 본문
규칙 본문규칙 요소의 시퀀스이다. 즉, 각 시퀀스 요소는 트리플 패턴 요소, 필터 요소, 부정 요소 또는 할당 요소이다.
규칙 집합 가져오기
규칙 집합 가져오기(흔히 단순히 "가져오기"라고 함)는 평가 중에 포함할 다른 규칙 집합의 URL 모음이다.
규칙
규칙규칙 헤드(흔히 단순히 "헤드"라고 함)와 규칙 본문(흔히 단순히 "본문"이라고 함)의 쌍이다. 규칙에는 식별에 도움이 되는 URI를 지정할 수 있다.
일회 실행 규칙
일회 실행 규칙은 규칙 집합 평가의 특정 지점에서 정확히 한 번 실행되는 규칙이다.
일반 규칙
일반 규칙일회 실행 규칙이 아닌 규칙이다. 일반 규칙은 규칙 집합 평가 중에 두 번 이상 실행될 수 있다.
규칙 집합
규칙 집합은 0개 이상의 규칙 모음, 0개 이상의 데이터 블록 모음 및 0개 이상의 규칙 집합 가져오기 모음이다. 해석된 규칙 집합은 가져오기가 없는 규칙 집합이다. 해석된 규칙 집합은 다른 규칙 집합가져오기 과정을 적용하여 생성한다.
기본 그래프
기본 그래프는 평가 과정의 입력으로 제공되는 RDF 그래프이다.
추론 그래프
추론 그래프규칙 집합 평가에서 생성되는 RDF 그래프이다. 이는 규칙 집합기본 그래프에 적용하여 추론한 트리플 중 기본 그래프에 존재하지 않는 모든 트리플을 포함한다.
규칙 집합 평가
규칙 집합 평가규칙 집합기본 그래프에 적용하여 추론 그래프를 생성하는 과정이다. 규칙 평가는 규칙을 한 번 평가하는 과정이다. 규칙을 평가하면 규칙 본문의 평가 결과에 따라 규칙 헤드에서 지정하는 모든 트리플을 생성한다. 트리플이 기본 그래프에 있거나, 규칙 집합 평가 중에 이미 추론되었거나, 새롭게 추론된 트리플인지 여부는 관계없다. 규칙 집합 평가 중에는 규칙을 두 번 이상 평가할 수 있다.

SPARQL-RL은 inferquery라는 두 가지 연산을 제공한다.

추론
추론규칙 세트를 주어진 기본 그래프에 적용하고 추론된 트리플을 포함하는 추론 그래프를 생성하는 연산이다. 이는 전체 규칙 세트 평가를 적용한다.
질의

질의는 주어진 목표 패턴이 기본 그래프에서 규칙 세트를 사용하여 도출될 수 있는지를 판정하는 연산이다. 모든 규칙을 평가하지 않을 수도 있으며, 대신 질의 목표에 답하는 데 필요한 규칙만 평가할 수 있다.

질의추론 연산을 수행한 다음 목표 패턴을 결합된 기본 그래프추론 그래프에 일치시키는 것과 동등하다.

SPARQL-RL 프로세서
SPARQL-RL 프로세서는 SPARQL-RL 명세를 구현하고, 규칙 세트를 평가할 수 있으며, 추론질의 연산 중 하나 또는 둘 모두를 제공하는 시스템이다.

트리플 패턴 또는 트리플 템플릿에서, 튜플의 위치 1은 비공식적으로 주어라고 하고, 위치 2는 비공식적으로 술어라고 하며, 위치 3은 비공식적으로 목적어라고 한다.

참고

규칙 요소 시퀀스의 요소에는 1부터 시작하는 레이블이 지정된다.

규칙 세트와 규칙의 다양한 구성 요소에는 다음 표기법을 사용한다.

구성 요소 표기법
구성 요소 용도
ruleset.rules 규칙 세트의 규칙.
ruleset.data 규칙 세트의 데이터 블록의 합집합으로 형성된 RDF 그래프.
ruleset.imports 규칙 세트가져오기 집합.
rule.head 규칙 헤드트리플 템플릿.
rule.body 규칙규칙 요소.
rule.data 불리언 플래그이다. false이면 규칙 본문기본 그래프와 일치시킨다.
rule.id 규칙의 식별자로, 빈 노드 또는 IRI이다.
filter.expr 필터 요소표현식
assign.var [할당 요소]의 할당 변수.
assign.expr 할당 표현식
negation.inner 부정 요소부정 요소 본문.
negation.data 불리언 플래그이다. false이면 negation.inner기본 그래프와 일치시킨다.

4.2 정형성 조건

정형성규칙 집합의 추상 구문에 관한 조건의 집합이다. 이러한 조건들은 함께 규칙의 헤드에 있는 변수가 규칙의 본문에서 정의된 값을 갖도록 보장하고, 필터 요소 또는 할당 표현식의 각 변수가 평가 시점에 값을 갖도록 보장하며, 규칙의 각 할당이 규칙 본문 앞부분에서 사용되지 않은 새로운 변수를 도입하도록 보장한다.

초기 변수 집합이 주어질 때 규칙 요소 시퀀스의 정형성을 정의한다.

elti규칙 요소 시퀀스의 i번째 요소라고 하자.

varsielti에서 정의하는 변수의 집합이라고 하며, 그 정의는 다음과 같다:

V0를 시퀀스의 초기 변수라고 하자.

ViV0와 모든 varsj의 합집합이라고 하자. 여기서 ji보다 작다.

VallVN이라고 하자. 여기서 N은 시퀀스의 길이이다.

변수 집합 V0가 주어질 때 다음 조건을 충족하는 규칙 요소 시퀀스를 정형 시퀀스라고 한다:

규칙V0가 공집합으로 주어질 때 규칙 본문의 시퀀스가 정형 시퀀스이고, 규칙 헤드트리플 템플릿에 있는 각 변수가 Vall의 요소인 경우 정형 규칙이다.

규칙 집합의 모든 규칙이 정형 규칙인 경우에만 그 규칙 집합을 정형 규칙 집합이라고 한다.

4.3 규칙 종속성

두 번째 규칙의 출력이 첫 번째 규칙의 본문 평가에 영향을 주는 경우, 규칙 R1은 규칙 R2에 종속된다. 즉, R2의 헤드에는 R1 본문의 트리플 패턴과 일치하는 트리플을 생성할 수 있는 트리플 템플릿이 있다. 해당 트리플 패턴은 트리플 패턴 요소이거나 부정 요소 내부에 있을 수 있다.

종속성에는 닫힌 종속성열린 종속성이라는 두 종류가 있다. 닫힌 종속성은 규칙 R1이 실행되기 전에 규칙 R2가 가능한 모든 출력을 생성하도록 보장한다. 규칙 종속성이 닫혀 있지 않으면 열린 종속성이며, 규칙 R2가 추가 트리플을 생성하기 위해 다시 실행될 수 있는 동안 첫 번째 규칙 R1을 실행할 수 있다. 그러면 R2의 새로운 트리플을 사용하여 R1을 다시 평가할 수 있다.

이 첫 번째 예제에서는 첫 번째 규칙이 두 번째 규칙에 대해 열린 종속성을 갖는다.

이 두 번째 예제에서는 첫 번째 규칙이 두 번째 규칙에 대해 닫힌 종속성을 갖는다. 트리플 패턴 ?x :status :criticallyExposed은 첫 번째 규칙의 부정 요소 내부에 나타나며, 두 번째 규칙의 헤드에 있는 트리플 템플릿과 일치한다. 두 번째 규칙이 가능한 모든 출력을 생성할 때까지 첫 번째 규칙을 평가할 수 없다.

트리플 패턴 일치

트리플 템플릿트리플 패턴일치하는 트리플을 생성할 수 있으면, 트리플 패턴은 트리플 템플릿과 일치한다.

트리플 패턴 종속성

트리플 패턴트리플 템플릿과 일치할 가능성이 있으면, 그 트리플 패턴은 트리플 템플릿에 종속된다.

트리플 패턴이 규칙의 헤드에 있는 트리플 템플릿 중 하나에 종속되면, 그 트리플 패턴은 규칙에 종속된다.

규칙 종속성

R1 본문의 트리플 패턴 중 하나가 트리플 패턴 요소이거나 부정 요소 내부에 있는지와 관계없이 R2의 헤드에 있는 트리플 템플릿종속되면, 규칙 R1R2종속된다.

닫힌 종속성

규칙 R1의 규칙 R2에 대한 규칙 종속성은 다음 조건 중 하나라도 충족되면 닫힌 종속성이다:

열린 종속성

규칙 R1의 규칙 R2에 대한 규칙 종속성닫힌 종속성이 아니면 열린 종속성이다. 즉, R2에 종속되는 R1의 모든 트리플 패턴트리플 패턴 요소로만 나타난다.

트리플 템플릿의 변수에 템플릿의 변수를 값으로 대체했을 때 생성되는 트리플 T2T1같도록 하는 값이 존재하면, 트리플 템플릿은 RDF 트리플 T1생성할 수 있다.

마찬가지로 트리플 패턴의 변수에 패턴의 변수를 값으로 대체했을 때 생성되는 트리플 T2T1같도록 하는 값이 존재하면, 트리플 패턴은 트리플 T1일치한다. 트리플 패턴의 경우 여기에는 대칭 트리플이 포함된다.

트리플 템플릿 또는 트리플 패턴에서 변수를 두 번 이상 사용하면, 대체할 때 동일한 RDF 항을 사용한다.

변수를 RDF 항으로 대체하는 작업에는 트리플 항 내부의 변수도 포함된다.

4.3.1 종속성 그래프

규칙 간 종속성은 종속성 그래프라는 방향 그래프로 나타낸다. 그래프의 정점은 규칙 집합의 규칙이며, 간선에는 종속성이 열린 종속성인지 닫힌 종속성인지에 따라 open 또는 closed라는 레이블을 지정한다.

종속성 그래프
규칙 집합종속성 그래프는 각 정점이 규칙 집합의 규칙인 방향 그래프이며, R1R2에 종속되는 경우 규칙 R1에서 규칙 R2로 향하는 간선이 존재한다. 간선에는 종속성이 열린 종속성인지 닫힌 종속성인지에 따라 open 또는 closed라는 레이블을 지정한다.
전이적 규칙 종속성
종속성 그래프에서 R1부터 R2까지의 경로가 있으면, 규칙 R1은 규칙 R2에 대해 전이적 종속성을 갖는다.
재귀 규칙 종속성

종속성 그래프R이 관련된 순환 경로가 있으면, 규칙 R재귀 종속성을 갖는다.

참고

종속성 그래프는 데이터 그래프의 영향을 받지 않는다.

4.3.2 종속성 그래프 알고리즘

다음 알고리즘은 규칙 집합에서 종속성 그래프를 구성하는 한 가지 가능한 방법을 제공한다. 적합성은 이 절차의 사용 여부가 아니라 종속성 그래프의 정의를 충족하는 종속성 그래프의 생성 여부에 따라 결정된다.

define mergeLabel(oldLabel, newLabel):
    ## 닫힌 종속성은 열린 종속성보다 우선한다.
    if oldLabel == "open" and newLabel == "open":
        return "open"
    else:
        return "closed"
    endif
enddefine

## 출력 -- 규칙 정점과 레이블이 지정된 간선이 있는 종속성 그래프.
define buildDependencyGraph(ruleSet):
    ## edgeLabelMap은 (R1, R2)를 "open" 또는 "closed"에 매핑한다
    let edgeLabelMap be a map from pair (rule, rule) to label

    foreach rule R1 in ruleSet.rules:
        ## 규칙의 각 트리플 패턴 TP를 "open" 또는 "closed"가 필요한 것으로 분류한다
        ## 이는 부정 요소 내부에 있는지 여부에 따라 결정한다.
        let bodyDependencies = {}
        foreach rule element RBE in R1.body:
            if RBE is a negation element:
                foreach triple pattern TP in RBE.inner
                    let item be a pair (TP, "closed")
                    add item to bodyDependencies
                endfor
            else if RBE is a triple pattern element of triple pattern TP:
                let item be a pair (TP, "open")
                add item to bodyDependencies
            else if RBE is a condition element:
                ## 아무 작업도 하지 않는다
            else if RBE is an assignment element:
                ## 아무 작업도 하지 않는다
            endif
        endfor

        foreach pair (triple pattern TP, depLabel) in bodyDependencies:
            if R1.body has an assignment element:
              set depLabel to "closed"
            endif
            if R1.head has a triple template with a blank node:
              set depLabel to "closed"
            endif
            ## 이 트리플 패턴 요소 또는 부정 요소의 종속성을 찾는다.
            foreach rule R2 in ruleSet.rules:
                foreach triple template TT in R2.head:
                    if triple pattern TP matches triple template TT:
                        let key = (R1, R2)
                        if edgeLabelMap contains key:
                            let oldLabel = edgeLabelMap.get(key)
                            let merged = mergeLabel(oldLabel, depLabel)
                            edgeLabelMap.set(key, merged)
                        else:
                            edgeLabelMap.set(key, depLabel)
                        endif
                    endif
                endfor
            endfor
        endfor
    endfor

    let DP = { }
    foreach entry ((R1, R2), label) in edgeLabelMap:
        add an edge (R1 -> R2) labeled with label to DP
    endfor

    the result is DP
    enddefine

4.4 층화

층화규칙 집합을 순서가 지정된 층화 계층의 시퀀스로 분할하는 과정이다("strata", 단수형 "stratum"이라고도 함). 더 낮은 의 규칙은 더 높은 의 규칙보다 먼저 평가한다.

층화부정 요소, 할당 요소규칙 헤드에서 생성된 빈 노드가 이전의 더 낮은 기본 그래프를 사용하여 계산된 결과에만 종속되도록 규칙 간 종속성에 제약을 부과한다. 이는 주어진 기본 그래프에 대한 규칙 집합 평가에서 하나의 명확하고 유한한 결과가 생성되도록 보장한다.

참고

층화 과정은 다른 평가 결정을 내리는 데에도 사용할 수 있다. 이 문서는 일관된 평가에 필요한 조건을 설명하고 층화를 구성하는 한 가지 가능한 방법을 제공한다. 구현은 호환되는 동작을 얻으려면 여기에 설명된 조건을 충족해야 하지만, 제시된 알고리즘을 구현할 필요는 없다.

층화 계층

층화 계층 SL은 서로소인 규칙 집합의 쌍(SL.once, SL.general)이다. SL.once에는 일회 실행 규칙이 포함된다. 이 규칙들은 할당 요소를 사용하거나 규칙 헤드에서 빈 노드를 생성하며, 각각 층화 계층의 평가를 시작할 때 정확히 한 번 평가한다. SL.general에는 나머지 규칙이 포함되며, 새로운 트리플이 더 이상 추론되지 않을 때까지 반복해서 평가한다.

층화
규칙 집합층화층화 계층의 시퀀스이다. 규칙 집합의 각 규칙은 층화 계층 중 하나에 속한 집합 하나에만 나타난다.

4.4.1 층화 조건

층화는 다음 조건을 충족하는 경우에만 정의된다. 규칙 집합이 이 조건을 충족하지 않으면, 이 명세는 그러한 규칙 집합의 평가 결과를 정의하지 않는다.

층화 조건
층화 조건에서는 규칙 집합종속성 그래프닫힌 종속성이 관련된 재귀 종속성이 없어야 한다.

즉, 종속성 그래프의 어떠한 전이적 종속성 순환에도 NOT 또는 일회 실행 규칙(할당이나 빈 노드가 관련된 규칙의 트리플 템플릿)이 없다.

4.4.2 층화 알고리즘

다음 알고리즘은 규칙 집합만을 기반으로 하는 한 가지 가능한 층화를 제공한다.

## 출력 -- 맵: 정수 -> 규칙 집합.

define stratification(ruleSet):

    let DP = Dependency graph for the rule set.
    let stratumMap be a map from rule to integer

    ## 종속성 그래프는 층화 조건을 충족해야 한다.
    ## 무제한 층화 검사는 층화 조건 위반으로부터 
    ## 보호하기 위한 것이다.
    let limit = num rules + 1
    let maxStratum = 0

    ## stratumMap 초기화
    foreach rule in ruleSet.rules:
        stratumMap.set(rule, 0)
        endfor

    boolean changed = true;
    while changed:
        changed = false;
        foreach edge E in DP:
            ## 레이블이 있는 pRule에서 qRule로 향하는 간선
            let pRule = source of edge
            let qRule = destination of the edge
            let label = edge label

            if label == "open" :
                if stratumMap.get(pRule) < stratumMap.get(qRule) :
                    stratumMap.set(pRule, stratumMap.get(qRule))
                    changed = true;
                endif
            endif
            if label == "closed" :
                if stratumMap.get(pRule) <= stratumMap.get(qRule) :
                    let xStratum = 1 + stratumMap.get(qRule)
                    if ( xStratum > limit )
                        ## 층화 요구 사항 위반
                        error "Stratification error"
                        endif
                    stratumMap.set(pRule, xStratum)
                    maxStratum = max(maxStratum, xStratum)
                    changed = true;
                endif
            endif
        endfor
    endwhile

    ## 결과 맵을 초기화한다.
    let stratumRules be a map from integer to rules.
    for i = 0 to maxStratum
        stratumRules.set(i, {})
    endfor

    ## stratumMap에서 계층 번호가 같은 규칙을 모은다
    for rule R in map stratumMap:
        let stratumNum = stratumMap.get(R)
        add R to stratumRules.get(stratumNum)
    endfor

    ## 각 계층을 once와 general로 분할한다
    let stratumLevels be a sequence of pairs of sets of rules.
    for i = 0 to maxStratum:
        let rules = stratumRules.get(i)
        let once = { R in rules | R is a run-once rule }
        let general = rules \ once
        stratumLevels.set(i, pair(once, general))
    endfor

    the result is stratumLevels
enddefine
참고

층화 조건의 결과로, 일회 실행 규칙을 한 번 평가하면 규칙의 결과를 판단하는 데 사용한 데이터는 이후의 평가 중에 변경되지 않는다.

전체 규칙 집합에 종속성 분석과 층화를 단계별로 적용하고 평가까지 수행하는 과정은 6.6 풀이 예제에서 설명한다.

4.5 가져오기 처리

웹에서 문서를 읽는 작업은 보안에 영향을 미친다. 규칙 집합 가져오기 지원은 SRL 프로세서에서 선택 사항이다. 또한 구현은 특정 규칙 집합만 가져오고 다른 집합은 가져오지 않거나, 검증된 사본에서만 가져오는 방식으로 부분적으로 지원할 수 있다.

가져오기 처리에는 다음 조건이 적용된다:

해석된 규칙 집합은 다른 규칙 집합의 가져오기에 언급된 모든 규칙 집합을 재귀적으로 읽어서 해당 규칙 집합으로부터 생성한다.

예제 알고리즘은 A. 가져오기 알고리즘 예제에서 제공한다.

5. SPARQL-RL과 SPARQL의 관계

이 절은 비규범적이다.

SRL과 SPARQL은 밀접한 관계가 있다. SRL은 SPARQL과 호환되도록 설계되었으며, SRL의 많은 구문은 SPARQL 패턴 일치에서 가져왔거나 그로부터 영감을 받았다. 그러나 몇 가지 차이점이 있다.

SRL에서 RULE 변수는 FILTERSET의 표현식에 사용되거나 트리플 템플릿에 사용되는지와 관계없이 항상 사용 전에 바인딩된다. 이는 규칙 헤드에도 적용된다. SPARQL CONSTRUCT 쿼리와 INSERT 갱신은 변수가 CONSTRUCT 또는 INSERT 템플릿에 나타나지만 WHERE 절에서 값이 지정되지 않으면 부분적인 결과를 생성한다.

그 밖의 차이점은 다음과 같다:

6. 규칙 집합 평가

이 절에서는 주어진 데이터에서 규칙 집합을 평가한 결과를 정의한다. 구현 방법으로 특정 알고리즘을 규정하지 않는다. 구현은 동일한 결과를 생성하는 어떤 알고리즘이든 사용할 수 있다.

Inputs: data graph G, called the base graph, and a rule set RS.
Output: an RDF graph GI of inferred triples

추론된 트리플에는 기본 그래프의 트리플 집합에 존재하는 트리플이 포함되지 않는다.

6.1 평가 정의

솔루션 매핑
솔루션 매핑 μ는 부분 함수 μ : VT이다. 여기서 V는 모든 변수의 집합이고, T는 모든 RDF 항의 집합이다. μ의 정의역은 dom(μ)으로 나타내며, 이는 μ가 정의된 V의 부분집합이다. 솔루션 매핑을 의미한다는 것이 명확한 경우 솔루션이라는 용어를 사용한다. dom(μ0)이 공집합인 솔루션 매핑을 μ0으로 표기한다.
치환 함수
치환 함수 또는 간단히 치환은 함수 subst(μ, 트리플 패턴)이며, 트리플 패턴에서 dom(μ)에 속하는 변수가 나타날 때마다 해당 변수를 var에 대해 솔루션 매핑이 지정한 RDF 항으로 대체한 트리플 패턴을 반환한다. 트리플 패턴 결과에 변수가 없으면 이는 RDF 트리플이다.
평가 그래프
평가 그래프RDF 그래프로, 기본 그래프와 규칙 세트를 평가하는 동안 생성된 모든 트리플을 결합한다.
그래프 일치
그래프 일치는 트리플 패턴을 RDF 그래프의 트리플에 매핑하는 방법을 찾는다.

GRDF 그래프, TP트리플 패턴이라고 하자. 함수 graphMatch(G, TP)는 트리플 패턴에 적용했을 때 평가 그래프에 있는 트리플을 생성하는 가능한 모든 솔루션의 집합을 반환한다

GRDF 그래프, TP트리플 패턴, VTP에 나타나는 변수의 집합이라고 하자.

graphMatch(G, TP) = { μ | dom(μ) = V and subst(μ, TP) is a triple in G }
솔루션 호환성
두 솔루션 S1과 S2가 공통 변수에 대해 일치하면 호환된다.

S1과 S2를 솔루션이라고 하자.

compatible1, μ2) = true
                      if forall v in dom1) intersection dom2)
                          μ1(v) = μ2(v)
compatible1, μ2) = false otherwise
솔루션 시퀀스
솔루션 시퀀스는 솔루션의 다중 집합이다. 시퀀스에는 정의된 순서가 없다. 이는 순서가 없는 목록과 동일하며 중복 항목을 포함할 수 있다.
솔루션 병합
두 솔루션이 호환되면 두 솔루션의 병합은 각 솔루션의 변수를 두 솔루션 중 하나의 RDF 항에 매핑하는 솔루션이다.
μ1, μ2를 솔루션 매핑, S1과 S2를 솔루션 시퀀스라고 하자.
merge(μ1, μ2) = { μ |
                    μ(v) = μ1(v) if v in dom(μ1)
                    μ(v) = μ2(v) otherwise }
merge(S1, S2) = { μ |
                    μ1 in S1, μ2 in S2
                    and compatible(μ1, μ2)
                    μ(v) = merge(μ1, μ2) }
참고

merge(S1, S2)의 정의역은 domain(S1) ∪︀ domain(S2)이다

두 솔루션에 공통 변수가 없으면 서로 호환되며, 두 솔루션의 병합은 S1S2의 합집합이다.

유효 불리언 값
함수 EBV(x)RDF 항의 유효 불리언 값을 반환한다.

6.2 평가 준비

규칙 집합 평가에는 가져온 모든 규칙 집합을 수집하고, 4.5 가져오기 처리에 설명된 대로 하나의 결합된 규칙 집합을 구축하는 과정이 포함된다.

그런 다음 다음 단계에 따라 결합된 규칙 집합을 평가할 수 있도록 준비한다.

  1. 4.2 올바른 형식 조건에 설명된 대로 각 규칙이 올바른 형식의 규칙인지 확인한다.
  2. 4.3.2 의존성 그래프 알고리즘에 설명된 대로 의존성 그래프를 계산한다.
  3. 4.4.2 계층화 알고리즘에 설명된 대로 결합된 규칙 집합의 계층화를 계산한다).

6.3 표현식 평가

필터 요소 또는 할당 요소에서 사용되는 표현식은, 표현식 안의 각 변수에 대해 RDF 용어인 값을 제공하는 해 매핑과 관련하여 평가됩니다. 4.2 올바른 형식 조건의 올바른 형식 요구사항은 표현식 안의 모든 변수가 해 매핑에 나타나도록 보장합니다.

define evalFunction(F, μ):
    ## F is an expression: an RDF term, a variable, or op(expr1, ..., exprN)
    ## where op is a function or a functional form.
    if F is an RDF term:
        return F
    if F is a variable:
        ## By well-formedness, F ∈ dom(μ).
        return μ(F)
    ## F is of the form F= op(expr1, ..., exprN)
    if op is a functional form (e.g. IF, logical-or):
        ## Evaluated specifically for op; op may evaluate only some arguments.
        ## For example, IF(c, t, f) evaluates c, then exactly one of t or f.
        return the value defined for op over expr1, ..., exprN under μ
    ## op is an ordinary function: evaluate all arguments first.
    return F(evalFunction(expr1, row), ..., evalFunction(exprN, row))
enddefine

6.4 규칙의 평가

규칙규칙 본문에서 해답 시퀀스를 계산한 다음, 해답 시퀀스의 각 해답 매핑을 사용하여 규칙 헤드를 통해 트리플을 생성하는 방식으로 평가된다.

트리플 패턴 내의 빈 노드는 변수처럼 동작한다. 이는 SPARQL 그래프 패턴 매칭과 호환된다.

# Evaluate rule body
# This function returns a sequence of solutions

define evalRuleElements(B, SEQ, G, GD):
    where 
        B is a sequence of rule elements
        SEQ is a solution sequence 
        G and GD are RDF graphs

    for each rule element rElt in B:

        if rElt is a triple pattern TP:
            X = graphMatch(G, TP)
            SEQ1 = {}
            for each μ1 in X:
                for each μ2 in SEQ:
                    if compatible(μ1, μ2)
                      μ3 = merge(μ1, μ2)
                      add μ3 to SEQ1
                    endif
                endfor
            endfor
        endif

        if rElt is a condition element F:
            SEQ1 = {}
            for each solution μ in SEQ:
                let x = evalFunction(F.expr, μ)
                if EBV(x) is true:
                    add μ to SEQ1
                endif
            endfor
        endif

        if rElt is a negation expression N:
            SEQ1 = {}
            for each solution μ in SEQ:
                S = sequence{ μ }
                if rElt with DATA:
                    NEG = evalRuleElements(N.inner, S, GD, GD)
                else:
                    NEG = evalRuleElements(N.inner, S, G, GD)
                if NEG is empty
                    add μ to SEQ1
                endif
            endfor
        endif

        if rElt is an assignment A:
            SEQ1 = {}
            for each solution μ in SEQ:
                let x = evalFunction(A.expr, μ)
                if x is not an error:
                    ## Add mapping V -> x to solution μ
                    let μ2 be a solution mapping μ ∪︀ { (A.var, x) }
                    add μ2 to SEQ1
                else
                    # Error: drop solution μ
                endif
            endfor
        endif

        SEQ = SEQ1
    endfor

    return SEQ
enddefine

define evalRule(R, G, GD):
    where 
        R is a well-formed rule
        G and GD are RDF graphs
    let B be R.body 
        where each blank node in a triple pattern in R.body
        is replaced by a variable which is not used in the rule. 
        The same variable is used for each occurrence of the
        same blank node, and a different variable is used for 
       each different blank node.

    # Solution sequence of one solution that does not map any variables.
    let SEQ0: Solution sequence = { μ0 }

    if R.data:
        let SEQ = evalRuleElements(B, SEQ0, GD, GD)
    else
        let SEQ = evalRuleElements(B, SEQ0, G, GD)
    
    # Evaluate rule head
    let OUT = empty set
    for each μ in SEQ:
        let S = {}
        for each triple template TT in R.head:
            let triple = subst(μ, TT)
            Add triple to S
        endfor
        OUT = OUT union S
    endfor
    return OUT
enddefine
참고

OUT에는 데이터 그래프에도 있는 트리플이 포함될 수 있다.

6.5 규칙 집합의 평가

규칙 집합의 평가는 해당 규칙 집합의 계층화에 있는 각 계층을 실행하는 것으로 정의되며, 각 계층은 다음 계층으로 이동하기 전에 순서대로 완전히 실행된다. 계층은 먼저 해당 계층의 각 일회 실행 규칙을 평가한 다음, 새 트리플이 더 이상 생성되지 않을 때까지 해당 계층의 일반 규칙을 반복해서 평가하는 방식으로 평가된다.

let G0 be the input base graph
let RS be the rule set
let D be the graph of all DATA triples in RS

Apply stratification to RS

let LS be the sequence of layers after stratification

# Inference graph
let GI = { t ∈ D | t ∉ G0 }

let GD = G0 ∪︀ D

# Evaluation graph.
let GE = GD

for each stratum ST in LS:
    for each rule R in ST.once:
        let X = evalRule(R, GE, G0)
        let Y = { t ∈ X | t ∉ GE }
        GI = GI ∪︀ Y
        GE = GE ∪︀ Y
    endfor

    let finished = false
    while !finished:
        finished = true
        for each rule R in ST.general:
            let X = evalRule(R, GE, G0)
            let Y = { t ∈ X | t ∉ GE }
            if Y is not empty:
                finished = false
                GI = GI ∪︀ Y
                GE = GE ∪︀ Y
            endif
        endfor
    endwhile
endfor
the result is GI

6.6 실제 예제

이 절은 비규범적이다.

이 절에서는 완전한 규칙 집합의 평가를 단계별로 설명한다. 즉, 규칙 의존성을 결정하고 (4.3 규칙 의존성), 계층화를 계산한 다음 (4.4 계층화), 각 계층을 차례로 평가하여 추론 그래프를 생성한다 (6.5 규칙 집합 평가).

이 예제는 소프트웨어 구성 요소와 그 의존성을 설명한다. 프런트엔드는 애플리케이션 서버에 의존하고, 애플리케이션 서버는 데이터베이스와 로깅 라이브러리에 의존한다. 데이터베이스에는 알려진 취약점이 있다. 규칙은 의존성 체인을 따라 취약점에 대한 노출을 전파하고, 심각한 취약점에 노출된 구성 요소에는 :criticallyExposed 상태를 부여하며, 심각하지 않은 구성 요소에는 :safeToDeploy 상태를 부여하고, 심각하게 노출된 각 구성 요소에 대한 알림을 생성한다. (실제로 취약점이 구성 요소에 영향을 미치는지는 배포된 버전에 따라 달라진다. 이 예제에서는 버전을 생략하고 취약점을 직접 명시한다.) 간결성을 위해 기본 그래프는 3.1 기본 패턴에서처럼 더 구체적인 관계로부터 도출하는 대신 :dependsOn 트리플을 직접 명시한다.

규칙은 주석에서 R1부터 R5까지의 레이블로 표시되며, 이 절의 나머지 부분에서는 이러한 레이블로 참조된다. 이는 3.2 재귀부터 3.5 할당 및 RDF 항 생성까지에서 소개된 규칙이다. 규칙 집합에는 IMPORTS가 없으므로 가져오기 처리를 거쳐도 변경되지 않으며, DATA 블록도 없으므로 평가는 기본 그래프만으로 시작된다.

6.6.1 종속성 결정

어떤 규칙이 어떤 규칙에 종속되는지 결정하기 위해 각 규칙 본문의 각 트리플 패턴을 모든 규칙 머리부의 트리플 템플릿과 비교한다 (4.3 규칙 종속성).

  • R1의 본문은 단일 트리플 패턴 ?x :hasVulnerability ?v이다. 어떤 규칙 머리부에도 술어가 :hasVulnerability인 트리플을 생성할 수 있는 트리플 템플릿이 없으므로 이 패턴은 데이터와만 일치할 수 있다. R1에는 종속성이 없다.
  • R2의 본문에는 두 개의 트리플 패턴이 있다. ?x :dependsOn ?y는 어떤 규칙 머리부와도 일치할 수 없으므로 데이터와만 일치한다. ?y :exposedTo ?vR1의 머리부 템플릿 ?x :exposedTo ?v과 일치하고, R2 자체의 머리부와도 일치한다. 두 항목 모두 트리플 패턴 요소이다 (부정 요소 내부에 나타나지 않으며, R2에는 할당 요소도 없고 머리부에 빈 노드도 없다). 따라서 R2R1에 대한 개방 종속성과 자기 자신에 대한 개방 종속성을 가진다. R2의 자기 자신에 대한 종속성으로 인해 R2는 재귀 규칙이 된다.
  • R3의 본문에서 패턴 ?x :exposedTo ?vR1R2의 머리부와 일치하므로 R3는 각각에 대해 개방 종속성을 가진다. 패턴 ?v :severity ?s는 어떤 규칙 머리부와도 일치하지 않는다.
  • R4의 본문에서 패턴 ?x rdf:type :Component는 어떤 규칙 머리부와도 일치하지 않는다. 술어가 rdf:type인 유일한 머리부 템플릿은 R5에 있으며, 그 목적어 :Notification:Component와 다른 RDF 용어이므로 생성된 어떤 트리플도 일치할 수 없다. 패턴 ?x :status :criticallyExposed부정 요소 NOT { ?x :status :criticallyExposed } 내부에 나타나며 R3의 머리부 템플릿과 일치한다. 패턴이 부정 요소에 나타나므로 R4R3에 대한 폐쇄 종속성을 가진다.
  • R5의 본문에서 패턴 ?x :status :criticallyExposedR3의 머리부와 일치한다. R5의 머리부에는 빈 노드가 포함되므로, 해당 패턴이 일반 트리플 패턴 요소임에도 R3에 대한 종속성은 폐쇄 종속성이다. 어떤 규칙 본문의 패턴도 R5의 머리부 템플릿과 일치하지 않으므로 어떤 규칙도 R5에 종속되지 않는다.

따라서 종속성 그래프에는 정점 5개와 간선 6개가 있다.

  • R2 → R1 (개방)
  • R2 → R2 (개방)
  • R3 → R1 (개방)
  • R3 → R2 (개방)
  • R4 → R3 (폐쇄)
  • R5 → R3 (폐쇄)

R4R5R1 또는 R2에 직접 종속되지 않지만, 각각 R3을 통해 양쪽 모두에 전이적 종속성을 가진다.

실제 예제 규칙 집합의 종속성 그래프 R1, R2, R3, R4, R5로 표시된 다섯 개의 정점. 점선 화살표는 개방 종속성을 나타낸다. R2에서 R1로, R2에서 자기 자신으로, R3에서 R1로, R3에서 R2로 향한다. 실선 화살표는 폐쇄 종속성을 나타낸다. R4에서 R3으로, R5에서 R3으로 향한다. R2 R1 R3 R4 R5 개방 종속성 폐쇄 종속성
그림 1 실제 예제 규칙 집합의 종속성 그래프. 개방 종속성은 점선 화살표로, 폐쇄 종속성은 실선 화살표로 표시한다. 각 간선은 본문에 일치하는 트리플 패턴이 포함된 규칙에서 머리부가 일치하는 트리플을 생성할 수 있는 규칙을 향한다. 규칙은 계층 0을 위쪽에 두고 더 높은 계층을 아래쪽에 두어 평가 순서와 일치하도록 배치한다.

그래프의 유일한 순환은 자기 간선 R2 → R2이며, 이는 개방 종속성이다. 폐쇄 종속성이 포함된 순환은 없으므로 계층화 조건이 충족되며 규칙 집합은 명확하게 정의된 결과를 가진다.

6.6.2 계층화 계산

계층화 알고리즘에 따라 모든 규칙은 계층 0에서 시작한다. 그런 다음 아무것도 변경되지 않을 때까지 간선을 반복해서 검사한다.

  • 개방 간선에서는 출발 규칙이 대상 규칙과 동일하거나 더 높은 계층에 있어야 한다. 모든 규칙이 계층 0에 있을 때 네 개의 개방 간선이 이미 이 조건을 충족하므로 변경이 발생하지 않는다.
  • 폐쇄 간선에서는 대상 규칙이 먼저 완료되어야 하므로 출발 규칙이 대상 규칙보다 엄격히 더 높은 계층에 있어야 한다. 간선 R4 → R3 (폐쇄)을 검사하면 R4R3이 모두 계층 0에 있으므로 R4를 계층 1로 이동한다. 마찬가지로 간선 R5 → R3 (폐쇄)은 R5를 계층 1로 이동한다.

간선을 한 번 더 순회해도 변경이 발생하지 않으므로 계층은 확정된다. 그런 다음 각 계층을 일회 실행 규칙일반 규칙으로 나눈다. R5의 머리부에는 빈 노드가 있으므로 일회 실행 규칙이다. 다른 규칙에는 할당 요소나 머리부의 빈 노드가 없다. 계층화 결과는 다음과 같다.

  • 계층 0: 일반 규칙 R1, R2, R3; 일회 실행 규칙 없음
  • 계층 1: 일회 실행 규칙 R5; 일반 규칙 R4

이 순서는 더 높은 계층에 있는 규칙의 의도를 반영한다. 구성 요소를 안전하게 배포할 수 있는지와 어떤 구성 요소에 알림이 필요한지는 모든 :status :criticallyExposed 트리플이 도출된 후에만 결정할 수 있다. 그리고 이를 도출하는 규칙 R3은 데이터를 제공하는 규칙 R1R2와 함께 아래 계층에서 완료된다.

6.6.3 계층 평가

평가는 6.5 규칙 집합 평가 알고리즘을 따른다. 평가 그래프 GE는 기본 그래프로 시작하고 추론 그래프 GI는 빈 상태로 시작한다. 각 계층은 순서대로 완료될 때까지 평가한다. 계층의 규칙을 여러 차례 순회하여 평가하며, 한 번의 순회에서 새 트리플이 생성되지 않을 때까지 순회를 반복한다. 알고리즘은 한 번의 순회 중에 계층의 규칙을 평가하는 순서를 정하지 않는다. 이 추적에서는 R1, R2, R3 순서를 사용한다. 다른 순서는 동일한 추론을 서로 다른 횟수의 순회에 분산시킬 수 있지만, 계층 0을 완료될 때까지 실행하므로 동일한 최종 그래프를 생성한다.

이 규칙 집합에는 DATA 블록이 없으므로 평가의 모든 시점에서 GEG0GI를 합친 것이다. 따라서 이 추적에서는 GI만 추적하고, 평가가 진행됨에 따라 그 상태를 표시하며 각 새 트리플에 이를 생성한 규칙을 표시한다.

계층 0, 첫 번째 순회.

  • R1: 본문이 :db :hasVulnerability :vuln1과 일치하여 ?x = :db?v = :vuln1을 바인딩한다. 머리부는 :db :exposedTo :vuln1을 생성한다. 이 트리플은 GE에 없으므로 GEGI에 추가한다.
  • R2: 본문은 ?x :dependsOn ?y?y :exposedTo ?v를 조인한다. 이제 GE에는 :db :exposedTo :vuln1이 포함되어 있으므로 조인 결과로 하나의 해가 나온다. ?x = :app, ?y = :db, ?v = :vuln1이다 (:app :dependsOn :db에서 유래). 머리부는 새로운 :app :exposedTo :vuln1을 생성하여 추가한다. 아직 :frontend에 대한 해는 없다. 이 R2 평가가 시작될 때 :app :exposedTo :vuln1GE에 없었기 때문이다.
  • R3: 이제 ?x :exposedTo ?v:db:app에 대해 일치한다. :vuln1 :severity 9.1과 조인하고 FILTER(?s >= 9.0)을 적용하면 두 해가 모두 유지된다. 머리부는 새로운 :db :status :criticallyExposed:app :status :criticallyExposed를 생성한다.
# 계층 0의 첫 번째 순회 후 GI
:db  :exposedTo :vuln1 .                    # 신규 (R1)
:app :exposedTo :vuln1 .                    # 신규 (R2)
:db  :status :criticallyExposed .           # 신규 (R3)
:app :status :criticallyExposed .           # 신규 (R3)

새 트리플이 생성되었으므로 계층 0의 평가는 다음 순회로 계속된다.

계층 0, 두 번째 순회.

  • R1: 이전과 같이 일치한다. :db :exposedTo :vuln1은 이미 GE에 있으므로 새로운 것은 생성되지 않는다.
  • R2: 이제 조인 결과에 ?x = :frontend, ?y = :app, ?v = :vuln1도 포함되어 새로운 트리플 :frontend :exposedTo :vuln1을 생성한다. 노출이 종속성 체인의 두 단계를 이동하는 데 두 번의 순회가 걸렸다.
  • R3: 새로운 트리플 :frontend :status :criticallyExposed을 생성한다.
# 계층 0의 두 번째 순회 후 GI
:db       :exposedTo :vuln1 .
:app      :exposedTo :vuln1 .
:frontend :exposedTo :vuln1 .               # 신규 (R2)
:db       :status :criticallyExposed .
:app      :status :criticallyExposed .
:frontend :status :criticallyExposed .      # 신규 (R3)

계층 0, 세 번째 순회. 이제 모든 규칙의 모든 해는 이미 GE에 있는 트리플만 생성한다. GI는 변경되지 않는다. 새 트리플이 없으므로 계층 0이 완료된다. 도출될 수 있는 모든 :exposedTo 트리플과 모든 :status :criticallyExposed 트리플이 도출되었다.

계층 1, 일회 실행 규칙. 계층의 일회 실행 규칙을 먼저 각각 정확히 한 번씩 평가한다.

  • R5: 본문은 세 개의 :status :criticallyExposed 트리플과 일치하여 ?x = :db, ?x = :app, ?x = :frontend인 해를 얻는다. 각 해에서 머리부를 인스턴스화하면 새로운 빈 노드가 생성되어 해마다 두 개의 트리플, 즉 심각한 각 구성 요소에 대한 알림을 생성한다. 이제 계층의 일반 규칙을 반복적으로 평가하더라도 R5는 다시 평가하지 않는다.

계층 1, 일반 규칙의 첫 번째 순회.

  • R4: 패턴 ?x rdf:type :Component:frontend, :app, :db, :logger와 일치한다. (R5가 방금 생성한 rdf:type :Notification 트리플과는 일치하지 않는다.) 부정 요소 NOT { ?x :status :criticallyExposed }:frontend, :app, :db에 대한 해를 거부한다. GE에 각각에 대한 :status :criticallyExposed 트리플이 포함되어 있기 때문이다. ?x = :logger인 해만 남아 새로운 트리플 :logger :status :safeToDeploy을 생성한다.
# 계층 1 이후의 GI
:db       :exposedTo :vuln1 .
:app      :exposedTo :vuln1 .
:frontend :exposedTo :vuln1 .
:db       :status :criticallyExposed .
:app      :status :criticallyExposed .
:frontend :status :criticallyExposed .
_:n1      rdf:type :Notification .          # 신규 (R5)
_:n1      :concerns :db .                   # 신규 (R5)
_:n2      rdf:type :Notification .          # 신규 (R5)
_:n2      :concerns :app .                  # 신규 (R5)
_:n3      rdf:type :Notification .          # 신규 (R5)
_:n3      :concerns :frontend .             # 신규 (R5)
:logger   :status :safeToDeploy .           # 신규 (R4)

계층 1, 일반 규칙의 두 번째 순회. 새 트리플은 없다. 평가가 완료되었으며, 위에 표시된 GI가 결과 추론 그래프이다.

계층화는 이 결과를 신뢰할 수 있도록 한다. :frontend :status :criticallyExposed이 도출되기 전인 계층 0의 첫 번째 순회 중에 평가했다면, R4:frontend :status :safeToDeploy이라고 잘못 결론 내렸을 것이며, R5:db:app에 대한 알림은 생성했지만 :frontend에 대한 알림은 생성하지 않았을 것이다. 두 규칙을 계층 1까지 지연하면 완전한 :status :criticallyExposed 트리플 집합을 확인하게 되므로 각 계층 내에서 규칙을 평가하는 순서가 최종 결과에 영향을 주지 않는다.

7. SPARQL-RL 문법

SPARQL-RL 문서는 UTF-8 [RFC3629]로 인코딩되고 RuleSet 생성 규칙으로 시작하며 7.6 문법에서 정의하는 추가 제약 조건을 준수하는 RDF 문자열이다. U+0000부터 U+D7FF까지 및 U+E000부터 U+10FFFF까지의 범위에 속하는 유니코드 스칼라 값만 허용된다. 따라서 U+D800부터 U+DFFF까지의 범위에 속하는 서로게이트 코드 포인트는 제외된다.

7.1 버전 선언

버전 레이블은 SPARQL-RL의 구문 및 의미론 적합성을 식별하는 문자열이다.

버전 레이블
버전 레이블
"1.2"

버전 선언은 문서 앞부분에서 하는 것이 좋다.

하나의 SPARQL-RL 문서에 여러 VERSION 지시문이 나타날 수 있다. 각 지시문은 해당 지시문 뒤에 있는 문서 부분에 적용되며, 다른 지시문을 만나거나 문서 끝에 도달할 때까지 적용된다.

버전 레이블미디어 유형version 매개변수로 지정할 수도 있다. 현재 적용되는 VERSION 지시문이 없으면 미디어 유형의 일부로 지정된 버전을 고려한다.

7.2 공백

공백 (생성 규칙 WS)은 공백이 없으면 하나의 종단 기호로 잘못 인식될 수 있는 두 종단 기호를 구분하는 데 사용된다. 아래에서 대문자로 표시된 규칙 이름은 공백이 중요한 위치를 나타내며, 이 규칙들은 SPARQL-RL 파서를 구성하는 데 사용할 수 있는 종단 기호의 한 가지 선택지를 형성한다.

생성 규칙 String에서는 공백이 중요하다.

7.3 주석

주석은 IRIREF, STRING_LITERAL1, STRING_LITERAL2, STRING_LITERAL_LONG1 또는 STRING_LITERAL_LONG2 외부의 #로 시작하며, 줄 끝(LF 또는 CR로 표시됨)까지 계속된다. 주석 표시 뒤에 줄 끝이 없으면 파일 끝까지 계속된다. 주석은 공백으로 취급된다.

7.4 IRI 참조

상대 IRI 참조통합 자원 식별자(URI): 일반 구문 [RFC3986]에 따라 기본 IRI를 사용하여 해석하며, 5.2절의 기본 알고리즘만 사용한다. 구문 기반 정규화와 스킴 기반 정규화 (RFC3986의 6.2.2절과 6.2.3절에서 설명됨)는 모두 수행하지 않는다. IRI 참조에서 추가로 허용되는 문자는 국제화 자원 식별자 (IRI) [RFC3987]의 6.5절에 따라 URI 참조의 예약되지 않은 문자와 같은 방식으로 처리한다.

BASE 지시문은 [RFC3986]에 따라 상대 IRI 참조를 해석하는 데 사용하는 기본 IRI를 정의한다. 5.1.1절, "콘텐츠에 포함된 기본 URI". 5.1.2절, "캡슐화 엔터티에서 가져온 기본 URI"에서는 범위 내 기본 IRI가 xml:base 지시문이 있는 SOAP 봉투나 Content-Location 헤더가 있는 MIME 멀티파트 문서와 같은 캡슐화 문서에서 제공될 수 있는 방법을 정의한다. 5.1.3절, "검색 URI에서 가져온 기본 URI"에서 식별하는 "검색 URI"는 특정 SPARQL-RL 문서를 검색한 URL이다. 위의 어느 항목도 기본 URI를 지정하지 않으면 기본 기본 URI(5.1.4절, "기본 기본 URI")를 사용한다. 각 BASE 지시문은 이전 URI를 기준으로 새로운 범위 내 기본 URI를 설정한다.

7.5 이스케이프 시퀀스

SRL 문서에는 다음 세 가지 형식의 이스케이프가 사용된다:

각 이스케이프 시퀀스 종류를 사용할 수 있는 문맥
숫자
이스케이프
문자열
이스케이프
예약 문자
이스케이프
PREFIX 또는 BASE 선언에서 RDF 항으로 사용하는 IRI 아니요 아니요
로컬 이름 아니요 아니요
문자열 아니요
참고

%-인코딩된 시퀀스는 IRI의 문자 범위에 속하며 로컬 이름에서 명시적으로 허용된다. 이러한 시퀀스는 % 뒤에 두 개의 16진수 문자가 이어지는 형식이며, 동일한 3개 문자 시퀀스를 나타낸다. 이러한 시퀀스는 처리 중에 디코딩되지 않는다. <http://a.example/%66oo-bar>로 작성한 항은 IRI http://a.example/%66oo-bar를 나타내며 IRI http://a.example/foo-bar를 나타내지 않는다. 접두사 PREFIX ex: <http://a.example/>와 함께 ex:%66oo-bar로 작성한 항도 IRI http://a.example/%66oo-bar를 나타낸다.

7.6 문법

여기서 사용하는 EBNF는 XML 1.0 [EBNF-NOTATION]에 정의되어 있다.

참고:

  1. 문법의 진입점은 RuleSet이다.
  2. 핵심어는 대소문자를 구분하는 'a'를 제외하고 대소문자를 구분하지 않는다.
  3. 이스케이프 시퀀스 UCHARECHAR는 대소문자를 구분한다.
  4. DATA 블록에서는 변수를 사용할 수 없다.
  5. 입력을 토큰화하고 문법 규칙을 선택할 때 가장 길게 일치하는 항목을 선택한다.
  6. 대문자 이름의 규칙을 종단 기호로 사용하면 SPARQL-RL 문법은 LL(1) 및 LALR(1)이다.
[1] RuleSet ::= RuleOrDataBlock
[2] RuleOrDataBlock ::= Prologue ( RuleOrData+ ( Prologue1 RuleOrData? )* )?
[3] RuleOrData ::= Rule | Data
[4] Prologue ::= Prologue1*
[5] Prologue1 ::= BaseDecl | PrefixDecl | VersionDecl | ImportsDecl
[6] BaseDecl ::= 'BASE' IRIREF
[7] PrefixDecl ::= 'PREFIX' PNAME_NS IRIREF
[8] VersionDecl ::= 'VERSION' VersionSpecifier
[9] VersionSpecifier ::= STRING_LITERAL1 | STRING_LITERAL2
[10] ImportsDecl ::= 'IMPORTS' iri
[11] Rule ::= 'RULE' iri? HeadTemplate 'WHERE' 'DATA'? BodyPattern
[12] Data ::= 'DATA' '{' DataTriplesBlock? '}'
[13] HeadTemplate ::= '{' HeadTemplateBlock? '}'
[14] BodyPattern ::= '{' BodyTriplesBlock? ( BodyNotTriples '.'? BodyTriplesBlock? )* '}'
[15] BodyNotTriples ::= Filter | Negation | Assignment
[16] Filter ::= 'FILTER' Constraint
[17] Constraint ::= BrackettedExpression | BuiltInCall | FunctionCall
[18] FunctionCall ::= iri ArgList
[19] ArgList ::= NIL | '(' Expression ( ',' Expression )* ')'
[20] ExpressionList ::= NIL | '(' Expression ( ',' Expression )* ')'
[21] Negation ::= 'NOT' 'DATA'? '{' BodyBasic '}'
[22] BodyBasic ::= BodyTriplesBlock? ( BodyBasicNotTriples '.'? BodyTriplesBlock? )*
[23] BodyBasicNotTriples ::= Filter
[24] Assignment ::= 'SET' '(' Var ':=' Expression ')'
[25] DataTriplesBlock ::= TriplesSameSubjectData ( '.' DataTriplesBlock? )?
[26] TriplesSameSubjectData ::= RDFTermData PropertyListNotEmptyData | TriplesNodeData PropertyListData | ReifiedTripleBlockData
[27] PropertyListData ::= PropertyListNotEmptyData?
[28] PropertyListNotEmptyData ::= VerbData ObjectListData ( ';' ( VerbData ObjectListData )? )*
[29] VerbData ::= iri | 'a'
[30] ObjectListData ::= ObjectData ( ',' ObjectData )*
[31] ObjectData ::= GraphNodeData AnnotationData
[32] GraphNodeData ::= RDFTermData | TriplesNodeData | ReifiedTripleData
[33] TriplesNodeData ::= CollectionData | BlankNodePropertyListData
[34] BlankNodePropertyListData ::= '[' PropertyListNotEmptyData ']'
[35] CollectionData ::= '(' GraphNodeData+ ')'
[36] AnnotationData ::= ( ReifierData | AnnotationBlockData )*
[37] AnnotationBlockData ::= '{|' PropertyListNotEmptyData '|}'
[38] ReifierData ::= '~' ReifierIdData?
[39] ReifierIdData ::= iri | BlankNode
[40] ReifiedTripleBlockData ::= ReifiedTripleData PropertyListData
[41] ReifiedTripleData ::= '<<' ReifiedTripleSubjectData VerbData ReifiedTripleObjectData ReifierData? '>>'
[42] ReifiedTripleSubjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTripleData | TripleTermData
[43] ReifiedTripleObjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTripleData | TripleTermData
[44] TripleTermData ::= '<<(' TripleTermSubjectData VerbData TripleTermObjectData ')>>'
[45] TripleTermSubjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTermData
[46] TripleTermObjectData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTermData
[47] HeadTemplateBlock ::= TriplesBlockTemplate
[48] TriplesBlockTemplate ::= TriplesSameSubjectTemplate ( '.' TriplesBlockTemplate? )?
[49] TriplesSameSubjectTemplate ::= VarOrRDFTerm PropertyListNotEmptyTemplate | TriplesNodeTemplate PropertyListTemplate | ReifiedTripleBlockTemplate
[50] PropertyListTemplate ::= PropertyListNotEmptyTemplate?
[51] PropertyListNotEmptyTemplate ::= Verb ObjectListTemplate ( ';' ( Verb ObjectListTemplate )? )*
[52] ObjectListTemplate ::= ObjectTemplate ( ',' ObjectTemplate )*
[53] ObjectTemplate ::= GraphNodeTemplate AnnotationTemplate
[54] GraphNodeTemplate ::= VarOrRDFTerm | TriplesNodeTemplate | ReifiedTriple
[55] TriplesNodeTemplate ::= CollectionTemplate | BlankNodePropertyListTemplate
[56] BlankNodePropertyListTemplate ::= '[' PropertyListNotEmptyTemplate ']'
[57] CollectionTemplate ::= '(' GraphNodeTemplate+ ')'
[58] AnnotationTemplate ::= ( Reifier | AnnotationBlockTemplate )*
[59] AnnotationBlockTemplate ::= '{|' PropertyListNotEmptyTemplate '|}'
[60] ReifiedTripleBlockTemplate ::= ReifiedTriple PropertyListTemplate
[61] BodyTriplesBlock ::= TriplesBlockPattern
[62] TriplesBlockPattern ::= TriplesSameSubjectPattern ( '.' TriplesBlockPattern? )?
[63] ReifiedTripleBlockPattern ::= ReifiedTriple PropertyListPattern
[64] TriplesSameSubjectPattern ::= VarOrRDFTerm PropertyListNotEmptyPattern | TriplesNodePattern PropertyListPattern | ReifiedTripleBlockPattern
[65] PropertyListPattern ::= PropertyListNotEmptyPattern?
[66] PropertyListNotEmptyPattern ::= ( VerbPath | Var ) ObjectListPattern ( ';' ( ( VerbPath | Var ) ObjectListPattern )? )*
[67] ObjectListPattern ::= ObjectPattern ( ',' ObjectPattern )*
[68] ObjectPattern ::= GraphNodePattern AnnotationPattern
[69] TriplesNodePattern ::= CollectionPattern | BlankNodePropertyListPattern
[70] BlankNodePropertyListPattern ::= '[' PropertyListNotEmptyPattern ']'
[71] CollectionPattern ::= '(' GraphNodePattern+ ')'
[72] AnnotationPattern ::= ( Reifier | AnnotationBlockPattern )*
[73] AnnotationBlockPattern ::= '{|' PropertyListNotEmptyPattern '|}'
[74] GraphNodePattern ::= VarOrRDFTerm | TriplesNodePattern | ReifiedTriple
[75] Reifier ::= '~' ReifierId?
[76] ReifierId ::= Var | iri | BlankNode
[77] ReifiedTriple ::= '<<' ReifiedTripleSubject Verb ReifiedTripleObject Reifier? '>>'
[78] ReifiedTripleSubject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[79] ReifiedTripleObject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | ReifiedTriple | TripleTerm
[80] TripleTerm ::= '<<(' TripleTermSubject Verb TripleTermObject ')>>'
[81] TripleTermSubject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[82] TripleTermObject ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | TripleTerm
[83] Verb ::= VarOrIri | 'a'
[84] VerbPath ::= Path
[85] Path ::= PathSequence
[86] PathSequence ::= PathEltOrInverse ( '/' PathEltOrInverse )*
[87] PathEltOrInverse ::= PathElt | '^' PathElt
[88] PathElt ::= ( iri | 'a' | '(' Path ')' )
[89] RDFTermData ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTermData
[90] VarOrRDFTerm ::= Var | iri | RDFLiteral | NumericLiteral | BooleanLiteral | BlankNode | NIL | TripleTerm
[91] VarOrIri ::= Var | iri
[92] Var ::= VAR1 | VAR2
[93] RDFLiteral ::= String ( LANG_DIR | '^^' iri )?
[94] NumericLiteral ::= NumericLiteralUnsigned | NumericLiteralPositive | NumericLiteralNegative
[95] NumericLiteralUnsigned ::= INTEGER | DECIMAL | DOUBLE
[96] NumericLiteralPositive ::= INTEGER_POSITIVE | DECIMAL_POSITIVE | DOUBLE_POSITIVE
[97] NumericLiteralNegative ::= INTEGER_NEGATIVE | DECIMAL_NEGATIVE | DOUBLE_NEGATIVE
[98] BooleanLiteral ::= 'true' | 'false'
[99] String ::= STRING_LITERAL1 | STRING_LITERAL2 | STRING_LITERAL_LONG1 | STRING_LITERAL_LONG2
[100] iri ::= IRIREF | PrefixedName
[101] PrefixedName ::= PNAME_LN | PNAME_NS
[102] BlankNode ::= BLANK_NODE_LABEL | ANON
[103] Expression ::= ConditionalOrExpression
[104] ConditionalOrExpression ::= ConditionalAndExpression ( '||' ConditionalAndExpression )*
[105] ConditionalAndExpression ::= ValueLogical ( '&&' ValueLogical )*
[106] ValueLogical ::= RelationalExpression
[107] RelationalExpression ::= NumericExpression ( '=' NumericExpression | '!=' NumericExpression | '<' NumericExpression | '>' NumericExpression | '<=' NumericExpression | '>=' NumericExpression | 'IN' ExpressionList | 'NOT' 'IN' ExpressionList )?
[108] NumericExpression ::= AdditiveExpression
[109] AdditiveExpression ::= MultiplicativeExpression ( '+' MultiplicativeExpression | '-' MultiplicativeExpression | ( NumericLiteralPositive | NumericLiteralNegative ) ( ( '*' UnaryExpression ) | ( '/' UnaryExpression ) )* )*
[110] MultiplicativeExpression ::= UnaryExpression ( '*' UnaryExpression | '/' UnaryExpression )*
[111] UnaryExpression ::= '!' PrimaryExpression
| '+' PrimaryExpression
| '-' PrimaryExpression
| PrimaryExpression
[112] PrimaryExpression ::= BrackettedExpression | BuiltInCall | iriOrFunction | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[113] iriOrFunction ::= iri ArgList?
[114] ExprTripleTerm ::= '<<(' ExprTripleTermSubject Verb ExprTripleTermObject ')>>'
[115] ExprTripleTermSubject ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var
[116] ExprTripleTermObject ::= iri | RDFLiteral | NumericLiteral | BooleanLiteral | Var | ExprTripleTerm
[117] BrackettedExpression ::= '(' Expression ')'
[118] BuiltInCall ::= 'STR' '(' Expression ')'
| 'LANG' '(' Expression ')'
| 'LANGMATCHES' '(' Expression ',' Expression ')'
| 'LANGDIR' '(' Expression ')'
| 'DATATYPE' '(' Expression ')'
| 'IRI' '(' Expression ')'
| 'URI' '(' Expression ')'
| 'BNODE' ( '(' Expression ')' | NIL )
| 'ABS' '(' Expression ')'
| 'CEIL' '(' Expression ')'
| 'FLOOR' '(' Expression ')'
| 'ROUND' '(' Expression ')'
| 'CONCAT' ExpressionList
| 'SUBSTR' '(' Expression ',' Expression ( ',' Expression )? ')'
| 'STRLEN' '(' Expression ')'
| 'REPLACE' '(' Expression ',' Expression ',' Expression ( ',' Expression )? ')'
| 'UCASE' '(' Expression ')'
| 'LCASE' '(' Expression ')'
| 'ENCODE_FOR_URI' '(' Expression ')'
| 'CONTAINS' '(' Expression ',' Expression ')'
| 'STRSTARTS' '(' Expression ',' Expression ')'
| 'STRENDS' '(' Expression ',' Expression ')'
| 'STRBEFORE' '(' Expression ',' Expression ')'
| 'STRAFTER' '(' Expression ',' Expression ')'
| 'YEAR' '(' Expression ')'
| 'MONTH' '(' Expression ')'
| 'DAY' '(' Expression ')'
| 'HOURS' '(' Expression ')'
| 'MINUTES' '(' Expression ')'
| 'SECONDS' '(' Expression ')'
| 'TIMEZONE' '(' Expression ')'
| 'TZ' '(' Expression ')'
| 'NOW' NIL
| 'UUID' NIL
| 'STRUUID' NIL
| 'IF' '(' Expression ',' Expression ',' Expression ')'
| 'STRLANG' '(' Expression ',' Expression ')'
| 'STRLANGDIR' '(' Expression ',' Expression ',' Expression ')'
| 'STRDT' '(' Expression ',' Expression ')'
| 'sameTerm' '(' Expression ',' Expression ')'
| 'isIRI' '(' Expression ')'
| 'isURI' '(' Expression ')'
| 'isBLANK' '(' Expression ')'
| 'isLITERAL' '(' Expression ')'
| 'isNUMERIC' '(' Expression ')'
| 'hasLANG' '(' Expression ')'
| 'hasLANGDIR' '(' Expression ')'
| 'REGEX' '(' Expression ',' Expression ( ',' Expression )? ')'
| 'isTRIPLE' '(' Expression ')'
| 'TRIPLE' '(' Expression ',' Expression ',' Expression ')'
| 'SUBJECT' '(' Expression ')'
| 'PREDICATE' '(' Expression ')'
| 'OBJECT' '(' Expression ')'

터미널 생성 규칙:

[119] IRIREF ::= '<' ([^<>"{}|^`\]-[#x00-#x20] | UCHAR )* '>'
[120] PNAME_NS ::= PN_PREFIX? ':'
[121] PNAME_LN ::= PNAME_NS PN_LOCAL
[122] BLANK_NODE_LABEL ::= '_:' ( PN_CHARS_U | [0-9] ) ((PN_CHARS|'.')* PN_CHARS)?
[123] VAR1 ::= '?' VARNAME
[124] VAR2 ::= '$' VARNAME
[125] LANG_DIR ::= '@' [a-zA-Z]+ ('-' [a-zA-Z0-9]+)* ('--' [a-zA-Z]+)?
[126] INTEGER ::= [0-9]+
[127] DECIMAL ::= [0-9]* '.' [0-9]+
[128] DOUBLE ::= ( ([0-9]+ ('.'[0-9]*)? ) | ( '.' ([0-9])+ ) ) [eE][+-]?[0-9]+
[129] INTEGER_POSITIVE ::= '+' INTEGER
[130] DECIMAL_POSITIVE ::= '+' DECIMAL
[131] DOUBLE_POSITIVE ::= '+' DOUBLE
[132] INTEGER_NEGATIVE ::= '-' INTEGER
[133] DECIMAL_NEGATIVE ::= '-' DECIMAL
[134] DOUBLE_NEGATIVE ::= '-' DOUBLE
[135] STRING_LITERAL1 ::= "'" ( ([^#x27#x5C#xA#xD]) | ECHAR | UCHAR )* "'"
[136] STRING_LITERAL2 ::= '"' ( ([^#x22#x5C#xA#xD]) | ECHAR | UCHAR )* '"'
[137] STRING_LITERAL_LONG1 ::= "'''" ( ( "'" | "''" )? ( [^'\] | ECHAR | UCHAR ) )* "'''"
[138] STRING_LITERAL_LONG2 ::= '"""' ( ( '"' | '""' )? ( [^"\] | ECHAR | UCHAR ) )* '"""'
[139] ECHAR ::= '\' [tbnrf\"']
[140] UCHAR ::= ('\u' HEX HEX HEX HEX) | ('\U' HEX HEX HEX HEX HEX HEX HEX HEX)
[141] NIL ::= '(' WS* ')'
[142] WS ::= #x20 | #x9 | #xD | #xA
[143] ANON ::= '[' WS* ']'
[144] PN_CHARS_BASE ::= [A-Z] | [a-z] | [#x00C0-#x00D6] | [#x00D8-#x00F6] | [#x00F8-#x02FF] | [#x0370-#x037D] | [#x037F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
[145] PN_CHARS_U ::= PN_CHARS_BASE | '_'
[146] VARNAME ::= ( PN_CHARS_U | [0-9] ) ( PN_CHARS_U | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040] )*
[147] PN_CHARS ::= PN_CHARS_U | '-' | [0-9] | #x00B7 | [#x0300-#x036F] | [#x203F-#x2040]
[148] PN_PREFIX ::= PN_CHARS_BASE ((PN_CHARS|'.')* PN_CHARS)?
[149] PN_LOCAL ::= (PN_CHARS_U | ':' | [0-9] | PLX ) ((PN_CHARS | '.' | ':' | PLX)* (PN_CHARS | ':' | PLX) )?
[150] PLX ::= PERCENT | PN_LOCAL_ESC
[151] PERCENT ::= '%' HEX HEX
[152] HEX ::= [0-9] | [A-F] | [a-f]
[153] PN_LOCAL_ESC ::= '\' ( '_' | '~' | '.' | '-' | '!' | '$' | '&' | "'" | '(' | ')' | '*' | '+' | ',' | ';' | '=' | '/' | '?' | '#' | '@' | '%' )

이 문법의 텍스트 버전은 여기에서 확인할 수 있습니다.

7.7 선택된 터미널 리터럴 문자열

이 문서는 몇 가지 특정 터미널 리터럴 문자열을 사용합니다 [EBNF-NOTATION]. 이러한 터미널 리터럴 문자열에 사용되는 유니코드 코드 포인트를 명확히 하기 위해 다음 표에서는 이 섹션에서 사용되는 특정 문자를 설명합니다.

코드 글리프 설명
U+000A LF 줄 바꿈
U+000D CR 캐리지 리턴
U+0023 # 숫자 기호
U+0025 % 퍼센트 기호
U+005C \ 백슬래시

A. 예제 가져오기 알고리즘

다음 알고리즘은 참조된 모든 문서를 재귀적으로 방문하여 가져오기 문을 해석하는 한 가지 방법을 보여준다.

두 규칙 집합 RS1RS2규칙 집합 병합은 다음과 같이 정의되는 규칙 집합 MR이다:

define ruleSetMerge(rule set R1,rule Set RS2):
    MR.rules = RS1.rules ∪︀ RS2.rules
    MR.data = rdf_merge(RS1.data, RS2.data)
    MR.imports = {}
    the result is MR
enddefine

define imports(rule set RS, set of URLs V), returning rule set
    let I = the set of import URLs declared for the rule set RS
    let RS2 be a rule set formed from RS.rules and RS.data
    foreach URL x in I:
        if x ∉ V:
            V = V ∪︀ { x }
            read rule set RS3 from URL x
            RS2 = rulesetMerge(RS2, imports(RS3, V))
        endif
    endfor
    the result is RS2
enddefine

let RS be a rule set
let V = {}
if RS has a location, V = { location of RS }
result is imports(RS, V)

여기서 rdf_mergeRDF 병합 연산이다.

B. 인터넷 미디어 유형 및 파일 확장자

SPARQL-RL의 인터넷 미디어 유형(이전 명칭은 MIME 유형)은 "application/sparql-rl"이다.

다음 정보는 검토, 승인 및 IANA 등록을 위해 인터넷 엔지니어링 운영 그룹(IESG)에 제출되었다.

유형 이름:
application
하위 유형 이름:
sparql-rl
필수 매개변수:
없음
선택적 매개변수:
version
이 매개변수는 선택 사항이다. version이 있으면 허용되는 값은 버전 레이블에 정의되어 있다.
profile
이 매개변수는 선택 사항이며 추가 정보를 포함하는 데 사용된다. 프로파일에 대한 지식 없이 처리하더라도 리소스 표현의 의미론을 변경하지 않는다. profile 매개변수의 값은 공백으로 구분된 비어 있지 않은 URI 목록이다. 자세한 정보와 배경은 [RFC6906]을 참조한다.
인코딩 고려 사항:
SPARQL-RL 구문은 유니코드 [UNICODE] 코드 포인트로 표현한다. 인코딩은 항상 UTF-8 [RFC3629]이다.
유니코드 코드 포인트는 X가 16진수 숫자 [0-9A-F]인 \uXXXX(U+0부터 U+FFFF까지) 또는 \UXXXXXXXX 구문(U+10000 이상)을 사용하여 표현할 수도 있다
보안 고려 사항:
C. 보안 고려 사항UTF-8, ISO 10646의 변환 형식 [RFC3629]의 7절, 보안 고려 사항을 참조한다.
상호 운용성 고려 사항:
알려진 상호 운용성 문제는 없다.
발행된 명세:
이 명세.
추가 정보:
매직 넘버:
SPARQL-RL 파일에는 문서 시작 부분 근처에 'PREFIX' 문자열(대소문자 구분 없음)이 있을 수 있다.
파일 확장자:
".srl"
기본 URI:
SPARQL-RL 'BASE <IRIref>' 항은 문서의 이후 부분에서 순차적으로 사용되는 쿼리 언어의 상대 IRIref에 대한 현재 기본 URI를 변경할 수 있다.
추가 정보를 문의할 담당자 및 이메일 주소:
데이터 셰이프 작업 그룹 <public-shacl@w3.org;
의도된 용도:
COMMON
사용 제한:
없음
작성자/변경 관리자:
SPARQL-RL 명세는 월드 와이드 웹 컨소시엄의 데이터 셰이프 작업 그룹이 작성한 결과물이다. W3C가 이 명세에 대한 변경 권한을 갖는다.

C. 보안 고려 사항

이 절은 비규범적이다.

SPARQL-RL 문서에는 다른 SPARQL-RL 문서를 참조하고 그 내용을 현재 문서로 가져오는 IMPORTS 문이 포함될 수 있다. 가져온 문서 자체에 IMPORTS 문이 있으면 해당 문서도 가져온다.

규칙 집합을 모듈화하는 데 유용하지만, IMPORTS 문을 사용하면 보안 위험이 발생할 수 있다. 위험에는 평가 중에 규칙 집합이 악의적으로 또는 실수로 과도한 계산을 유발하는 경우와 HTTP 요청이 가로채져 오래된 사본을 포함한 다른 문서가 반환되는 경우 등이 포함되며 이에 국한되지 않는다.

SPARQL-RL 규칙 집합을 데이터 그래프에 적용하면 상당한 계산 및 메모리 사용량이 발생할 수 있으며, 이를 악용하여 서비스 거부를 유발할 수 있다. 애플리케이션은 SPARQL-RL 규칙 집합을 적용하여 발생할 수 있는 계산량과 메모리 사용량을 제한하도록 주의해야 한다.

SPARQL-RL 구문은 UTF-8 [RFC3629]로 인코딩되며 문자열 데이터에서 이스케이프되지 않은 제어 문자를 사용할 수 있다. 이 명세는 이러한 내용을 최종 사용자에게 직접 노출하지 않지만 사용자 에이전트를 통해 표시될 수 있으며, 그러한 문자가 표시되어 제공되는 텍스트가 난독화될 수 있다.

SPARQL-RL은 임의의 애플리케이션 데이터를 처리하고 생성하는 데 사용할 수 있으며, 보안 고려 사항은 사용 영역에 따라 달라진다. 텍스트에 적용할 수 있는 보안 도구와 프로토콜 (예: PGP 암호화, 체크섬 검증, 암호로 보호된 압축)을 SPARQL-RL 문서에도 사용할 수 있다. SPARQL-RL 규칙 집합 평가 결과에 포함된 정보의 민감도를 반영하는 보안/개인정보 보호 프로토콜을 적용해야 한다.

SPARQL-RL의 보안 고려 사항에는 RDF 데이터RDF Turtle과 같은 형식의 보안 고려 사항도 포함된다.

D. 개인정보 보호 고려 사항

이 절은 비규범적이다.

SPARQL-RL 문서에는 개인 식별 정보(PII)의 표현이나 민감한 것으로 간주할 수 있는 기타 정보를 포함할 수 있는 추가 애플리케이션 데이터가 포함될 수 있다. 이러한 정보가 포함된 규칙 집합을 발행하는 작성자는 그러한 정보를 발행할 필요성과 용도를 신중하게 고려하고, 데이터가 사용되거나 공개될 것으로 예상되는 지역에 적용되는 규정 (예: GDPR, CCPA, 기타 규정)도 고려하는 것이 좋다. 특히 데이터 접근에 권한 부여 조치가 필요한지 고려해야 한다.

E. 감사의 말

이 절은 비규범적이다.

다음 사람들은 데이터 셰이프 작업 그룹의 규칙 태스크포스에서 SPARQL-RL 개발에 기여했다: Robert David, David Habgood, Livio Robaldo, Ognjen Savkovic, Simon Steyskal, Ted Thibodeau Jr 및 Andy Seaborne.

데이터 셰이프 작업 그룹의 구성원에는 @@가 포함되었다.

F. 색인

F.1 이 명세에서 정의하는 용어

F.2 참조를 통해 정의되는 용어

G. 이슈 요약

이 명세에 나열된 이슈는 없다.

H. 참고 문헌

H.1 규범적 참고 문헌

[EBNF-NOTATION]
EBNF 표기법. Tim Bray; Jean Paoli; Michael Sperberg-McQueen; Eve Maler; François Yergeau 외. W3C. W3C 권고안. URL: https://www.w3.org/TR/xml/#sec-notation
[I18N-GLOSSARY]
국제화 용어집. Richard Ishida; Addison Phillips. W3C. 2024년 10월 17일. W3C 작업 그룹 노트. URL: https://www.w3.org/TR/i18n-glossary/
[rdf-concepts]
리소스 기술 프레임워크(RDF): 개념 및 추상 구문. Graham Klyne; Jeremy Carroll. W3C. 2004년 2월 10일. W3C 권고안. URL: https://www.w3.org/TR/rdf-concepts/
[RDF12-CONCEPTS]
RDF 1.2 개념 및 추상 데이터 모델. Andy Seaborne; Gregg Kellogg; Olaf Hartig; Pierre-Antoine Champin. W3C. 2026년 4월 7일. W3C 후보 권고안. URL: https://www.w3.org/TR/rdf12-concepts/
[RDF12-SEMANTICS]
RDF 1.2 의미론. Peter Patel-Schneider; Enrico Franconi; Dörthe Arndt. W3C. 2026년 4월 7일. W3C 후보 권고안. URL: https://www.w3.org/TR/rdf12-semantics/
[RDF12-TURTLE]
RDF 1.2 Turtle. Gregg Kellogg; Andy Seaborne; Dominik Tomaszuk. W3C. 2026년 8월 12일. W3C 작업 초안. URL: https://www.w3.org/TR/rdf12-turtle/
[RFC2119]
요구 사항 수준을 나타내기 위해 RFC에서 사용하는 핵심어. S. Bradner. IETF. 1997년 3월. 현행 최적 관행. URL: https://www.rfc-editor.org/info/rfc2119/
[RFC3629]
UTF-8, ISO 10646의 변환 형식. F. Yergeau. IETF. 2003년 11월. 인터넷 표준. URL: https://www.rfc-editor.org/info/rfc3629/
[RFC3986]
통합 자원 식별자(URI): 일반 구문. T. Berners-Lee; R. Fielding; L. Masinter. IETF. 2005년 1월. 인터넷 표준. URL: https://www.rfc-editor.org/info/rfc3986/
[RFC3987]
국제화 자원 식별자 (IRI). M. Duerst; M. Suignard. IETF. 2005년 1월. 제안 표준. URL: https://www.rfc-editor.org/info/rfc3987/
[RFC6906]
'profile' 링크 관계 유형. E. Wilde. IETF. 2013년 3월. 정보 제공. URL: https://www.rfc-editor.org/info/rfc6906/
[RFC8174]
RFC 2119 핵심어에서 대문자와 소문자의 모호성. B. Leiba. IETF. 2017년 5월. 현행 최적 관행. URL: https://www.rfc-editor.org/info/rfc8174/
[shacl12-node-expr]
SHACL 1.2 노드 표현식. Robert David; Holger Knublauch; Simon Steyskal. W3C. 2026년 7월 21일. W3C 작업 초안. URL: https://www.w3.org/TR/shacl12-node-expr/
[SPARQL12-QUERY]
SPARQL 1.2 쿼리 언어. Olaf Hartig; Andy Seaborne; Ruben Taelman; Gregory Williams; Thomas Pellissier Tanon. W3C. 2026년 6월 25일. W3C 작업 초안. URL: https://www.w3.org/TR/sparql12-query/
[UNICODE]
유니코드 표준. 유니코드 컨소시엄. URL: https://www.unicode.org/versions/latest/