메인 콘텐츠로 건너뛰기
dbpedia 데이터셋에는 Wikipedia의 100만 개 아티클과 OpenAI의 text-embedding-3-large 모델로 생성한 벡터 임베딩이 포함되어 있습니다. 이 데이터셋은 벡터 임베딩, 벡터 유사도 검색, 생성형 AI를 이해하기에 매우 좋은 입문용 데이터셋입니다. 이 데이터셋은 ClickHouse의 근사 최근접 이웃 검색과 간단하지만 강력한 Q&A 애플리케이션을 보여 주는 데 사용합니다.

데이터셋 세부 정보

이 데이터셋에는 huggingface.co에 있는 26개의 Parquet 파일이 포함되어 있습니다. 파일 이름은 0.parquet, 1.parquet, …, 25.parquet입니다. 데이터셋의 예시 행 몇 개를 보려면 이 Hugging Face 페이지를 방문하십시오.

테이블 생성

문서 ID, 제목, 텍스트, 임베딩 벡터를 저장할 dbpedia 테이블을 생성합니다:
CREATE TABLE dbpedia
(
  id      String,
  title   String,
  text    String,
  vector  Array(Float32) CODEC(NONE)
) ENGINE = MergeTree ORDER BY (id);

테이블 불러오기

모든 Parquet 파일의 데이터를 불러오려면 다음 셸 명령을 실행하세요:
for i in $(seq 0 25); do
  echo "파일 ${i} 처리 중..."
  clickhouse client -q "INSERT INTO dbpedia SELECT _id, title, text, \"text-embedding-3-large-1536-embedding\" FROM url('https://huggingface.co/api/datasets/Qdrant/dbpedia-entities-openai3-text-embedding-3-large-1536-1M/parquet/default/train/${i}.parquet') SETTINGS max_http_get_redirects=5,enable_url_encoding=0;"
  echo "파일 ${i} 완료."
done
또는 아래와 같이 개별 SQL 문을 실행해 25개의 Parquet 파일을 각각 로드할 수 있습니다:
INSERT INTO dbpedia SELECT _id, title, text, "text-embedding-3-large-1536-embedding" FROM url('https://huggingface.co/api/datasets/Qdrant/dbpedia-entities-openai3-text-embedding-3-large-1536-1M/parquet/default/train/0.parquet') SETTINGS max_http_get_redirects=5,enable_url_encoding=0;
INSERT INTO dbpedia SELECT _id, title, text, "text-embedding-3-large-1536-embedding" FROM url('https://huggingface.co/api/datasets/Qdrant/dbpedia-entities-openai3-text-embedding-3-large-1536-1M/parquet/default/train/1.parquet') SETTINGS max_http_get_redirects=5,enable_url_encoding=0;
...
INSERT INTO dbpedia SELECT _id, title, text, "text-embedding-3-large-1536-embedding" FROM url('https://huggingface.co/api/datasets/Qdrant/dbpedia-entities-openai3-text-embedding-3-large-1536-1M/parquet/default/train/25.parquet') SETTINGS max_http_get_redirects=5,enable_url_encoding=0;

dbpedia 테이블에 100만 개의 행이 있는지 확인하십시오:
SELECT count(*)
FROM dbpedia
   ┌─count()─┐
1. │ 1000000 │
   └─────────┘
권장 읽을거리: “벡터 임베딩 ” OpenAPI 가이드 벡터 임베딩을 사용하는 시맨틱 검색(또는 유사도 검색)은 다음 단계로 이루어집니다:
  • 사용자가 자연어로 검색 쿼리를 입력합니다. 예: “경치 좋은 철도 여행을 알려줘”, “유럽을 배경으로 한 서스펜스 소설”
  • LLM 모델을 사용해 검색 쿼리의 임베딩 벡터를 생성합니다
  • 데이터셋에서 검색 임베딩 벡터와 가장 가까운 이웃을 찾습니다
