AgensGraph
/
  • v2.18 (latest)
  • v2.17
  • v2.16
  • v2.15
EN한국어
  • 시작하기
    • AgensGraph란
    • AgensGraph 설치
    • 예제 데이터셋
    • 첫 쿼리
  • 개념
    • 속성 그래프 모델
    • 그래프가 어떻게 저장되는가
    • 레이블 상속
    • Cypher, GQL, SQL
  • 쿼리하기
    • 그래프 읽기
    • 그래프 쓰기
    • 쿼리 조합하기
    • 경로
    • 인덱스와 제약
    • 속성을 컬럼으로 승격하기
    • SQL과 Cypher 섞기
    • 쿼리 튜닝
  • 레퍼런스
    • 구문
    • 데이터 타입
    • 절
      • MATCH
      • OPTIONAL MATCH
      • WHERE
      • LOAD FROM
      • RETURN
      • WITH
      • LET
      • ORDER BY
      • SKIP과 LIMIT
      • CREATE
      • INSERT
      • MERGE
      • SET
      • REMOVE
      • DELETE
      • UNWIND
      • FOR
      • FILTER
      • NEXT
      • FINISH
      • UNION
      • CALL
      • CALL … YIELD
      • CALL { subquery }
      • OPTIONAL CALL
      • 서브쿼리 값 표현식
    • 데이터 정의
      • CREATE GRAPH
      • DROP GRAPH
      • CREATE VLABEL
      • CREATE ELABEL
      • ALTER VLABEL과 ALTER ELABEL
      • DROP VLABEL과 DROP ELABEL
      • CREATE PROPERTY INDEX
      • DROP PROPERTY INDEX
      • REINDEX VLABEL과 REINDEX ELABEL
      • CREATE CONSTRAINT
      • DROP CONSTRAINT
    • 함수
      • 모든 함수
      • 집계 함수
      • 조건 함수
      • 스칼라 함수
      • 리스트 함수
      • 문자열 함수
      • 수치 함수
      • 경로 함수
      • 타입 변환 함수
      • jsonb 연산자와 함수
    • 서버 설정
    • agens 클라이언트
  • 가이드
    • 데이터 적재
    • 벡터 검색
      • 개요
      • pgvector 설치
      • 예제 데이터
      • 유사도 검색
      • HNSW로 인덱싱하기
      • 승격된 컬럼 인덱싱하기
      • GraphRAG
    • 전문 검색
      • 개요
      • 예제 데이터
      • 텍스트 속성 검색하기
      • 결과 순위 매기기
      • 정확한 단어 대조
      • GIN으로 인덱싱하기
      • 승격된 컬럼 인덱싱하기
      • GraphRAG
    • 하이브리드 검색
      • 개요
      • 상호 순위 융합(RRF)
      • 예제 데이터
      • 하이브리드 쿼리
      • 양쪽 모두 인덱싱하기
      • 조정
      • GraphRAG
    • AI·LLM 연동
      • 개요
      • LangChain
      • LlamaIndex
      • LightRAG
      • cognee
      • MCP 서버
      • 프레임워크 없이
  • 드라이버와 클라이언트 라이브러리
    • Python 드라이버
    • 다른 언어
    • 접속과 매개변수
    • AI·LLM 연동
      • 개요
      • LangChain
      • LlamaIndex
      • LightRAG
      • cognee
      • MCP 서버
      • 프레임워크 없이
  • 운영
    • 배포
    • 설정
    • 보안
    • 백업과 복구
    • 서버 측 도구
  • 시스템 카탈로그
    • 그래프 카탈로그
    • 그래프 뷰
    • 그래프 메타데이터
  • 릴리스 노트
    • AgensGraph 2.18.6.0
    • 2.18로 업그레이드하기
    • 업그레이드 실습
    • AgensGraph 2.17.0
  • 부록
    • GQL 적합성
    • Cypher 호환성
    • 키워드
    • 오류 코드
    • 제한
    • 용어집

이 페이지에서

  • 개요
  • pgvector 설치
  • 예제 데이터
  • 유사도 검색
  • HNSW로 인덱싱하기
  • 승격된 컬럼 인덱싱하기
  • GraphRAG
  1. AgensGraph /
  2. 가이드 /
  3. 벡터 검색
Markdown 으로 보기 ChatGPT 에서 열기 Claude 에서 열기

벡터 검색#

개요#

