ONTOLOGICAL DB 문서 원문 보기

설정

이 문서가 답하는 질문

  • 확장 자체의 설정은 어디에 있고 어떻게 바꾸는가?
  • 씨앗으로 들어 있는 설정 키 중 실제로 읽히는 것은 무엇인가?
  • PostgreSQL 파라미터는 무엇을 어떻게 맞춰야 하는가?
  • Studio와 Bolt 게이트웨이의 환경변수는?

1. 확장 설정 — og_catalog.setting

저장 위치와 형태

CREATE TABLE og_catalog.setting (
    key   text PRIMARY KEY,
    value text NOT NULL
);

(engine/sql/bootstrap.sql:252-255)

키·값 모두 text다. 타입 검증은 읽는 쪽에서 한다.

쓰기 — og_set_setting

SELECT og_set_setting('genai.enabled', 'on');

구현은 upsert 한 줄이다 (engine/src/compat/genai.rs:56-63):

INSERT INTO og_catalog.setting (key, value) VALUES ($1, $2)
ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value

실패 시 오류 문자열: failed to set '{key}': {e} (engine/src/compat/genai.rs:62).

읽기는 표준 SELECT로 한다:

SELECT key, value FROM og_catalog.setting ORDER BY key;

씨앗 키 4개 — 실측 평가

engine/sql/bootstrap.sql:256-260이 심는 값:

INSERT INTO og_catalog.setting (key, value) VALUES
    ('chunk_size',        '256'),
    ('supernode_threshold','4096'),
    ('inference_max_depth','16'),
    ('schema_version',    '1');

이 네 키를 코드가 실제로 읽는지 저장소 전체를 grep한 결과:

키 씨앗값 코드가 읽는가 근거
chunk_size 256 아니다 인접 세그먼트 크기는 컴파일 타임 상수 pub const CHUNK: i32 = 256; (engine/src/storage/adjacency.rs:15). og_graph_stats도 이 상수를 읽는다 (engine/src/storage/stats.rs:68)
supernode_threshold 4096 아니다 engine/src/, engine/sql/ 어디에서도 참조되지 않는다
inference_max_depth 16 아니다 위와 동일
schema_version 1 아니다 (이 키로는) 스키마 버전은 별도 테이블 og_catalog.schema_version에서 관리된다 (engine/src/agent/mod.rs:25, engine/src/catalog/labeling.rs:172-179)

금지 (Forbidden): og_set_setting('chunk_size', '512') 같은 호출로 동작이 바뀔 것이라 기대하지 말 것. 아무 효과도 없다. 세그먼트 크기를 바꾸려면 engine/src/storage/adjacency.rs:15를 고치고 재빌드해야 한다. → 10_improvements_ops.md OPS-10

이 네 키는 백업 대상에서도 제외되어 있다 (engine/sql/bootstrap.sql:420-422), 확장 스크립트가 다시 심기 때문이다.

실제로 읽히는 설정 키 — genai.*

읽히는 유일한 설정군은 genai.vector.encode(= og_genai_encode)의 것이다. 읽는 함수는 setting() (engine/src/compat/genai.rs:43-51)이며, 빈 문자열은 미설정으로 취급한다.

키 기본값 의미 근거
genai.enabled (없음 = 비활성) 'on'이 아니면 og_genai_encode가 거부한다 engine/src/compat/genai.rs:101-107
genai.endpoint (없음 = 오류) 임베딩 HTTP 엔드포인트 URL. 인자로 받지 않는다 — 질의 권한이 곧 fetch 권한이 되지 않도록 하기 위함 engine/src/compat/genai.rs:108-113, 모듈 주석 :21-24
genai.provider ollama ollama | openai | azureopenai 만 허용 engine/src/compat/genai.rs:116-126
genai.model (없음 = 오류) 모델 이름. 호출 시 configuration->>'model'로 덮어쓸 수 있다 engine/src/compat/genai.rs:128-133
genai.dimensions (없음 = 자르지 않음) 반환 벡터를 이 길이로 절단 후 재정규화 engine/src/compat/genai.rs:160-169
genai.timeout_ms 5000 HTTP 타임아웃(ms). 상수 DEFAULT_TIMEOUT_MS engine/src/compat/genai.rs:41,135-137
genai.token (없음) 설정되면 Authorization: Bearer <token> 헤더로 전송 engine/src/compat/genai.rs:140-142

