[RAG] RAG 검색기 (2) Keyword Search

Hunie_07·2025년 4월 14일
0

Langchain

목록 보기
27/35

(1) Semantic Search 에서 이어집니다.

📌 RAG 검색기

2️⃣ Keyword Search (키워드 검색)

  • 키워드 검색BM25 등 전통적 알고리즘 기반의 단어 매칭 방식

  • 정확한 단어/구문 매칭에 강점이 있으며 계산 효율성이 우수

  • 직접적인 키워드 검색에는 효과적이나 의미적 연관성 파악에는 제한적

  • 구현이 단순하고 처리 속도가 빠르다는 장점

  • 정확한 키워드 매칭이 필요한 경우에 적합하나 의미론적 검색의 보완이 필요


1. BM25 검색기

  • BM25: TF-IDF (Term Frequency-Inverse Document Frequency)의 확장된 버전

  • pip install rank_bm25 / poetry add rank_bm25


저장소의 문서 객체 로드

# 벡터 저장소에 저정한 문서 객체를 로드하여 확인
chroma_db.get().keys()

- 출력

dict_keys(['ids', 'embeddings', 'documents', 'uris', 'data', 'metadatas', 'included'])
# BM25 검색기 생성을 위해 문서 객체를 로드
documents = chroma_db.get()["documents"]
metadatas = chroma_db.get()["metadatas"]

# Document 객체로 변환
from langchain_core.documents import Document
docs = [Document(page_content=content, metadata=metadata) for content, metadata in zip(documents, metadatas)]

print("문서의 수:" , len(docs))
print("=" * 200)
for doc in docs[:3]:
    print(f"{doc.page_content} [출처: {doc.metadata['source']}]")
    print("-" * 200)

- 출력

