Postgres EmbeddingPostgres용 오픈 소스 vector 유사도 검색으로, 근사 최근접 이웃 검색을 위해 Hierarchical Navigable Small Worlds (HNSW)를 사용합니다.
다음 기능을 지원합니다:
  • HNSW를 사용한 정확 및 근사 최근접 이웃 검색
  • L2 거리
이 노트북은 Postgres vector 데이터베이스(PGEmbedding)를 사용하는 방법을 보여줍니다.
PGEmbedding 통합은 pg_embedding extension을 생성해 주지만, 다음 Postgres 쿼리를 실행하여 추가할 수 있습니다:
CREATE EXTENSION embedding;
# Pip install necessary package
pip install -qU  langchain-openai langchain-community
pip install -qU  psycopg2-binary
pip install -qU  tiktoken
OpenAIEmbeddings를 사용하려면 환경 변수에 OpenAI API Key를 추가하세요.
import getpass
import os

if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass.getpass("OpenAI API Key:")
OpenAI API Key:········
## Loading Environment Variables
from typing import List, Tuple
from langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import PGEmbedding
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings
from langchain_text_splitters import CharacterTextSplitter
if "DATABASE_URL" not in os.environ:
    os.environ["DATABASE_URL"] = getpass.getpass("Database Url:")
Database Url:········
loader = TextLoader("state_of_the_union.txt")
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

embeddings = OpenAIEmbeddings()
connection_string = os.environ.get("DATABASE_URL")
collection_name = "state_of_the_union"
db = PGEmbedding.from_documents(
    embedding=embeddings,
    documents=docs,
    collection_name=collection_name,
    connection_string=connection_string,
)

query = "What did the president say about Ketanji Brown Jackson"
docs_with_score: List[Tuple[Document, float]] = db.similarity_search_with_score(query)
for doc, score in docs_with_score:
    print("-" * 80)
    print("Score: ", score)
    print(doc.page_content)
    print("-" * 80)

Postgres에서 vectorstore 사용하기

PG에 vectorstore 업로드하기

db = PGEmbedding.from_documents(
    embedding=embeddings,
    documents=docs,
    collection_name=collection_name,
    connection_string=connection_string,
    pre_delete_collection=False,
)

HNSW 인덱스 생성

기본적으로 이 extension은 100% 재현율을 갖는 순차 스캔 검색을 수행합니다. similarity_search_with_score 실행 시간을 단축하기 위해 approximate nearest neighbor (ANN) 검색용 HNSW 인덱스 생성을 고려할 수 있습니다. vector 컬럼에 HNSW 인덱스를 생성하려면 create_hnsw_index 함수를 사용하세요:
PGEmbedding.create_hnsw_index(
    max_elements=10000, dims=1536, m=8, ef_construction=16, ef_search=16
)
위 함수는 아래 SQL 쿼리를 실행하는 것과 동일합니다:
CREATE INDEX ON vectors USING hnsw(vec) WITH (maxelements=10000, dims=1536, m=3, efconstruction=16, efsearch=16);
위 문에서 사용된 HNSW 인덱스 옵션은 다음과 같습니다:
  • maxelements: 인덱싱할 element의 최대 개수를 정의합니다. 필수 파라미터입니다. 위 예시에서는 값이 3입니다. 실제 환경에서는 1000000과 같이 훨씬 큰 값을 사용합니다. 여기서 “element”는 데이터셋의 데이터 포인트(벡터)를 의미하며, HNSW 그래프에서 노드로 표현됩니다. 일반적으로 데이터셋의 행 수를 수용할 수 있는 값으로 설정합니다.
  • dims: vector 데이터의 차원 수를 정의합니다. 필수 파라미터입니다. 위 예시에서는 작은 값을 사용했습니다. 예를 들어 OpenAI의 text-embedding-ada-002 모델로 생성된 데이터(1536 차원)를 저장한다면 1536으로 설정합니다.
  • m: 그래프 구성 시 각 노드에 대해 생성되는 양방향 링크(“edges”)의 최대 개수를 정의합니다. 다음과 같은 추가 인덱스 옵션도 지원합니다:
  • efConstruction: 인덱스 구성 중 고려할 최근접 이웃의 개수를 정의합니다. 기본값은 32입니다.
  • efsearch: 인덱스 검색 중 고려할 최근접 이웃의 개수를 정의합니다. 기본값은 32입니다. 이러한 옵션을 구성하여 HNSW 알고리즘에 영향을 주는 방법은 Tuning the HNSW algorithm을 참고하세요.

PG에서 vectorstore 조회하기

store = PGEmbedding(
    connection_string=connection_string,
    embedding_function=embeddings,
    collection_name=collection_name,
)

retriever = store.as_retriever()
retriever
VectorStoreRetriever(vectorstore=<langchain_community.vectorstores.pghnsw.HNSWVectoreStore object at 0x121d3c8b0>, search_type='similarity', search_kwargs={})
db1 = PGEmbedding.from_existing_index(
    embedding=embeddings,
    collection_name=collection_name,
    pre_delete_collection=False,
    connection_string=connection_string,
)

query = "What did the president say about Ketanji Brown Jackson"
docs_with_score: List[Tuple[Document, float]] = db1.similarity_search_with_score(query)
for doc, score in docs_with_score:
    print("-" * 80)
    print("Score: ", score)
    print(doc.page_content)
    print("-" * 80)

Connect these docs programmatically to Claude, VSCode, and more via MCP for real-time answers.
I