호돌찌의 AI 연구소
article thumbnail

이전 글까지 Milvus에서 데이터 insert부터 검색까지 다루어보았습니다.

2023.10.10 - [AI/Vector Database] - [Vector DB] 3. Milvus 튜토리얼 (1) - 설치, 변수 정의, Collection 생성하기

2023.10.12 - [AI/Vector Database] - [Vector DB] 4. Milvus 튜토리얼 (2) - Collection에 데이터 insert 하기

2023.10.13 - [AI/Vector Database] - [Vector DB] 5. Milvus 튜토리얼 (3) - Query 임베딩 생성 & Vector DB 검색하기

 

이번 글에서는 upsert를 해보는 과정을 설명하고자 합니다. 이전글의 코드들과 이어서 설명하기 때문에 흐름을 보면 좋겠습니다. 사전에 collection이 구성이 되어있다고 가정하고 시작하겠습니다.

 

Upsert란?


DB에서 "DML"(데이터 조작어, Data Manipulation Language)에는 Select, Insert, Update, Delete 4개가 존재합니다. Upsert는 "update"와 "insert"의 합성어이며 DB에서 특정 작업을 뜻합니다. Upsert는 특정 레코드를 데이터베이스에 삽입하려 할 때 해당 레코드가 이미 존재하는 경우에는 그 레코드를 업데이트하고, 존재하지 않는 경우에는 새로운 레코드를 삽입하는 동작을 말합니다. pk가 중복 등으로 Insert 하려는 값이 존재하는 경우 해당 값을 update 하는 쿼리라고 생각하시면 됩니다. 

Milvus에서는 Upsert가 맥락은 비슷하지만 Insert와 Delete 작업의 조합입니다. 매핑된 인덱싱을 작업 실행 중에 데이터를 삭제하는 작업을 포함하기 때문입니다. Vector DB에서는 Upsert가 이 방식을 적용할 수 있으며 공식 문서에서 참고할 수 있습니다.

참고로 Upsert 시 유의사항은 다음과 같습니다.

  • milvus 2.2.x 이하 버전에서는 지원이 되질 않습니다. 
  • Upsert 할 데이터의 유형은 당연히 사전에 정의된 Collection의 스키마와 일치해야합니다. 

 

Upsert Test 하기 위한 데이터 준비


이전 글에서 튜토리얼 예제에 이어서 진행할 예정입니다. 새로운 데이터를 부르고 간단한 전처리를 수행합니다.

def clean(text:str):
    # https://github.com/YongWookHa/kor-text-preprocess/blob/master/src/clean.py
    not_used = re.compile('[^ .?!/@$%~|0-9|ㄱ-ㅣ가-힣]+')
    dup_space = re.compile('[ \t]+')  # white space duplicate
    dup_stop = re.compile('[\.]+')  # full stop duplicate

    cleaned = not_used.sub('', text.strip()) 
    cleaned = dup_space.sub(' ', cleaned)
    cleaned = dup_stop.sub('.', cleaned) 

    return cleaned

df_test = pd.read_csv("BalancedNewsCorpus_test.csv")
df_test['News'] = df_test['News'].apply(lambda text: text.replace('<p>', '\n').replace('</p>', '\n'))
df_test['News'] = df_test['News'].apply(clean)

 

여기서 df_test를 2개로 분할합니다. 900개는 Upsert를 수행할 예정이고, 나머지 900개중에서 하나를 쿼리로 잡아서 새로 Upsert 되는지 확인해보고자 합니다.

from sklearn.model_selection import train_test_split
df_test_upsert, df_test_not_upsert = train_test_split(df_test, 
                                                    test_size=0.5, 
                                                    random_state=42, 
                                                    stratify=df_test['Topic'])

test_idx = 123
query = df_test_not_upsert.iloc[test_idx]['News']
query_embedding = embedder.encode(query, show_progress_bar=False, normalize_embeddings=True)

print(query)

 

테스트하고자 하는 과거 뉴스 쿼리는 다음과 같습니다. 한 줄 요약하 "국립김치연구소가 2010년 광주에 설립될 예정이며, 총리가 광주시의 건의를 적극 검토"하겠다는 내용입니다. 사전에 Insert 되어있는 vector DB는 김치 관련된 내용은 없습니다. 쿼리로 사용한 해당 뉴스는 참고 정치 관련 뉴스입니다. 실제로 Upsert 된 내용이 정치와 유관한 쿼리가 나타나면 어느 정도 성공입니다.


Query 뉴스 
국립김치연구소 광주 설립 청신호 한승수 총리 광주시 건의 적극 검토 지시 가뭄대책비 2천450억 원 긴급 지원 요청 오는 2010년 완공 예정인 국립김치연구소의 광주 설립에 파란불이 켜졌다. 한승수 국무총리가 김치산업 활성화 등 관련 인프라를 감안해 적극적인 검토를 약속했기 때문이다.  (중략)  한편 한 총리는 이날 정부 관계부처 합동으로 진행된 신성장동력 호남권 설명회에서 녹색성장의 단기적 핵심은 4대 강 살리기이고 질적 경제성장의 중심에는 기술혁신을 위한 신성장동력이 있다며 향후 50년 국가발전의 모델이 될 녹색성장에 지자체와 공무원들이 적극 동참해 달라고 강조했다.

 