문서의 수: 39
========================================================================================================================================================================================================
[출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
Rivian Automotive, Inc.2009년에 설립된 미국의 전기 자동차 제조업체, 자동차 기술 및 야외 레크리에이션 회사입니다.

**주요 정보:** [출처: data\리비안_KR.md]
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[출처] 이 문서는 리비안에 대한 문서입다.
----------------------------------
- **회사 유형:** 상장
...

BM25 검색기 생성

  • 검색 문서 수 Default (k = 4)
  • 리비안 관련 쿼리를 사용했으나 검색 결과에 테슬라가 포함된 모습 (키워드 검색의 한계)
from langchain_community.retrievers import BM25Retriever

# BM25 검색기 생성
bm25_retriever = BM25Retriever.from_documents(docs)

# BM25 검색기를 사용하여 검색
query = "리비안은 언제 사업을 시작했나요?"

retrieved_docs = bm25_retriever.invoke(query)

for doc in retrieved_docs:
    print(f"- {doc.page_content} [출처: {doc.metadata['source']}]")
    print("="*200)

- 출력

- [출처] 이 문서는 테슬라에 대한 문서입니다.
----------------------------------
## 파트너

Tesla는 Panasonic과 파트너십을 맺고 있으며 리튬 공급에 대한 장기 계약을 맺고 있습니다. 이전 파트너로는 Daimler와 Toyota가 있습니다.

## 소송 및 논란

Tesla는 성희롱, 노동 분쟁, 사기 혐의, 대리점 분쟁, 지적 재산권, 환경 위반, 재산 피해, 인종 차별, COVID-19 팬데믹 대응 및 수리 권리와 관련된 소송 및 논란에 직면했습니다.

## 비판

Tesla는 데이터 개인 정보 보호, 공매도자, 지연, 차량 제품 문제, 화재, Autopilot 충돌, 소프트웨어 해킹, 가상 제동 및 주행 거리 성능과 관련된 비판에 직면했습니다. [출처: data\테슬라_KR.md]
========================================================================================================================================================================================================
- [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
**시설**

- **Irvine, California:** 차량 엔지니어링 및 설계에 중점을 둔 본사.
...

BM25 점수 확인

  • BM25 점수가 전부 0점인 모습 (쿼리에 단어가 포함되어 있지 않음)
# BM25 점수를 확인 - 단어가 쿼리에 포함되어 있지 않아 검색 결과가 없음
query = "리비안은 언제 사업을 시작했나요?"
tokenized_query = query.split()
print(tokenized_query)
print("="*200)

# 문서의 BM25 점수 확인
doc_scores = bm25_retriever.vectorizer.get_scores(tokenized_query)

# 문서의 BM25 점수를 내림차순으로 정렬
doc_scores_sorted = sorted(enumerate(doc_scores), key=lambda x: x[1], reverse=True)

# 상위 5개 문서의 인덱스와 점수를 출력
for idx, score in doc_scores_sorted[:5]:
    print(f"[{idx}] {docs[idx].page_content}")
    print(f"BM25 Score: {score}")
    print("-"*200)

- 출력

['리비안은', '언제', '사업을', '시작했나요?']
========================================================================================================================================================================================================
[0] [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
Rivian Automotive, Inc.2009년에 설립된 미국의 전기 자동차 제조업체, 자동차 기술 및 야외 레크리에이션 회사입니다.

**주요 정보:**
BM25 Score: 0.0
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[1] [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
- **회사 유형:** 상장
- **거래소:** NASDAQ: RIVN
- **설립:** 20096, 플로리다 주 록ledge
- **설립자:** R. J. 스캐린지
- **본사:** 미국 캘리포니아 주 어바인
- **서비스 지역:** 북미
- **주요 인물:** R. J. 스캐린지 (CEO)
- **제품:** 전기 자동차, 배터리
- **생산량 (2023):** 57,232- **서비스:** 전기 자동차 충전, 자동차 보험
- **수익 (2023):** 443천만 미국 달러
- **순이익 (2023):** -54억 미국 달러
- **총 자산 (2023):** 168억 미국 달러
BM25 Score: 0.0
...

BM25 검색 재시도

# 같은 의미를 갖는 쿼리로 변경하여 다시 검색 
query = "리비안이 설립된 연도는?"

retrieved_docs = bm25_retriever.invoke(query)

for doc in retrieved_docs:
    print(f"- {doc.page_content} [출처: {doc.metadata['source']}]")
    print("="*200)

- 출력

- [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
Rivian Automotive, Inc.2009년에 설립된 미국의 전기 자동차 제조업체, 자동차 기술 및 야외 레크리에이션 회사입니다.

**주요 정보:** [출처: data\리비안_KR.md]
========================================================================================================================================================================================================
- [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
**시설**

- **Irvine, California:** 차량 엔지니어링 및 설계에 중점을 둔 본사.
- **Normal, Illinois:** 차량 부품을 생산하고 조립을 수행하는 제조 공장.
- **Plymouth, Michigan:** 차량 엔지니어링, 프로토타입 제작, 공급망 및 회계에 중점을 둡니다.
- **Palo Alto, California:** 소프트웨어 개발 및 엔지니어링에 중점을 둡니다.
- Carson, California 및 Woking, England에 추가 사무실이 있습니다.
- 애틀랜타 동쪽에 있는 새로운 50억 달러 규모의 배터리 및 조립 공장은 보류 중입니다.

**재정**

Rivian의 재무 성과는 상당한 수익 성장과 상당한 순손실로 특징지어집니다. [출처: data\리비안_KR.md]
...

BM25 점수 재확인

  • '설립된' 이라는 단어가 쿼리에 포함되어 있어 검색 결과 존재
# BM25 점수를 확인 - "설립된" 라는 단어가 쿼리에 포함되어 있어 검색 결과가 있음
query = "리비안이 설립된 연도는?"
tokenized_query = query.split()
print(tokenized_query)
print("="*200)

# 문서의 BM25 점수 확인
doc_scores = bm25_retriever.vectorizer.get_scores(tokenized_query)

# 문서의 BM25 점수를 내림차순으로 정렬
doc_scores_sorted = sorted(enumerate(doc_scores), key=lambda x: x[1], reverse=True)

# 상위 5개 문서의 인덱스와 점수를 출력
for idx, score in doc_scores_sorted[:5]:
    print(f"[{idx}] {docs[idx].page_content}")
    print(f"BM25 Score: {score}")
    print("-"*200)

- 출력

['리비안이', '설립된', '연도는?']
========================================================================================================================================================================================================
[0] [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
Rivian Automotive, Inc.2009년에 설립된 미국의 전기 자동차 제조업체, 자동차 기술 및 야외 레크리에이션 회사입니다.

**주요 정보:**
BM25 Score: 4.606669099813676
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[1] [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
- **회사 유형:** 상장
- **거래소:** NASDAQ: RIVN
- **설립:** 20096, 플로리다 주 록ledge
- **설립자:** R. J. 스캐린지
- **본사:** 미국 캘리포니아 주 어바인
- **서비스 지역:** 북미
- **주요 인물:** R. J. 스캐린지 (CEO)
- **제품:** 전기 자동차, 배터리
- **생산량 (2023):** 57,232- **서비스:** 전기 자동차 충전, 자동차 보험
- **수익 (2023):** 443천만 미국 달러
- **순이익 (2023):** -54억 미국 달러
- **총 자산 (2023):** 168억 미국 달러
BM25 Score: 0.0
...

2. kiwi 한국어 토크나이저

  • Kiwi : 한국어 형태소 분석기 라이브러리

  • pip install kiwipiepy / poetry add kiwipiepy

  • Kiwi Github


형태소 분석

# 한국어 토크나이저를 사용하여 문장을 토큰화
from kiwipiepy import Kiwi

kiwi = Kiwi()

print(kiwi.analyze("리비안은 언제 사업을 시작했나요?"))
print("="*200)
print(kiwi.analyze("리비안이 설립된 연도는?"))

- 출력

[([Token(form='리비아', tag='NNP', start=0, len=3), Token(form='ᆫ', tag='JX', start=2, len=1), Token(form='은', tag='JX', start=3, len=1), Token(form='언제', tag='MAG', start=5, len=2), Token(form='사업', tag='NNG', start=8, len=2), Token(form='을', tag='JKO', start=10, len=1), Token(form='시작', tag='NNG', start=12, len=2), Token(form='하', tag='XSV', start=14, len=1), Token(form='었', tag='EP', start=14, len=1), Token(form='나요', tag='EF', start=15, len=2), Token(form='?', tag='SF', start=17, len=1)], -63.28779602050781)]
========================================================================================================================================================================================================
[([Token(form='리비아', tag='NNP', start=0, len=3), Token(form='ᆫ', tag='JX', start=2, len=1), Token(form='이', tag='JKS', start=3, len=1), Token(form='설립', tag='NNG', start=5, len=2), Token(form='되', tag='XSV', start=7, len=1), Token(form='ᆫ', tag='ETM', start=7, len=1), Token(form='연도', tag='NNG', start=9, len=2), Token(form='는', tag='JX', start=11, len=1), Token(form='?', tag='SF', start=12, len=1)], -57.9343147277832)]

사용자 정의 형태소 추가

  • 기존 형태소 분석이 '리바아' , 'ㄴ' 으로 되던 것이 '리비안' 으로 되는 모습
# 단어를 추가 
kiwi.add_user_word('리비안', 'NNP')  # NNP: 고유명사

print(kiwi.analyze("리비안은 언제 사업을 시작했나요?"))
print("="*200)
print(kiwi.analyze("리비안이 설립된 연도는?"))

- 출력

[([Token(form='리비안', tag='NNP', start=0, len=3), Token(form='은', tag='JX', start=3, len=1), Token(form='언제', tag='MAG', start=5, len=2), Token(form='사업', tag='NNG', start=8, len=2), Token(form='을', tag='JKO', start=10, len=1), Token(form='시작', tag='NNG', start=12, len=2), Token(form='하', tag='XSV', start=14, len=1), Token(form='었', tag='EP', start=14, len=1), Token(form='나요', tag='EF', start=15, len=2), Token(form='?', tag='SF', start=17, len=1)], -43.62751770019531)]
========================================================================================================================================================================================================
[([Token(form='리비안', tag='NNP', start=0, len=3), Token(form='이', tag='JKS', start=3, len=1), Token(form='설립', tag='NNG', start=5, len=2), Token(form='되', tag='XSV', start=7, len=1), Token(form='ᆫ', tag='ETM', start=7, len=1), Token(form='연도', tag='NNG', start=9, len=2), Token(form='는', tag='JX', start=11, len=1), Token(form='?', tag='SF', start=12, len=1)], -37.719932556152344)]

Kiwi 토크나이저 활용한 문장 토큰화 / BM25 검색기 생성

# 한국어 토크나이저를 사용하여 문장을 토큰화하는 함수를 정의 
def bm25_process_func(text, kiwi_model=Kiwi()):
    """
    BM25Retriever에서 사용할 전처리 함수
    한국어 토크나이저를 사용하여 문장을 토큰화
    :param text: 토큰화할 문장
    :param kiwi_model: Kiwi 객체 (from kiwipiepy import Kiwi 사용)
    """

    return [t.form for t in kiwi_model.tokenize(text)]

# BM25Retriever 객체 생성
bm25_retriever = BM25Retriever.from_documents(
    documents=docs,
    preprocess_func=lambda x: bm25_process_func(x, kiwi_model=kiwi),
    )

# 이전에 사용한 검색어를 입력하여 문서를 검색
query = "리비안이 설립된 연도는?"

retrieved_docs = bm25_retriever.invoke(query)

for doc in retrieved_docs:
    print(f"- {doc.page_content} [출처: {doc.metadata['source']}]")
    print("="*200)

- 출력

- [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
Rivian Automotive, Inc.2009년에 설립된 미국의 전기 자동차 제조업체, 자동차 기술 및 야외 레크리에이션 회사입니다.

**주요 정보:** [출처: data\리비안_KR.md]
========================================================================================================================================================================================================
- [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
**EV 충전**

Rivian은 미국과 캐나다 전역에 공공 충전소 네트워크를 개발하고 있습니다. Rivian은 2021년에 Waypoint 충전기 설치를 시작했지만 20234월에 Rivian Adventure Network가 Rivian 이외의 차량에도 개방될 것이라고 발표되었습니다. Rivian은 또한 2025년 모델 연도부터 북미에서 차량에 북미 충전 시스템(NACS)을 채택할 예정입니다.

**시설** [출처: data\리비안_KR.md]
========================================================================================================================================================================================================
- [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
**재정**

Rivian의 재무 성과는 상당한 수익 성장과 상당한 순손실로 특징지어집니다.

| 연도 | 수익 (백만 USD) | 순이익 (백만 USD) | 총 자산 (백만 USD) |
| ---- | --------------- | ----------------- | ------------------ |
| 2020 | 0               | -1,018            | 4,602              |
| 2021 | 55              | -4,688            | 22,294             |
| 2022 | 1,658           | -6,752            | 17,876             |
...

BM25 점수 확인

  • 검색 결과 품질이 향상된 모습
# BM25 점수를 확인
query = "리비안이 설립된 연도는?"

tokenized_query = [t.form for t in kiwi.tokenize(query)]
print(tokenized_query)
print("="*200)

# 문서의 BM25 점수 확인
doc_scores = bm25_retriever.vectorizer.get_scores(tokenized_query)

# 문서의 BM25 점수를 내림차순으로 정렬
doc_scores_sorted = sorted(enumerate(doc_scores), key=lambda x: x[1], reverse=True)

# 상위 5개 문서의 인덱스와 점수를 출력
for idx, score in doc_scores_sorted[:5]:
    print(f"[{idx}] {docs[idx].page_content}")
    print(f"BM25 Score: {score}")
    print("-"*200)

- 출력

['리비안', '이', '설립', '되', 'ᆫ', '연도', '는', '?']
========================================================================================================================================================================================================
[0] [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
Rivian Automotive, Inc.2009년에 설립된 미국의 전기 자동차 제조업체, 자동차 기술 및 야외 레크리에이션 회사입니다.

**주요 정보:**
BM25 Score: 7.793054716561638
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[8] [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
**EV 충전**

Rivian은 미국과 캐나다 전역에 공공 충전소 네트워크를 개발하고 있습니다. Rivian은 2021년에 Waypoint 충전기 설치를 시작했지만 20234월에 Rivian Adventure Network가 Rivian 이외의 차량에도 개방될 것이라고 발표되었습니다. Rivian은 또한 2025년 모델 연도부터 북미에서 차량에 북미 충전 시스템(NACS)을 채택할 예정입니다.

**시설**
BM25 Score: 7.606096389131943
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[10] [출처] 이 문서는 리비안에 대한 문서입니다.
----------------------------------
**재정**

Rivian의 재무 성과는 상당한 수익 성장과 상당한 순손실로 특징지어집니다.

| 연도 | 수익 (백만 USD) | 순이익 (백만 USD) | 총 자산 (백만 USD) |
...

0개의 댓글