설정 예 (모듈 주석 engine/src/compat/genai.rs:29-35에 있는 그대로):

SELECT og_set_setting('genai.enabled',  'on');
SELECT og_set_setting('genai.endpoint', 'http://localhost:11434/api/embed');
SELECT og_set_setting('genai.provider', 'ollama');
SELECT og_set_setting('genai.model',    'qwen3-embedding:latest');
SELECT og_set_setting('genai.dimensions', '1024');

운영 관점 경고: 이 함수는 PostgreSQL 백엔드가 직접 외부 HTTP 요청을 보낸다. engine/Cargo.toml:25-29의 주석이 명시하듯 블로킹 ureq 클라이언트이므로, 요청이 진행되는 동안 그 백엔드는 다른 질의를 처리하지 않는다. 기본이 비활성인 것은 의도된 설계다. 켤 때는 genai.timeout_ms를 함께 짧게 잡을 것. genai.dimensions를 2000 이하로 두는 것도 실무적으로 필요하다 — pgvector의 HNSW 인덱스가 2000차원에서 멈추기 때문이다 (engine/src/compat/genai.rs:155-159 주석).

히스토리 설정 키

og_enable_history(graph, type_name)은 트리거를 만들면서 history.<graph>.<type_name> 키를 'on'으로 기록한다 (engine/src/agent/mod.rs:462-467). 이 키는 기록용이며, 조회 경로가 이 값을 보고 분기하지는 않는다 — og_as_of는 og_data.og_history에 행이 있는지로 판단한다 (engine/src/agent/mod.rs:503-516).

-- 어떤 타입에 히스토리가 켜져 있는가
SELECT key, value FROM og_catalog.setting WHERE key LIKE 'history.%' ORDER BY key;

2. 에이전트 역할 — 세션 리소스 제한

og_create_role / og_apply_role은 세션에 리소스 제한을 거는 경로다 (engine/src/agent/mod.rs:405-441).

SELECT og_create_role('analyst', '{
  "statement_timeout_ms": 5000,
  "work_mem_kb": 65536,
  "read_only": true,
  "max_rows": 10000
}'::jsonb);

SELECT og_apply_role('analyst');

og_apply_role이 실제로 실행하는 SET (engine/src/agent/mod.rs:426-439):

limits 키 실행되는 문장 실효성
statement_timeout_ms SET statement_timeout = {ms} 실효 — PostgreSQL 표준 GUC
work_mem_kb SET work_mem = {mem} 실효 — PostgreSQL 표준 GUC
read_only (true) SET default_transaction_read_only = on 실효 — 표준 GUC
max_rows SET og.max_rows = {rows} 무효 — og.max_rows를 읽는 코드가 저장소에 없다

og.max_rows 확인: engine/src/agent/mod.rs:438이 유일한 참조이며, current_setting('og.max_rows')를 호출하는 곳은 없다. → OPS-11

또한 네 개의 Spi::run(...)이 모두 .ok()로 끝나므로 SET 실패는 조용히 무시된다 (engine/src/agent/mod.rs:427,430,434,438).

존재하지 않는 역할을 적용하면: no agent role named '{name}' (engine/src/agent/mod.rs:424).


3. PostgreSQL 파라미터

아래 표에서 사실은 저장소에서 확인된 값이고, 권장은 그 사실로부터 도출한 판단이다. 저장소에는 postgresql.conf 템플릿이 없으므로 권장값에 근거 파일이 붙지 않는다.

사실 — 스토리지 레이아웃이 만드는 제약

사실 근거
og_data.og_adj는 fillfactor = 80으로 만들어진다 engine/sql/bootstrap.sql:206
nbr/eid 배열은 STORAGE MAIN으로 강제되어 TOAST되지 않는다. 세그먼트당 최대 256 이웃 × 8B × 2 = 4KB로 8KB 힙 페이지 안에 들어간다 engine/sql/bootstrap.sql:210-211, engine/src/storage/adjacency.rs:13-15
og_reach와 og_csr_*는 PARALLEL RESTRICTED로 선언된다 — 병렬 워커에서 실행되지 않는다 engine/src/storage/traverse.rs:80,359,442, docs/deep-traversal.md:263-267
깊은 순회 재작성 여부는 플래너 통계로 결정된다. 통계가 없으면 깊이만 보고 판단한다 docs/deep-traversal.md:220-226 — "An unanalysed database has no statistics to answer with and falls back to depth alone"
Cypher 컴파일 결과는 평범한 SQL이며 플래너가 순회 스캔을 직접 본다 engine/src/storage/mod.rs:7-9 주석

