파트너십
TwelveLabs와 LanceDB를 활용한 시맨틱 비디오 추천 시스템 구축하기

제임스 러
개발자는 태그나 키워드 대신 의미를 바탕으로 콘텐츠를 매칭하는 시맨틱 비디오 추천 시스템을 구축할 수 있습니다. 이 시스템은 Twelve Labs의 Embed API, LanceDB, Geneva를 활용하며, Marengo 2.7을 통한 임베딩 생성, LanceDB를 이용한 벡터 저장, 그리고 Geneva와 Ray를 통한 분산 파이프라인 확장을 모두 아우릅니다.
개발자는 태그나 키워드 대신 의미를 바탕으로 콘텐츠를 매칭하는 시맨틱 비디오 추천 시스템을 구축할 수 있습니다. 이 시스템은 Twelve Labs의 Embed API, LanceDB, Geneva를 활용하며, Marengo 2.7을 통한 임베딩 생성, LanceDB를 이용한 벡터 저장, 그리고 Geneva와 Ray를 통한 분산 파이프라인 확장을 모두 아우릅니다.

In this article
뉴스레터 구독하기
뉴스레터 구독하기
영상 이해 분야의 최신 기술 업데이트, 튜토리얼 및 인사이트를 받아보세요.
영상 이해 분야의 최신 기술 업데이트, 튜토리얼 및 인사이트를 받아보세요.
AI로 영상을 검색하고, 분석하고, 탐색하세요.
2025. 9. 1.
5분
링크 복사하기
참고: 이 포스트의 예제들은 가독성을 위해 간략화된 샘플 코드를 사용합니다. 실행 가능한 노트북에서 전체 코드를 확인하고 싶으시다면, 여기에서 찾으실 수 있습니다.
대부분의 추천 시스템은 제목, 태그, 자막과 같은 메타데이터에 의존합니다. 이 방식도 유효하지만, 비디오 내부에서 실제로 일어나고 있는 일을 놓치게 됩니다. 만약 시스템이 시각 및 청각 콘텐츠 자체를 이해할 수 있다면 어떨까요?
이 포스트에서는 TwelveLabs, LanceDB, 그리고 LanceDB의 피처 엔지니어링 패키지인 Geneva를 사용하여 시맨틱 추천 엔진을 구축하는 방법을 보여드립니다. 이 시나리오에서 TwelveLabs는 비디오의 의미를 나타내는 강력한 멀티모달 임베딩을 제공합니다. LanceDB는 이러한 임베딩을 메타데이터와 함께 저장하고 간단한 Python API를 통해 빠른 벡터 검색을 제공합니다. Geneva는 LanceDB를 기반으로 Ray를 사용하여 클러스터 전체로 파이프라인을 확장하므로, 노트북에서 실행한 것과 완전히 동일한 코드를 수백 대의 머신에서 실행할 수 있습니다.
왜 TwelveLabs, LanceDB, Geneva 조합일까요?
TwelveLabs를 사용하면 내러티브의 흐름, 분위기, 행동을 포착하는 방식으로 비디오를 임베딩할 수 있습니다. "석양 아래에서 파도를 타는 서퍼"와 같은 쿼리는 해당 클립에 그러한 태그가 지정되어 있지 않더라도 일치하는 결과를 반환할 수 있습니다.
LanceDB는 Apache Arrow를 기반으로 구축된 벡터 데이터베이스입니다. 세 가지 주요 강점이 있습니다:
개발자에게 친숙하고 직관적인 간단한 Python API.
외부 서비스 필요 없이 로컬에서 실행되는 임베디드 데이터베이스.
비디오, 이미지, 텍스트, 벡터를 모두 간편하게 저장할 수 있는 네이티브 멀티모달 지원.
Geneva는 LanceDB를 기반으로 구축되어 분산 데이터 처리를 추가합니다. 하단에 구성된 Ray를 통해 수많은 워커(Worker)에 걸쳐 임베딩 생성 및 쿼리를 확장합니다.
이 조합은 에이전트, 임베드, 저장, 검색, 확장에 이르는 전체 파이프라인을 커버합니다.
비디오 로드 및 구체화(Materializing)
HuggingFace의 FineVideo라는 샘플 데이터셋으로 시작하겠습니다. 로더는 원본 비디오 바이트와 함께 캡션, 제목, ID, 메타데이터가 포함된 RecordBatch를 생성합니다.
def load_videos(): dataset = load_dataset("HuggingFaceFV/finevideo", split="train", streaming=True) batch = [] processed = 0 for row in dataset: if processed >= 10: break video_bytes = row['mp4'] json_metadata = row['json'] batch.append({ "video": video_bytes, "caption": json_metadata.get("youtube_title", "No description"), "youtube_title": json_metadata.get("youtube_title", ""), "video_id": f"video_{processed}", "duration": json_metadata.get("duration_seconds", 0), "resolution": json_metadata.get("resolution", "") }) processed += 1 return pa.RecordBatch.from_pylist(batch)
이를 통해 원본 비디오 바이트와 사람이 읽을 수 있는 메타데이터를 모두 포함하는 테이블이 생성됩니다. 비디오 데이터와 구조화된 데이터를 분리할 필요가 없다는 것이 장점입니다. LanceDB가 두 가지 모두를 매끄럽게 처리해 줍니다.
Geneva를 사용하여 이 데이터셋을 LanceDB 지원 테이블로 구체화합니다.
db = geneva.connect("/content/quickstart/") tbl = db.create_table("videos", load_videos(), mode="overwrite")
이제 비디오 임베디드 데이터베이스가 준비되었습니다. 임베딩을 추가하기 전이라도, 이 구조 덕분에 쿼리 실행, 변환 또는 시각화 작업을 손쉽게 진행할 수 있습니다.
TwelveLabs로 비디오 임베딩하기
다음 단계는 TwelveLabs의 Marengo 2.7 모델을 사용하여 임베딩을 생성하는 것입니다. 이 모델은 비디오의 의미를 나타내는 1024차원 벡터를 출력합니다. 전체 비디오 임베딩을 얻기 위해 "clip"과 "video" 범위를 모두 사용합니다.
task = client.embed.tasks.create( model_name="Marengo-retrieval-2.7", video_file=video_file, video_embedding_scope=["clip", "video"] ) status = client.embed.tasks.wait_for_done(task.id) result = client.embed.tasks.retrieve(task.id) video_segments = [seg for seg in result.video_embedding.segments if seg.embedding_scope == "video"] embedding_array = np.array(video_segments[0].float_, dtype=np.float32)
여기서는 clip과 video 범위를 모두 요청하여 비디오의 전체 맥락을 포착하도록 합니다. 이 벡터는 시각적 요소와 소리의 패턴을 모두 포착하므로, 메타데이터가 부족하더라도 유사한 행동들이 함께 그룹화됩니다.
Geneva를 사용하면 임베딩이 테이블의 또 다른 열이 됩니다.
tbl.add_columns({"embedding": GenVideoEmbeddings( twelve_labs_api_key=os.environ['TWELVE_LABS_API_KEY'] )}) tbl.backfill("embedding", concurrency=1)
backfill 호출은 모든 행을 처리하고 임베딩을 계산합니다. 개발 단계에서는 동시성(concurrency)을 1로 설정하지만, 실제 서비스 환경에서 Geneva는 높은 동시성으로 실행되어 Ray가 여러 워커에 작업을 분산하고 병렬로 처리할 수 있도록 지원합니다. 이것이 바로 수십 개의 비디오에서 시작해 수백만 개 규모로 손쉽게 확장하는 방법입니다.
LanceDB로 검색하기
임베딩이 저장되면 LanceDB는 벡터 검색을 위한 직관적인 API를 제공합니다. 일반 텍스트로 쿼리를 보내면 TwelveLabs가 이를 임베딩하고, LanceDB에서 비디오 벡터와 비교합니다.
query = "educational tutorial" query_result = client.embed.create( model_name="Marengo-retrieval-2.7", text=query ) qvec = np.array(query_result.text_embedding.segments[0].float_) lance_db = lancedb.connect("/content/quickstart/") lance_tbl = lance_db.open_table("videos") results = (lance_tbl .search(qvec) .metric("cosine") .limit(3) .to_pandas())
LanceDB는 Arrow 기반으로 네이티브 구현되어 있어 결과가 pandas DataFrame으로 반환됩니다. 이를 통해 분석 툴이나 웹 애플리케이션과의 연동이 매우 간단해집니다.
Pegasus로 요약하기
때로는 벡터 일치 결과만으로는 충분하지 않습니다. TwelveLabs는 비디오 요약을 생성하는 Pegasus도 제공합니다. 이러한 요약본을 LanceDB의 또 다른 열로 추가하여 검색 결과를 사용자가 더 직관적으로 이해할 수 있도록 만들 수 있습니다.
index = client.indexes.create( index_name=f"lancedb_demo_{int(time.time())}", models=[{"model_name": "pegasus1.2", "model_options": ["visual", "audio"]}] )
이 과정을 적용하면 각 추천 비디오와 함께 사람이 쉽게 읽을 수 있는 짧은 요약본을 보여줄 수 있어 사용자 경험이 한층 향상됩니다.
Geneva와 Ray로 규모 확장하기
Geneva가 없다면 수집 및 임베딩 작업을 수동으로 관리해야 합니다. 소수의 비디오라면 괜찮겠지만, 규모가 커지면 무리가 따릅니다. Geneva는 선언적 파이프라인을 구축해 주며, Ray는 이를 병렬로 실행합니다.
주요 고려 사항 | LanceDB 단독 사용 시 | Geneva 및 Ray 사용 시 |
데이터 수집 | 수동 로더 | 선언적 파이프라인 |
임베딩 | 순차적 처리 | 여러 워커를 이용한 병렬 처리 |
저장소 | 로컬 테이블 | 분산 LanceDB 테이블 |
ML 및 분석 | 커스텀 스크립트 작성 | 내장 분산 UDF 지원 |
즉, 워크플로를 다시 작성할 필요 없이 로컬에서 프로토타입을 제작한 다음 바로 클러스터 생산 환경으로 손쉽게 업그레이드할 수 있습니다.
결론
TwelveLabs, LanceDB, Geneva를 올바르게 결합하면 비디오 콘텐츠를 직접 이해하는 강력한 추천 시스템을 구축할 수 있습니다.
TwelveLabs는 키워드를 넘어서 의미를 포착하는 임베딩과 요약을 제공합니다.
LanceDB는 사용하기 쉬우며 임베디드 데이터베이스로 동작하고, 비디오, 이미지, 텍스트, 벡터 등의 멀티모달 데이터를 효율적으로 보관합니다.
Ray를 탑재한 Geneva를 사용하면 동일한 코드로 로컬 개발 단계에서 분산 클러스터 인프라까지 스케일아웃을 투명하게 해결할 수 있습니다.
이 스택은 대규모의 시맨틱 비디오 추천 기능이 필요한 미디어 플랫폼, 교육용 앱, 분석 도구를 위한 완벽하고 실용적인 기반을 제공합니다.
직접 시도해 보세요
TwelveLabs Playground – API 키를 등록하고 즉시 비디오 임베딩을 만들어보세요: https://playground.twelvelabs.io
LanceDB 빠른 시작 가이드 (Quickstart) – 로컬 환경에 LanceDB를 설치하고 Python으로 첫 벡터 검색을 시작해 보세요: https://lancedb.com/docs/quickstart
Geneva 공식 문서 – Ray를 이용한 임베딩 배포 확장 및 파이프라인 관리 방식을 알아보세요: https://lancedb.com/docs/geneva
본 튜토리얼 전체 노트북 – 작동 가능한 실행 코드를 상세히 확인하고 직접 테스트해 보세요: https://colab.research.google.com/drive/1jZiMT1QFYGvPgrps2Vpge9CtlRKFY1L0?usp=sharing#scrollTo=046o2pt62413
참고: 이 포스트의 예제들은 가독성을 위해 간략화된 샘플 코드를 사용합니다. 실행 가능한 노트북에서 전체 코드를 확인하고 싶으시다면, 여기에서 찾으실 수 있습니다.
대부분의 추천 시스템은 제목, 태그, 자막과 같은 메타데이터에 의존합니다. 이 방식도 유효하지만, 비디오 내부에서 실제로 일어나고 있는 일을 놓치게 됩니다. 만약 시스템이 시각 및 청각 콘텐츠 자체를 이해할 수 있다면 어떨까요?
이 포스트에서는 TwelveLabs, LanceDB, 그리고 LanceDB의 피처 엔지니어링 패키지인 Geneva를 사용하여 시맨틱 추천 엔진을 구축하는 방법을 보여드립니다. 이 시나리오에서 TwelveLabs는 비디오의 의미를 나타내는 강력한 멀티모달 임베딩을 제공합니다. LanceDB는 이러한 임베딩을 메타데이터와 함께 저장하고 간단한 Python API를 통해 빠른 벡터 검색을 제공합니다. Geneva는 LanceDB를 기반으로 Ray를 사용하여 클러스터 전체로 파이프라인을 확장하므로, 노트북에서 실행한 것과 완전히 동일한 코드를 수백 대의 머신에서 실행할 수 있습니다.
왜 TwelveLabs, LanceDB, Geneva 조합일까요?
TwelveLabs를 사용하면 내러티브의 흐름, 분위기, 행동을 포착하는 방식으로 비디오를 임베딩할 수 있습니다. "석양 아래에서 파도를 타는 서퍼"와 같은 쿼리는 해당 클립에 그러한 태그가 지정되어 있지 않더라도 일치하는 결과를 반환할 수 있습니다.
LanceDB는 Apache Arrow를 기반으로 구축된 벡터 데이터베이스입니다. 세 가지 주요 강점이 있습니다:
개발자에게 친숙하고 직관적인 간단한 Python API.
외부 서비스 필요 없이 로컬에서 실행되는 임베디드 데이터베이스.
비디오, 이미지, 텍스트, 벡터를 모두 간편하게 저장할 수 있는 네이티브 멀티모달 지원.
Geneva는 LanceDB를 기반으로 구축되어 분산 데이터 처리를 추가합니다. 하단에 구성된 Ray를 통해 수많은 워커(Worker)에 걸쳐 임베딩 생성 및 쿼리를 확장합니다.
이 조합은 에이전트, 임베드, 저장, 검색, 확장에 이르는 전체 파이프라인을 커버합니다.
비디오 로드 및 구체화(Materializing)
HuggingFace의 FineVideo라는 샘플 데이터셋으로 시작하겠습니다. 로더는 원본 비디오 바이트와 함께 캡션, 제목, ID, 메타데이터가 포함된 RecordBatch를 생성합니다.
def load_videos(): dataset = load_dataset("HuggingFaceFV/finevideo", split="train", streaming=True) batch = [] processed = 0 for row in dataset: if processed >= 10: break video_bytes = row['mp4'] json_metadata = row['json'] batch.append({ "video": video_bytes, "caption": json_metadata.get("youtube_title", "No description"), "youtube_title": json_metadata.get("youtube_title", ""), "video_id": f"video_{processed}", "duration": json_metadata.get("duration_seconds", 0), "resolution": json_metadata.get("resolution", "") }) processed += 1 return pa.RecordBatch.from_pylist(batch)
이를 통해 원본 비디오 바이트와 사람이 읽을 수 있는 메타데이터를 모두 포함하는 테이블이 생성됩니다. 비디오 데이터와 구조화된 데이터를 분리할 필요가 없다는 것이 장점입니다. LanceDB가 두 가지 모두를 매끄럽게 처리해 줍니다.
Geneva를 사용하여 이 데이터셋을 LanceDB 지원 테이블로 구체화합니다.
db = geneva.connect("/content/quickstart/") tbl = db.create_table("videos", load_videos(), mode="overwrite")
이제 비디오 임베디드 데이터베이스가 준비되었습니다. 임베딩을 추가하기 전이라도, 이 구조 덕분에 쿼리 실행, 변환 또는 시각화 작업을 손쉽게 진행할 수 있습니다.
TwelveLabs로 비디오 임베딩하기
다음 단계는 TwelveLabs의 Marengo 2.7 모델을 사용하여 임베딩을 생성하는 것입니다. 이 모델은 비디오의 의미를 나타내는 1024차원 벡터를 출력합니다. 전체 비디오 임베딩을 얻기 위해 "clip"과 "video" 범위를 모두 사용합니다.
task = client.embed.tasks.create( model_name="Marengo-retrieval-2.7", video_file=video_file, video_embedding_scope=["clip", "video"] ) status = client.embed.tasks.wait_for_done(task.id) result = client.embed.tasks.retrieve(task.id) video_segments = [seg for seg in result.video_embedding.segments if seg.embedding_scope == "video"] embedding_array = np.array(video_segments[0].float_, dtype=np.float32)
여기서는 clip과 video 범위를 모두 요청하여 비디오의 전체 맥락을 포착하도록 합니다. 이 벡터는 시각적 요소와 소리의 패턴을 모두 포착하므로, 메타데이터가 부족하더라도 유사한 행동들이 함께 그룹화됩니다.
Geneva를 사용하면 임베딩이 테이블의 또 다른 열이 됩니다.
tbl.add_columns({"embedding": GenVideoEmbeddings( twelve_labs_api_key=os.environ['TWELVE_LABS_API_KEY'] )}) tbl.backfill("embedding", concurrency=1)
backfill 호출은 모든 행을 처리하고 임베딩을 계산합니다. 개발 단계에서는 동시성(concurrency)을 1로 설정하지만, 실제 서비스 환경에서 Geneva는 높은 동시성으로 실행되어 Ray가 여러 워커에 작업을 분산하고 병렬로 처리할 수 있도록 지원합니다. 이것이 바로 수십 개의 비디오에서 시작해 수백만 개 규모로 손쉽게 확장하는 방법입니다.
LanceDB로 검색하기
임베딩이 저장되면 LanceDB는 벡터 검색을 위한 직관적인 API를 제공합니다. 일반 텍스트로 쿼리를 보내면 TwelveLabs가 이를 임베딩하고, LanceDB에서 비디오 벡터와 비교합니다.
query = "educational tutorial" query_result = client.embed.create( model_name="Marengo-retrieval-2.7", text=query ) qvec = np.array(query_result.text_embedding.segments[0].float_) lance_db = lancedb.connect("/content/quickstart/") lance_tbl = lance_db.open_table("videos") results = (lance_tbl .search(qvec) .metric("cosine") .limit(3) .to_pandas())
LanceDB는 Arrow 기반으로 네이티브 구현되어 있어 결과가 pandas DataFrame으로 반환됩니다. 이를 통해 분석 툴이나 웹 애플리케이션과의 연동이 매우 간단해집니다.
Pegasus로 요약하기
때로는 벡터 일치 결과만으로는 충분하지 않습니다. TwelveLabs는 비디오 요약을 생성하는 Pegasus도 제공합니다. 이러한 요약본을 LanceDB의 또 다른 열로 추가하여 검색 결과를 사용자가 더 직관적으로 이해할 수 있도록 만들 수 있습니다.
index = client.indexes.create( index_name=f"lancedb_demo_{int(time.time())}", models=[{"model_name": "pegasus1.2", "model_options": ["visual", "audio"]}] )
이 과정을 적용하면 각 추천 비디오와 함께 사람이 쉽게 읽을 수 있는 짧은 요약본을 보여줄 수 있어 사용자 경험이 한층 향상됩니다.
Geneva와 Ray로 규모 확장하기
Geneva가 없다면 수집 및 임베딩 작업을 수동으로 관리해야 합니다. 소수의 비디오라면 괜찮겠지만, 규모가 커지면 무리가 따릅니다. Geneva는 선언적 파이프라인을 구축해 주며, Ray는 이를 병렬로 실행합니다.
주요 고려 사항 | LanceDB 단독 사용 시 | Geneva 및 Ray 사용 시 |
데이터 수집 | 수동 로더 | 선언적 파이프라인 |
임베딩 | 순차적 처리 | 여러 워커를 이용한 병렬 처리 |
저장소 | 로컬 테이블 | 분산 LanceDB 테이블 |
ML 및 분석 | 커스텀 스크립트 작성 | 내장 분산 UDF 지원 |
즉, 워크플로를 다시 작성할 필요 없이 로컬에서 프로토타입을 제작한 다음 바로 클러스터 생산 환경으로 손쉽게 업그레이드할 수 있습니다.
결론
TwelveLabs, LanceDB, Geneva를 올바르게 결합하면 비디오 콘텐츠를 직접 이해하는 강력한 추천 시스템을 구축할 수 있습니다.
TwelveLabs는 키워드를 넘어서 의미를 포착하는 임베딩과 요약을 제공합니다.
LanceDB는 사용하기 쉬우며 임베디드 데이터베이스로 동작하고, 비디오, 이미지, 텍스트, 벡터 등의 멀티모달 데이터를 효율적으로 보관합니다.
Ray를 탑재한 Geneva를 사용하면 동일한 코드로 로컬 개발 단계에서 분산 클러스터 인프라까지 스케일아웃을 투명하게 해결할 수 있습니다.
이 스택은 대규모의 시맨틱 비디오 추천 기능이 필요한 미디어 플랫폼, 교육용 앱, 분석 도구를 위한 완벽하고 실용적인 기반을 제공합니다.
직접 시도해 보세요
TwelveLabs Playground – API 키를 등록하고 즉시 비디오 임베딩을 만들어보세요: https://playground.twelvelabs.io
LanceDB 빠른 시작 가이드 (Quickstart) – 로컬 환경에 LanceDB를 설치하고 Python으로 첫 벡터 검색을 시작해 보세요: https://lancedb.com/docs/quickstart
Geneva 공식 문서 – Ray를 이용한 임베딩 배포 확장 및 파이프라인 관리 방식을 알아보세요: https://lancedb.com/docs/geneva
본 튜토리얼 전체 노트북 – 작동 가능한 실행 코드를 상세히 확인하고 직접 테스트해 보세요: https://colab.research.google.com/drive/1jZiMT1QFYGvPgrps2Vpge9CtlRKFY1L0?usp=sharing#scrollTo=046o2pt62413
참고: 이 포스트의 예제들은 가독성을 위해 간략화된 샘플 코드를 사용합니다. 실행 가능한 노트북에서 전체 코드를 확인하고 싶으시다면, 여기에서 찾으실 수 있습니다.
대부분의 추천 시스템은 제목, 태그, 자막과 같은 메타데이터에 의존합니다. 이 방식도 유효하지만, 비디오 내부에서 실제로 일어나고 있는 일을 놓치게 됩니다. 만약 시스템이 시각 및 청각 콘텐츠 자체를 이해할 수 있다면 어떨까요?
이 포스트에서는 TwelveLabs, LanceDB, 그리고 LanceDB의 피처 엔지니어링 패키지인 Geneva를 사용하여 시맨틱 추천 엔진을 구축하는 방법을 보여드립니다. 이 시나리오에서 TwelveLabs는 비디오의 의미를 나타내는 강력한 멀티모달 임베딩을 제공합니다. LanceDB는 이러한 임베딩을 메타데이터와 함께 저장하고 간단한 Python API를 통해 빠른 벡터 검색을 제공합니다. Geneva는 LanceDB를 기반으로 Ray를 사용하여 클러스터 전체로 파이프라인을 확장하므로, 노트북에서 실행한 것과 완전히 동일한 코드를 수백 대의 머신에서 실행할 수 있습니다.
왜 TwelveLabs, LanceDB, Geneva 조합일까요?
TwelveLabs를 사용하면 내러티브의 흐름, 분위기, 행동을 포착하는 방식으로 비디오를 임베딩할 수 있습니다. "석양 아래에서 파도를 타는 서퍼"와 같은 쿼리는 해당 클립에 그러한 태그가 지정되어 있지 않더라도 일치하는 결과를 반환할 수 있습니다.
LanceDB는 Apache Arrow를 기반으로 구축된 벡터 데이터베이스입니다. 세 가지 주요 강점이 있습니다:
개발자에게 친숙하고 직관적인 간단한 Python API.
외부 서비스 필요 없이 로컬에서 실행되는 임베디드 데이터베이스.
비디오, 이미지, 텍스트, 벡터를 모두 간편하게 저장할 수 있는 네이티브 멀티모달 지원.
Geneva는 LanceDB를 기반으로 구축되어 분산 데이터 처리를 추가합니다. 하단에 구성된 Ray를 통해 수많은 워커(Worker)에 걸쳐 임베딩 생성 및 쿼리를 확장합니다.
이 조합은 에이전트, 임베드, 저장, 검색, 확장에 이르는 전체 파이프라인을 커버합니다.
비디오 로드 및 구체화(Materializing)
HuggingFace의 FineVideo라는 샘플 데이터셋으로 시작하겠습니다. 로더는 원본 비디오 바이트와 함께 캡션, 제목, ID, 메타데이터가 포함된 RecordBatch를 생성합니다.
def load_videos(): dataset = load_dataset("HuggingFaceFV/finevideo", split="train", streaming=True) batch = [] processed = 0 for row in dataset: if processed >= 10: break video_bytes = row['mp4'] json_metadata = row['json'] batch.append({ "video": video_bytes, "caption": json_metadata.get("youtube_title", "No description"), "youtube_title": json_metadata.get("youtube_title", ""), "video_id": f"video_{processed}", "duration": json_metadata.get("duration_seconds", 0), "resolution": json_metadata.get("resolution", "") }) processed += 1 return pa.RecordBatch.from_pylist(batch)
이를 통해 원본 비디오 바이트와 사람이 읽을 수 있는 메타데이터를 모두 포함하는 테이블이 생성됩니다. 비디오 데이터와 구조화된 데이터를 분리할 필요가 없다는 것이 장점입니다. LanceDB가 두 가지 모두를 매끄럽게 처리해 줍니다.
Geneva를 사용하여 이 데이터셋을 LanceDB 지원 테이블로 구체화합니다.
db = geneva.connect("/content/quickstart/") tbl = db.create_table("videos", load_videos(), mode="overwrite")
이제 비디오 임베디드 데이터베이스가 준비되었습니다. 임베딩을 추가하기 전이라도, 이 구조 덕분에 쿼리 실행, 변환 또는 시각화 작업을 손쉽게 진행할 수 있습니다.
TwelveLabs로 비디오 임베딩하기
다음 단계는 TwelveLabs의 Marengo 2.7 모델을 사용하여 임베딩을 생성하는 것입니다. 이 모델은 비디오의 의미를 나타내는 1024차원 벡터를 출력합니다. 전체 비디오 임베딩을 얻기 위해 "clip"과 "video" 범위를 모두 사용합니다.
task = client.embed.tasks.create( model_name="Marengo-retrieval-2.7", video_file=video_file, video_embedding_scope=["clip", "video"] ) status = client.embed.tasks.wait_for_done(task.id) result = client.embed.tasks.retrieve(task.id) video_segments = [seg for seg in result.video_embedding.segments if seg.embedding_scope == "video"] embedding_array = np.array(video_segments[0].float_, dtype=np.float32)
여기서는 clip과 video 범위를 모두 요청하여 비디오의 전체 맥락을 포착하도록 합니다. 이 벡터는 시각적 요소와 소리의 패턴을 모두 포착하므로, 메타데이터가 부족하더라도 유사한 행동들이 함께 그룹화됩니다.
Geneva를 사용하면 임베딩이 테이블의 또 다른 열이 됩니다.
tbl.add_columns({"embedding": GenVideoEmbeddings( twelve_labs_api_key=os.environ['TWELVE_LABS_API_KEY'] )}) tbl.backfill("embedding", concurrency=1)
backfill 호출은 모든 행을 처리하고 임베딩을 계산합니다. 개발 단계에서는 동시성(concurrency)을 1로 설정하지만, 실제 서비스 환경에서 Geneva는 높은 동시성으로 실행되어 Ray가 여러 워커에 작업을 분산하고 병렬로 처리할 수 있도록 지원합니다. 이것이 바로 수십 개의 비디오에서 시작해 수백만 개 규모로 손쉽게 확장하는 방법입니다.
LanceDB로 검색하기
임베딩이 저장되면 LanceDB는 벡터 검색을 위한 직관적인 API를 제공합니다. 일반 텍스트로 쿼리를 보내면 TwelveLabs가 이를 임베딩하고, LanceDB에서 비디오 벡터와 비교합니다.
query = "educational tutorial" query_result = client.embed.create( model_name="Marengo-retrieval-2.7", text=query ) qvec = np.array(query_result.text_embedding.segments[0].float_) lance_db = lancedb.connect("/content/quickstart/") lance_tbl = lance_db.open_table("videos") results = (lance_tbl .search(qvec) .metric("cosine") .limit(3) .to_pandas())
LanceDB는 Arrow 기반으로 네이티브 구현되어 있어 결과가 pandas DataFrame으로 반환됩니다. 이를 통해 분석 툴이나 웹 애플리케이션과의 연동이 매우 간단해집니다.
Pegasus로 요약하기
때로는 벡터 일치 결과만으로는 충분하지 않습니다. TwelveLabs는 비디오 요약을 생성하는 Pegasus도 제공합니다. 이러한 요약본을 LanceDB의 또 다른 열로 추가하여 검색 결과를 사용자가 더 직관적으로 이해할 수 있도록 만들 수 있습니다.
index = client.indexes.create( index_name=f"lancedb_demo_{int(time.time())}", models=[{"model_name": "pegasus1.2", "model_options": ["visual", "audio"]}] )
이 과정을 적용하면 각 추천 비디오와 함께 사람이 쉽게 읽을 수 있는 짧은 요약본을 보여줄 수 있어 사용자 경험이 한층 향상됩니다.
Geneva와 Ray로 규모 확장하기
Geneva가 없다면 수집 및 임베딩 작업을 수동으로 관리해야 합니다. 소수의 비디오라면 괜찮겠지만, 규모가 커지면 무리가 따릅니다. Geneva는 선언적 파이프라인을 구축해 주며, Ray는 이를 병렬로 실행합니다.
주요 고려 사항 | LanceDB 단독 사용 시 | Geneva 및 Ray 사용 시 |
데이터 수집 | 수동 로더 | 선언적 파이프라인 |
임베딩 | 순차적 처리 | 여러 워커를 이용한 병렬 처리 |
저장소 | 로컬 테이블 | 분산 LanceDB 테이블 |
ML 및 분석 | 커스텀 스크립트 작성 | 내장 분산 UDF 지원 |
즉, 워크플로를 다시 작성할 필요 없이 로컬에서 프로토타입을 제작한 다음 바로 클러스터 생산 환경으로 손쉽게 업그레이드할 수 있습니다.
결론
TwelveLabs, LanceDB, Geneva를 올바르게 결합하면 비디오 콘텐츠를 직접 이해하는 강력한 추천 시스템을 구축할 수 있습니다.
TwelveLabs는 키워드를 넘어서 의미를 포착하는 임베딩과 요약을 제공합니다.
LanceDB는 사용하기 쉬우며 임베디드 데이터베이스로 동작하고, 비디오, 이미지, 텍스트, 벡터 등의 멀티모달 데이터를 효율적으로 보관합니다.
Ray를 탑재한 Geneva를 사용하면 동일한 코드로 로컬 개발 단계에서 분산 클러스터 인프라까지 스케일아웃을 투명하게 해결할 수 있습니다.
이 스택은 대규모의 시맨틱 비디오 추천 기능이 필요한 미디어 플랫폼, 교육용 앱, 분석 도구를 위한 완벽하고 실용적인 기반을 제공합니다.
직접 시도해 보세요
TwelveLabs Playground – API 키를 등록하고 즉시 비디오 임베딩을 만들어보세요: https://playground.twelvelabs.io
LanceDB 빠른 시작 가이드 (Quickstart) – 로컬 환경에 LanceDB를 설치하고 Python으로 첫 벡터 검색을 시작해 보세요: https://lancedb.com/docs/quickstart
Geneva 공식 문서 – Ray를 이용한 임베딩 배포 확장 및 파이프라인 관리 방식을 알아보세요: https://lancedb.com/docs/geneva
본 튜토리얼 전체 노트북 – 작동 가능한 실행 코드를 상세히 확인하고 직접 테스트해 보세요: https://colab.research.google.com/drive/1jZiMT1QFYGvPgrps2Vpge9CtlRKFY1L0?usp=sharing#scrollTo=046o2pt62413