AgensGraph는 PostgreSQL 위에 만들어졌으므로, pgvector 확장이 그래프에 벡터 유사도 검색을 곧바로 더합니다. 그러면 임베딩이 그래프 데이터 옆에 놓이고, 데이터베이스 하나가 의미(벡터) 검색과 Cypher 그래프 순회를 결합할 수 있습니다. 검색 증강 생성(RAG)과 GraphRAG 응용의 토대가 그것입니다.

벡터 검색은 단어가 아니라 의미로 일치시킵니다. 두 글이 어휘를 하나도 공유하지 않아도 벡터 공간에서는 가까울 수 있습니다. 키워드로 대조하는 전문 검색에 견준 강점이 그것입니다.

둘을 결합하는 것은 하이브리드 검색이 다룹니다. 세 페이지의 예제가 모두 같은 영화 집합을 쓰므로 동작을 직접 견주어 볼 수 있습니다.

임베딩은 정점이나 간선의 수치 배열 속성으로 저장됩니다. 속성은 jsonb이므로 배열은 JSON 배열로 보관됩니다. 벡터 연산이 필요할 때마다 ::vector(n) 형 변환이 그것을 pgvector의 vector 타입으로 바꿉니다.

그 형 변환은 읽을 때마다 일어납니다. 행이 몇천 개일 때는 괜찮지만 규모가 커지면 낭비입니다. 2.18부터는 대신 그 속성을 실제 vector 컬럼으로 승격할 수 있습니다.

그러면 형 변환은 쓰기 시점에 한 번 일어나고, HNSW 인덱스를 그 컬럼 자체에 만들 수 있습니다. 승격된 컬럼에 남아 있는 ::vector(n)은 접혀 사라지므로, 이 페이지의 쿼리는 그대로 동작하고 인덱스도 계속 씁니다.

승격하면 두 가지가 달라집니다.

값의 타입입니다. 승격된 d.emb는 vector로 돌아오고 승격하지 않은 것은 jsonb로 돌아오므로, JSON 형태를 파싱하는 클라이언트는 고쳐야 합니다.

인덱스의 모양입니다. 승격된 컬럼 위에서는 형 변환 표현식에 대한 인덱스가 아니라 평범한 컬럼 인덱스가 되며, 그래서 덤프하고 복원할 인덱스로는 이 형태가 낫습니다.

pgvector 설치#

pgvector는 별도의 확장이며, 쓰고 있는 AgensGraph 설치본에 맞춰 빌드해 설치해야 합니다. 쓸 수 있게 된 뒤에는 데이터베이스마다 켜십시오:

CREATE EXTENSION vector;

예제 데이터#

예제는 예제 데이터셋을 씁니다. 영화 18편이 각각 plot과 그 줄거리의 4차원 embedding을 가지고 있습니다. 더 가기 전에 그것을 적재하십시오.

실제 임베딩은 text-embedding-3-small이나 로컬 sentence-transformers 모델 같은 모델에서 나오며 차원이 수백 개입니다. 여기서는 지면에서 기하 구조가 읽히도록 넷으로 줄였습니다.

유사도 검색#

pgvector는 거리 연산자와 그에 대응하는 함수를 제공합니다. 두 피연산자를 vector(n)으로 변환한 뒤 거리로 정렬하십시오.

연산자

함수

거리

HNSW 연산자 클래스

<=>

cosine_distance

코사인 거리

vector_cosine_ops

<->

l2_distance

유클리드(L2)

vector_l2_ops

<#>

inner_product

(음의) 내적

vector_ip_ops

<+>

l1_distance

맨해튼(L1)

vector_l1_ops

줄거리가 쿼리 벡터에 가장 가까운(코사인 거리) 영화를 찾습니다. 여기서 쿼리는 The Matrix의 줄거리 임베딩이므로, 검색은 의미가 가장 비슷한 영화를 돌려줍니다:

MATCH (m:movie)
RETURN m.title AS title
ORDER BY m.embedding::vector(4) <=> '[-0.07594558, 0.04081754, 0.29592122, -0.11921061]'::vector(4)
LIMIT 4;
           title
----------------------------
 "The Matrix"
 "The Matrix Reloaded"
 "The Matrix Resurrections"
 "Total Recall"
(4 rows)

처음 세 결과는 뻔한 속편이지만, 흥미로운 것은 네 번째입니다. Total Recall의 줄거리는 “a construction worker discovers that his memories have been implanted” 입니다. The Matrix의 “a hacker … a simulated world controlled by machines” 와 키워드를 하나도 공유하지 않습니다.