Upsert 


Upsert를 수행하는 방법은 collection.upsert()를 수행하면 됩니다. Insert와 같은 방식입니다. flush() 후 num_entities를 하면 기존 9000개에서 추가된 900개가 반영되어 9900개가 나타남을 확인이 가능했습니다.

texts_test_upsert = df_test_upsert['News'].tolist()
texts_test = df_test_not_upsert['News'].tolist()

embeddings_test_upsert = embedder.encode(texts_test_upsert, 
                    show_progress_bar=True, 
                    normalize_embeddings=True)
embeddings_test_not_upsert = embedder.encode(texts_test, 
                    show_progress_bar=True, 
                    normalize_embeddings=True)
                    

dataset = CustomDataset(df_test_upsert, embeddings_test_upsert, field2column, EMBEDDING_FIELD_NAME)

for data in tqdm(iter(dataset), total=len(dataset)):
    collection.upsert(data)
    
for index in range(len(dataset)):
    item = dataset[index]
    print([_ for _ in item.keys()])
    print()
    print([type(_) for _ in item.values()])
    break
    
collection.flush()
collection.num_entities

 

Upsert 된 내용들이 잘 나타나는지 확인하기


이제 쿼리와 유사한 뉴스 내용들이 나오는지 확인해 보겠습니다. 이전과 마찬가지로 collection.search()를 이용하여 검색을 수행합니다. 

result_after_upsert = collection.search(
        data = [query_embedding],
        anns_field = EMBEDDING_FIELD_NAME,
        param = index_params,
        limit = num_news,
        output_fields = ['filename','date', 'NewsPaper', 'Topic', 'News']
    )

result_list_after_upsert = []
for hits in result_after_upsert: 
    for hit in hits:
        result_list_after_upsert.append(hit.to_dict())

 

top3, 4위 뉴스 내용이 추가됨을 확인할 수 있었습니다. Top3 뉴스는 "나주예총 9대 회장 취임한 김관선은 나주의 대표 문화브랜드를 발굴, 조성하여 문화예술의 질적 향상을 도모"한다는 내용입니다. Top4 뉴스는 " 전남창조경제혁신센터가 내년 3월 여수에 개소 예정이며, 이와 관련한 협의와 준비 작업이 진행 중"인 뉴스입니다. 


Top 3 뉴스 (L2 0.63077)
지역 대표 문화브랜드 발굴조성 앞장 문화융성시대를 맞아 나주의 대표 문화브랜드를 발굴하고 조성해 발전시키고 이를 통해 시민화합과 문화예술의 질적 향상을 도모하는데 앞장서겠습니다. 최근 나주예총 9대 회장에 취임한 김관선 광주매일신문 부국장은 취임 포부를 이같이 밝히면서 나주지역에 훌륭하신 많은 선배 예술인들이 계신데도 불구하고 부족한 제가 나주예총의 책임을 맡게 돼 무한한 책임감을 느낀다고 덧붙였다. (중략) 강인규 나주시장은 축사에서 시민들의 생활예술활동이 갈수록 활발해지고 빛가람 혁신도시 활성화로 더욱 다양한 문화욕구를 수용해야 하며 문화가 지역행복지수의 중요한 척도가 되는 시대에서 나주예총의 역할은 매우 중요한 의미와 가치를 지닌다며 김 회장 취임 축하와 함께 왕성한 활동을 기대했다.


Top 4 뉴스 (L2 0.634915)
전남창조혁신센터 내년 3월 여수 개소 예정 정몽구 현대차그룹 회장의 광주 방문으로 광주창조경제혁신센터 추진이 속도를 내고 있는 가운데 그룹이 파트너로 참여하고 있는 전남창조경제혁신센터 추진 상황에도 관심이 모아지고 있다. (중략)  전남도는 가 에너지 분야에 초점을 맞추고 있는 만큼 협력사업도 이에 맞춰 준비한다는 원칙을 세우고 협의를 벌이고 있다. 이런 상황에서 전남도가 내년도 정부 예산에서 기능성 화학소재 클러스터 구축 국비 예산 25억 원을 확보함에 따라 관련 사업 추진에도 탄력을 붙을 전망이다.

 

뉴스 내용을 살펴보면 정치 관련 뉴스까지는 정확히 나옵니다. 쿼리에서는 광주 지역이 언급이 되어있었습니다. Top3과 4에서 나주와 여수 지역이 언급됩니다. 저도 튜토리얼 예제 데이터를 아무거나 선정하고 샘플 데이터 또한 랜덤으로 선정했습니다. 근데 전라남도 지역 내용이 search 되는 것 보니 신기합니다. 겹쳐지는 단어들은 없지만 정치적인 뉴스와 무언가 예산이야기, 전라남도 부분 발전을 위한 이야기들이 상위권에 잡히는 것을 보아 나름대로 Semantic Search가 되는 것을 알 수 있었습니다.

 