_가장 가까운 이웃_은 사용자 쿼리와 관련된 문서, 이미지 또는 기타 콘텐츠입니다. 검색된 결과는 생성형 AI 애플리케이션에서 검색 증강 생성(RAG)의 핵심 입력입니다. KNN(k - 최근접 이웃) 검색 또는 브루트포스 검색은 데이터셋의 각 벡터와 검색 임베딩 벡터 사이의 거리를 계산한 뒤, 최근접 이웃을 찾기 위해 거리순으로 정렬하는 방식입니다. dbpedia 데이터셋에서는 시맨틱 검색을 시각적으로 빠르게 확인하는 한 가지 방법으로 데이터셋 자체의 임베딩 벡터를 검색 벡터로 사용할 수 있습니다. 예를 들면 다음과 같습니다:
Query
SELECT id, title
FROM dbpedia
ORDER BY cosineDistance(vector, ( SELECT vector FROM dbpedia WHERE id = '<dbpedia:The_Remains_of_the_Day>') ) ASC
LIMIT 20
Response
    ┌─id────────────────────────────────────────┬─title───────────────────────────┐
 1. │ <dbpedia:The_Remains_of_the_Day>          │ The Remains of the Day          │
 2. │ <dbpedia:The_Remains_of_the_Day_(film)>   │ The Remains of the Day (film)   │
 3. │ <dbpedia:Never_Let_Me_Go_(novel)>         │ Never Let Me Go (novel)         │
 4. │ <dbpedia:Last_Orders>                     │ Last Orders                     │
 5. │ <dbpedia:The_Unconsoled>                  │ The Unconsoled                  │
 6. │ <dbpedia:The_Hours_(novel)>               │ The Hours (novel)               │
 7. │ <dbpedia:An_Artist_of_the_Floating_World> │ An Artist of the Floating World │
 8. │ <dbpedia:Heat_and_Dust>                   │ Heat and Dust                   │
 9. │ <dbpedia:A_Pale_View_of_Hills>            │ A Pale View of Hills            │
10. │ <dbpedia:Howards_End_(film)>              │ Howards End (film)              │
11. │ <dbpedia:When_We_Were_Orphans>            │ When We Were Orphans            │
12. │ <dbpedia:A_Passage_to_India_(film)>       │ A Passage to India (film)       │
13. │ <dbpedia:Memoirs_of_a_Survivor>           │ Memoirs of a Survivor           │
14. │ <dbpedia:The_Child_in_Time>               │ The Child in Time               │
15. │ <dbpedia:The_Sea,_the_Sea>                │ The Sea, the Sea                │
16. │ <dbpedia:The_Master_(novel)>              │ The Master (novel)              │
17. │ <dbpedia:The_Memorial>                    │ The Memorial                    │
18. │ <dbpedia:The_Hours_(film)>                │ The Hours (film)                │
19. │ <dbpedia:Human_Remains_(film)>            │ Human Remains (film)            │
20. │ <dbpedia:Kazuo_Ishiguro>                  │ Kazuo Ishiguro                  │
    └───────────────────────────────────────────┴─────────────────────────────────┘
20 rows in set. Elapsed: 0.261 sec. Processed 1.00 million rows, 6.22 GB (3.84 million rows/s., 23.81 GB/s.)
ANN(벡터 인덱스 사용)의 쿼리 지연 시간과 비교할 수 있도록 쿼리 지연 시간을 기록해 두십시오. 또한 실제 컴퓨트 사용량과 스토리지 대역폭 사용량을 파악할 수 있도록, OS 파일 캐시가 콜드 상태일 때의 쿼리 지연 시간과 max_threads=1일 때의 쿼리 지연 시간도 기록하십시오 (이를 수백만 개의 벡터가 있는 프로덕션 데이터셋에 외삽해 보십시오!)

벡터 유사도 인덱스 생성

다음 SQL을 실행하여 vector 컬럼에 벡터 유사도 인덱스를 정의하고 생성하십시오:
ALTER TABLE dbpedia ADD INDEX vector_index vector TYPE vector_similarity('hnsw', 'cosineDistance', 1536, 'bf16', 64, 512);

ALTER TABLE dbpedia MATERIALIZE INDEX vector_index SETTINGS mutations_sync = 2;
인덱스 생성 및 검색에 대한 매개변수와 성능 고려 사항은 문서에 설명되어 있습니다. 인덱스를 생성하고 저장하는 데는 사용 가능한 CPU 코어 수와 스토리지 대역폭에 따라 몇 분 정도 소요될 수 있습니다. 근사 최근접 이웃 또는 ANN은 정확 벡터 검색보다 훨씬 빠르게 결과를 계산하는 기법들의 모음(예: 그래프나 랜덤 포레스트 같은 특수한 데이터 구조)입니다. 결과 정확도는 일반적으로 실제 사용에 충분할 만큼 “좋은 수준”입니다. 많은 근사 기법은 결과 정확도와 검색 시간 사이의 절충점을 조정할 수 있는 매개변수를 제공합니다. 벡터 유사도 인덱스가 구축되면 벡터 검색 쿼리는 자동으로 해당 인덱스를 사용합니다:
Query
SELECT
    id,
    title