권장 (판단)

파라미터 권장 이유
shared_buffers 인접 세그먼트 전체가 들어갈 만큼 og_adj가 순회의 핫 릴레이션이고 배열이 인라인이므로 캐시 적중이 곧 성능이다. 필요 크기는 pg_total_relation_size('og_data.og_adj')로 실측할 것 — 06_monitoring.md
work_mem 기본보다 넉넉히 og_reach의 방문집합과 집계가 여기서 나온다. 세션 단위로는 og_apply_role의 work_mem_kb로도 걸 수 있다
statement_timeout 반드시 설정 가변 길이 매치가 재작성되지 못하는 형태(경로 변수 바인딩 등, docs/deep-traversal.md:197-215)면 degree^k 행을 열거한다. 벤치 하네스도 같은 이유로 기본 120초 캡을 둔다 (bench/harness.py:1263-1265)
autovacuum 켠 채로 두되 og_adj는 별도 관찰 세그먼트가 UPDATE로 자라고 비면 삭제된다 (engine/src/storage/adjacency.rs:65-71) — 07_maintenance.md
max_parallel_workers_per_gather 깊은 순회 성능 기대치에 포함하지 말 것 순회 함수들이 PARALLEL RESTRICTED라 리더에서만 돈다
pg_stat_statements 필요하면 직접 추가 docker/Dockerfile.dev가 shared_preload_libraries를 설정하지 않으므로 기본 이미지에는 활성화되어 있지 않다

pgrx 관리 인스턴스의 설정 파일을 고치려면 cargo pgrx가 만든 데이터 디렉터리의 postgresql.conf를 직접 수정한 뒤 재기동해야 한다. 저장소에는 그 경로가 명시되어 있지 않으므로 미확인이며, 다음으로 실측할 수 있다:

docker exec ontological-dev bash -lc \
  "psql -h localhost -p 28816 -d postgres -tAc 'SHOW config_file'"
docker exec ontological-dev bash -lc \
  "psql -h localhost -p 28816 -d postgres -tAc 'SHOW data_directory'"

세션 단위 설정은 postgresql.conf 없이도 즉시 확인·변경할 수 있다:

SHOW statement_timeout;
SHOW work_mem;
SHOW shared_buffers;
SET statement_timeout = '30s';

4. Studio 환경변수

portal/server/index.js:17-29가 읽는 전부:

변수 기본값 의미 근거
PORT 7474 HTTP 리스닝 포트 portal/server/index.js:17
PGHOST localhost PostgreSQL 호스트 :22
PGPORT 28816 PostgreSQL 포트 :23
PGDATABASE og 데이터베이스 :24
PGUSER dev 역할 :25
PGPASSWORD undefined 비밀번호. 미설정이면 pg가 무인증/.pgpass 등에 의존 :26
OG_BENCH_DIR <repo>/bench/results 벤치마크 리포트가 읽을 디렉터리 :19
OG_STUDIO_HOST 127.0.0.1 바인드 주소. 루프백이 아니면 OG_STUDIO_ALLOW_REMOTE=1 없이는 기동을 거부한다 portal/server/index.js
OG_STUDIO_ALLOW_REMOTE 미설정 1 이면 루프백 외 바인드를 허용. 이 서버에는 인증이 없다 portal/server/index.js
OG_STUDIO_ALLOW_RAW_SQL 미설정 1 이 아니면 POST /api/sql 이 403 portal/server/index.js

변경 이력: 이 세 변수는 SEC-01/SEC-02 수정으로 추가되었다. 그 전에는 server.listen(PORT, cb) 가 모든 인터페이스에 바인드하면서 기동 로그는 http://localhost 라고 출력했고, POST /api/sql 에 게이트가 없었다.

풀 설정은 환경변수가 아니라 하드코딩되어 있다 (portal/server/index.js:27-28):

max: 8,
idleTimeoutMillis: 30_000,

운영 관점: 커넥션 8개가 상한이고 질의 타임아웃 설정이 없다. 장기 질의 8개가 동시에 걸리면 /api/health를 포함한 모든 엔드포인트가 대기한다. POST /api/sql은 임의 SQL을 그대로 풀에 넘긴다 (portal/server/index.js:296-308). → OPS-12

