호랭이 분석가

[Azure] Cognitive Search Vector Search 벡터 유사도 검색(Python) 본문

Azure/Cognitive Search

[Azure] Cognitive Search Vector Search 벡터 유사도 검색(Python)

데이터호랑이 2023. 7. 11. 23:16
반응형

 

미드저니를 통해 생성한 이미지

 

2023. 07. 11. Azure에서 Cognitive Search에 Vector Search(벡터 검색) 기능을 추가하여 공개하였습니다.

 

 

Vector search - Azure Cognitive Search

Describes concepts, scenarios, and availability of the vector search feature in Cognitive Search.

learn.microsoft.com

 

벡터 검색은 문장을 벡터로 임베딩하여 Cognitive Search의 인덱싱으로 활용하는 기능인데

이를 통해 유사성 검색, 다중 모달 검색, 추천 엔진 또는 RAG(검색 증강 기능)을 구현할 수 있다고 합니다.

자세한 내용은 링크를 통해 확인하시면 됩니다.

 

일단 이번 글에서는 Python으로 문장을 벡터로 임베딩하여 인덱스에 저장하여 사용하는 방법을 확인해 보도록 하겠습니다.

Azure Github의 예시를 보며 진행해보겠습니다.

 

 

GitHub - Azure/cognitive-search-vector-pr: The official private preview documentation and code samples for the Vector search fea

The official private preview documentation and code samples for the Vector search feature in Azure Cognitive Search. - GitHub - Azure/cognitive-search-vector-pr: The official private preview docume...

github.com

 

기존에는 azure-search-documents를 이용하여 인덱스를 생성하고 검색을 하였지만

현재 Vector Search를 파이썬으로 활용하기 위한 라이브러리는 Dev버전을 설치하여 활용해야 합니다.

 

pip uninstall azure-search-documents
pip install azure-search-documents==11.4.0a20230509004

# pip install azure-search-documents==11.4.0a20230509004 -i https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-python/pypi/simple/ --no-cache-dir

pip install openai
pip install python-dotenv

 

우선 기존에 설치하셨던 라이브러리를 삭제하시고 아래의 버전을 설치하여야 합니다.

설치 시 에러가 발생한다면 주석처리된 부분을 사용하시면 설치가 되실 겁니다.

 

그리고 임베딩을 위한 openai 라이브러리 등을 설치합니다.

 

# 라이브러리 셋팅 
import os  
import json  
import openai  
from dotenv import load_dotenv  
from tenacity import retry, wait_random_exponential, stop_after_attempt  
from azure.core.credentials import AzureKeyCredential  
from azure.search.documents import SearchClient  
from azure.search.documents.indexes import SearchIndexClient  
from azure.search.documents.models import Vector  
from azure.search.documents.indexes.models import (  
    SearchIndex,  
    SearchField,  
    SearchFieldDataType,  
    SimpleField,  
    SearchableField,  
    SearchIndex,  
    SemanticConfiguration,  
    PrioritizedFields,  
    SemanticField,  
    SearchField,  
    SemanticSettings,  
    VectorSearch,  
    VectorSearchAlgorithmConfiguration,  
)  
  
# 환경변수 셋팅
load_dotenv('your_location/.env')  
service_endpoint = os.getenv("AZURE_SEARCH_SERVICE_ENDPOINT") 
index_name = os.getenv("AZURE_SEARCH_INDEX_NAME") 
key = os.getenv("AZURE_SEARCH_ADMIN_KEY") 
openai.api_type = "azure"  
openai.api_key = os.getenv("AZURE_OPENAI_API_KEY")  
openai.api_base = os.getenv("AZURE_OPENAI_ENDPOINT")  
openai.api_version = os.getenv("AZURE_OPENAI_API_VERSION")  
credential = AzureKeyCredential(key)

 

.env 파일에 환경 변수(Azure Search API Key 등)를 저장해 놓고 불러오기 위해 dotenv를 사용하였지만