그런데도 벡터 검색은 그것을 네 번째로 올립니다. 두 영화 모두 자기 현실이 꾸며진 것임을 알아차리는 인물의 이야기이기 때문입니다. 키워드 검색은 둘을 결코 잇지 못합니다.

의미 검색은 바로 그것을 잡아내고 어휘 검색은 그러지 못합니다. 같은 데이터에 대한 전문 검색 결과와 견주어 보고, 둘을 결합하는 것은 하이브리드 검색을 참고하십시오.

ORDER BY는 거리 표현식이 RETURN 목록에 없어도 그것을 참조할 수 있습니다(AgensGraph 2.17 이상). title만 반환하면 출력이 깔끔해지고, 더 중요하게는 HNSW 인덱스가 그 정렬을 맡을 수 있습니다. 거리를 그대로 반환하면 jsonb로 변환되어 인덱스를 쓰지 못하게 됩니다.

함수 형태는 「The Terminator와 가장 비슷한 영화」처럼 저장된 다른 벡터와 견줄 때 편리합니다. 쿼리 벡터를 손으로 쓰지 않아도 됩니다:

MATCH (m:movie), (q:movie {title: 'The Terminator'})
RETURN m.title AS title
ORDER BY m.embedding::vector(4) <=> q.embedding::vector(4)
LIMIT 4;
            title
----------------------------
 "The Terminator"
 "Terminator 2: Judgment Day"
 "Minority Report"
 "Blade Runner"
(4 rows)

HNSW로 인덱싱하기#

인덱스가 없으면 유사도 쿼리마다 모든 행을 스캔하며 각각의 거리를 계산합니다. 데이터가 크다면 플래너가 인덱스 스캔을 쓸 수 있도록 HNSW 인덱스를 만드십시오. 인덱싱하는 값이 형 변환 표현식이므로 속성 인덱스를 쓰십시오:

CREATE PROPERTY INDEX ON movie
    USING hnsw ((embedding::vector(4)) vector_cosine_ops);

연산자 클래스는 쿼리에 쓰는 거리에 맞추십시오(<=>에는 vector_cosine_ops, <->에는 vector_l2_ops 하는 식입니다). 그러면 앞의 유사도 쿼리가 인덱스를 씁니다:

EXPLAIN
MATCH (m:movie)
RETURN m.title AS title
ORDER BY m.embedding::vector(4) <=> '[-0.07594558, 0.04081754, 0.29592122, -0.11921061]'::vector(4)
LIMIT 4;
 Limit
   ->  Index Scan using movie_embedding_idx on movie m
         Order By: ((properties.'embedding'::text)::vector(4) <=> '[...]'::vector(4))

행이 18개뿐인 이 예제에서는 순차 스캔이 더 싸므로 플래너가 여전히 그것을 고를 수 있습니다. 인덱스 계획을 보려면 SET enable_seqscan = off를 더하십시오. 실제 말뭉치에서는 플래너가 알아서 인덱스를 고릅니다.

::vector(n) 형 변환에 대한 HNSW 속성 인덱스는 AgensGraph 2.17 이상이 필요합니다.

승격된 컬럼 인덱싱하기#

위의 인덱스는 형 변환 표현식 위에 만들어집니다. 속성을 승격하면 형 변환이 사라지므로, 인덱스는 컬럼에 대한 평범한 인덱스가 됩니다.

승격은 jsonb properties 옆에 그 속성을 위한 실제 타입 컬럼을 만들고 쓰기 시점에 채웁니다. 선언하는 것은 컬럼 이름이고, 그것이 비추는 속성은 같은 단어로 지칭됩니다:

DROP PROPERTY INDEX movie_embedding_idx;
ALTER VLABEL movie ADD COLUMN embedding vector(4) GENERATED;

GENERATED만 쓰면 컬럼 이름과 같은 이름의 속성, 여기서는 embedding을 비춥니다. 컬럼을 다른 이름으로 부르려면 GENERATED (sourceKey)라고 쓰십시오 — ALTER VLABEL movie ADD COLUMN emb vector(4) GENERATED (embedding)은 같은 속성을 emb이라는 컬럼에 저장합니다. 어느 쪽이든 쿼리는 컬럼이 아니라 속성의 이름을 계속 댑니다. 해석은 속성 키로 이루어지고 컬럼 이름은 Cypher에 나타나지 않습니다. 자세한 것은 속성을 컬럼으로 승격하기에 있습니다.

