diff --git a/app/services/search/retrieval_service.py b/app/services/search/retrieval_service.py index cf93602..3db8cfa 100644 --- a/app/services/search/retrieval_service.py +++ b/app/services/search/retrieval_service.py @@ -142,7 +142,9 @@ def _license_sql(alias: str) -> str: 술어 정의 = license_filter.restricted_exclude_sql 공유(digest/briefing/study 풀이와 단일 source). """ from services.search.license_filter import restricted_exclude_sql - return " AND " + restricted_exclude_sql(alias) + _p = (alias + ".") if alias else "" + # ASME clause-KB(379): clause docs (doc_kind='clause') = read/nav/backlink only, excluded from retrieval/digest legs. + return " AND " + restricted_exclude_sql(alias) + f" AND {_p}doc_kind = 'standard'" def cloud_eligible_doc_sql(alias: str = "") -> str: diff --git a/migrations/379_asme_clause_kb.sql b/migrations/379_asme_clause_kb.sql new file mode 100644 index 0000000..b092c49 --- /dev/null +++ b/migrations/379_asme_clause_kb.sql @@ -0,0 +1,37 @@ +-- 379_asme_clause_kb.sql +-- ASME 절-지식베이스: 절 = 개별 documents 행(parent_id) + 절↔절 백링크 + 태깅 (additive, idempotent) +-- 검색 무접촉: 절 doc 은 embedding NULL(벡터 제외) + doc_kind='clause'(retrieval doc-leg 필터로 제외). + +ALTER TABLE documents + ADD COLUMN IF NOT EXISTS parent_id bigint REFERENCES documents(id), + ADD COLUMN IF NOT EXISTS doc_kind text NOT NULL DEFAULT 'standard', + ADD COLUMN IF NOT EXISTS clause_code text, + ADD COLUMN IF NOT EXISTS clause_part text, + ADD COLUMN IF NOT EXISTS clause_order int; + +CREATE INDEX IF NOT EXISTS idx_documents_parent_id ON documents(parent_id) WHERE parent_id IS NOT NULL; +CREATE INDEX IF NOT EXISTS idx_documents_doc_kind ON documents(doc_kind); +CREATE INDEX IF NOT EXISTS idx_documents_clause_code ON documents(clause_code) WHERE clause_code IS NOT NULL; + +-- 절↔절 백링크 (dangling 허용: dst_doc_id nullable) +CREATE TABLE IF NOT EXISTS clause_links ( + id bigserial PRIMARY KEY, + src_doc_id bigint NOT NULL REFERENCES documents(id) ON DELETE CASCADE, + dst_code text NOT NULL, + dst_doc_id bigint REFERENCES documents(id) ON DELETE SET NULL, + anchor text, + ctx text, + char_off int +); +CREATE INDEX IF NOT EXISTS idx_clause_links_src ON clause_links(src_doc_id); +CREATE INDEX IF NOT EXISTS idx_clause_links_dst ON clause_links(dst_doc_id) WHERE dst_doc_id IS NOT NULL; +CREATE INDEX IF NOT EXISTS idx_clause_links_dstcode ON clause_links(dst_code); + +-- 태깅 (Part 자동 + 주제) +CREATE TABLE IF NOT EXISTS document_tags ( + doc_id bigint NOT NULL REFERENCES documents(id) ON DELETE CASCADE, + tag text NOT NULL, + tag_kind text NOT NULL DEFAULT 'topic', + PRIMARY KEY (doc_id, tag) +); +CREATE INDEX IF NOT EXISTS idx_document_tags_tag ON document_tags(tag);