FROM dbpedia
ORDER BY cosineDistance(vector, (
        SELECT vector
        FROM dbpedia
        WHERE id = '<dbpedia:Glacier_Express>'
    )) ASC
LIMIT 20
Response
    ┌─id──────────────────────────────────────────────┬─title─────────────────────────────────┐
 1. │ <dbpedia:Glacier_Express>                       │ Glacier Express                       │
 2. │ <dbpedia:BVZ_Zermatt-Bahn>                      │ BVZ Zermatt-Bahn                      │
 3. │ <dbpedia:Gornergrat_railway>                    │ Gornergrat railway                    │
 4. │ <dbpedia:RegioExpress>                          │ RegioExpress                          │
 5. │ <dbpedia:Matterhorn_Gotthard_Bahn>              │ Matterhorn Gotthard Bahn              │
 6. │ <dbpedia:Rhaetian_Railway>                      │ Rhaetian Railway                      │
 7. │ <dbpedia:Gotthard_railway>                      │ Gotthard railway                      │
 8. │ <dbpedia:Furka–Oberalp_railway>                 │ Furka–Oberalp railway                 │
 9. │ <dbpedia:Jungfrau_railway>                      │ Jungfrau railway                      │
10. │ <dbpedia:Monte_Generoso_railway>                │ Monte Generoso railway                │
11. │ <dbpedia:Montreux–Oberland_Bernois_railway>     │ Montreux–Oberland Bernois railway     │
12. │ <dbpedia:Brienz–Rothorn_railway>                │ Brienz–Rothorn railway                │
13. │ <dbpedia:Lauterbrunnen–Mürren_mountain_railway> │ Lauterbrunnen–Mürren mountain railway │
14. │ <dbpedia:Luzern–Stans–Engelberg_railway_line>   │ Luzern–Stans–Engelberg railway line   │
15. │ <dbpedia:Rigi_Railways>                         │ Rigi Railways                         │
16. │ <dbpedia:Saint-Gervais–Vallorcine_railway>      │ Saint-Gervais–Vallorcine railway      │
17. │ <dbpedia:Gatwick_Express>                       │ Gatwick Express                       │
18. │ <dbpedia:Brünig_railway_line>                   │ Brünig railway line                   │
19. │ <dbpedia:Regional-Express>                      │ Regional-Express                      │
20. │ <dbpedia:Schynige_Platte_railway>               │ Schynige Platte railway               │
    └─────────────────────────────────────────────────┴───────────────────────────────────────┘
20 rows in set. Elapsed: 0.025 sec. Processed 32.03 thousand rows, 2.10 MB (1.29 million rows/s., 84.80 MB/s.)

검색 쿼리를 위한 임베딩 생성

지금까지 살펴본 유사도 검색 쿼리는 dbpedia 테이블에 있는 기존 벡터 중 하나를 검색 벡터로 사용합니다. 실제 애플리케이션에서는 자연어일 수 있는 사용자 입력 쿼리로부터 검색 벡터를 생성해야 합니다. 검색 벡터는 데이터셋의 임베딩 벡터를 생성할 때 사용한 것과 동일한 LLM 모델을 사용해 생성해야 합니다. 아래는 OpenAI API를 프로그래밍 방식으로 호출하여 text-embedding-3-large 모델로 임베딩 벡터를 생성하는 방법을 보여주는 Python 예시 스크립트입니다. 그런 다음 검색 임베딩 벡터를 SELECT 쿼리의 cosineDistance() 함수에 인수로 전달합니다. 스크립트를 실행하려면 환경 변수 OPENAI_API_KEY에 OpenAI API Key가 설정되어 있어야 합니다. OpenAI API Key는 https://platform.openai.com에 등록한 후 발급받을 수 있습니다.
import sys
from openai import OpenAI
import clickhouse_connect

ch_client = clickhouse_connect.get_client(compress=False) # ClickHouse 자격 증명 전달
openai_client = OpenAI() # OPENAI_API_KEY 환경 변수 설정

def get_embedding(text, model):
  text = text.replace("\n", " ")
  return openai_client.embeddings.create(input = [text], model=model, dimensions=1536).data[0].embedding

while True:
    # 사용자로부터 검색 쿼리 입력 받기
    print("Enter a search query :")
    input_query = sys.stdin.readline();

    # OpenAI API 엔드포인트를 호출하여 임베딩 가져오기
    print("Generating the embedding for ", input_query);
    embedding = get_embedding(input_query,
                              model='text-embedding-3-large')

    # ClickHouse에서 벡터 검색 쿼리 실행
    print("Querying clickhouse...")
    params = {'v1':embedding, 'v2':10}
    result = ch_client.query("SELECT id,title,text FROM dbpedia ORDER BY cosineDistance(vector, %(v1)s) LIMIT %(v2)s", parameters=params)

    for row in result.result_rows:
        print(row[0], row[1], row[2])
        print("---------------")