그러면 인덱스는 형 변환도 괄호도 없는, 컬럼에 대한 평범한 인덱스가 됩니다:

CREATE PROPERTY INDEX ON movie USING hnsw (embedding vector_cosine_ops);

이 페이지의 모든 쿼리는 고치지 않아도 그대로 동작합니다. 승격된 컬럼에 남은 ::vector(4)는 접혀 사라지므로 m.embedding과 m.embedding::vector(4)는 같은 계획을 만듭니다:

EXPLAIN (COSTS OFF)
MATCH (m:movie)
RETURN m.title AS title
ORDER BY m.embedding <=> '[-0.07594558, 0.04081754, 0.29592122, -0.11921061]'::vector(4)
LIMIT 4;
 Limit
   ->  Index Scan using movie_embedding_idx on movie m
         Order By: (embedding <=> '[-0.07594558,0.04081754,0.2959212,-0.11921061]'::vector(4))

중요

위에서처럼, 표현식 인덱스가 읽는 키를 승격하기 전에 그 인덱스를 지우십시오. 표현식에 대한 속성 인덱스는 jsonb properties를 상대로 만들어지고 승격된 키에 대한 쿼리는 컬럼을 읽으므로, 둘은 더는 만나지 않습니다. 표현식 속성 인덱스는 properties에 걸린다를 참고하십시오.

승격하면 값의 타입이 달라집니다. 이제 m.embedding은 vector로 돌아오며, 승격하지 않은 속성은 jsonb로 돌아왔습니다.

GraphRAG#

그래프 데이터베이스 안의 벡터 검색에는 남다른 강점이 있습니다. 의미 일치가 그래프 순회의 출발점이 될 수 있다는 것입니다.

전형적인 GraphRAG 검색은 쿼리 하나로 두 가지를 합니다. 벡터 유사도로 질문에 가장 관련 있는 항목을 찾고, 그다음 관계를 따라 뻗어 나가 언어 모델에 줄 연결된 맥락을 모읍니다.

예제 데이터셋에는 영화 사이의 related_to 간선이 이미 들어 있습니다. 시리즈 속편과 주제로 이어진 작품들입니다. 그래서 아래 순회가 따라갈 것이 있습니다.

쿼리할 때는 줄거리에 쓴 것과 같은 모델로 사용자의 질문을 임베딩합니다. 그런 다음 가장 가까운 영화를 가져와 그 이웃으로 뻗는 Cypher 쿼리 하나를 실행합니다. 여기서 질문 임베딩은 The Matrix의 벡터입니다:

MATCH (seed:movie)
WITH seed
ORDER BY seed.embedding::vector(4) <=> '[-0.07594558, 0.04081754, 0.29592122, -0.11921061]'::vector(4)
LIMIT 2
MATCH (seed)-[:related_to]-(ctx:movie)
RETURN seed.title AS seed, collect(DISTINCT ctx.title) AS related_context;
         seed          |                      related_context
-----------------------+-----------------------------------------------------------
 "The Matrix"          | ["The Matrix Reloaded", "The Terminator", "Total Recall"]
 "The Matrix Reloaded" | ["The Matrix", "The Matrix Revolutions"]
(2 rows)

WITH … ORDER BY … LIMIT 2가 벡터 유사도로 질문에 가장 잘 맞는 영화 둘을 고릅니다. 그것이 시드입니다. 두 번째 MATCH는 각 시드에서 related_to 간선을 따라가 이웃 영화를 모읍니다.

합쳐진 집합은 시드와 그 그래프 이웃입니다. 벡터 검색만으로 얻는 것보다 풍부한 맥락을 이루며, 언어 모델에 넘겨 최종 답을 만들게 할 수 있습니다.

이 방식은 일반화됩니다. 시드를 여러 홉으로 뻗거나, 간선 종류나 속성으로 거르거나, 다른 레이블(사람·스튜디오·출처)에 조인해 RAG 파이프라인에 필요한 맥락을 정확히 조립할 수 있습니다.

프레임워크가 그 일을 대신 해 주기를 바란다면, AI·LLM 연동이 그런 라이브러리를 나열합니다.

이전
데이터 적재
다음
전문 검색

2026, SKAI Worldwide Co., Ltd

Made with Shibuya theme.