ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Faiss] 파이스를 이용한 문서 검색 시스템 만들기
    Python/자연어처리 2024. 6. 28. 12:57
    반응형

    Faiss를 이용한 문서 검색 시스템 만들기


    Faiss(Facebook AI Similarity Search)란 데이터의 유사도 검색 및 벡터 클러스터링을 위한 라이브러리라고 합니다. 간단히 말해, 자연어 유사도를 기반으로 문서 검색을 구현할 수 있다는 말이지요. 유사도 검색이라고 하면, 예전에도 이와 같은 기능을 구현하는 라이브러리가 없었던건 아니지만, 파이스를 이용할 경우 성능이 제법 좋고, 옵션을 자유자재로 설정할 수 있기 때문에 문서 검색 시스템을 구현할 때 이만한 선택이 없어 보입니다.

     

    프로그램 구성


    이번에는 파이썬(Python)을 이용한 문서 검색 시스템을 만들어 보겠습니다, 구현 방법은 간단한데요, 원하는 문서를 읽은 뒤, 적당한 크기로 자르고 임베딩을 한 다음 Faiss 데이터베이스를 만들어 줍니다. 다음에는 자연어를 이용해 해당 DB를 쿼리하면 끝이지요.

     

    이 프로그램을 만들기 위해서 파이썬은 기본이고, 🦜️🔗랭체인(Langchain) 커뮤니티와 파이스를 설치해 주셔야 합니다. 모두 pip 패키지 관리자를 이용해 설치할 수 있으며, 내 컴퓨터의 GPU 상태에 따라 faiss-cpu 또는 faiss-gpu 중 하나를 설치해 주시면 됩니다.

     

    검색용 문서


    이번 파이썬 문서 검색 시스템에서 검색 대상으로 삼을 문서는 mdn web docs에서 제공하는 HTML 기본 한국어 문서입니다. mdn 깃허브에 방문하면 해당 문서를 마크다운 파일로 다운로드할 수 있는데, 저는 이 파일에서 별도 편집은 거치지 않고 그대로 이용했습니다.

     

    이제, 이 문서를 300자 단위로 자르고, 임베딩을 통해 데이터를 벡터화한 다음 이를 Faiss 데이터베이스로 만드는 작업입니다. 아래 코드를 참고해 주세요.

     

    # Import Package
    from langchain_community.document_loaders import TextLoader
    from langchain_community.vectorstores import FAISS
    from langchain.embeddings import HuggingFaceBgeEmbeddings
    from langchain_text_splitters import CharacterTextSplitter
    from IPython.display import display_markdown
    
    embeddings = HuggingFaceBgeEmbeddings()

     

    # Load Data
    documents = TextLoader("./html_basics.md", encoding='utf8').load()
    
    # Text Split
    text_splitter = CharacterTextSplitter(chunk_size=300, chunk_overlap=0)
    docs = text_splitter.split_documents(documents)
    
    # Create DB
    db = FAISS.from_documents(docs, embeddings)
    Created a chunk of size 438, which is longer than the specified 300
    Created a chunk of size 1402, which is longer than the specified 300
    Created a chunk of size 330, which is longer than the specified 300

     

    Faiss 데이터 쿼리


    이번에는 Faiss를 이용해 만든 데이터베이스를 쿼리해 보도록 하겠습니다. 해당 작업은 FAISS.similarity_search() 함수를 이용해서 수행할 수 있는데요, 이 때 쿼리 내용은 일반적인 자연어를 그대로 입력해 주시면 됩니다. 예를 들어, 해당 문서에서 HTML의 정의를 알고 싶다면 'HTML은 무엇일까' 라는 말을 적으면 되겠지요.

     

    # Query
    query = "HTML은 무엇일까"
    answer = db.similarity_search(query)
    display_markdown(answer[0].page_content, raw=True)

    HTML은 콘텐츠의 구조를 정의하는 마크업 언어 입니다. HTML은 콘텐츠의 서로 다른 부분들을 씌우거나 감싸서 다른 형식으로 보이게하거나 특정한 방식으로 동작하도록 하는 일련의 {{Glossary("element", "요소")}} 로 이루어져 있습니다. {{Glossary("tag", "태그")}}로 감싸는 것으로 단어나 이미지를 다른 어딘가로 하이퍼링크하거나 단어들을 이탤릭체로 표시하고 글씨체를 크게 또는 작게 만드는 등의 일을 할 수 있습니다. 아래에 나오는 줄의 내용과 같이 예를 들 수 있습니다.

     

    쿼리 결과 유사도 확인하기


    만약, 해당 쿼리 결과의 유사도가 궁금하거나, 2순위 이하의 결과가 궁금하다면 FAISS.similarity_search_with_score() 함수를 이용해 보시는걸 추천드립니다. 해당 결과는 유사도 점수를 기반으로 상위 몇 가지의 답변을 리스트로 리턴해 주기 때문에, 원하는 답변을 선택하거나 어느정도 이상의 유사도를 걸러내기 위해 추가 작업을 할 때 도움이 됩니다.

     

    db.similarity_search_with_score(query)
    [(Document(page_content='HTML은 콘텐츠의 구조를 정의하는 _마크업 언어_ 입니다. HTML은 콘텐츠의 서로 다른 부분들을 씌우거나 감싸서 다른 형식으로 보이게하거나 특정한 방식으로 동작하도록 하는 일련의 **{{Glossary("element", "요소")}}** 로 이루어져 있습니다. {{Glossary("tag", "태그")}}로 감싸는 것으로 단어나 이미지를 다른 어딘가로 하이퍼링크하거나 단어들을 이탤릭체로 표시하고 글씨체를 크게 또는 작게 만드는 등의 일을 할 수 있습니다. 아래에 나오는 줄의 내용과 같이 예를 들 수 있습니다.', metadata={'source': './html_basics.md'}),
      0.16946973),
     (Document(page_content='여기서 우리는 HTML 맛보기를 하였습니다. 더 알아보기 위해, [HTML 배우기](/ko/docs/Learn/HTML) 페이지로 가보세요.\n\n{{PreviousMenuNext("Learn/Getting_started_with_the_web/Dealing_with_files", "Learn/Getting_started_with_the_web/CSS_basics", "Learn/Getting_started_with_the_web")}}', metadata={'source': './html_basics.md'}),
      0.1735438),
     (Document(page_content='많은 웹의 내용은 목록이기 때문에, HTML은 이것을 위한 특별한 요소를 가지고 있습니다. 목록을 나타내는 것은 항상 최소 두 개의 요소로 구성됩니다. 가장 일반적인 목록의 종류는 순서가 있는 것과 순서 없는 것이 있습니다.', metadata={'source': './html_basics.md'}),
      0.17826173),
     (Document(page_content='### 문단\n\n위에서 설명했듯이, {{htmlelement("p")}} 요소는 문자의 문단을 포함하기 위한 것입니다. 일반적인 문자 내용을 나타낼 때 많이 사용하게 될 것입니다.\n\n```html\n<p>This is a single paragraph</p>\n```', metadata={'source': './html_basics.md'}),
      0.17929386)]
    반응형

    댓글

문의: jwkang3929@naver.com