Q&A 데모 애플리케이션

위의 예시에서는 ClickHouse를 사용한 시맨틱 검색과 문서 검색을 보여주었습니다. 다음으로는 매우 간단하지만 활용 가능성이 큰 생성형 AI 예시 애플리케이션을 소개합니다. 이 애플리케이션은 다음 단계를 수행합니다:
  1. 사용자로부터 주제를 입력받습니다
  2. text-embedding-3-large 모델로 OpenAI API를 호출하여 주제에 대한 임베딩 벡터를 생성합니다
  3. dbpedia 테이블(table)에서 벡터 유사도 검색을 사용해 관련성이 매우 높은 Wikipedia 문서를 검색합니다
  4. 주제와 관련된 자유 형식의 자연어 질문을 사용자로부터 입력받습니다
  5. OpenAI gpt-3.5-turbo Chat API를 사용하여 3단계에서 검색된 문서의 지식을 바탕으로 질문에 답변합니다. 3단계에서 검색된 문서는 Chat API에 컨텍스트로 전달되며, 이것이 생성형 AI의 핵심 연결 고리입니다.
먼저 Q&A 애플리케이션을 실행한 대화 예시 몇 가지를 아래에 제시한 다음, Q&A 애플리케이션 코드를 제공합니다. 애플리케이션을 실행하려면 환경 변수 OPENAI_API_KEY에 OpenAI API Key가 설정되어 있어야 합니다. OpenAI API Key는 https://platform.openai.com 에 등록한 후 발급받을 수 있습니다.
$ python3 QandA.py

Enter a topic : FIFA world cup 1990
Generating the embedding for 'FIFA world cup 1990' and collecting 100 articles related to it from ClickHouse...

Enter your question : Who won the golden boot
Salvatore Schillaci of Italy won the Golden Boot at the 1990 FIFA World Cup.

Enter a topic : Cricket world cup
Generating the embedding for 'Cricket world cup' and collecting 100 articles related to it from ClickHouse...

Enter your question : Which country has hosted the world cup most times
England and Wales have hosted the Cricket World Cup the most times, with the tournament being held in these countries five times - in 1975, 1979, 1983, 1999, and 2019.

$
코드:
import sys
import time
from openai import OpenAI
import clickhouse_connect

ch_client = clickhouse_connect.get_client(compress=False) # ClickHouse 자격 증명을 여기에 전달하세요
openai_client = OpenAI() # OPENAI_API_KEY 환경 변수를 설정하세요

def get_embedding(text, model):
  text = text.replace("\n", " ")
  return openai_client.embeddings.create(input = [text], model=model, dimensions=1536).data[0].embedding

while True:
    # 사용자로부터 관심 주제를 입력받습니다
    print("Enter a topic : ", end="", flush=True)
    input_query = sys.stdin.readline()
    input_query = input_query.rstrip()

    # 검색 주제에 대한 임베딩 벡터를 생성하고 ClickHouse에 쿼리합니다
    print("Generating the embedding for '" + input_query + "' and collecting 100 articles related to it from ClickHouse...");
    embedding = get_embedding(input_query,
                              model='text-embedding-3-large')

    params = {'v1':embedding, 'v2':100}
    result = ch_client.query("SELECT id,title,text FROM dbpedia ORDER BY cosineDistance(vector, %(v1)s) LIMIT %(v2)s", parameters=params)

    # 일치하는 모든 문서/기사를 수집합니다
    results = ""
    for row in result.result_rows:
        results = results + row[2]

    print("\nEnter your question : ", end="", flush=True)
    question = sys.stdin.readline();

    # OpenAI Chat API용 프롬프트
    query = f"""Use the below content to answer the subsequent question. If the answer cannot be found, write "I don't know."

Content:
\"\"\"
{results}
\"\"\"

Question: {question}"""

    GPT_MODEL = "gpt-3.5-turbo"
    response = openai_client.chat.completions.create(
        messages=[
        {'role': 'system', 'content': "You answer questions about {input_query}."},
        {'role': 'user', 'content': query},
       ],
       model=GPT_MODEL,
       temperature=0,
    )

    # 질문에 대한 답변을 출력합니다!
    print(response.choices[0].message.content)
    print("\n")
마지막 수정일 2026년 6월 10일