Elasticsearch의 스토어 임베딩

Elasticsearch는 벡터 저장 및 검색을 완벽하게 지원하므로 임베딩 작업에 이상적인 데이터베이스입니다.

필드 유형

이 튜토리얼의 전체 텍스트 검색 장에서는 여러 필드가 있는 인덱스를 만드는 방법을 배웠습니다. 그 당시에는 Elasticsearch가 대부분의 경우 데이터 자체를 기반으로 각 필드에 사용할 최적의 유형을 자동으로 결정할 수 있다고 언급했습니다. Elasticsearch 8.11은 일부 벡터 유형을 자동으로 매핑할 수 있지만, 이 장에서는 이 유형을 명시적으로 정의하여 Elasticsearch의 유형 매핑에 대해 자세히 알아볼 수 있는 기회를 제공합니다.

유형 매핑 검색

인덱스의 각 필드와 관련된 유형은 매핑이라는 프로세스에서 결정되며, 매핑은 동적이거나 명시적일 수 있습니다. 이 튜토리얼의 전체 텍스트 검색 부분에서 생성된 매핑은 모두 Elasticsearch에서 동적으로 생성되었습니다.

Elasticsearch 클라이언트는 주어진 인덱스에 대해 유효한 유형 매핑을 반환하는 get_mapping 메서드를 제공합니다. 이러한 매핑을 직접 살펴보고 싶다면 Python 셸을 시작하고 다음 코드를 입력하세요:

get_mapping() 메서드의 응답은 인덱스의 모든 필드에 대한 정보가 포함된 사전입니다. 편의를 위해 아래는 튜토리얼의 전체 텍스트 검색 섹션에서 만든 my_documents 색인에 대한 이 정보를 멋진 형식의 구조로 정리한 것입니다:

이를 통해 created_onupdated_at 필드는 date 로 자동 입력된 반면 다른 모든 필드는 text 로 입력되었음을 알 수 있습니다. 유형을 결정하려고 할 때 Elasticsearch는 먼저 데이터 유형을 확인하여 숫자, 부울 및 객체 유형을 필드에 할당하는 데 도움을 줍니다. 필드 데이터가 문자열인 경우 데이터가 날짜 패턴과 일치하는지 확인합니다. 원하는 경우 패턴을 기반으로 한 문자열에 대한 검색을 숫자에 대해서도 활성화할 수 있습니다.

텍스트 필드에는 keyword 항목이 있는 fields 정의가 있습니다. 이를 하위 필드라고 하며, 적절한 경우 사용할 수 있는 대체 또는 보조 유형입니다. Elasticsearch에서 동적으로 입력된 text 필드에는 keyword 하위 필드가 지정됩니다. 이미 category.keyword 하위 필드를 사용하여 특정 카테고리에 대한 정확한 검색을 수행했습니다. 하위 필드가 추가되지 않도록 하려면 text 또는 keyword 의 명시적 매핑을 지정하면 이 유형이 기본 유형이자 유일한 유형이 됩니다.

인덱스에 벡터 필드 추가하기

각 문서에 대한 임베딩이 저장될 새 필드를 인덱스에 추가해 보겠습니다.

명시적 매핑의 구조는 Elasticsearch 클라이언트의 get_mapping() 메서드에서 반환된 응답의 mappings 키와 일치합니다. 매핑에 포함되지 않은 필드는 이전처럼 계속 동적으로 입력되므로 명시적으로 입력해야 하는 필드만 지정하면 됩니다.

아래에서 Search 클래스의 create_index() 메서드의 새 버전을 볼 수 있으며, embedding 이라는 명시적으로 입력된 필드가 추가되었습니다. search.py에서 이 메서드를 대체합니다:

보시다시피 embedding 필드에는 임베딩을 저장할 때 적절한 유형인 dense_vector 유형이 지정되어 있습니다. 나중에 다른 유형의 시맨틱 검색 애플리케이션에 유용한 또 다른 유형의 벡터인 sparse_vector 에 대해 배우게 됩니다.

dense_vector 유형은 몇 가지 매개 변수를 허용하며, 모두 선택 사항입니다.

  • dims저장할 벡터의 크기입니다. 버전 8.11부터는 첫 번째 문서가 삽입될 때 치수가 자동으로 할당됩니다.
  • indexTrue 로 설정하여 검색을 위해 벡터를 색인화해야 함을 나타내야 합니다. 기본값입니다.
  • similarity벡터를 비교할 때 사용할 거리 함수입니다. 가장 일반적인 두 가지는 dot_productcosine 입니다. 도트 곱이 더 효율적이지만 벡터를 정규화해야 합니다. 기본값은 cosine 입니다.

문서에 임베딩 추가하기

이전 섹션에서는 SentenceTransformers 프레임워크와 all-MiniLM-L6-v2 모델을 사용하여 임베딩을 생성하는 방법을 배웠습니다. 이제 모델을 애플리케이션에 통합할 차례입니다.

우선, Search 클래스 생성자에서 모델을 인스턴스화할 수 있습니다:

이 튜토리얼의 전체 텍스트 검색 부분에서 기억했듯이 Search 클래스에는 각각 단일 문서와 여러 문서를 색인에 삽입하는 insert_document()insert_documents() 메서드가 있습니다. 이제 이 두 가지 방법은 각 문서에 맞는 해당 임베딩을 생성해야 합니다.

다음 코드 블록에는 임베딩을 반환하는 새로운 get_embedding() 헬퍼 메서드와 함께 이 두 메서드의 새 버전이 나와 있습니다.

수정된 메서드는 삽입할 문서에 새 embedding 필드를 추가합니다. 임베딩은 각 문서의 summary 필드에서 생성됩니다. 일반적으로 임베딩은 문장이나 짧은 단락에서 생성되므로 이 경우 요약이 사용하기에 이상적인 필드입니다. 다른 옵션으로는 문서 제목이 포함된 name 필드 또는 문서의 body 에서 처음 몇 문장을 입력할 수도 있었을 것입니다.

이러한 변경 사항을 적용하면 색인을 재구축하여 각 문서에 대한 임베딩을 저장할 수 있습니다. 인덱스를 다시 작성하려면 이 명령을 사용합니다:

참고로 flask reindex 명령은 app.py의 reindex() 함수에 구현되어 있습니다. Search 클래스의 reindex() 메서드를 호출하면 create_index() 를 호출한 다음 data.json 파일의 모든 데이터를 insert_documents() 로 전달합니다.

최첨단 검색 환경을 구축할 준비가 되셨나요?

충분히 고급화된 검색은 한 사람의 노력만으로는 달성할 수 없습니다. Elasticsearch는 여러분과 마찬가지로 검색에 대한 열정을 가진 데이터 과학자, ML 운영팀, 엔지니어 등 많은 사람들이 지원합니다. 서로 연결하고 협력하여 원하는 결과를 얻을 수 있는 마법 같은 검색 환경을 구축해 보세요.

직접 사용해 보세요