조금 더 정밀하게 살펴보기 위해 Top1, 2 뉴스를 살펴보겠습니다. 이 2개 뉴스는 upsert 된 내용이 아닌, 기존 9000개 뉴스에서 검색이 되었는데 한번 살펴보겠습니다. 


Top 1 뉴스 (거리 0.57397)
호남고속철 무안공항 경유 확정 올해는 정부의 국정과제에 518 정신의 헌법 전문 수록이 선정되고 수년 동안 제동이 걸렸던 호남고속철의 무안공항 경유 문제가 새 정부 출범과 함께 해결되는 등 광주전남지역에 반가운 소식이 많았다.  (중략) 전남도는 10년 연속 노사민정 협력 최우수 자치단체로 선정되는 등 56개 분야에서 정부 평가 수상실적을 냈고 인센티브로 410억여원을 받았다고 밝혔다. 농어업 기반 확충을 통한 경쟁력 강화도 성과로 꼽았다. 나주에 호남권 친환경농산물 종합물류센터를 개장하고 전남산 친환경 농산물의 학교급식을 전국으로 확대하고 목포에 국내 최대 규모 친환경 수산종합단지 착공과 함께 수산식품수출단지 조성 사업에 대한 국비를 확보했다. 전남도는 다만 전남 인구가 지난 3월 190만 명 아래로 내려가고 청렴도가 지난해보다 4단계 올랐지만 도민 기대에 부응하지 못했다는 것을 아쉬운 점으로 평가했다. 이 권한대행은 올해는 비록 힘든 일은 많았지만 도정에 적잖은 변화를 가져옴으로써 할 수 있다는 자신감을 얻은 한 해였다며 앞으로도 도민을 믿고 지역 현안을 슬기롭게 헤쳐가면서 전남의 미래를 위한 일들을 준비하는데 최선을 다하겠다고 말했다.


Top 2 뉴스 (L2 0.62869)
한국농어촌공사 광주.전남 공동혁신도시에 신청사 착공 한국농어촌공사는 본사이전을 위한 신사옥 착공식을 8일 광주. 전남공동혁신도시인 나주시 금천에서 열었다. 이날 착공식에는 김황식 국무총리의 축하메시지가 전달됐고 서규용 농림수산식품부 장관 강운태 광주광역시장 박준영 전라남도지사 박재순 한국농어촌공사사장 농어업인 단체 지역주민 등 800여 명이 참석했다. (중략) 15개 기관이 이전하는 광주. 전남 공동혁신도시는 면적이 7327천으로 국내 두 번째 규모의 중앙호수공원 20만을 조성하여 인구 5만 명이 사는 주거. 문화. 교육. 의료. 산업기능을 갖춘 자족형 독립신도시로 건설되고 있다. 올 1월 말까지 부지조성률은 92.2%에 이르고 이전기관의 신축부지는 공사가 완료되어 혁신도시 건설이 순조롭게 정상정으로 진행되고 있다. 또한 광주. 전남 혁신도시 내 이전기관 종사자의 정주여건 마련을 위해 올해까지 공동주택 6200 가구를 우선 공급하고 공동주택 입주시기에 맞춰 유치원 1개소 초등학교 1개교 중학교 1개교 고등학교 1개교도 개교할 계획이다.

 

금액과 숫자관련된 내용들이 더 많이 잡히는 느낌이 드는 것 같습니다. Top 1,2 또한 정치 카테고리 뉴스는 물론이고 전라남도 지역 뉴스들이 잡히는 것을 알 수 있었습니다. 임베딩 모델이 바라보는 뷰가 얼추 비슷함을 확인이 가능한 것 같습니다. 인덱싱과 임베딩 모델이 좋으면 좋은 Semantic 검색이 되는 것을 이번 튜토리얼을 통해 알 수 있었습니다. 더 세밀한 검색이 되려면 뉴스 데이터에 대해서 길이를 EDA하고, 구문을 chunk로 나누어 임베딩을 하거나 더 고도화해야 할 부분이 많습니다. 또한 더 많은 뉴스 데이터를 수집 및 임베딩하여 vector DB에 Insert 한다면 유사 뉴스를 찾을 수 있을 것입니다.

 

여기까지 내용은 튜토리얼 수준으로 간단하게 다뤄볼 수 있습니다. 다음 글에는 Milvus에서 지원하는 인덱스들에 대해서 이야길 나눠보겠습니다. 긴 글 읽어주셔서 감사합니다 :)

 


아래는 블로그 주인장의 토스 익명 후원 링크입니다. 글이 도움 되거나 흡족스러웠다면 후원해 주시면 감사하겠습니다.

https://toss.me/hotorch

 

hotorch님에게 보내주세요

토스아이디로 안전하게 익명 송금하세요.

toss.me

 

 

profile

호돌찌의 AI 연구소

@hotorch's AI Labs

포스팅이 도움이 되셨다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!