정적 파일은 portal/web/에서 서빙되며, 경로 탈출은 full.startsWith(WEB_DIR) 검사로 막는다 (portal/server/index.js:359-360).

OG_BENCH_DIR은 /^bench-(\d+)-(\d{8}T\d{6}Z)\.json$/ 패턴에 맞는 파일만 읽는다 (portal/server/index.js:91) — baseline.json은 리포트에 포함되지 않는다.


5. Bolt 게이트웨이 환경변수

설정 수단은 환경변수뿐이다 (bolt/src/main.rs:9 주석: "Configuration is environment only").

변수 기본값 의미 근거
OG_BOLT_LISTEN 127.0.0.1:7687 Bolt 연결을 받을 주소. Bolt 는 비밀번호를 평문으로 받으므로 기본이 루프백이다 (SEC-15). start.sh 는 컨테이너 안이라 0.0.0.0:7687 을 명시적으로 넘긴다 bolt/src/main.rs
OG_BOLT_MAX_SESSIONS 256 동시 세션 상한. 초과분은 연결을 끊는다 (SEC-16) bolt/src/main.rs
OG_BOLT_PGHOST localhost PostgreSQL 호스트 bolt/src/main.rs:39
OG_BOLT_PGPORT 5432 PostgreSQL 포트. 파싱 실패 시 조용히 5432로 되돌아간다 (.parse().unwrap_or(5432)) bolt/src/main.rs:40
OG_BOLT_PGDATABASE og 데이터베이스 bolt/src/main.rs:41
OG_BOLT_GRAPH default 세션이 database를 지정하지 않았을 때 쓸 그래프 bolt/src/main.rs:42
OG_BOLT_ADVERTISED OG_BOLT_LISTEN과 동일 라우팅 테이블에서 알릴 주소 bolt/src/main.rs:43

함정: OG_BOLT_PGPORT의 기본값 5432는 이 프로젝트의 실제 포트 28816과 다르다. 환경변수 없이 바이너리만 실행하면 엉뚱한 서버에 붙거나 붙지 못한다. start.sh:62가 이 값을 명시적으로 넘기는 이유다.

인증은 게이트웨이가 하지 않는다. HELLO의 user/password는 PostgreSQL 역할과 그 비밀번호 이며, 게이트웨이는 인증된 사용자 외의 누구로도 접속하지 않는다 (bolt/README.md:43, bolt/README.md:49-51). 따라서 RLS·권한·감사는 모두 PostgreSQL의 것이다.

TLS는 종단하지 않는다 — 앞단에 TLS 프록시를 두라고 명시되어 있다 (bolt/README.md:68).

기동 시 stderr로 한 줄을 남긴다 (bolt/src/main.rs:53-57):

ontological-bolt: listening on 0.0.0.0:7687, forwarding to postgres://localhost:28816/og (default graph 'default')

바인드 실패는 exit code 1 (bolt/src/main.rs:49-51):

ontological-bolt: cannot bind {listen}: {e}

금지 / 필수

금지 (Forbidden)

  • 씨앗 설정 키 4종(chunk_size, supernode_threshold, inference_max_depth, schema_version)을 튜닝 노브로 취급하지 말 것 — 읽히지 않는다.
  • og_apply_role의 max_rows를 행 수 제한으로 신뢰하지 말 것 — 읽히지 않는다.
  • genai.endpoint를 신뢰할 수 없는 URL로 설정하지 말 것 — 백엔드가 그 URL로 직접 요청한다.
  • Bolt 게이트웨이를 OG_BOLT_PGPORT 없이 기동하지 말 것.
  • Studio를 공개망에 노출하지 말 것 — POST /api/sql이 임의 SQL 통로다.

필수 (Required)

  • genai.*를 켤 때는 genai.timeout_ms를 반드시 함께 설정할 것.
  • 세션 단위 가드레일이 필요하면 og_apply_role의 statement_timeout_ms / work_mem_kb / read_only 세 개만 쓸 것 (실효가 확인된 것).
  • 설정 변경 후에는 SELECT key, value FROM og_catalog.setting ORDER BY key로 실제 반영을 확인할 것.

이 페이지는 docs/08_operations/03_configuration.md 에서 만들어졌습니다 · python3 web/build_docs.py