보안에 주의해 주세요.

 

# 위의 깃에 제공된 text-sample.json으로 임베딩을 진행합니다.

with open('../data/text-sample.json', 'r', encoding='utf-8') as file:
    input_data = json.load(file)

@retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
def generate_embeddings(text):
    response = openai.Embedding.create(
        input=text, engine="text-embedding-ada-002")
    embeddings = response['data'][0]['embedding']
    return embeddings

# title, content 필드 임베딩 진행
for item in input_data:
    title = item['title']
    content = item['content']
    title_embeddings = generate_embeddings(title)
    content_embeddings = generate_embeddings(content)
    item['titleVector'] = title_embeddings
    item['contentVector'] = content_embeddings

# 벡터 데이터 저장
with open("../output/docVectors.json", "w") as f:
    json.dump(input_data, f)

 

Azure Github에서 제공한 데이터를 예제로 활용하여 임베딩을 진행합니다.

Azure의 text-embedding-ada-002 모델이 Azure Cognitive Seavice에서 배포된 상태여야 합니다.

 

# 인덱스 생성 및 벡터 검색 설정
index_client = SearchIndexClient(
    endpoint=service_endpoint, credential=credential)
fields = [
    SimpleField(name="id", type=SearchFieldDataType.String, key=True),
    SearchableField(name="title", type=SearchFieldDataType.String,
                    searchable=True),
    SearchableField(name="content", type=SearchFieldDataType.String,
                    searchable=True),
    SearchableField(name="category", type=SearchFieldDataType.String,
                    filterable=True, searchable=True),
    SearchField(name="titleVector", type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
                searchable=True, dimensions=1536, vector_search_configuration="my-vector-config"),
    SearchField(name="contentVector", type=SearchFieldDataType.Collection(SearchFieldDataType.Single),
                searchable=True, dimensions=1536, vector_search_configuration="my-vector-config"),
]

vector_search = VectorSearch(
    algorithm_configurations=[
        VectorSearchAlgorithmConfiguration(
            name="my-vector-config",
            kind="hnsw",
            hnsw_parameters={
                "m": 4,
                "efConstruction": 400,
                "efSearch": 500,
                "metric": "cosine"
            }
        )
    ]
)

semantic_config = SemanticConfiguration(
    name="my-semantic-config",
    prioritized_fields=PrioritizedFields(
        title_field=SemanticField(field_name="title"),
        prioritized_keywords_fields=[SemanticField(field_name="category")],
        prioritized_content_fields=[SemanticField(field_name="content")]
    )
)

# semantic 셋팅을 생성합니다.
semantic_settings = SemanticSettings(configurations=[semantic_config])

# 인덱스 생성 요청
index = SearchIndex(name=index_name, fields=fields,
                    vector_search=vector_search, semantic_settings=semantic_settings)
result = index_client.create_or_update_index(index)
print(f' {result.name} created')

 

기본적인 인덱스 필드와 벡터 검색에 필요한 구성을 세팅하여 인덱스를 생성합니다.

 

# 인덱스에 데이터 업로드
with open('../output/docVectors.json', 'r') as file:  
    documents = json.load(file)  
search_client = SearchClient(endpoint=service_endpoint, index_name=index_name, credential=credential)
result = search_client.upload_documents(documents)  
print(f"Uploaded {len(documents)} documents")

 

데이터를 업로드하였다면 벡터를 이용한 유사 검색을 실행 가능합니다.

 

query = "tools for software development"  
  
search_client = SearchClient(service_endpoint, index_name, AzureKeyCredential(key))  
  
results = search_client.search(  
    search_text=None,  
    vector=Vector(value=generate_embeddings(query), k=3, fields="contentVector"),  
    select=["title", "content", "category"] 
)  
  
for result in results:  
    print(f"Title: {result['title']}")  
    print(f"Score: {result['@search.score']}")  
    print(f"Content: {result['content']}")  
    print(f"Category: {result['category']}\n")
Comments